The problem is that if the system was world class then it might actually be ok if it was in js. Most codebases are a bit of a mess, like you say, and js just makes it much harder to figure out what is going on. It's not just a dynamic language, it seems to encourage a gratuitously dynamic style. So you have to figure out everything in the debugger. That is if you can even determine where to set a breakpoint!
Yeah, I actually agree with you especially for ES6. Because it requires you to transpile, and because promises/async/await break the control flow model, it is extremely difficult, often impossible to place breakpoints. With await in particular, you can forget to await a promise and then your app just stops working, mysteriously, and there’s no way to find out what’s happening except to one by one disable parts of the app until the situation becomes clear.
Transpilation as a norm means it’s kind of 50/50 whether the source code you encounter while debugging will even be readable.
Actually what I see most often, professionally, is that JavaScript developers stop believing they can inspect their application at all, and when something is wrong immediately just try to guess what’s happening. Then see if their imagined fix helps, if not try again. Basically guess and check. Which is a fine technique but it’s pretty bad if that’s your only way to debug problems.
I am able to code in ES5 sometimes on independent projects (without Webpack) and it’s a joy. The debugger works everywhere, in a consistent way. I have callbacks everywhere so asynchronous code is simple to trace and easy to understand. It’s great.
I am working slowly towards a fork of NPM/Node ecosystem that starts over before ES6. I think early JavaScript is actually a wonderful, fast, elegant language.
I would say that ES6 is so bad in terms of debuggability that you almost have to use TypeScript to make coding in ES6 bearable.
The other aspect of what you’re saying: that you have no static analysis tools so you HAVE to debug, is spot on. I think to build a great JS application you have to put an equal amount of effort into designing the test harness. Basically all the time you would have spent wrangling the type system you have to put into the tests.
And you can’t just half- ass the tests. They need to really accurately mirror your business needs, and really model the relationship between your app and your tests, in order to provide an equivalent static analysis value to what a type system would give you.
However one final point, which is that the fact that ES5 is so impoverished in terms of control flow and data modeling, I think actually helps solve all of these problems. If you limit yourselves to basically just functions and literals, you are forced to write really strong clean interfaces. I find myself being able to focus almost entirely on separation of concerns. Because I’m not dealing with fancy language features, and because I literally can’t afford to build giant complex modules and applications, it forces me to build small, simple modules that have very clear responsibilities.
That might seem like a limitation to many, but I actually find it helps me to avoid headaches before they happen.