The Cost of Convenience

thepassle

Pascal Schilp

Posted on May 4, 2023

The Cost of Convenience

Something I see happen time and time again in frontend development is developers reaching for conveniences. It may be the hot new tool in town, it may be existing tooling, but developers just love to take shortcuts. And this is fine! We all love to spend our time being productive, right? We'll just add this one little convenience that will surely make our lives better, never think about it again and move on.

The conveniences

When we talk about conveniences, we generally talk about non-standardisms or any kind of magical behavior. A useful rule of thumb is to ask: "Does it run natively in a browser?". A good example of this are imports, which often get subjected to magical behavior and transformed into non-standardisms, like the following examples:

import icon from './icon.svg';
import data from './data.json';
import styles from './styles.css';
import whatever from '~/whatever.js';
import transformed from 'transform:whatever.js';
Enter fullscreen mode Exit fullscreen mode

None of these examples will actually work in a browser, because they are non-standard. Some of you might have correctly spotted that a browser standard exists for two of the imports pointed out in the example, namely the Import Attributes proposal (previously known as Import Assertions), but these imports in their current shape will not work natively in a browser. Many of these non-standard imports exist for good reason; they are very convenient.

Other conveniences may include any kind of build-time transformations; like for example JSX. Nobody wants to write createElement calls by hand, but JSX will not run in a browser as is. The same goes for TypeScript. Developers evidently are very happy writing types in their source code (and will get very upset when you tell them you can use TypeScript without compiling your code), but alas, TypeScript source code does not run natively in the browser. Not until the Type Annotations proposal lands anyway, which is only stage 1 at the time of writing.

Using Node.js globals like process.env to enable special development-time logging is another convenience often added by libraries, but will also cause runtime errors in the browser when not specifically handled by adding additional tooling.

It is important to note that this is not to say that anything that doesn't run natively in the browser is wrong or bad. Exactly the opposite is true; It is convenient. Keep reading. It's also important to note that these are only some examples of conveniences.

The cost

The problem with conveniences is that they come at a cost. How easy is it to add this one little convenience that will surely make our lives better, never think about it again and move on.

It should come as no surprise to anybody that the frontend tooling ecosystem is complex, and in large part stems from the conveniences developers insist upon. When we apply a convenience to one tool, we have to now also make sure all of our other tooling plays nice with it, and enforce everything to also support anything. Whenever new tooling comes about, it is then also pressured into supporting these conveniences for it to ever be able to catch on, and to ease migrations to it.

But more concerningly, we become so accustomed to our toolchains and conveniences, that it often leads to assumptions of other people using the same toolchain as you do. Which then leads to packages containing conveniences to be published to the NPM registry. This, as you might have guessed, forces other projects to also adopt additional tooling to be able to support these packages that they want to use, and cause a never-ending spiral of imposed conveniences.

It is disappointing to see that we have still not learned from the mistakes made by the recently sunsetted starter kit of one of the most popular JavaScript frameworks over the past decade, when contemporary popular development tools are making the exact same mistakes as the one before it by enabling conveniences out of the box.

Where you apply conveniences, you apply lock in. What happens when the next, faster tool comes out? Will it support all of your conveniences?

The conclusion

Is this all to say that conveniences are bad? Are they not helpful, and not valuable? Should our tooling not be allowed to support conveniences? Should they be shunned, or should tooling not support them? Are they simply wrong? The answer is no. Conveniences have their merits and are undeniably valuable. But they come at a cost, and tools should absolutely not enable them by default.

Additionally, when you build for the lowest common denominator and don't rely on conveniences, your code will work anywhere. It ensures compatibility with new tools and web standards, eliminating conflicts. This practice is sometimes referred to as buildless development. While it may seem unnecessary to prioritize portability, the importance of this approach becomes evident when circumstances change; you might be right, until you're not.

And finally, you might actually find it refreshing to try frontend development without all the bells and whistles. Maybe you'll find that buildless development can get you pretty far, you'll often really only need a dev server with node resolution to resolve bare module specifiers, if at all. Maybe try it out some time.

💖 💪 🙅 🚩
thepassle
Pascal Schilp

Posted on May 4, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related