If you have to use Javascript (you're building the front-end of a web app), then it seems like Typescript is probably a decent solution. For anything else it (or any form of Javascript) isn't the right tool for the job, in part for the reasons outlined in this post. Nothing is more frustrating than to see people build command line apps or servers with Typescript and bring all the added complexity and bad habits of the JS world to a place where much better solutions exist. Go, Rust even Zig are better choices than introducing the JS nightmare workflow and tooling where it doesn't belong.
I strongly disagree. Nothing is worse than developers being forced to work in a language they are not used to - not just because it's inefficient, but because they won't write it in an idiomatic way.
If all you have are TS developers, writing a CLI in TS is not just fine, it's the right decision. Forcing Rust upon them is not going to make anyone involved more happy.
I just don't get this way of thinking and can't imagine calling myself an "X developer". The human brain is more than capable of being proficient in more than one language. It's also boring only using one language every day. If all you have are TS developers, then IMHO, you don't have very good developers.
I think that’s not really relevant. Not every company can afford to have the best developers that can do everything. And not every developer wants to struggle through a new language for (unknown time) writing a tool (or anything) that could be done in an hour in a language they’re familiar with instead.
A lot of common screwdrivers can turn Philips head screws enough to get the job done.
Then imagine he said "all-round developers who in their current job spend 95%+ of their programming time writing Typescript", if that's less offensive.
His point remains. If someone is so uncomfortable in all other languages that they have to pick a bad tool for the job, then they are probably not a good developer. Obviously, we can't always pick or even know the absolute 'best' tool, but good grief there are a lot of better choices than typescript for cli tools.
Even if they know better suited languages, do they know the same better suited languages?
I'm in a TS shop, 95% of our code is TS. I would assume that almost everyone we've hired knows at least one compiled language but that language might be C++, Go, or Java. The only way to write a CLI tool that anyone at the company can edit is to write it in TS and so, indeed, >90% of the CLI tools we write are in TS. Works fine.
> The only way to write a CLI tool that anyone at the company can edit is to write it in TS
The only way? If you know C++, Java, or Go, even Typescript for that matter, they are all almost exactly the same. There is a little nuance with respect to setting up a project idiomatically, but once that groundwork is laid anyone can come along as they're simply going to copy the structure and style of what is already there anyway.
> There is a little nuance with respect to setting up a project idiomatically, but once that groundwork is laid anyone can come along as they're simply going to copy the structure and style of what is already there anyway.
You might think so! Having seen this tried in multiple 100+ engineering orgs, I think empirical evidence is against you. CLI tools can get surprisingly complicated (or use a surprisingly complicated set of language features). Many engineers will simply give up if a solution is not obvious in the first 5 minutes.
The end result is you have a lot of team A asking team B for a minor feature or fix to team B's CLI tool, or worse, team A just writes a hacky workaround to the broken-ness in the CLI tool.
Most people just don't care enough to put in the kind of effort for anything but the easy path.
Most developers I work with seem to prefer to stick to a single language. I don’t have this preference or consider myself a “typescript only developer”, however since I primarily contribute to a Typescript codebase day to day I end up the most practiced at Typescript. TS code flows out my fingers much faster than other languages I know like Go or Ruby. I am fine reading Rust or Ocaml but need a lot of reference material to write new features.
Sure I could ask my devs to write our CLI tools in Rust, and some of them would habituate to both languages but there’s no denying it’s a higher mental burden to split training time between two languages, or three languages.
Transitioning from any derivative of a given ur-language to another should be fairly trivial. I don't think anyone expects table stakes for devs to be proficiency in Java as well as APL
On the other hand, it's quite plausible that TS is one of only a small number of languages that you know that all your co-workers will be proficient in.
And in general I expect that the actual work I'm doing will be more interesting than the programming language I get to use. I really enjoy learning new things, and digging into new programming languages just for the sake of it, but when I need to actually ship something I don't want my programming language to be the exciting part of what I'm doing.
> it's quite plausible that TS is one of only a small number of languages that you know that all your co-workers will be proficient in.
If by TS you mean Javascript with ": any" tacked onto the end of each variable, then perhaps. Actual TS proficiency is rare, in my experience.
But if proficiency is a concern, you're not going to slap any random web developer on a command line tool project. It is an entirely different skillset. Amongst the developers proficient in command line tools, I expect the common language they are familiar with is typically not TS.
> If by TS you mean Javascript with ": any" tacked onto the end of each variable, then perhaps. Actual TS proficiency is rare, in my experience.
This isn't even a lack of proficiency, this is just hiring bad people. Who doesn't know how to annotate a type? That hardly takes Typescript "proficiency," you can learn it in 5 minutes.
> This isn't even a lack of proficiency, this is just hiring bad people.
If there was some specific reason to hire Typescript developers, maybe.
But across an organization, many developers won't be working on Typescript projects and there would be no reason to hire based on Typescript ability for those projects. It may be one of the few language all developers have some familiarity with, as proposed earlier, but that doesn't mean it is the language all developers focus on.
And when hiring developers with a background in building command line tooling, it is likely that Typescript has never been a language that has garnered their attention.
> Who doesn't know how to annotate a type? That hardly takes Typescript "proficiency," you can learn it in 5 minutes.
Typescript is its own language – one that is even turing complete. While you likely can learn it in 5 minutes, same goes for any language, including the aforementioned Go, Rust, and Zig. Proficiency takes quite a lot longer, though.
If our hypothetical web developer needs a command-line tool, why shouldn't they write it themselves? And why would using different programming languages be the same skill-set, but CLIs vs GUIs be a different skill-set?
There are other considerations to take into account, too: in an environment that commonly uses `npm`, a JS or TS package may be the easiest way to distribute your CLI tool. Especially if it's a tool intended to be used in the context of an NPM-based project.
For what it's worth, I have published CLI tools: `downgrade-build` is written in TypeScript, published with NPM, and used by my other NPM packages. `dabl` is written in Rust, published on crates.io, and honestly will probably only ever be used by me but it's useful to me :).
While I totally agree, and I come from a time where one couldn't be a full stack JavaScript developer. (Also a time when folks DID make their living doing bread and butter style Delphi/PowerBuilder/FoxPro/VB apps). I get that some folks spend ALL day in a certain language/stack and it's easy for everything to begin to look like a problem they could solve using that language/stack.
I do agree that is boring, but it also pays the bills!
What is this magical world you live in where a company can put up job listings for "Polyglot Software Engineers" and consistently, successfully get them through the hiring pipeline and staff up teams?
Where I live, (a) there's much more junior and mid-level talent with 0-2 years of experience than anyone else, (b) talent is far more likely to have TS/JS experience.
If you hire for JS talent, you ship. If you try to hire anybody else, you struggle to hire, struggle to collaborate ("I don't know X, so I'd prefer to open a ticket than to struggle and open a PR to that other team's repository"), and therefore ultimately struggle to ship.
Startups should run on the JS ecosystem by default and only write code in other ecosystems if there's a very good reason to do so (business competitive advantage, JS ecosystem options are severely lacking...).
Obviously you gotta work with what you got and it might be the best business decision to hire some junior devs with no experience outside of JS/TS and build your CLI tool in that.
But that's never going to be the best tool for CLI development, and someone with no experience outside of JS/TS (or any single language) is never going to be the best engineer.
The best business decision is the only relevant decision in the real-world, unless you're building the software as a hobby and you're willing to essentially self-fund the development without regard to anything else outside your own enjoyment.
If it's not your hobby, then you don't get to build perfect software, you get to build software that people are willing to fund (either through investment or purchase). People are only willing to fund software that ships. Professional development is an endless struggle to manage the sources of imperfection in the codebase; shipping perfect software is a pipedream. Shipping necessarily requires getting comfortable with shipping something imperfect and improving through iteration by shipping some more. So the first thing that you need to optimize for is shipping, and that is a function of who you can hire, what skillsets they have, and organizational design (including making cross-team collaboration easier by choosing standards, including language standards) that promotes shipping.
Should you be so fortunate that you have many, many people purchasing your software, or your investors (or CFO/VP Finance by proxy) are convinced that you need to leave the JS ecosystem to attain or preserve competitive advantage, then fine, build your CLI in a language that offers more technical advantage to building CLI tools. But that's not the default.
This feels a lot like a self-fulfilling prophecy that Javascript just happened to be chosen for.
- Javascript is "easy" and the only option for browsers, so lets teach it to beginners.
- We have all of these beginner programmers who can't work on the backend without learning a new language, so lets put javascript on servers.
- CPU, memory, and bandwidth have continued to become cheaper, so lets just run everything in javascript because "we can"
- Let's hire javascript developers because we've made them the easiest to hire for
- It's too expensive to use a different technology because our entire engineering team is javascript developers
I honestly can't fathom the reasons why we've encouraged Javascript to eat the world, but I don't think there's any arguing that it has. Is this good or bad for business in the long term? My personal take is that it isn't, but there are enough variables to make this really difficult to say with any kind of certainty. It feels more like we've just:
- Lowered the bar for acceptable quality over time
- Convinced ourselves that the Javascript ecosystem is a one-size-fits all optimization for time-to-product
> I honestly can't fathom the reasons why we've encouraged JavaScript to eat the world
Who is "we"? The scenario isn't some God-like figure who made the decisions and handed them down to mortals to live with. The reality is more like evolution (one you actually described very well), where many different, independent players are each working in their own interest.
> Lowered the bar for acceptable quality
Define "quality". Especially given the evolution prism, I'd argue that quality is not a rubric like "best technical performance" but rather one like "permits as many people as possible to engage with as many parts of the stack as possible." With that definition of quality, the JS ecosystem is by far and indisputably the king of the mountain. Graveyards are littered with many "best technical quality" options (Betamax, Itanium...).
> time-to-product
Nitpick, the term is time-to-market. What matters is not just building and shipping your MVP (which can be done by one person, who can choose whichever technology stack) but continually shipping at high velocity over time as the company grows, the original engineers leave, etc.
"we" is everyone in the industry. I recognize it's more of an evolutionary thing, it's just my stance that the current environment is pushing us towards an evolutionary dead end.
> Define "quality"
I also agree that software quality is fairly subjective depending on your lense, unfortunately. For example, I wouldn't view quality as permitting as many people as possible to work at every level. Diversity of ideas is great, but I want those ideas to come from folks who have the skillset. If someone who roofs houses decides to pour foundations without gaining the proper skillset or picking up different tools I would view that as a loss of quality, not a gain.
> the term is time-to-market
I chose time-to-product fairly intentionally, because I think the benefits of something like Javascript start to rapidly decay once you start approaching any sort of product maturity. The problem is teams rarely optimize towards stability and quality until they have literally no other option
> I want those ideas to come from folks who have the skillset
When the industry/society comes around and finally can get behind the idea of requiring licensing for software engineers to practice, get back to me :) . Until such a level playing field is imposed on all players, such practices impose a cost that your competitors are not paying, and they will out-manuever you and out-ship you.
> start to rapidly decay once you start approaching any sort of product maturity
Perhaps time-to-maturity then? Because it's besides the point that maturity is a characteristic necessarily of successful products. You find success by iteratively shipping.
> teams rarely optimize towards stability and quality until they have literally no other option
First make it run, then make it stable, then make it optimized. Pre-mature optimization is the root of all evil. This additionally lends focus to why the business can get behind such efforts: you need product flexibility to grow from $0 to $Xmillion/year, then you need to protect the $Xmillion/year so that it's not at risk from incompetence, hackers, etc., then after your user count stops growing, you continue to grow profits by cutting costs (e.g. by using more efficient languages like Rust that let you serve the same customers on less hardware).
Proficient? Yes. But I have better things to do with my time. I enjoy spending time with my family, woodworking, baking, gardening, home remodeling, painting, studying ancient Afro-asiatic languages, reading, hiking, etc.
The only way I’m going to learn a new language is if my work requires it and makes time for me to learn it. Well, we have far too much work to do to carve out time to learn new languages, so they just keep us using what we already know. That’s fine with me. I receive a hefty six figure income to pay for my life outside of work.
> If all you have are TS developers, the. IMHO, you don’t have very good developers.
Does it change anything to reframe this as having a common denominator across all developers? As in, rather than “All of my developers know only TS” to “TS is the common language all of my developers know”.
Particularly in small companies I think it makes more sense to focus on a restricted set of tools and technologies. It makes interviewing easier, ensures mobility of hires to different areas of the code, and produces an easier onboarding experience for new team members.
> It is also boring using only one programming language every day
Interest and passion come from more aspects of a project than the language it was written in. Some projects are interesting because of they incorporate cutting edge research, some because they have highly visible impact on users, and others because the solution involves a careful balance of design constraints. Choice of (or diversity between) language doesn’t have to be the distinguishing factor that makes a project interesting.
I think that person made a mistake in specifically mentioning rust and zig, because those are relatively uncommonly known languages among working webdevs.
But I think you're making a mistake in assuming they mean someone should force a specific language on them. In practice nearly every working TS dev knows something else, python, ruby, elixir, yeah maybe go. They should choose one of those other languages for the tool. A specific one doesn't need to be forced on them, just the decision that it should not be TS.
If you're saying "just use something else", you'll have to actually compare TS to the languages you're proposing. If for example someone were to suggest Python for a backend, I'd argue that TS is many, many times better than Python. Can you explain why TS is so very much the wrong tool in your eyes?
Just on a quick skim it seems like there are enough other people willing to take the other side of your "JS is good actually" position so I'm gonna pass today.
> If all you have are TS developers, writing a CLI in TS is not just fine, it's the right decision.
Companies should be properly staffed to support the platforms they're distributing on. If you're building a CLI tool, you should have devs familiar with doing that use an appropriate language. You should not repurpose front-end web developers to build the CLI tool in a web front-end language just because that's all they know. That's pushing your business, training and hiring problems down to the user.
Not to say web front-end devs can't make great CLIs (or servers)! It's just that they should train up on an appropriate stack if they're going to do so.
If everyone thought as you do, many companies simply wouldn't release a CLI tool, because hiring experienced developers just so you can use the "appropriate" language for a domain isn't realistic for most companies. I know it sounds nice, and I'd like the world to work differently too, but the reality is that resources are constrained enough that many developers have to be all-rounders, and you don't do that by learning the "right" language for every problem.
> many companies simply wouldn't release a CLI tool
That's his point, though. Command line tools require a different skillset. If a team has only worked on browser applications, they won't have the skills for command line tools and will need to learn them. Taking time to learn contradicts the grandparent comment, which suggests that people should stay in their lane and that there is nothing worse than forcing developers to work on things they are not already familiar with.
If one is going to hold that developers shouldn't be forced to learn on the job, even if by way of fellow teammates trying new approaches that others will need to maintain, you simply can't have them working on CLI tools and bringing on new teams that will operate independently is the only way to see movement into new areas.
> Taking time to learn contradicts the grandparent comment, which suggests that people should stay in their lane and that there is nothing worse than forcing developers to work on things they are not already familiar with.
My comment said no such thing. There is a difference between "types of applications you build in a language" and "language" (the first 7 words in the earlier one). It is much easier to learn how to write a different kind of application in a language you know, because you already know the language. You have to learn less.
I'm not sure why you're putting things as if I've made some absolutist statement. All I'm saying is: You only have the resources you have, and the efficient way to use them (especially in the long term) is not to leave architecture and implementation to a team that knows neither the language nor the environment.
What's proper here? I work in a TS shop, 95% of our in-house CLIs are in written in TS and to date it has been an issue... once a year? If we really need better than TS has to offer then sure, go write some Rust or Go, but most of the time we get a lot of added benefit from the fact that literally any developer in the company can bugfix or extend the CLIs without assistance from these teams.
>Nothing is worse than developers being forced to work in a language they are not used to
I think there are much, much worse things than this. Most of the time, I would count among those things the humongous downsides of JS, but it depends on your situation, obviously. There are plenty of cases where you should use JS/TS. But if I only knew TS and had an opportunity to write a CLI in Rust, I'd jump at the opportunity. It's not always the case, but lots of things are appropriate to use as an excuse to learn something new.
This line of thinking is precisely why node and TypeScript are so pervasive. It has nothing to do with them being the right tool for the right job and everything to do with perceived lower barrier to entry and resistance to learning better tools. I would never try and use a hammer to saw a board in half, and yet that's exactly what people try and do with node/TS
I'm not saying that you should use TS & Node for everything, not sure how you got that wrong. I'm saying: use the tools your developers know. If you have Java developers, use Java. If you have Rust developers, use Rust. If you have Typescript developers, use Typescript. Don't give a metaphorical person without arms a saw to split a board in half, even if it's supposedly the right tool.
I didn't really think you were saying they should be used for everything, but I do think discouraging branching out into better suited tools perpetuates using the lowest common denominator. If devs are never pushed out of their comfort zones, it's really hard for them to grow arms in order to use the saw.
I do acknowledge I have a lot of bias, though, because I work at a TS shop where the primary reason we continue to use it is because we always have. The longer I have to put up with it, the more I feel like this is a broken foundation to stand on
You shouldn't let developers branch out by trying to write their first real application in a completely new language as a productive thing for your company or your customers. They should learn by implementing real projects that will not be important or improved and maintained long-term.
I mean, they're also just kind of fun. Suppose you are building a CLI tool just for yourself, Deno is way more fun than Bash, say. Especially if your usecase starts to get into like tree traversals and stuff.
A large part of the bullshit that this industry has had to endure was exactly because a lot of front-end developers writing Javascript declared "we are all backend engineers now" and started using Node, thinking that UI development somehow translates to backend concepts. These are totally different areas of craft, like e-commerce vs game development.
But also many, many wonderful things came about because backend development became more approachable. You're right that inexperienced developers working in an environment they don't know produces a lot of horrible stuff, but that doesn't invalidate the good!
And I wouldn't strictly differentiate between these areas. My game development experience helps me to write better backends and frontends alike. They are separate insofar that you have to learn each environment to be able to write idiomatic code, but it's not like you can't re-use parts of your knowledge across all of them.
I think the worst aspect of it is that the cohort of engineers was not taught to appreciate the complexity (of distributed systems in particular). This is something the industry is just trying to burry itself out of.
It was a bad combination of "green" JS engineers writing servers and a new batch of fresh FAANG veterans mentoring them into writing extremely complex and expensive systems. There is a large dollar value attached to this fiasco.
> I think the worst aspect of it is that the cohort of engineers was not taught to appreciate the complexity (of distributed systems in particular). This is something the industry is just trying to burry itself out of.
It sounds like you have a bone to pick - because when was this ever not the case? Most developers of any generation don't really know about the complexity of distributed systems. Some developers do, even in "the cohort of engineers" who you say wasn't taught this. People using inexperienced (in the topic) developers for complex systems is not something new either. People use who they have.
I mean while I think hiring and availability is an important reason to pick a language, and so it makes sense to have e.g. Node / JS / TS as a back-end language. But it's not ideal.
Another one would be to pick Java or C#, but the stereotype of a developer like that is that they will overcomplicate and make a heavy, enterprisey back-end; Node backends feel lighter, so I can again understand why they would rather have a Node / JS type developer, they're more pragmatic.
Ideally you'd get a "polyglot" developer, or a developer who has embraced that language is just an implementation detail, someone who can see beyond a language and its ecosystem and stereotypes. But the hiring pool for those is small, and convincing them to work for your company is really difficult if it doesn't do anything exciting, new, or cannot pay a lot.
> Ideally you'd get a "polyglot" developer, or a developer who has embraced that language is just an implementation detail, someone who can see beyond a language and its ecosystem and stereotypes. But the hiring pool for those is small, and convincing them to work for your company is really difficult if it doesn't do anything exciting, new, or cannot pay a lot.
That's kind of the approach I'm proposing. Don't care about the language, use the one your developers know best, because the language itself is just an implementation detail, while the proficiency will help you in any language. You're not going to get a large group of great polyglot developers, so you have to reverse the process and choose the language your developers know best.
What about the users? This whole thread is entirely developer centric. Odds are you are going to have 1000x more time users than developers. A native solution and not some node interpreted monstrosity is the right choice. We all loathe electron apps because they perform like shit. What's worse, inconvenience a handful of developers to learn a native language, or make thousands of users run node apps? The carbon footprint alone is worth it.
I disagree. If the program is fast enough for its purpose, and my developers can write better code (as in, code with better architecture allowing for flexible development while being easy to read) and develop features faster, it doesn't matter which language is "right", it matters which one will get the thing developed in an acceptable amount of time. Users would rather have bad software than no software, as you can see with Electron apps that perform like shit.
I'm not saying that performance, memory consumption etc. are completely insignificant. I myself prefer to use faster tools that use less memory. But if all you have is a bunch of Typescript devs, and you want them to develop a CLI, you're not going to get a better result by telling them to do it in Rust. To get a better result you'd have to tell them to learn Rust and work in it for half a year. And yes, that would be better for users in the long run, but that doesn't mean it's realistic in all cases.
It's fine if you don't like JS, but it speaks to a bias or lack of experience if you think Zig is a better tool. Maybe it will be one day, but it's a flat out unfinished language with numerous bugs.
I was with you when you said command lines, but servers? JS is a fine choice for servers. I haven't seen Rust do anything on the server but slow people down, and I have found people who think they know Rust don't really
Plenty of people are productive in JS, and when working with ES6, it can even be comparable to immutable functional languages. It's on the team if they aren't reviewing code or are allowing bad habits.
> I was with you when you said command lines, but servers? JS is a fine choice for servers.
I disagree. JS is single threaded. Sure there are some hacks to kinda, sorta get around that, but it's the nature of the language. Tying yourself to a single thread or dancing around that is an unnecessary restriction that compiled languages aren't going to have. JS is designed for web pages, not servers and not apps.
The single threading isn't an issue for many backend use cases and even though JS was initially designed for use in the browser, there's been a decade of development on the language and ecosystem for using it outside the browser.
Also people routinely use other single threaded things for the web, notably Python and Ruby have global interpreter locks and PHP has also usually been multithreaded only by being multi-process (you have to add pthreads on I think?).
Multithreading is a nice to have; it has a bunch of costs around needing to introduce locking and synchronization primitives into the language, those costs aren't the worst thing ever but it's often nice to not have to deal with them.
I think you are mixing up lots of stuff or at least write about them in a misleading way.
Python has async, has green threads, and has OS threads through the multiprocessing module. The fact that it has the GIL does not mean, that it cannot use OS threads or multiple processes. JavaScript in comparison does not have multithreading. NodeJS itself is multithreaded, but you cannot put application computation on those threads. You will need to use worker-threads and basically like PHP run multiple instances.
However, neither of those languages is particularly nice for using the multiple cores available in modern machines anyway.
In actual practice a single thread is a non-issue. Web applications are almost never CPU bound, wait times are almost always a function of IO—database queries and requests to external services.
JavaScript's async IO is plenty fast for any typical web use case, and the marginal savings you might get from having a few fewer servers will be more than made up for by the time your team of web developers (who already know JavaScript) wasted learning Rust or Zig.
The fact that JS is single threaded doesn't make it any less useful as a web server. It seems like you're evaluating languages based on runtime performance and some made-up arbitrary metric that JS fails to meet, while completely ignoring the ecosystem that makes shipping projects possible in the first place.
Zig looks promising, but the ecosystem isn't mature yet. Suggesting that Zig can replace a production-grade server based on Express.js today is.. madness.
Lack of threads is just one example of how JS is hobbled. You don't always need multi-threaded programming but there are times you do! I've also noticed that devs that understand how to do multi-threaded programming are the most proficient.
> completely ignoring the ecosystem that makes shipping projects possible in the first place.
There are so many bad js libraries out there, more than any other language I've ever seen. There's no special sauce in the JS ecosystem, there's tons of libraries available for any modern language (not Zig, I included that as it probably will get there). There's nothing you can do in JS that you can't also do in Go and the quality of the library your using is going to be much higher than whatever's on NPM.
> You don't always need multi-threaded programming but there are times you do!
Are you a working web developer? If so, can you give a concrete example of a web application you've worked on that required multithreading on the web server?
I've needed it client-side to avoid freezing the UI with heavy computations, but in all my years working on server-side code (in PHP, Java, Ruby, JavaScript, and Python) I have never wanted to manually create a new thread on the server, even in Java where I could have!
> I've also noticed that devs that understand how to do multi-threaded programming are the most proficient.
Knowing how to do multi-threaded is different from insisting on using a language that supports multi-threading on a project that will never require multi-threading. I've noticed that devs that understand their project requirements and don't engineer for problems that the project will never face are the most proficient.
> Are you a working web developer? If so, can you give a concrete example of a web application you've worked on that required multithreading on the web server?
Yep, I'm a working (and successful) developer who has built a lot of different types of programs, often web servers.
A concrete multi-threaded example would be a web server that federates to Mastodon (which is quite noisy and benefits from having the "bridge" be in its own long running thread(s)). Really anything with long running processes that aren't keyed off of ux events is best done with multiple threads.
Fair enough. If you're working on something like that, absolutely go with a different server than TypeScript! But it's still weird to insist that TypeScript has no valid applications when long-running processes that aren't direct responses to users are the exception and not the norm.
When I've run into specific cases in TypeScript projects that require that, I've tended to just spin up a new long-running service for those requirements.
> When I've run into specific cases in TypeScript projects that require that, I've tended to just spin up a new long-running service for those requirements.
But then you're not sharing memory and have to rely on message passing... it's all doable of course, but this is just one of many examples where the language will hold you back.
Yes, you're not sharing, but the deployment requirements are usually quite different for services like that, which makes them better as standalone services regardless of implementation language. For one thing, you usually don't want to run multiple copies of long-running daemon-type services, where for your application servers redundancy is good to have no matter what language you're using.
In my controversial opinion: yes they're bad for servers. Not just because they're single threaded but because they're interpreted and have dated tooling. Compiled languages have reached a DX level that I see no reason to use something interpreted in 2023 unless you really are building a web page and need to use js in the browser.
> Because compiled languages tend to introduce a class of errors that are hard to deal with
I've actually never heard this before, can you elaborate? Typically it's expected that the compiler will give you better errors than what you get if your app crashes at runtime.
As in compiled languages are usually low level languages that require some amount of memory management. So in C++, I have to worry about integer overflow. In Rust, I have to worry about how I return a variable or where a variable can still be used.
In JavaScript, I return whatever I want and the garbage collector handles it. Slower, but perfectly fine when my servers main job is waiting. Using Rust instead is not just "better errors," it's more potential for errors. If CPU cycles aren't important for my app, why not just use Typescript? Rust is not just "JavaScript but with better errors," it's targeting a completely different use case.
If you want a fast, multi threaded language with a good type system, you can do it without Rust. C# is extremely fast, and in some use cases, faster than Rust.
> As in compiled languages are usually low level languages that require some amount of memory management.
That's not true of any of the languages I've listed. You may not like the borrow checker, but it's not manual memory management. Also, Go has a garbage collector you don't manually manage memory there. I don't think any of these languages would be considered "low level".
That's why I brought up golang as an example of a GC language. It's a bigger success story for servers because a GC language is more appropriate
But no, just because Rust has a borrow checker doesn't mean you aren't manually managing memory. It just means there are guard rails for it and the way you do it is different. Here's the gut check, does Go not allow me to use a variable because it's location has already been freed? That's what automatic memory management looks like. Not only does Rust not have that, it's even more complicated than c++ RAII in some places
> But claiming that that is the reason JavaScript is faster is actually a reflection of not understanding what this compilation does for you.
I didn't even kind of say this. Rust is complicated for reasons beyond compilation. I actually like F# and strong type systems.
> The amount of tooling that you need to use to surround your JavaScript code to make it somewhat correct is insane.
There's no practical evidence of this, it's just a feeling you have. Big systems are built in dynamic languages fine.
> This statement is the reason we're all having to use Electron applications.
How is "JS is fine for servers" the reason you have to use Electron apps? Pick a topic. I am not overapplying JS
> You're using a dynamic language. There is literally a whole slew of bugs that you cannot detect until you actually run the code.
If you're using Rust, you're introducing a whole slew of bugs that you cannot detect unless you compile the code, and that you wouldn't run into in a GC language. And you're potentially doing it for no benefit because you don't understand servers aren't typically CPU bound.
If you use TypeScript on the server and client, you can define object types (interfaces) just once, which makes it a lot faster to write. If you use anything else you lose out on this luxury.
That's true, and I was impressed first time someone showed me that. But the cost of this luxury might not be worth it. Indeed, you mostly (only ?) communicate through an API. And if it's properly documented, which is now essentially automatic, you can easily generate your types from the frontend. To me, the cost of bringing JS to the backend dominates this luxury to the point where it's just not worth it. I'll just generate my types from the frontend and be done with it.
I've tried a few of those, and the bundle size is typically insane. The amount of code you have to ship just to get the semantics of your language and your standard library is nuts.
There may be a few exceptions that were designed from the outset with JavaScript in mind, but then you're back to being at the mercy of JS quirks.
Why need another dialect if you can just use Javascript.
I think most people don't really know Javascript, and what is possible.
Most arguments to use Typescript are not good arguments, and Javascript can more than most people think.
Typescript is more a combined box of tools, and a lot of things can be done without Typescript or another dialects.
A programming language is a tool to get to the desired outcome. The 'best' programming language is one that allows me to get to my desired outcome the quickest, with the fewest bugs and highest maintainability.
For me (and, I would argue, for pretty much everyone), that would probably be whatever programming language I am most familiar with. Unless the language has huge barriers compared to another one I am somewhat familiar but less familiar with.
I wish the dogmatic hate on JS would stop, it was boring 10 years ago, it's still boring.
I too wish the dogmatic hate of anything in particular would stop, but I also wish the stubborn assertion that the decades-long hate of JS is all dogmatic would stop. As long as JS is extremely wide-spread and has very stand-out negatives as compared to almost all other ecosystems, the hate will understandably continue.
Even if that part of the desired outcome is true (it's not though, as it rarely takes into consideration long term benefits and focuses purely on "instant gratification"), people who go to online programming forums as HN are hobbyists. And hobbyists do care about tools. You can't expect enthusiast to have this boring approach of someone who simply want to finish job on passable level and get the fuck out of office as quickly as possible.
And even if you are not a hobbyist, using a computer to do your/some job for you is literally what programming is about. So dismissing the topic of improving that process with better tools is simply ignorant
You're assuming I'm not a hobbyist programmer (I am). Or that I don't take into account future requirements (I do). That I only care about a passable level of software (I am a big proponent of software craftsmanship... see: https://news.ycombinator.com/item?id=36586248#36587807, and also my original comment talked about maintainability...)
In a hobbyist mentality, go wild! Do whatever makes you happy. In a professional, business environment I want to deliver outcomes first, my personal happiness comes from delivering those outcomes so it matters less on the technical choice.
Typescript is the language I am most familiar with (and Javascript before that, going back to the early Netscape days), being the language I use like 90% of the time in the work I do, but it unquestionably won't be the quickest way to the desired outcome for me. I'm way more productive in certain other languages, even when I only use them infrequently. The Typescript/Javascript tooling is just not there to support efficient, bug free, and maintainable development.
Of all the languages you could pitch to someone already familiar with JS these would be at the bottom of the list. You want something dynamically typed, well trodden, and with a huge package ecosystem which to me sounds like Python or maybe Ruby. But honestly JS minus mountains of tooling is a really good general purpose language.
Use the right tool for the job, not the meme tool for the job.
Zig may be useful in some contexts but it’s also in beta and it has a bus factor of one.
Rust is unnecessary for most projects that don’t need the extreme degree of efficiency it offers and would rather have a GC do all that work for them.
Go is fine, if you get along with it. Many people don’t like it because the type system is from the 1980s, but if you like that kind of thing then go ahead.
I think, if you write server code / command line apps.
It is better to choose for Javascript over Typescript, so you don't have the translation, and you know the system where you running on, and you can build for that Node version.
Typescript makes it indeed too complex, keep it simple with just Node.js without a build step, or use indeed another language like Go or Rust.
I have no dog in the game, I love plain Javascript as my second programming language and have limited knowledge of TypeScript. That said, please look at the large set of CLI tools that have already been created in Javascript. It's not inappropriate language for the job by any means. Even portions of NPM and Node are written in Javascript. Grunt, Bower, Angular CLI etc. are just a few examples of CLI tools in Javascript.
> For anything else it (or any form of Javascript) isn't the right tool for the job, in part for the reasons outlined in this post.
I genuinely don't understand how someone could make a statement like this. You mention command line apps and servers, but surely whether TS is the best solution would depend entirely what you're trying to achieve. If there's a great NPM library to help you with the problem you're solving why wouldn't you use TypeScript?
Not to mention the fact that TypeScript servers when paired with web frontends have obvious advantages. One project I worked on involved analysing 3D objects then visualising this on a web app. The simplest solution we found for visualising the analysis we were doing on the backend was just to build it all with Three.js and TypeScript then use common libraries.
I'll also note that good JS developers are generally competent enough to avoid "bad habits" and that "bad habits" in my experience are not isolated to the JS ecosystem.
That you suggest Rust and Zig as alternatives suggests to me that you may not understand the requirements of a typical web application. These aren't usually CPU-bound apps that benefit from running close to the metal: the main bottleneck is DB queries and requests to other services. Adding all the complexity of the borrow checker isn't usually worth it unless your devs are already fluent in Rust, and using an early-stage C replacement like Zig would be an odd choice.
Here are the criteria I'd use for choosing a language for a web server, in order of importance:
1. What does my team already know?
2. What languages have a robust ecosystem of web-related libraries?
3. Static types are better than dynamic if the team is larger than 1 or if the project will last more than 6 months.
Performance considerations might come in after this if there are still two languages left to decide between. But judging from those criteria, I think you can see why TypeScript would not be a bad choice for a full stack web team.
I find this kind of approach so limiting to a business in general. Basically you limit your choice of programming language and with that the ecosystem early on. You got 3 devs only knowing language X? OK cannot use any other language ever, because then they would have to learn something new (oh noes!). This will of course mean that additional developers also cannot apply their additional knowledge and will have to use the same language and ecosystem as the others, because they can't possibly be bothered to learn another language.
Learning a new language should be a frequent thing. I don't know how many languages I have learned, but it has only ever increased my understanding of computer programming, advantages and disadvantages of approaches and it certainly has made me a better engineer. If a business does not want better engineers, sure, stick to the "we can only use what we already know!" approach.
Let it take 2 weeks for people to learn a language! So what? It will pay off in the long run. You will have more experienced engineers, we have a less limited idea about computer programming and how to solve programming problems well, since they have gotten into contact with other concepts from other languages. You also get a more flexible team, that can accept building better and safer services, using the right tool for the job, instead of shoehorning everything into their only one language. You will open up more ecosystems for your whole business.
As he's written a few books about it, unless he exaggerates, the books may look boring but the reality is, JS/TS isn't as bad as he wants to exaggerate.
So, the better advice is, real world can't be perfect, live with it and move on than complain. If you have so much to say, you're better off contributing to the project.
Genuine question here: would it be better for a backend server or cli to be written in a language that allows for compilation to a single executable, or run through an interpreter (python, deno/node/ts-node etc)? I'm not familiar with Go or Zig in that regard.
A single executable would be easier to deploy/version/sign. You could in theory also make a bundle with typescript/javascript files as well. It would be no different from deploying a WAR file on a server running JAVA.
Compiling to a single executable like Go and Rust and Haskell do, has a bunch of benefits for a server. Notably, it used to be the case (before the container revolution) that if you used a scripting language like Python, say, you had to carefully pip install all your dependencies identically between your prod and staging and test environments and your local dev env. Scripting languages have this nasty habit of preferring to not break, they will start a script without having all of its dependencies in the hopes that by the time the dependency is actually used, it will have been installed dynamically. This is also why wizened programmers from those cultures write so many damn tests, because if there is a dependency that does not get exercised at test time then you might have a prod outage on the weekend when some user figures out how to exercise it, etc.
In other words you can view the rise of Docker as saying, “give me your scripts and I will give you this magical unicorn called a container image, which can be used to run your script like a single executable.” People did not use Docker for its security features (the people who cared about that used VMs before Docker and put Docker into a VM after), but for its operational feature. If anyone had understood this before the rise of Docker, I think they would have architected Docker differently: multiprocess containers and weird networking stacks could have been done away with, you would probably not throw all of the OS into the binary because that's overkill (just Terraform-like “providers” or so?) ...also Docker needs to run as root to establish its tentacular spectacular: if you had viewed the goal as packaging the scripting language as a virtual binary you probably wouldn't need this stuff.
If you are running a large enough company then you need something like kubernetes because you have thousands of developers all needing to deploy on to the same prod hardware clusters. Cloud computing generally tries to lump you into this bucket too. In those cases there is no difference.
But if you are running a small dev shop of less than 20 devs at a larger 100-300 person company, now prod is whatever Casey your sysadmin says it is, and Docker is forbidden by some policy that you can't run as root or so, so now it's easiest to just compile static binaries and then build a lightweight gitops thing out of that, put an NginX server in front (except Casey gets mad and makes you use Apache) and some FastCGI and with a bit of luck you can get it so that if the build or tests fail, the system sends you an email via nagios but keeps humming along with the old build. It's a few weeks of work and you'll complain to every dev you onboard “I'm sorry this is all held together by duct tape” but it'll chug along fine until that company becomes 5,000 strong and you have 500 developers and can afford to containerize or shift to cloud for new applications and "do it right".
Its starting argument is based on an asserted ignorance of some devs on what TypeScript actually is. From there, it outlines all the limitations of the language it can think of.
Obviously TS is not a good-for-all solution, never intended to be, and never claimed to be.
So going around saying TS is not something it was never meant to be, just because some people misunderstood what TS is, sounds, to say the least, redundant
> If you want to get into TypeScript, don’t think you can leave JavaScript behind. It will find you, and it will get you.
And do what?
Perhaps it's my experience with a somewhat large(150k LoC) pre-CommonJS codebase, but I get the feeling that the language is being presented as much more intimidating than it really is.
Yeah, strange things happen when you add an array literal to an array literal, or do any sort of type coercion really.
My advice is: don't do it then. Seriously, you have to actively try to even encounter these quirks - especially now that we have language constructs like template strings, which prevent most such issues.
I think only (3) lands as a good point. And it is a big weakness of Typescript. Practically, any TS application is going to get data from an API or DB. You really would like to validate the shape of this data and TS offers little here. Hence the explosion of tools like zod to go to/from TS type definition to validation rules. Feels very wrong to have to add in a type manipulation library to a language that is basically only Types.
In every single decent language with a static type system you'll have to convince the type checker that data coming from outside the boundaries is of a certain shape by parsing it. If you're not doing it, then you are implicitly assuming it's of some type and you risk runtime type errors.
E.g. in Elm you do have to parse every single thing coming in from outside the boundaries both from http requests or other external ports.
This is the part that's missing. Or more completely there's no runtime types at all. So you can't do stuff like:
result = fetch....
if(result is User){
return result
}else{
Throw error
}
The mechanism TS gives you to do that is essentially recreating all your type rules in a validation. Which is keeping the same information in two places and risks them getting out of sync.
Most people pick up a library that generates the types and validations for you to solve this. Which works but it's kind of weird that you have to.
> Most people pick up a library that generates the types and validations for you to solve this. Which works but it's kind of weird that you have to.
Why would it?
Which static languages include automatic parsing at boundaries? Elm sort of does on ports, but that's like the only example I can think of, I'm perfectly sure that I may not know enough about it.
It's not a must, you can absolutely model IO and roll your own class validation/serializers methods and get both build time type safety and runtime validations without including a library for it. It's typical old school JS style validation we've done for decades with just some stylistic adaptations to stay type safe.
However, grabbing Zod or io/ts is a lot less work and with tools like https://quicktype.io/typescript or https://transform.tools/json-to-zod you can paste in an API response, copy over a validator and export a type. My homegrown validator classes won't be nearly as clean or as quick.
It's awful to incorporate as part of a project (all the configuration for compilation, mapping errors etc.). It's also extremely complex language with plenty of footguns. The required TS tooling is also an argument against it.
I always say, Typescript is no language but a dialect.
JavaScript is the official language that will used in production.
You can talk in a dialect, but for official things you have to write and talk the official language.
Always think if the Typescript dialect will help your team, or it can cause confusion, e.g. after translation to the code that runs in production.
(Error reporting, debugging, running tests, ...)
Javascript is easy to write and understand, easy to play with, without transpiling, e.g. in your browser.
When you write code in the native language, you know what you write, how it will run on the system.
When you write in Typescript, it generates some Javascript that is sometimes hard to recognize as your code.
> When you write in Typescript, it generates some Javascript that is sometimes hard to recognize as your code.
Every time I have tried to compare the output of `tsc`, I have reached the opposite conclusion.
It's incredibly faithful most of the time. And when not, it's consistent.
So if you understand why it does what it does once, life becomes much easier.
Perhaps you are referring to minified code. Even then, with source-maps correctly setup,
I rarely if ever have a reason to leave TypeScript-land.
Without the type-checker, my productivity (and sanity!) would likely be cut in 1/2 or more.
I'd be very interested in examples that resulted in your opinion.
I found it easy to pick up, and my React development experience is much better than when I used vanilla JS. I'm not even close to a full time frontend guy, so your experience may be completely different. I guess when you have worked with a bunch of languages, you tend to see them as tools to fix problems rather than something to be crazy about.
- even further verbose and hard to read compiler errors
- advanced uses require extreme prophiciency in TS
- poorly typed libraries (including the standard ones, for easier transitions to ts), e.g. JSON.parse returning `any`s
- untyped error channels. Got a function that can throw an error? You can't type it unless you change the shape of the returned type to some ADT like `Either<A,B>`. Have a promise that can reject with some generic error `E`? Well, `Promise<A>` takes only one generic argument, the errors are untyped, so you need to use stuff like `Promise<Either<A,B>>` and handle it manually or with external libraries.
- Hard time to implement many kinds of stuff with a fluent api (meaning stuff like Foo.get().map(someMappingFunction).call(Baz) needs to be implemented as `get`, `map`, `call` as separate functions, not as methods). This is what forced `fp-ts` to go for `pipeable` APIs ( pipe(get, map(someMappingFunction), call(Baz) ) rather than the fluent api before. It also led for a period the `effect` ecosystem to write their own extensions for TS, called TS+ [1]
With all of that being said, TypeScript is one of the most productive and efficient and flexible programming languages out there, I know very few languages that allow to write so many kind of software for so many kind of platforms. TypeScript's structural typing has a long list of pros, and for functionally-inclined developers like me TypeScript allows to express and implement stuff that other languages e.g. Haskell cannot such as more generic typeclasses like Ordering, Eq, etc, without the same being "attached" to the type itself and being unique (which has no mathematical foundation, there's infinite ways to implement a sorting on any kind of type, there's zero mathematical reasons why there should be only one).
The cost benefit of typescript is a range. The benefit is that you have some greater chance that your code does not suffer from passing bad parameters. Bad parameters have some characteristics: missing, too many, too few, wrong types and bad values at least.
It is important to understand that you are not "using typescript". You are in fact adding a layer of code on top of javascript. This layer is a variant of javascript, adds tooling and requires additional effort. One overlooked aspect of typescript is that it requires of typescript to read it. If you publish your typescript code, for example in an open source project, it is less accessible to javascript programmers.
The tradeoff between these two is something that is use case dependent.
As a sole developer, after a couple of attempts I am adopting option #3. Instead of
` function dosomething({duck, dog}) { console.log("%s, %s", duck, dog)} `
I find this gets me at least 50% of type problems that I usually miss, and the cost is extremely low.
As a sole developer who needs to be extremely productive I simply can't afford typescript. I can afford this. And maybe there are other easier-to-use ways to catch other type problems?
I subscribe to one of the TypeScript newsletters, just to keep and eye on the latest additions, and at some point I became exhausted. Every update (and those are very frequent!) comes with some new esoteric option most average developers will never use or will be totally confused by.
TypeScript seems to be losing the plot to its own movie, turning into a sprawling, complex language like C++ or Scala - the "choose your own adventure" type.
Typescript is currently the best way to avoid the myriad of issues writing JS. It's an amazing hold over until we get native types. ECMAScript proposals take a long time, but it will eventually come.
133 comments
[ 717 ms ] story [ 3116 ms ] threadIf all you have are TS developers, writing a CLI in TS is not just fine, it's the right decision. Forcing Rust upon them is not going to make anyone involved more happy.
[1]: https://andrewkelley.me/post/not-a-js-developer.html
[2]: The creator of Zig[3]
[3]: https://ziglang.org/
A lot of common screwdrivers can turn Philips head screws enough to get the job done.
I'm in a TS shop, 95% of our code is TS. I would assume that almost everyone we've hired knows at least one compiled language but that language might be C++, Go, or Java. The only way to write a CLI tool that anyone at the company can edit is to write it in TS and so, indeed, >90% of the CLI tools we write are in TS. Works fine.
The only way? If you know C++, Java, or Go, even Typescript for that matter, they are all almost exactly the same. There is a little nuance with respect to setting up a project idiomatically, but once that groundwork is laid anyone can come along as they're simply going to copy the structure and style of what is already there anyway.
You might think so! Having seen this tried in multiple 100+ engineering orgs, I think empirical evidence is against you. CLI tools can get surprisingly complicated (or use a surprisingly complicated set of language features). Many engineers will simply give up if a solution is not obvious in the first 5 minutes.
The end result is you have a lot of team A asking team B for a minor feature or fix to team B's CLI tool, or worse, team A just writes a hacky workaround to the broken-ness in the CLI tool.
Most people just don't care enough to put in the kind of effort for anything but the easy path.
Sure I could ask my devs to write our CLI tools in Rust, and some of them would habituate to both languages but there’s no denying it’s a higher mental burden to split training time between two languages, or three languages.
Maybe most people are not good human based on your definition.
And in general I expect that the actual work I'm doing will be more interesting than the programming language I get to use. I really enjoy learning new things, and digging into new programming languages just for the sake of it, but when I need to actually ship something I don't want my programming language to be the exciting part of what I'm doing.
If by TS you mean Javascript with ": any" tacked onto the end of each variable, then perhaps. Actual TS proficiency is rare, in my experience.
But if proficiency is a concern, you're not going to slap any random web developer on a command line tool project. It is an entirely different skillset. Amongst the developers proficient in command line tools, I expect the common language they are familiar with is typically not TS.
This isn't even a lack of proficiency, this is just hiring bad people. Who doesn't know how to annotate a type? That hardly takes Typescript "proficiency," you can learn it in 5 minutes.
If there was some specific reason to hire Typescript developers, maybe.
But across an organization, many developers won't be working on Typescript projects and there would be no reason to hire based on Typescript ability for those projects. It may be one of the few language all developers have some familiarity with, as proposed earlier, but that doesn't mean it is the language all developers focus on.
And when hiring developers with a background in building command line tooling, it is likely that Typescript has never been a language that has garnered their attention.
> Who doesn't know how to annotate a type? That hardly takes Typescript "proficiency," you can learn it in 5 minutes.
Typescript is its own language – one that is even turing complete. While you likely can learn it in 5 minutes, same goes for any language, including the aforementioned Go, Rust, and Zig. Proficiency takes quite a lot longer, though.
There are other considerations to take into account, too: in an environment that commonly uses `npm`, a JS or TS package may be the easiest way to distribute your CLI tool. Especially if it's a tool intended to be used in the context of an NPM-based project.
For what it's worth, I have published CLI tools: `downgrade-build` is written in TypeScript, published with NPM, and used by my other NPM packages. `dabl` is written in Rust, published on crates.io, and honestly will probably only ever be used by me but it's useful to me :).
I do agree that is boring, but it also pays the bills!
Where I live, (a) there's much more junior and mid-level talent with 0-2 years of experience than anyone else, (b) talent is far more likely to have TS/JS experience.
If you hire for JS talent, you ship. If you try to hire anybody else, you struggle to hire, struggle to collaborate ("I don't know X, so I'd prefer to open a ticket than to struggle and open a PR to that other team's repository"), and therefore ultimately struggle to ship.
Startups should run on the JS ecosystem by default and only write code in other ecosystems if there's a very good reason to do so (business competitive advantage, JS ecosystem options are severely lacking...).
But that's never going to be the best tool for CLI development, and someone with no experience outside of JS/TS (or any single language) is never going to be the best engineer.
The best business decision is the only relevant decision in the real-world, unless you're building the software as a hobby and you're willing to essentially self-fund the development without regard to anything else outside your own enjoyment.
If it's not your hobby, then you don't get to build perfect software, you get to build software that people are willing to fund (either through investment or purchase). People are only willing to fund software that ships. Professional development is an endless struggle to manage the sources of imperfection in the codebase; shipping perfect software is a pipedream. Shipping necessarily requires getting comfortable with shipping something imperfect and improving through iteration by shipping some more. So the first thing that you need to optimize for is shipping, and that is a function of who you can hire, what skillsets they have, and organizational design (including making cross-team collaboration easier by choosing standards, including language standards) that promotes shipping.
Should you be so fortunate that you have many, many people purchasing your software, or your investors (or CFO/VP Finance by proxy) are convinced that you need to leave the JS ecosystem to attain or preserve competitive advantage, then fine, build your CLI in a language that offers more technical advantage to building CLI tools. But that's not the default.
This feels a lot like a self-fulfilling prophecy that Javascript just happened to be chosen for.
- Javascript is "easy" and the only option for browsers, so lets teach it to beginners.
- We have all of these beginner programmers who can't work on the backend without learning a new language, so lets put javascript on servers.
- CPU, memory, and bandwidth have continued to become cheaper, so lets just run everything in javascript because "we can"
- Let's hire javascript developers because we've made them the easiest to hire for
- It's too expensive to use a different technology because our entire engineering team is javascript developers
I honestly can't fathom the reasons why we've encouraged Javascript to eat the world, but I don't think there's any arguing that it has. Is this good or bad for business in the long term? My personal take is that it isn't, but there are enough variables to make this really difficult to say with any kind of certainty. It feels more like we've just:
- Lowered the bar for acceptable quality over time
- Convinced ourselves that the Javascript ecosystem is a one-size-fits all optimization for time-to-product
Who is "we"? The scenario isn't some God-like figure who made the decisions and handed them down to mortals to live with. The reality is more like evolution (one you actually described very well), where many different, independent players are each working in their own interest.
> Lowered the bar for acceptable quality
Define "quality". Especially given the evolution prism, I'd argue that quality is not a rubric like "best technical performance" but rather one like "permits as many people as possible to engage with as many parts of the stack as possible." With that definition of quality, the JS ecosystem is by far and indisputably the king of the mountain. Graveyards are littered with many "best technical quality" options (Betamax, Itanium...).
> time-to-product
Nitpick, the term is time-to-market. What matters is not just building and shipping your MVP (which can be done by one person, who can choose whichever technology stack) but continually shipping at high velocity over time as the company grows, the original engineers leave, etc.
"we" is everyone in the industry. I recognize it's more of an evolutionary thing, it's just my stance that the current environment is pushing us towards an evolutionary dead end.
> Define "quality"
I also agree that software quality is fairly subjective depending on your lense, unfortunately. For example, I wouldn't view quality as permitting as many people as possible to work at every level. Diversity of ideas is great, but I want those ideas to come from folks who have the skillset. If someone who roofs houses decides to pour foundations without gaining the proper skillset or picking up different tools I would view that as a loss of quality, not a gain.
> the term is time-to-market
I chose time-to-product fairly intentionally, because I think the benefits of something like Javascript start to rapidly decay once you start approaching any sort of product maturity. The problem is teams rarely optimize towards stability and quality until they have literally no other option
When the industry/society comes around and finally can get behind the idea of requiring licensing for software engineers to practice, get back to me :) . Until such a level playing field is imposed on all players, such practices impose a cost that your competitors are not paying, and they will out-manuever you and out-ship you.
> start to rapidly decay once you start approaching any sort of product maturity
Perhaps time-to-maturity then? Because it's besides the point that maturity is a characteristic necessarily of successful products. You find success by iteratively shipping.
> teams rarely optimize towards stability and quality until they have literally no other option
First make it run, then make it stable, then make it optimized. Pre-mature optimization is the root of all evil. This additionally lends focus to why the business can get behind such efforts: you need product flexibility to grow from $0 to $Xmillion/year, then you need to protect the $Xmillion/year so that it's not at risk from incompetence, hackers, etc., then after your user count stops growing, you continue to grow profits by cutting costs (e.g. by using more efficient languages like Rust that let you serve the same customers on less hardware).
The only way I’m going to learn a new language is if my work requires it and makes time for me to learn it. Well, we have far too much work to do to carve out time to learn new languages, so they just keep us using what we already know. That’s fine with me. I receive a hefty six figure income to pay for my life outside of work.
Does it change anything to reframe this as having a common denominator across all developers? As in, rather than “All of my developers know only TS” to “TS is the common language all of my developers know”.
Particularly in small companies I think it makes more sense to focus on a restricted set of tools and technologies. It makes interviewing easier, ensures mobility of hires to different areas of the code, and produces an easier onboarding experience for new team members.
> It is also boring using only one programming language every day
Interest and passion come from more aspects of a project than the language it was written in. Some projects are interesting because of they incorporate cutting edge research, some because they have highly visible impact on users, and others because the solution involves a careful balance of design constraints. Choice of (or diversity between) language doesn’t have to be the distinguishing factor that makes a project interesting.
But I think you're making a mistake in assuming they mean someone should force a specific language on them. In practice nearly every working TS dev knows something else, python, ruby, elixir, yeah maybe go. They should choose one of those other languages for the tool. A specific one doesn't need to be forced on them, just the decision that it should not be TS.
Companies should be properly staffed to support the platforms they're distributing on. If you're building a CLI tool, you should have devs familiar with doing that use an appropriate language. You should not repurpose front-end web developers to build the CLI tool in a web front-end language just because that's all they know. That's pushing your business, training and hiring problems down to the user.
Not to say web front-end devs can't make great CLIs (or servers)! It's just that they should train up on an appropriate stack if they're going to do so.
That's his point, though. Command line tools require a different skillset. If a team has only worked on browser applications, they won't have the skills for command line tools and will need to learn them. Taking time to learn contradicts the grandparent comment, which suggests that people should stay in their lane and that there is nothing worse than forcing developers to work on things they are not already familiar with.
If one is going to hold that developers shouldn't be forced to learn on the job, even if by way of fellow teammates trying new approaches that others will need to maintain, you simply can't have them working on CLI tools and bringing on new teams that will operate independently is the only way to see movement into new areas.
My comment said no such thing. There is a difference between "types of applications you build in a language" and "language" (the first 7 words in the earlier one). It is much easier to learn how to write a different kind of application in a language you know, because you already know the language. You have to learn less.
I'm not sure why you're putting things as if I've made some absolutist statement. All I'm saying is: You only have the resources you have, and the efficient way to use them (especially in the long term) is not to leave architecture and implementation to a team that knows neither the language nor the environment.
I think there are much, much worse things than this. Most of the time, I would count among those things the humongous downsides of JS, but it depends on your situation, obviously. There are plenty of cases where you should use JS/TS. But if I only knew TS and had an opportunity to write a CLI in Rust, I'd jump at the opportunity. It's not always the case, but lots of things are appropriate to use as an excuse to learn something new.
Could you explain these "humongous downsides of JS"?
I do acknowledge I have a lot of bias, though, because I work at a TS shop where the primary reason we continue to use it is because we always have. The longer I have to put up with it, the more I feel like this is a broken foundation to stand on
And I wouldn't strictly differentiate between these areas. My game development experience helps me to write better backends and frontends alike. They are separate insofar that you have to learn each environment to be able to write idiomatic code, but it's not like you can't re-use parts of your knowledge across all of them.
It was a bad combination of "green" JS engineers writing servers and a new batch of fresh FAANG veterans mentoring them into writing extremely complex and expensive systems. There is a large dollar value attached to this fiasco.
It sounds like you have a bone to pick - because when was this ever not the case? Most developers of any generation don't really know about the complexity of distributed systems. Some developers do, even in "the cohort of engineers" who you say wasn't taught this. People using inexperienced (in the topic) developers for complex systems is not something new either. People use who they have.
Another one would be to pick Java or C#, but the stereotype of a developer like that is that they will overcomplicate and make a heavy, enterprisey back-end; Node backends feel lighter, so I can again understand why they would rather have a Node / JS type developer, they're more pragmatic.
Ideally you'd get a "polyglot" developer, or a developer who has embraced that language is just an implementation detail, someone who can see beyond a language and its ecosystem and stereotypes. But the hiring pool for those is small, and convincing them to work for your company is really difficult if it doesn't do anything exciting, new, or cannot pay a lot.
That's kind of the approach I'm proposing. Don't care about the language, use the one your developers know best, because the language itself is just an implementation detail, while the proficiency will help you in any language. You're not going to get a large group of great polyglot developers, so you have to reverse the process and choose the language your developers know best.
I'm not saying that performance, memory consumption etc. are completely insignificant. I myself prefer to use faster tools that use less memory. But if all you have is a bunch of Typescript devs, and you want them to develop a CLI, you're not going to get a better result by telling them to do it in Rust. To get a better result you'd have to tell them to learn Rust and work in it for half a year. And yes, that would be better for users in the long run, but that doesn't mean it's realistic in all cases.
Just write it in C# and take the afternoon off.
I was with you when you said command lines, but servers? JS is a fine choice for servers. I haven't seen Rust do anything on the server but slow people down, and I have found people who think they know Rust don't really
Plenty of people are productive in JS, and when working with ES6, it can even be comparable to immutable functional languages. It's on the team if they aren't reviewing code or are allowing bad habits.
I disagree. JS is single threaded. Sure there are some hacks to kinda, sorta get around that, but it's the nature of the language. Tying yourself to a single thread or dancing around that is an unnecessary restriction that compiled languages aren't going to have. JS is designed for web pages, not servers and not apps.
Multithreading is a nice to have; it has a bunch of costs around needing to introduce locking and synchronization primitives into the language, those costs aren't the worst thing ever but it's often nice to not have to deal with them.
Python has async, has green threads, and has OS threads through the multiprocessing module. The fact that it has the GIL does not mean, that it cannot use OS threads or multiple processes. JavaScript in comparison does not have multithreading. NodeJS itself is multithreaded, but you cannot put application computation on those threads. You will need to use worker-threads and basically like PHP run multiple instances.
However, neither of those languages is particularly nice for using the multiple cores available in modern machines anyway.
JavaScript's async IO is plenty fast for any typical web use case, and the marginal savings you might get from having a few fewer servers will be more than made up for by the time your team of web developers (who already know JavaScript) wasted learning Rust or Zig.
Zig looks promising, but the ecosystem isn't mature yet. Suggesting that Zig can replace a production-grade server based on Express.js today is.. madness.
> completely ignoring the ecosystem that makes shipping projects possible in the first place.
There are so many bad js libraries out there, more than any other language I've ever seen. There's no special sauce in the JS ecosystem, there's tons of libraries available for any modern language (not Zig, I included that as it probably will get there). There's nothing you can do in JS that you can't also do in Go and the quality of the library your using is going to be much higher than whatever's on NPM.
Are you a working web developer? If so, can you give a concrete example of a web application you've worked on that required multithreading on the web server?
I've needed it client-side to avoid freezing the UI with heavy computations, but in all my years working on server-side code (in PHP, Java, Ruby, JavaScript, and Python) I have never wanted to manually create a new thread on the server, even in Java where I could have!
> I've also noticed that devs that understand how to do multi-threaded programming are the most proficient.
Knowing how to do multi-threaded is different from insisting on using a language that supports multi-threading on a project that will never require multi-threading. I've noticed that devs that understand their project requirements and don't engineer for problems that the project will never face are the most proficient.
Yep, I'm a working (and successful) developer who has built a lot of different types of programs, often web servers.
A concrete multi-threaded example would be a web server that federates to Mastodon (which is quite noisy and benefits from having the "bridge" be in its own long running thread(s)). Really anything with long running processes that aren't keyed off of ux events is best done with multiple threads.
When I've run into specific cases in TypeScript projects that require that, I've tended to just spin up a new long-running service for those requirements.
But then you're not sharing memory and have to rely on message passing... it's all doable of course, but this is just one of many examples where the language will hold you back.
Compiled GC languages? Maybe. There's a reason Go is exploding, even though it's type system actually sucks.
I've actually never heard this before, can you elaborate? Typically it's expected that the compiler will give you better errors than what you get if your app crashes at runtime.
In JavaScript, I return whatever I want and the garbage collector handles it. Slower, but perfectly fine when my servers main job is waiting. Using Rust instead is not just "better errors," it's more potential for errors. If CPU cycles aren't important for my app, why not just use Typescript? Rust is not just "JavaScript but with better errors," it's targeting a completely different use case.
If you want a fast, multi threaded language with a good type system, you can do it without Rust. C# is extremely fast, and in some use cases, faster than Rust.
That's not true of any of the languages I've listed. You may not like the borrow checker, but it's not manual memory management. Also, Go has a garbage collector you don't manually manage memory there. I don't think any of these languages would be considered "low level".
But no, just because Rust has a borrow checker doesn't mean you aren't manually managing memory. It just means there are guard rails for it and the way you do it is different. Here's the gut check, does Go not allow me to use a variable because it's location has already been freed? That's what automatic memory management looks like. Not only does Rust not have that, it's even more complicated than c++ RAII in some places
This statement is the reason we're all having to use Electron applications.
The amount of tooling that you need to use to surround your JavaScript code to make it somewhat correct is insane.
You're using a dynamic language. There is literally a whole slew of bugs that you cannot detect until you actually run the code.
You do get those things with Rust.
Getting Rust (same like when I used F#) to compile is hard.
But claiming that that is the reason JavaScript is faster is actually a reflection of not understanding what this compilation does for you.
I didn't even kind of say this. Rust is complicated for reasons beyond compilation. I actually like F# and strong type systems.
> The amount of tooling that you need to use to surround your JavaScript code to make it somewhat correct is insane.
There's no practical evidence of this, it's just a feeling you have. Big systems are built in dynamic languages fine.
> This statement is the reason we're all having to use Electron applications.
How is "JS is fine for servers" the reason you have to use Electron apps? Pick a topic. I am not overapplying JS
> You're using a dynamic language. There is literally a whole slew of bugs that you cannot detect until you actually run the code.
If you're using Rust, you're introducing a whole slew of bugs that you cannot detect unless you compile the code, and that you wouldn't run into in a GC language. And you're potentially doing it for no benefit because you don't understand servers aren't typically CPU bound.
Why choose Typescript over any of the other hundreds of languages that transpile to JavaScript?
There may be a few exceptions that were designed from the outset with JavaScript in mind, but then you're back to being at the mercy of JS quirks.
For me (and, I would argue, for pretty much everyone), that would probably be whatever programming language I am most familiar with. Unless the language has huge barriers compared to another one I am somewhat familiar but less familiar with.
I wish the dogmatic hate on JS would stop, it was boring 10 years ago, it's still boring.
Even if that part of the desired outcome is true (it's not though, as it rarely takes into consideration long term benefits and focuses purely on "instant gratification"), people who go to online programming forums as HN are hobbyists. And hobbyists do care about tools. You can't expect enthusiast to have this boring approach of someone who simply want to finish job on passable level and get the fuck out of office as quickly as possible.
And even if you are not a hobbyist, using a computer to do your/some job for you is literally what programming is about. So dismissing the topic of improving that process with better tools is simply ignorant
In a hobbyist mentality, go wild! Do whatever makes you happy. In a professional, business environment I want to deliver outcomes first, my personal happiness comes from delivering those outcomes so it matters less on the technical choice.
The Javascript hate is absolutely warranted.
Of all the languages you could pitch to someone already familiar with JS these would be at the bottom of the list. You want something dynamically typed, well trodden, and with a huge package ecosystem which to me sounds like Python or maybe Ruby. But honestly JS minus mountains of tooling is a really good general purpose language.
Zig may be useful in some contexts but it’s also in beta and it has a bus factor of one.
Rust is unnecessary for most projects that don’t need the extreme degree of efficiency it offers and would rather have a GC do all that work for them.
Go is fine, if you get along with it. Many people don’t like it because the type system is from the 1980s, but if you like that kind of thing then go ahead.
I genuinely don't understand how someone could make a statement like this. You mention command line apps and servers, but surely whether TS is the best solution would depend entirely what you're trying to achieve. If there's a great NPM library to help you with the problem you're solving why wouldn't you use TypeScript?
Not to mention the fact that TypeScript servers when paired with web frontends have obvious advantages. One project I worked on involved analysing 3D objects then visualising this on a web app. The simplest solution we found for visualising the analysis we were doing on the backend was just to build it all with Three.js and TypeScript then use common libraries.
I'll also note that good JS developers are generally competent enough to avoid "bad habits" and that "bad habits" in my experience are not isolated to the JS ecosystem.
Here are the criteria I'd use for choosing a language for a web server, in order of importance:
1. What does my team already know?
2. What languages have a robust ecosystem of web-related libraries?
3. Static types are better than dynamic if the team is larger than 1 or if the project will last more than 6 months.
Performance considerations might come in after this if there are still two languages left to decide between. But judging from those criteria, I think you can see why TypeScript would not be a bad choice for a full stack web team.
Learning a new language should be a frequent thing. I don't know how many languages I have learned, but it has only ever increased my understanding of computer programming, advantages and disadvantages of approaches and it certainly has made me a better engineer. If a business does not want better engineers, sure, stick to the "we can only use what we already know!" approach.
Let it take 2 weeks for people to learn a language! So what? It will pay off in the long run. You will have more experienced engineers, we have a less limited idea about computer programming and how to solve programming problems well, since they have gotten into contact with other concepts from other languages. You also get a more flexible team, that can accept building better and safer services, using the right tool for the job, instead of shoehorning everything into their only one language. You will open up more ecosystems for your whole business.
This is a joke, right?
It's enough knowing client/server types move together, avoids null/undefined/[]/0/falsy edge case bugs, param/return mismatches, etc.
So, the better advice is, real world can't be perfect, live with it and move on than complain. If you have so much to say, you're better off contributing to the project.
Do what is the easiest for you and your team.
In other words you can view the rise of Docker as saying, “give me your scripts and I will give you this magical unicorn called a container image, which can be used to run your script like a single executable.” People did not use Docker for its security features (the people who cared about that used VMs before Docker and put Docker into a VM after), but for its operational feature. If anyone had understood this before the rise of Docker, I think they would have architected Docker differently: multiprocess containers and weird networking stacks could have been done away with, you would probably not throw all of the OS into the binary because that's overkill (just Terraform-like “providers” or so?) ...also Docker needs to run as root to establish its tentacular spectacular: if you had viewed the goal as packaging the scripting language as a virtual binary you probably wouldn't need this stuff.
If you are running a large enough company then you need something like kubernetes because you have thousands of developers all needing to deploy on to the same prod hardware clusters. Cloud computing generally tries to lump you into this bucket too. In those cases there is no difference.
But if you are running a small dev shop of less than 20 devs at a larger 100-300 person company, now prod is whatever Casey your sysadmin says it is, and Docker is forbidden by some policy that you can't run as root or so, so now it's easiest to just compile static binaries and then build a lightweight gitops thing out of that, put an NginX server in front (except Casey gets mad and makes you use Apache) and some FastCGI and with a bit of luck you can get it so that if the build or tests fail, the system sends you an email via nagios but keeps humming along with the old build. It's a few weeks of work and you'll complain to every dev you onboard “I'm sorry this is all held together by duct tape” but it'll chug along fine until that company becomes 5,000 strong and you have 500 developers and can afford to containerize or shift to cloud for new applications and "do it right".
Its starting argument is based on an asserted ignorance of some devs on what TypeScript actually is. From there, it outlines all the limitations of the language it can think of.
Obviously TS is not a good-for-all solution, never intended to be, and never claimed to be.
So going around saying TS is not something it was never meant to be, just because some people misunderstood what TS is, sounds, to say the least, redundant
And do what?
Perhaps it's my experience with a somewhat large(150k LoC) pre-CommonJS codebase, but I get the feeling that the language is being presented as much more intimidating than it really is.
Yeah, strange things happen when you add an array literal to an array literal, or do any sort of type coercion really.
My advice is: don't do it then. Seriously, you have to actively try to even encounter these quirks - especially now that we have language constructs like template strings, which prevent most such issues.
In every single decent language with a static type system you'll have to convince the type checker that data coming from outside the boundaries is of a certain shape by parsing it. If you're not doing it, then you are implicitly assuming it's of some type and you risk runtime type errors.
E.g. in Elm you do have to parse every single thing coming in from outside the boundaries both from http requests or other external ports.
This is the part that's missing. Or more completely there's no runtime types at all. So you can't do stuff like:
The mechanism TS gives you to do that is essentially recreating all your type rules in a validation. Which is keeping the same information in two places and risks them getting out of sync.Most people pick up a library that generates the types and validations for you to solve this. Which works but it's kind of weird that you have to.
Why would it?
Which static languages include automatic parsing at boundaries? Elm sort of does on ports, but that's like the only example I can think of, I'm perfectly sure that I may not know enough about it.
However, grabbing Zod or io/ts is a lot less work and with tools like https://quicktype.io/typescript or https://transform.tools/json-to-zod you can paste in an API response, copy over a validator and export a type. My homegrown validator classes won't be nearly as clean or as quick.
Javascript is easy to write and understand, easy to play with, without transpiling, e.g. in your browser. When you write code in the native language, you know what you write, how it will run on the system. When you write in Typescript, it generates some Javascript that is sometimes hard to recognize as your code.
Every time I have tried to compare the output of `tsc`, I have reached the opposite conclusion.
It's incredibly faithful most of the time. And when not, it's consistent. So if you understand why it does what it does once, life becomes much easier.
Perhaps you are referring to minified code. Even then, with source-maps correctly setup, I rarely if ever have a reason to leave TypeScript-land.
Without the type-checker, my productivity (and sanity!) would likely be cut in 1/2 or more.
I'd be very interested in examples that resulted in your opinion.
- extremely verbose
- even further verbose and hard to read compiler errors
- advanced uses require extreme prophiciency in TS
- poorly typed libraries (including the standard ones, for easier transitions to ts), e.g. JSON.parse returning `any`s
- untyped error channels. Got a function that can throw an error? You can't type it unless you change the shape of the returned type to some ADT like `Either<A,B>`. Have a promise that can reject with some generic error `E`? Well, `Promise<A>` takes only one generic argument, the errors are untyped, so you need to use stuff like `Promise<Either<A,B>>` and handle it manually or with external libraries.
- Hard time to implement many kinds of stuff with a fluent api (meaning stuff like Foo.get().map(someMappingFunction).call(Baz) needs to be implemented as `get`, `map`, `call` as separate functions, not as methods). This is what forced `fp-ts` to go for `pipeable` APIs ( pipe(get, map(someMappingFunction), call(Baz) ) rather than the fluent api before. It also led for a period the `effect` ecosystem to write their own extensions for TS, called TS+ [1]
[1] https://dev.to/effect-ts/the-case-for-ts-18b3
With all of that being said, TypeScript is one of the most productive and efficient and flexible programming languages out there, I know very few languages that allow to write so many kind of software for so many kind of platforms. TypeScript's structural typing has a long list of pros, and for functionally-inclined developers like me TypeScript allows to express and implement stuff that other languages e.g. Haskell cannot such as more generic typeclasses like Ordering, Eq, etc, without the same being "attached" to the type itself and being unique (which has no mathematical foundation, there's infinite ways to implement a sorting on any kind of type, there's zero mathematical reasons why there should be only one).
How do you type it?
[1] https://www.typescriptlang.org/play?#code/C4TwDgpgBAUgygeQHI...
It is important to understand that you are not "using typescript". You are in fact adding a layer of code on top of javascript. This layer is a variant of javascript, adds tooling and requires additional effort. One overlooked aspect of typescript is that it requires of typescript to read it. If you publish your typescript code, for example in an open source project, it is less accessible to javascript programmers.
The tradeoff between these two is something that is use case dependent.
As a sole developer, after a couple of attempts I am adopting option #3. Instead of
`function dosomething(params) { console.log("%s, %s",params.duck, params.dog)}`
I now write
` function dosomething({duck, dog}) { console.log("%s, %s", duck, dog)} `
I find this gets me at least 50% of type problems that I usually miss, and the cost is extremely low.
As a sole developer who needs to be extremely productive I simply can't afford typescript. I can afford this. And maybe there are other easier-to-use ways to catch other type problems?
TypeScript seems to be losing the plot to its own movie, turning into a sprawling, complex language like C++ or Scala - the "choose your own adventure" type.
https://github.com/tc39/proposal-type-annotations