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.
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?
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.