Simplicity as a Feature
Tags: javascript, webdev
Published: 2021-11-26 23:55:06

I recently came across the article "[Complexity is killing software developers](https://www.infoworld.com/article/3639050/complexity-is-killing-software-developers.html)," 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](https://swc.rs/) 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.