It is tragic that the world standardized on Javascript. They are just now discovering some of the module issues that Prof. Wirth solved in his great Modula-2 langauge in 1974. His system allowed separate compilation, and a way to detect when the interface API changed so that it could be cross-checked. I used Modula-2 to great effect on very large projects, and am greatly relieved that the Modula-2 module system has more or less made it into JavaScript.
Aren't most large-scale javascript applications using typescript or flow these days? I definitely wouldn't try building a large scale javascript codebase without either of those anymore.
The downside of Typescript is the constant friction from bolting a type system on top of a dynamic ecosystem.
It's like Babel and Webpack where you incur time spent on debugging your own tooling and getting these systems to collaborate. By the time I put in the effort, I decided it was simpler to go all in and use a compile-to-JS language instead of something that tried to be Javascript with types.
This is 100% spot-on. With our web development product, Elevate Web Builder, the furthest that we went in the compiler with "giving in" to the dynamic typing in the target JS was a variant type. The rest has to be given an external interface declaration (classes, functions, and variables) that the compiler uses to type-check all calls to external JS or the built-in interfaces in the browser APIs. Other products have tried to allow for in-lining JS or simply include-ing it via special declarations, but that really handicaps what the compiler can do in terms of statically analyzing your codebase, which kind of defeats the whole purpose of using types in the first place.
It's quite possible that people feel they lack the technical baggage to cope with typescript's type system (typescript = javascript + types). However, I would argue that the same technical baggage is a prerequisite to be able to architect large-scale javascript front-ends. So, IMHO, in the context of large scale apps typescript or flow are a no-brainer.
The fact that it requires a build step turns out not to matter because everyone uses a babel / webpack pipeline anyway, so all that same complexity is there for regular javascript as well.
Front-end dev usually have a tight feedback loop. You don't want to wait longer then necessary to see your changes on the screen. You only run the build pipeline when you are about to push your updates into production.
I like TS a lot, but it's a different language so you need to transpile it. When webpack cached recompilation already takes up more than 30sec (which is the case for most of our routes), I will do everything in my power to keep it away from the project.
I haven't tried it myself but I'm pretty sure both TypeScript and Flow has support for JSdoc, so while you don't have to transpile your code you can still use it as a linter. And you should also get the auto-complete and re-factory goodies. Also note that TypeScript and flow can do inference, eg they can know the type without you annotating it. Microsoft will not fully support inference and doctype though as it's their strategy to Embrace and extend JavaScript, but they have tried for many years and not succeeded. Google also tried with Dart, which is a much better language but too complicated/hard to learn compared to JS. It's very nice that they make tools like static analysis for JavaScript, but they don't have to turn it into another language! For example instead of making the programmer write annotations everywhere, show a hint where inference fail and where interface is needed. Ohh and don't get me started on "correctness", even static type systems like in Java can't prove "correctness" and has to rely on runtime checks. And it's not like the type system will detect all bugs, just the obvious ones. And JavaScript is far from static, it can change many times during runtime. Instead of bolting on a type system, embrace the dynamic nature of JavaScript, and write dumb naive code that a five year old can understand. Use abstractions, use proper naming (even name the anonymous functions), comment where needed. Check function parameters and throw errors! And write tests!
It does have IDE support. VSCode, Visual Studio and WebStorm all support using jsdoc for autocomplete/intellisense.
So, the only thing it doesn't have is compile-time failures and I'm fine with that because I don't really make mistakes that often so I'm not doing a bunch of extra work to identify types for the compiler so it can help me find mistakes.
Famous last words. Everyone makes mistakes. All software has bugs!
But let's grant that you don't for the sake of argument. Is the rest of your team similarly infallible? Even if they are when writing code, will they be able to perfectly parse code they didn't write? What about when you're refactoring and you want to make sure you didn't forget to update any place a function is called? What about when you come back to the code in six months and don't remember what it does? What about when the code changes but you forget to update the JSDoc?
If you're writing something quick and don't have to work with people, sure, I'll buy that types are too much overhead. But when you start doing things at scale, they're a powerful tool for checking and documenting your code.
I’m with you. I actually prefer type systems when the language has them, however I find that languages that transpile to JS come with their own set of problems.
The jsdoc for my code is right next to the code so for all intents and purposes, it is the code. Intellisense for vars is always showing itself, to remind you if the jsdoc type is wrong.
It’s just a trade off, like many things in engineering. Millions of people have been coding in just JavaScript pretty well so far, so I wouldn’t limit the question to just my team.
Thank you. I should say that I don’t make that many mistakes when I’m typing in the code.
When I’m designing it, I make plenty of mistakes. When I’m picking out libraries to use, I make plenty of mistakes there too. Most of my mistakes come from architecting things incorrectly like recently, when I chose to make a huge app into an SPA instead of classic web app which would’ve been simpler and would’ve performed just fine.
The module system in nodejs is far superior as it lets you treat modules like variables, pass them around etc. The root of all complexity is that different code parts entangles. With local requre's all code parts can truly separate which makes it easy reuse and delete code. And you don't have to hunt a function/variable across the whole code base to figure out where and what it's used for.
And it also lazy loads the module. ES6 modules might be a 44 years old standard, but NodeJS modules are better !
For use on the web the web server could grep require from the source and push modules to the browser, so when a module is required it will be loaded from cache. The browser could even pre-parse the module to speed up run-time for when it's required.
worst case scenario is that the browser has to request it from the server. This is bad because the execution would have to stop and wait, but for most cases it would just be for a few milliseconds. And the developer should take that into account and maybe prep the cache for possible paths.