This is my biggest criticism of JavaScript: it fails silently quite often. `{}.foo` returning `undefined` is the most common culprit, but there are many other possible causes.
Django templates also do this, which causes all sorts of debugging problems.
The worst part about javascript failing is a lot of time it doesn't do it at the thing that is the problem.
I've run into a lot of cases in node where I passed something not quite right to a crypt library but didn't find out until like 2 pages later. Usually for things that in python would throw an exception immediately.
That's not really a Javascript problem. That's a dynamically typed language problem. Unless you add some kind of assertion/test at the entry point to a library, the failure will always be postponed to the point of use (or silent if it's never used, until the day someone turns a feature on). If the same sort of issue works differently in Python, the Python library has asserts or other tests, or is using the value at an earlier point so it's more easily discovered.
As pointed out, {}.foo will not cause an error. In Python and any good dynamic language, that will generate an error.
Another problem is all the implicit (silent) type conversions. JavaScript will happily add an Object and an integer, then multiply that by a string. Any sensible type system would not allow that, but JavaScript silently produces a NaN.
The problem isn't that its a dynamic type system, but that the type system ignores things which are clearly problems.
> That's not really a Javascript problem. That's a dynamically typed language problem.
I disagree; I do a lot of work in both dynamic and strongly typed languages. Most often, when I find a bug "not where the error occurs," it's because, for example, I'm accidentally computing a minimum and later assuming it to be a maximum. Unit tests catch most of this, so such debugging puzzles usually happen to me in fresh new code with unstable interfaces...
No, it's definitely a JavaScript problem. Dynamic languages like Python are perfectly capable of throwing exceptions when you reference a property that doesn't exist.
Failing silently makes sense in a language like C, where performance is a high priority and you can avoid adding assertions for performance. But JavaScript has to add an assertion to return an undefined value anyway, so you're not even getting a performance benefit from it. It's purely bad design with no benefit.
Coming from python, my other least favorite javascript-ism is that you can call functions with the wrong number of parameters and it'll just set the missing ones as undefined and assume that's what you meant to do.
Maybe people who are used to js take advantage of this and do it on purpose, but from my perspective all it's done is take mistakes and move the errors farther downstream so that you can't trivially find where the problem started.
If I wanted a function to accept a variable number of parameters or have default values for a parameter that can be omitted, I would much rather have to have to define that behavior per function.
It's possible to configure Django to display some placeholder ("FIXME", for example) or raise an exception when non-existent variable is accessed in template. It can be enabled in the TEMPLATES configuration. And it's better to enable it early during development because it's extremely hard to enable this in any moderately big project: too many pages begin to fail.
For example, in ETL pipelines, I would greatly prefer to have an entire DAG go down quickly and noisily than to risk having it generate incorrect data. It's the difference between a crappy morning, and a crappy day or even a crappy week.
Just curious since a lot of my work is on an ETL - what are your favorite DAG libraries/approaches? Some of my ETL workflows can run in parallel with each other because there aren't data dependencies between them, and others should definitely crash loudly
We use a home-grown solution, and try to keep it pretty minimal. For example, we can run all our pipeline steps serially and still get all the work done plenty fast, so, for now, we're keeping that parallelism can of worms firmly shut.
It's also viable because it's the convention. Library calls are likely to return {error, {the bad data you sent}} so it's easy to write receive {error, _) -> {missiles, {launch false}} end.
And, the fact that an Erlang server is explicitly intended for handling zillions of tiny, independent requests. A request fails? Meh. They'll call again if it's important. What matters now is the next tiny, independent request.
What he might be getting at, that others have certainly discussed, is that things like "crash only software!" are not winning marketing slogans when trying to sell a piece of technology to higher-ups in your company.
It reminds me of how people love, for marketing purposes, to have technology, say in vehicles, that is "adaptive". In software in general, but particularly in cars, there is nothing I hate more. Because "adaptive" makes people think of a partner that anticipates your needs, but it can't do that, not being intelligent so adaptive ends up being the opposite of responsive.
i'm a huge fan of erlang and i'm familiar w/ this philosophy and tend to have a hard time w/ applying it. when i develop software, i read man pages for the functions i call. i intently study their return values and do my best to address whatever conditions i can at that moment. if i'm unable to handle the fault, i generate a message with the intent to add context to the error and let it bubble up. that context is important. it's _very_ beneficial when a failure does occur because i can quickly ascertain the root cause due to my diligence in annotating the _BAD_ path with context--all the way to the top of the function stack.
i've noticed that when erlang programs crash, the error message and stack trace is a WTF moment. i hate that. so yes, there are all these benefits when focusing on the happy path, but there are down sides, can we explorer those? once software is written, it's how the _BAD_ path is presented to maintainers that matters. this philosophy, in my current understanding, throws those people under the bus.
Django templates also do this, which causes all sorts of debugging problems.