I recently came across the article "Complexity is killing software developers," and I've been thinking about it ever since.
The article covers a broad spectrum around software development in general, but I've been thinking specifically around the domain of front-end web development, and the multiple layers of abstraction we often buy into as being zero-cost--essentially: all feature benefits, with no significant drawbacks.
We write our components in JavaScript. Except it isn't. It's TypeScript. We write a function call to update the DOM. Except it isn't a function call. It's JSX (TSX). It'll be a function call later. The JSX contains markup of what HTML elements it will render. Except it doesn't. They're "styled components", all of which are abstracted from both the elements they render and the CSS that will eventually be read by a browser. We include this component in our HTML document, except we don't. Someone wrote a 200-line Webpack config file that will magically split this component and others, along with other assets and resources, and render a linked document, based on an abstracted template. Maybe Webpack itself is abstracted, behind a tool like Next.js or Vite.
At my company, I started working on a site and just mentally tallying the layers of abstraction: styled components, TypeScript, React, Redux, route strings as typed enums, content as JSON...and I started to wonder: was all this necessary? Is it worth it?
Or another way to ask it: what is this costing us?
First of all, I have to acknowledge that this question is ironic coming from someone who's been one of the maintainers of Less (the CSS pre-processor) for the last few years. So, it should be said that I'm not against any of these abstractions on their face. I may have strong opinions about this or that tool, but there's no question (to me) that the rise of reactive libraries were a net benefit to web development, or the adoption of component-based design. I've often advocated strongly for tools like TypeScript.
That said, in the past little while, I've started to feel differently, and I've been thinking about this problem from a different perspective. What I've started to see is that, where we used to add these tools to solve a particular pain point where we had before, as a culture, we in web development have acclimated to complexity regardless of the costs. Why wouldn't we use Webpack? We used it before. Why wouldn't we use TypeScript? It's what we're comfortable with.
I think what we've failed to recognize--and I will include myself in this--is that for each benefit it may provide, there is a maintenance and cognitive overhead cost (among other costs) in each additional abstraction that we add into our workflow.
Our monorepo takes forever to run yarn install
, and no one knows exactly why. The complex nest of dependencies is not something we've been able to really dig into yet, as we're plowing through each sprint. Each app takes mountains of time to compile, and to run tests, and bundles seem unnecessarily large, but to decipher that just takes more time with each layer of abstraction.
Recently, I switched our dev build compiler of some of our shared packages to SWC from TypeScript (along with removing other abstractions), which, on the one hand, is great! You definitely should explore doing that.
But... on the other hand, I was solving a problem that we ourselves had created, and this sacrilegious thought also occurred to me: what if we weren't compiling / transpiling our code at all? How much faster would that be?
Immediately after I had that thought, I looked around me to make sure the web development gods were not about to smite me. After all, we've lived in a world of, if not TypeScript, surely at least Babel-ified JavaScript, but there's a question if that's needed anymore.
I'm not the first one to have this thought. Rich Harris, a prominent figure in web development, having developed Ractive, Rollup, and Svelte, had this to say about moving from TypeScript back to JavaScript (with JSDoc type annotations): "Among other things, the resulting code is generally smaller than transpiled code. Building, testing etc all become much less finicky. And .d.ts files are still generated from source code."
I don't want to make this entirely about TypeScript; for many teams, TypeScript may be the best option! But I think there's an overlooked value in sincerely asking the question of just how complex any project needs to be, and recognizing that each layer of abstraction is not zero-cost. It may increase development time, even as it decreases it in other areas. It may increase build time or deploy time. It may increase tech debt. It can increase cognitive overhead, or the time to onboard a new developer.
Do you need React, or will Svelte do? Or maybe something even lighter?
Do you need Less / Sass, or styled components, or is your design system simple enough that regular ol' CSS will work?
Do you need Webpack? Or is there something simpler, maybe with fewer options, but with less cognitive overhead?
Do you need Redux, or can you use Zustand? Do you even need a global state library?
Do you need JSX? Do you need TypeScript?
I've begun to think about this as Simplicity as a Feature. Just in the way that we may optimize for performance, and build for Performance as a Feature, I'm starting to think we should optimize our tools and codebases for simplicity. Not to use the simplest tools but to simply use only the tools with only the features that we really need. And if we start to need that next abstraction, that's okay! Sometimes there are things that are trade-offs for performance, just like there are things that are trade-offs for simplicity.
But the leaner you keep your tools and your code, in theory, the faster you and your team can iterate, build, and deploy.
So stop using giant boilerplate-y project templates with every conceivable feature and tool you might ever need. If you use TypeScript, it's okay to not use it on some things! Heck, it's okay to manually write an .html
file! It doesn't make you a bad developer, I promise!
And if you're new to web development, don't buy into web sites and apps needing to be necessarily complex, and you needing to learn and use myriad layers of abstraction.
It's okay for things to be simple. That might even be best.
Top comments (5)
Nice article! I think most of the time how big a software will grow is overestimated, and if the selected options would fit that growth, not taking to account other variables that might affect, such as team prior knowledge and available tools/resources to develop it. The community would benefit a lot if that discussion would be brought more frequently to architecture decisions, sometimes it feel almost automatic to go along with the tide in those options.
It sounds like you're slowly moving to the viewpoint I adopted a little over a decade ago. That all these frameworks and abstractions do not deliver on their promises.
With me, it reached the point where I am no 100% against front end frameworks, and a lot of the tools like LESS/SASS/SCSS because to be brutally frank, EVERY claim of "benefits" to their use is a bald faced LIE!
They add more to learn, more steps to the development process, quite often piss on the separation of concerns and reason HTML and CSS even exist from so on-high you'd think the almighty just got back from a kegger, and are nothing more than predatory scams. When you get to CSS frameworks like bootcrap or failwind, it gets many times worse as they slop presentational classes at everything defeating most of the reason CSS even exists, dragging things back to the worst of mid '90's markup practices. Same goes for idiotic code-bloat like BEM.
I should like BEM, any time someone comes up with a consistent naming convention I'm all in... but dumping classes into the markup destroying caching advantages, doubling or more the code size... much like the trashy ARIA roles the only time I could see the advantage is if you're ignoring semantics and using the wrong markup. Solution? Rather than sleazing all the extra classes or roles at things, just use the right markup!
Same for the pre-processor nonsense. I can see how people who think that a homepage of 4k of plaintext and a half dozen content images needs 100k of markup, 500k of CSS in 6 files, and two megabytes of scripting in dozens of files MIGHT think that LESS/SASS/SCSS and equally rubbish server-side junk like REACT or VUE serves a purpose.
But for those of us who would use 10k of HTML, 48k of CSS for the entire site, and probably have little to no client side scripting such "tools" are monuments to ignorance, incompetence, and ineptitude. The only thing about them that could be called professional grade tools are the people promoting their use!
That might sound harsh, but as an accessibility and efficiency consultant, these frameworks, tools, and so forth have spent a decade on my hit list for the problems they create and lack of real-world benefits. They CLAIM to be easier, simpler, or better, but that in now way, shape, or form lines up with the reality of just writing semantic markup, vanilla style and CSS, maintaining separation of concerns, and using semi-fluid elastic design.
All these tools have to offer developers are shiny beads and shallow flattery. The moment you actually understand HTML, why CSS is separate from it, and embrace the idea that scripting only functionality is garbage, you will immediately see through the facade these frameworks try and hide behind.
Sadly, far too many people making websites aren't qualified to write a single blasted line of HTML. Lands sake, most folks can't even use h1..h6 properly. That lack of understanding is why people sleaze presentational classes at everything recreating the worst of HTML 3.2, slop static style in the markup or link to stylesheets without media="" or worse declaring media="all"... etc, etc...
Hell, just view source anything built with bootcrap or failwind -- even their own examples. Look for the LINK tags... do you see media="screen" in there? NO YOU DO NOT! Proof positive the clowns who CREATED these frameworks are unqualified to write a single line of HTML/CSS, much less have the unmitigated gall to tell others how to do so!
It's all -- pre-processors, client-side frameworks, etc -- a bunch of garbage that preys on those who scream "wah wah, eye dunz wunna lurn HTML and CSS" because of course learning all the rest of this stuff is so much "easier". BULLCOOKIES!
Any and all claims of this chazerei being easier, simpler, or better is nothing more than ignorant fools parroting propaganda. It is in no way, shape, or form based in reality.
In the defense of framework writers a los of these CSS frameworks appeared at a time when there were vast browser incompatibilities. Today browsers have standardized a lot but a decade or so ago they were vastly incompatible in key areas.
So for example jQuery didn't only make it a bit shorter to write, it also saved you to some degree of having to worry so much about IE incompatibilities. The same goes for some of the other frameworks of it's time.
And Typescript is more about bringing static typing to the browser.
But I definitely agree that too many decisions are being made out of fashion choice rather than true technical merit. And there seems to be a compulsive need to follow the "new best thing" all the time. It seems unhealthy for the industry to me.
Obligatory quote (Simplicity Matters - Rich Hickey, 2012):
"Programmers know the benefit of everything and the tradeoffs of nothing."
But it actually has an incredibly interesting dynamic when it comes to cost/benefit.
Quote:
"TypeScript began its life as an attempt to bring traditional object-oriented types to JavaScript so that the programmers at Microsoft could bring traditional object-oriented programs to the web."
There wasn't that much interest when it was introduced in 2012. That increased slightly when Angular 2.0 adopted it in 2015 but in my judgement the availability of VSCode in the same year, bringing code completion (IntelliSense) for TypeScript to the masses, was the watershed moment (even though WebStorm 6 supported DefinitelyTyped back in 2013).
People proclaim that it's about static type checking but the appeal of intelliSense is undeniable - to the point now that many people will ignore projects that do not support TypeScript outright. Svelte suffered from this until it finally added support in July 2020.
So as it is so typical in open source software, the people who "demand" the benefit aren't typically the ones who have to pay the cost.
Mark Erikson (Redux) documented his TypeScript journey from the perspective of a library maintainer (who has to pay the cost) - which comes off as a lot more gruelling than the typical reported application developer (who benefits) experience. Once converted there may be legitimate claims to improved code quality, though I'm not sure that is quantifiable.
In order to mitigate the inherent tradeoffs of forced transpilation and generated code bloat projects like Preact have adopted "JS Doc TS" instead. Ironically I strongly suspect that competent "JS Doc TS" development requires a much higher skill level than plain TypeScript development.
The "JS -> JS Doc TS" learning path just doesn't seem to exist, mandating the "JS -> TS -> JS Doc TS" route, making it far more likely to just get stuck at "TS" and never get to the "JS Doc TS" level.
So in the end it may be far more difficult to recruit people who can competently maintain a "JS Doc TS" code base as opposed to a pure TypeScript one. There are some vanilla JavaScript projects that are fortunate enough to get user contributed declaration files but those can vary in quality, especially considering that some JavaScript code cannot be effectively typed and not every TypeScript developer is a ninja in TypeScript's typing language.
In summary - TypeScript as a technology:
So in some cases the aggregation of complexity (despite its tradeoffs) often results because those who benefit often don't have to pay the cost.
This article is the one of the most honest technical blogs I have read in a while and I completely understand and agree with the writing. Loved it!