The JavaScript Black Hole: A playbook for ethical engineering on the web
obsessivefacts.com
obsessivefacts.com
[1] https://en.wikipedia.org/wiki/Canvas_fingerprinting
[2] https://en.wikipedia.org/wiki/Device_fingerprint
Bullshit. Yes, javascript has evolved a ton over the decades, and it has a lot of cruft that it pulls with it. So what? So does virtually every other successful language.
I was a Java developer for over 15 years before I switched to mainly developing in Node/Typescript, and I feel I am much more productive in this ecosystem than I was in Java.
And I must actually say that it's a joy to work in modern JavaScript. It has some very nice features (async/await, destructuring, null coalescing, functional features) which make it expressive and succint. It has decent performance as well, nice (lack of) tooling (no need to compile anything!)
I probably would not do a huge project with it though (TS would be better fit there).
When you account for that, I would strongly disagree that JS has less weirdness and cruft than Python.
Compile time of the FE SPA code, webpack, and everything else from JS land, 5 minutes.
Then there is the whole issue regarding performance and tiny errors that bork a complete page.
Yeah, really productive.
However, JS accumulated significantly more cruft and legacy BS than the other 7 languages I learned and worked with. So let's not pretend JS is on par with everybody else. It's not.
We simply had no choice -- for like 20 years -- but to use JS. That didn't, and still doesn't, make it good. It makes it the half-baked language that everyone is stuck with nowadays.
If anything I find it ironic that Java was supposed to be the language that was "run everywhere", but Java was never successful in the browser. For the very first time I have front end and back end teams using TypeScript for pretty much our entire code base and it has unlocked a huge amount of team productivity that I've never seen in environments where different teams are 'siloed' behind totally different programming languages and ecosystems.
As long as we agree that siloing is not a problem everywhere. It's all about the people first, technology second, or that has been my experience at least.
But I still can't get past the fact that when I work for a company that wants to write a web app it is just like magic that it works across all these operating systems, phones, and etc provided they have a capable browser.
To me that utility is amazing. I don't see how to get around that, and for all the issues listed, I don't see a reason to throw the baby out with the bathwater / not really sure what the alternative is supposed to be.
As for privacy, if we weren't doing things in a browser as much and you had to install an app... would OSes be a better host / not have all these issues?
Granted the article is sort of a goulash of not incorrectly but not entirely connected ideas. Like a lot of JavaScript criticisms you couldn't possibly address them all, maybe that means something ;)
That matters a lot when you start running things at scale.
Also, once you have any interactivity, there's a point where it's nicer when all of the application is in the domain of Javascript instead of only parts of it.
Server-side rendering has some nice upsides, but there are various trade-offs, good and bad, at play here.
Maybe I am misreading you because this sounds to me like "we only want to hire JS devs".
When done this way, I think there's more incentive to actually optimize API requests.
Server side rendering is challenging to do correctly for any app with transient state, inter-app navigation can be slow, it has user experience challenges around interactivity.
It also has advantages, like providing a more resilient history stack and a faster initial render.
There's no one reason why an app would choose a SPA over a "traditional" SSR app, but there are definitely advantages and disadvantages to both. It shouldn't be a surprise that many web apps, especially ones with a lot of client state to manage or a high level of interactivity, find SPA a more attractive option.
Sure, there are definitely examples of overzealous SPAs (cough Reddit cough), but there are also plenty of complex sites that are being SSR'd and that hurt for the interactivity and intra-app navigation speed of a SPA (thinking about kludgy enterprise software).
Ultimately, for most projects of any significant size, you end up using both in some way. Lots of companies will use a static site, CMS, or simple SSR'd app to handle "front-of-house" concerns - homepage, marketing, blog, login page. The main app will typically be a SPA.
- What's an inter-app navigation btw? I honestly don't know.
- Transient states have never been a problem in my backender career for 18 years. Only when somebody figures it's a good idea to dump a raw object with 3 levels of preloaded associations in an HTTP session, which they quickly learn to never do again (cookie size limits).
- UX challenges around interactivity can and are handled very nicely by being strictly an SSR project and sprinkle Vue.JS where it makes sense, with impressive results. (Sure, some projects need the complexity and the machinery of React, I am not denying that.)
---
As for raw speed, well, maybe it's time to start admitting Python Django and Ruby on Rails aren't that fast then, is it? PHP's Laravel is okay due to PHP 7 mostly, and due to diligent pursuit of performance, for which their team deserves a round of applause. Node.JS is also okay however its struggle to properly utilize all CPU cores and the finicky evented I/O stack that crumbles under not-that-big-a-pressure are a turn off.
I started working with Elixir's Phoenix ~3.5 years ago and only had apps return in more than 5ms when you do complex SQL queries (which part of the time can be alleviated with query optimisation). While Rails' ActiveRecord easily swallows 150-200ms just serializing and deserializing from/to the DB, on an i7 CPU! Python's Django is better, but not by much. Laravel is OK but still not that impressive in 2020, when commodity i3/i5 CPUs ace various real-world benchmarks otherwise.
---
My point here is:
Let's not conflate "most SSR frameworks are crap and are written in slow languages" with the more general "SSR is slow". No, it really isn't, if using the right tools. Most web projects in my life could have been served from a Raspberry Pi 4 and written in Elixir's Phoenix and never break a sweat (maybe you'll need to attach an SSD though, because microSD cards are usually breaking easily).
(Or Rust's Rocket, which makes you feel like you are visiting a static HTML page. It's that fast.)
Elixir has, on average, 1% to 3% overhead, while Rust's is hard to even measure (likely 0.1% or below). So 97% to 99.9% of the time, those languages' web frameworks simply wait on I/O. And that's not the case with the vast majority of web frameworks out there, sadly.
This has a lot to do with the religious sticking to PHP, Python and Ruby on the backend, which are practically the worst choices of all. Even Node.JS performs better. Or Java, when written well and not having 20 layers of enterprise-y stuff.
1) They are easy to add
2) Economic incentives are not aligned with technical rigor and security.
3) No matter how much we write and post on this forum, we're shouting into a void composed of the 80% of developers who do not care, and the 100% of people who pay them who do not care. Why should they care about the occasional user getting compromised by russian hackers? "Not my problem" attitude won't get fixed by social enforcement.
4) Progressive web apps + modern stack need an expert hand, and are not straightforward to set up in most cases. Much more difficult at any rate than setting up a quick react app. Next.js and others do well at making this less difficult, but see #3.
Everywhere I've worked that just shipped a "static" SPA, doing so did not materially affect the business over shipping progressive functionality. Embracing "rigor" was seen by a waste of time to anyone who had a hand in task scheduling, and why should they care? No PM or startup CEO is going to care a whit about anything this article talks about, unless it happens to be central to their business.
"Imagine an operating system where all software development must be done in QBasic; it's an operating system that downloads, installs and executes any program the moment it is encountered, without your permission, and it leaks information about your activities to anyone who wants to spy on you. No it's not Windows 10; you've basically imagined a modern web browser."
It's not like one couldn't create a fully-fledged client side application before Angular and React.
What this reads as, to me, is "Gmail, a highly-stateful tool, is downloaded locally and then it requests a large portion of the user's inbox and other data for usage."
I highly doubt the JavaScript is re-downloaded every time the author visits Gmail. If it is, something has gone wrong. I don't think the initial load time is a good metric of performance for a true web app; on subsequent visits that 12.6MB should be loaded directly from disk, just like the binary of an installed native program.
Also, JSON is leaner than HTML, so the only reason that "3.5 megabytes of XHR data" would be larger than what was already being downloaded before is if Gmail is loading data more eagerly (loading the first several hundred entire messages of your inbox, for example, instead of just the subject lines of the first 50). This eager loading would presumably be done to make subsequent actions faster, and while we can debate the decision that was made in this particular case about exactly how eager to be, that isn't exactly an endemic issue like the author makes it out to be.
I don't know about Gmail, but this argument misses something important. A web app with several megs of JS is most likely being developed and pushed to production on a schedule (daily, or weekly, or something). So you're probably re-downloading the whole thing every few days.
> Also, JSON is leaner than HTML
Mmmaybe. With gzip, the difference isn't that large. And since not all developers are perfectly careful, the initial JSON will often contain stuff that isn't necessary for the initial UI state, so server side rendered HTML will often be leaner and faster.
That's a fair point that I hadn't considered. But still: native apps get updates too. I've been annoyed by really frequent update prompts. Maybe the web streamlines the process to a point where devs may not notice the overhead it's causing for users, but that still comes back to being a UX issue, not a technical one, IMO. Maybe continuous-integration isn't a good idea when it comes to client software in general. Maybe releases need to be artificially slowed to a weekly or monthly cadence, for the sake of the user experience.
It can't be THAT friggin' hard to split those JS resources in 3-5 files, or even 10 (having in mind the huge amount of HTTP requests their JS initiates). It's relatively easy to identify which parts are updated very often and which rarely change. There are numerous ways to optimise the time to first contentful paint.
Google can absolutely pull it off. The reality is that they just don't care. And yes Gmail is slow, even on Chrome. Even on a modern Xeon workstation.
QBasic has no built-in array sort. QBasic has no function references, and by extension no anonymous functions. QBasic has no objects. It does have structs, of a kind, but they're much more limited, and don't have prototypes or participate in inheritance.
I write a lot of internal tools for my company used in manufacturing/fulfillment. We generally deploy these as fleets of Raspberry Pis. The front ends for these systems are generally pretty simple, they just walk an operator through what they should be scanning, and for hardware interaction I use a small node server. I serve a React App to these stations (from an internal server) to render this UI.
What (modern) alternatives are there for this that do not use web technologies? I've recently grown an affinity for ruby and attempted to rewrite my frontend in Shoes, but the barebones documentation and lack of SO answers made that a huge pain in the ass, not to mention the added steps in deployment of updates. Going any other route just seems like so much more work for no true benefit.
The alternatives for you are probably pretty time-intensive for you and probably annoying for your users ("hey, install this program/app/etc"). I'd say if you want to rely less on JS and use more server-generated HTML, PHP might be the simplest option for you. People around here shit on PHP, but PHP was "serverless" before it was cool and has a lot of tools to do exactly what you're doing. But again, ask yourself what you gain by switching to another technology.
There are lighter weighted options that optimise for minimum latency and minimum CPU overhead.
What minimal alternatives would you suggest given the constraints?
- Elixir's Nerves: https://nerves-project.org - Golang: + https://github.com/tinygo-org/tinygo + https://gobot.io/ + https://github.com/golang/go/wiki/GoArm - Rust I suppose you can just directly compile for any SoC like the RPi.
In that case, Java is probably your best option.
1. They work on every device: desktops, mobile, tablets, kiosks, etc.
2. To upgrade a client installation, you just need to refresh the page. There's no app signing keys, no special download server, or installation framework. You don't need to worry about installing ruby, python or any other libraries.
3. You have a huge pool of developers, since practically every company has some sort of web app. Also, any problem you run into will already be on Stack Overflow.
But I agree with some of the posters here. If what you have works well you're much better off just iterating on it and not changing the tech stack.
Now that we have compilers and transpilers like Babel and Typescript, it means we can effectively code how we want (even with different languages like reasonml, ocaml, purescript, or ESNext), and in theory browser venders can simply make a new target language or version of JS that these compilers can target.
The tools aren't always perfect, but they get better all the time. It's also a spectrum of choice for which stack you feel comfortable with. Babel and Typescript do increasingly less transpilation with major browser releases. In many cases Typescript today really is just JS with Types. Certainly options like ReasonML and Purescript exist on the opposite end of the spectrum, very little resemble JS, do a lot of more work in transpilation (and do sometimes make JS interop intentionally hard by treating it as an FFI or equivalent boundary). The added "indirection" has trade-offs in productivity, developer "comfort", project aesthetics and synergies.
To put anything on the screen in an accessible fashion, you will still need JS with your WASM.
You can draw to a canvas with minimal JS, but lose text search, highlighting text, copy/paste and screen reader compatibility, to name a few.
Also, it's hard to call any language like (Q)BASIC or Javascript a "toy language" when it is used to build so many real world practical applications. The esoteric programming language is full of some truly interesting toy languages. Both Javascript and almost every flavor of BASIC has powered real world applications for decades. The underlying fundamentals/foundation of JS is sound enough that many things have been accomplished with the language, even if it isn't aesthetically pleasing to some (or sometimes betrays its very rough, "quick and dirty" development origins).
(Then there's of course the digression in whether or not WASM is also building a sound VM option for languages that really don't want to work with JS directly on the web/in web browsers.)
Can we stop conflating "it's popular because we had no choice but to build web apps with it for two decades" and "it's a good language", please?
Mud bricks also saw huge usage thousands of years ago. Still doesn't mean they were a good building material for houses.
But mud brick (AKA adobe) actually is a good material for building houses in certain climates, and it's still being used to this day.
If it's the case that Javascript being necessary doesn't make it good, it's also the case that Javascript being old doesn't make it bad.
That's not the argument at all. It's all the quirks and widely accepted strange behaviours that JS devs grew a Stockholm Syndrome for. And that you can do without if you used another language on the browser.
Javascript is an interesting language on the evolutionary chart with genes from Scheme and from Self. While those genetic traits are sometimes obscured by the last minute bolting of an ALGOL-like syntax on top (by way of Java, and thus the odd name), they are still fundamentally there. There are some really smart (albeit quick) decisions underpinning the language that have helped it to survive multiple decades of (ab)use on the web and elsewhere. It has had its flaws, its evolutionary dead ends, its quirks, but show me any language without those (and I'll sell you a bridge).
If there is a risk of a conflation problem here, I'd suggest it has more to do with people conflating "easy/accessible" and/or "populist" with weak or bad. BASIC is "bad" because it was made to be easy and welcoming to beginners. (But it still got a lot of serious work done in almost every field, by just as many [domain] experts as language beginners.) JS is "weak" because it was made for being embedded in browsers. (But the web browser became one of the most important forces on the internet for better and worse, and most of its weaknesses have been scrupulously filed off in daily usage and security audits and the pendulum swings between market competition and monopoly.)
I never said that and never will because it would be quite naive. Let's not resort to strawman.
I don't mind languages being "easy/accessible" -- if I did I wouldn't make Elixir my main language. There are many, valid, well-documented, warts of JS, so much so that an actual book called "Javascript: The Good Parts" had to be written. (I find that quite amusing.)
> I think it is a good language under the hood, and it remains in browsers because it is popular.
You might be mistaking what you said with "we literally had no choice for 20 years except use JS on the browser" (VB, ActiveX, Java Applets et. al. had game-breaking problems, cross-OS compatibility included, so they fell to the sides). "Popular" is the consequence of having no choice for a long time, not a function of any perceived high quality of JS.
Google's efforts with Dart failed simply because Google has a short attention span and their numerous cancelled products can attest to that much better than any argument I could make.
There's absolutely nothing preventing any corporation adopting any language and slapping a small DOM access library on top of it. This is not being done for HR reasons: the companies want to choose from a singular pool of devs so its operations are easier and quicker. A valid business decision which has zero correlation to JS being good.
JS survived because it was "the least bad" at the time when everyone needed a browser language. Everyone is too busy making a living so we just rolled with whatever the browser vendors and corporations half-begrudgingly (and rather urgently) settled at. Assuming you hated JS, can you tell me with a straight face that you'll sacrifice all your free evenings and weekends to produce another browser language? For like 2 years?
> It has had its flaws, its evolutionary dead ends, its quirks, but show me any language without those (and I'll sell you a bridge).
It will have them for a looooong time still though. Even if many will stop supporting IE11 soon-ish, there's still a ton of baggage left that will never get fixed.
The much more likely scenario is people will just start compiling language X to WASM and will go with that when hiring frontenders. And we will see the return of the full-stack role when you actually can work on the entire stack only with Rust, D, Nim, C++, or your language of choice. It is very probable we'll again start seeing web shops proudly touting themselves as "we only do C++ (or PHP, or Pascal) here".
This works on one computer for me, and get obfuscated on another (on a different network). Interesting!
Just install an ad blocker, turn off JavaScript or if you are really paranoid, pick one of the many linux distributions to load up into VirtualBox and browse the web that way, changing your distro daily. Use various VPN services on top of it. Use Tor. Most people don't care enough to do anything like this.
Most people in San Francisco might understand it. Do most people in Chennai, Nairobi, Rio or even in Smalltown, USA understand that?
While the author is not alone with this view, it's shared by many of my backend colleges. With such a condescending view I will hardly gain any insight I'm afraid.
The author also trots out the standard go-to argument of JavaScript haters. He writes that JavaScript "has deeply ingrained quirks and bugs which can never be fixed without breaking the millions of scripts that have made peace with the existence of those bugs and depend upon the well-known workaround" and he links to https://github.com/denysdovhan/wtfjs, a typical list of JavaScript's well-known type-casting quirks, etc.
Pretty much all languages have little quirks. Actual JavaScript programmers usually learn how to avoid JavaScript's quirks pretty quickly and easily. In my experience, people who fixate on JavaScript's quirks generally do not understand the language very well. If they did, they could criticize more substantial things about JavaScript than just things like "[] == ![]; // -> true".
(Except for C, but in that case it's obviously by design, and for good reasons.)
The mere fact that JavaScript doesn't have unchecked array bounds eliminates about 70% of the really serious security hacks of the last 30 years.
With native apps, you have very little control. You basically either run it or you don't. You can't just pick the parts you want to run. And you need to use a mitm proxy just to see what it's doing. The OS gives you no power here unlike the browser. A native app can send a request to Google Analytics on every keystroke and it's nontrivial to find that out compared to opening a browser's network tab.
Native apps have some advantages like performance, but they are no free lunch, especially when it comes to privacy.