JavaScript actually handles async IO nicely, and I've never heard this term before (callback hell, yes). So promises and async/await sugar actually make it pretty nice.
> poor ecosystem
Ecosystem is fine, just don't jump on everything new. The well-known problem is standard library, it is indeed a problem, usually addressed with a mix of additional packages.
> For the extra tax you pay in terms of build pipeline
This pipeline is norm in the frontend development, so in case you have people proficient in tooling, it is not that high (of course, it is hard if you have Java developers).
> Typescript vs Javascript as if these are the only two possible options for web development
They are not, but the nice thing about it is that you can have almost the same tooling as on your frontend, if you have some sort of complex application. So that increases speed of development, and TypeScript gives you some sense of scalability.
Last part is that TypeScript can be adopted incrementally, while another languages will require complete rewrite (and different deployment, etc).
As you put it, "Once you get into the controllers they tend to become entirely procedural and effectively completely synchronous" but that's because for most people it's far easier to think about a problem as a series of individual steps. Even then, if you have a bunch of serial awaits it's usually pretty trivial to go back and then await on a Promise.all() if you realize things can be run concurrently.
I see this over and over.
"Thing thing = await loadThing(); ": Start loading thing, then await so the main thread can continue doing other stuff while thing is loaded.
"Thing other = await thing.doSomething();": Invoke some other function that does some stuff in the background, then await so the main thread can continue doing other stuff while thing does something.
"thing = await saveThing();": Saving can often be done in parallel so no need to block the App while something is saved. Invoke the save function, then await so the main thread can continue doing other stuff while thing is saved.
This gets you the advantages of async programming while still maintaining a legible coding style that looks similar to common synchronous code.
You sound like we can be innovative on how we code but how can steps that do
- Parse inputs
- Query database
- Return output
be asynchronous?
Unless I'm writing a background job that is decoupled from HTTP requests, everything after the router is synchronous.
Can you elaborate on promise fatigue. In our setup we use async/await and the latest ES (although most of us prefer not using decorators if we don't have to - only used it with mobx for UI code) bundled through webpack.
I am not sure what you mean by poor eco-system either. Both JS and TS (increasingly), I feel like is the second best eco-system (in terms of libraries and tooling) after a mainstream language like Java.
There are some warts I think in JS (around numbers, stream handling in pipes), but I think very few languages don't, and it depends on how likely you would be fiddling in those areas.
Extra tax on build pipeline cannot be escaped for anything with any complexity.
I feel like anyone who can write a complex app in good js, refactoring along the way at good speed, and meeting deadlines along the way and not introducing too many regressions, and come back and maintain it after a 6 month context switch, either has way too much time on his hands and/or works too many hours, or is much more smarter than I am and has it figured out.
These are all, at the end of the day, XY-style problems whose suboptimal answers can snowball into unmaintainable code. I do think there is a serious lack of training material in this area, though.
I'm interested in learning more about this, any other keywords I should throw in if I start Googling about it?
So it makes absolute sense to write the backend in the same language...if you can. Typescript goes a long way in making this pleasant.
Nothing is stopping you from writing the backend in different language...but as an organization, you lose the advantage of shared thinking in one stack.
I'd argue that buying into a more comprehensive language would probably be worth it if everyone was into it, but in my own experience JS devs really, really like JS and have very little interest in learning something better suited to the problem they're solving. This is true outside of software too. People love familiar tools and methods, even if they aren't the best ones.
There's also the fact that your team's output will be best based on their enjoyment and engagement. Even if the tooling isn't perfect, they'll probably build better software if they're enjoying it. JS and TS are good enough in most cases to get teams where they need to be.
Actually, async-await is a nice feature of the JS paradigm that simplifies things and that I miss in the threaded world of Java.
But yes - use TS where you would have used JS, but TS up against other, more classical languages may not be the right choice for a lot of non-web projects.
You can start this promise early, await two parallel DB request + one API request, branch off some more async work depending on a response, await that initial promise that had a head-start because now you actually need it, and then run 10 tasks with no more than 3 in-flight at a given moment. And the code would look exactly how I just described it. And it's ubiquitous.
It's a good tool in the belt and imo the most trivial async implementation out there.
In my own Hades moment -- Microsoft know how to build great developer tools. The developer ergonomics of TypeScript and Visual Studio Code are excellent. It's really quite surprising to see how far the JavaScript world has come.
Similarly, the DevOps world is becoming much (much) more JavaScript friendly. Serverless, Netlify, and things like AWS Amplify -- all with their foibles, but pushing JavaScript in meaningful ways. I don't think this is the case for many other languages/ecosystems.
Elm, bucklescript, Scala.js to name a few.
```
(defn simple-component []
[:div
[:p "I am a component!"]
[:p.someclass
"I have " [:strong "bold"]
[:span {:style {:color "red"}} " and red "] "text."]])
```The problem is really the Node ecosystem, which is a mess and a circus of security issues. Deno[1] may fix most of JS/Node's problems eventually.
For now, if you want a type system that's comparable to TS with a great ecosystem, the best you can get is either F# or Kotlin. If you're not a fan of ML, then you might want to start with Kotlin.