Hey friends 👋 Welcome to a new edition of Frontend at Scale—your friendly software design and architecture newsletter. Today we'll talk about boring technology, exciting technology, FOMO in the 1970s, and the unmatched deliciousness of donut components in React. Let's dive in!
The Latest vs. The Greatest
Ok, it might not have been Feynman who said that, but I still think it’s true.
React is the perfect example of this phenomenon. Spend just five minutes on Twitter and it’s almost guaranteed you’ll find someone expressing their displeasure for it. We’re annoyed at React. We feel it’s old, and slow, and bloated, and confusing; and we all agree there are objectively better alternatives out there like Vue, Solid, or Svelte.
And yet, here we all are. Keeping React in the number one spot by collectively choosing it over and over again.
Some will say they continue to use it because they have no other choice, but I like to view it from a different angle—I choose to use React despite its many flaws because it’s boring, and in my books, that is a very good thing.
Dan McKinley wrote the original argument for choosing boring technology nearly a decade ago, and in the years since, countless developers have joined the movement of crafting bland, reliable, and predictable tech stacks.
Dan says it’s important we don’t associate “boring” with “bad.” Boring means stable, tried and tested, and well-understood—yet unexciting. Java, Python, PHP, and MySQL are all boring, and yes, so is React.
At the core of this argument in favor of boring tech is the concept of risk. Compared to new and shiny alternatives, boring technology is less risky not only because we understand it better, but because it has a smaller set of unknown unknowns. Here’s how Dan puts it:
The nice thing about boringness (so constrained) is that the capabilities of these things are well understood. But more importantly, their failure modes are well understood.
You might remember the pyramid of knowledge from one of the early issues of the newsletter. We used the pyramid to talk about technical depth and breadth, but if we zoom in on a particular technology, we can also use it to visualize its level of risk.
For instance, here’s what the pyramid might look like for a tried and tested, stable, and absolutely boring tool like React.
Even with all of its quirks and shortcomings, React (and we're talking about "traditional" React here, we'll get to Server Components in a moment) is a generally well-understood technology. Developers have been building and maintaining production applications with it for the last decade, so it’s safe to say it will work for your next project as well. There are very few ways in which React can surprise us at this point.
Compare that to how the pyramid looks for a new and exciting technology. We could choose any of the modern React competitors to make this point, but let’s use React Server Components as an example to keep this a fair game.
While we might have a good enough understanding of the advantages of RSC, we don’t exactly know where it starts to fall short. We don’t know what maintaining a large RSC application over the course of five years looks like, or how painful (or seamless) upgrading third-party dependencies built with RSC will be.
When it comes to new and exciting technology, we simply don’t know what we don’t know, and that comes with a lot of risk.
This is important because reducing risk is a crucial part of our jobs as software architects (some will say it’s the most important), and using boring technology is one of the most effective ways to minimize it to a comfortable level.
So, should we all just use plain-old-React until the end of time? Fortunately, we have other options.
Balancing Boredom and Innovation
With all this praise for boring technology, we might understandably come to the conclusion that we should always use the most boring tools at our disposal. But this is of course not the entire picture.
While we should always have a bias towards boring tech, we must also learn to balance our choices with our needs for innovation and solving hard and novel problems.
This is clearly easier said than done, so here are a few principles that can help us better navigate this delicate balance between boredom and innovation.
1. Spend Your Innovation Tokens Wisely
In a follow-up presentation to his original article, Dan McKinley talked about the idea of using innovation tokens—a made-up currency that you could spend whenever you wanted to incorporate an exciting but unproven technology into your stack.
Using Bun instead of Node costs a token, and so does using Fresh or HTMX. Do you want to try that new graph database and migrate your frontend to Qwik? Well, if you only have one token remaining, you’ll have to choose.
You don’t have to do this for every tool or framework you bring into your application. But if you’re choosing a technology that will have an impact beyond your team or even the entire organization, the constraints imposed by innovation tokens can really help.
In general, the more foundational a technology is for your application, the more boring it should be—and the higher the cost of replacing it with a new and exciting alternative.
We don’t get that many innovation tokens as an organization (Dan recommends a budget of three tokens). You can choose a different number that works for you and your team, as long as there is a finite amount of them and you take them seriously.
At the very least, this constraint should get us thinking more seriously about whether the cost of adopting a new technology is really worth it, or if we should save our tokens for a rainy day.
2. Squeeze First
A sure way to waste an innovation token is by using it on a technology that solves a problem that we don’t have.
There is, however, a much sneakier way in which we end up adopting new and exciting tools, which is when we bring them on to solve a problem we do have.
Imagine our frontend codebase truly has a scalability problem. Our monolithic application is starting to cause dev teams to step on each other’s toes, and we’re considering adopting a micro-frontend strategy using something like Webpack Module Federation to tackle this challenge.
This is perfectly reasonable. After all, we’re simply choosing the “best tool for the job.” But as we saw before, the adoption of any new technology comes with a fair amount of risk. So before making a decision, it’s worth asking if it’s possible to solve this problem with the tools we’re already using.
The answer might involve some extra work, or even using some library in an unconventional way. But as long as the cost of adopting your stack to the new problem is lower than the cost of maintaining a new technology for the foreseeable future, it probably makes sense to stick with your existing tools.
Dan Slimmon (this is a different Dan) put this very succinctly in a recent blog post: before adopting a new tool or paradigm that would cause a jump in complexity, make sure you first squeeze the hell out of the system you already have.
3. Avoid FOMO-Driven Refactors
Addy Osmani wrote about the importance of sticking to boring architecture on his blog, where he specifically calls out FOMO (Fear of Missing Out) as a strong driving force behind our technology choices.
This unfortunately happens way too often. Technology trends are really powerful and they deeply influence the way we feel about our codebases, which can sometimes lead us to refactor a perfectly good REST API just for the sake of using GraphQL (or maybe it’s the other way around these days.)
There are certainly cases when modernizing a legacy codebase becomes necessary. But boring technology should not be confused with tech debt, so we shouldn’t always spend our precious innovation tokens to pay it off.
Trying to keep up with technology advancements is pretty much a losing game. We might think that this is a problem of the modern era, but the truth is developers have been dealing with FOMO since the beginning of time. UNIX-time, that is.
To drive this point home, here’s Fred Brooks talking about the “joys and woes” of programming in his 1970s essay The Tar Pit:
The last woe, and sometimes the last straw, is that the product over which one has labored so long appears to be obsolete upon (or before) completion. Already colleagues and competitors are in hot pursuit of new and better ideas. Already the displacement of one’s thought-child is not only conceived, but scheduled.[...]Of course the technological base on which one builds is always advancing. As soon as one freezes a design, it becomes obsolete in terms of its concepts. But implementation of real products demands phasing and quantizing. The obsolescence of an implementation must be measured against other existing implementations, not against unrealized concepts. The challenge and the mission are to find real solutions to real problems on actual schedules with available resources.
How can we avoid the trap of FOMO-Driven development? The key is in the last sentence in Brook’s quote: stop playing catch-up with technology and focus your efforts on solving your user’s real problems—even if those solutions involve a fair share of boring legacy code.
In the world of machine learning (among other disciplines), there is a famous decision-making concept known as the explore-exploit dilemma: should we stick with what we know and love (exploit), or should we take a chance and see if there is a better alternative out there (explore)?
This happens all the time in our daily lives: do we go to our favorite coffee place, or should we try the fancy one that just opened? Listen to our usual playlist, or try something new? The latest, or the greatest?
It’s similar with technology choices, except that the feedback cycles are much longer. Sometimes we won’t know if we’ve made the right decision until many months or even years in the future, so it’s important to evaluate these long-term investments carefully.
If we're lucky, the latest might also turn out to be the greatest (I'm looking at you, Astro), but this won't always be the case. So when in doubt, choose a boring technology. It might not be as exciting as the framework of the week, but it'll probably give you (and your team) a much easier time.
📝 FROM THE BLOG
Delicious Donut Components
If you like donuts and React, I’m sure you’ll enjoy my latest article on the Frontend at Scale blog. You probably won’t enjoy it as much as an actual donut, but hopefully it'll still bring you some joy.
If you don’t like donuts… well, you might enjoy it as well. It’s not really about donuts. It’s about component composition with React Server Components, explained with a bunch of interactive diagrams and a few "don't try this at home" experiments. I hope you check it out, and please let me know what you think!
|Read on the blog
Links Worth Checking Out
- Great write-up by Eric Burel on client-server relaying—a Next.js architectural pattern to reap the benefits of both server-side and client-side rendering.
- Igor Roztropiński wrote an insightful article on his experience combining Web Components and HTMX.
- Do you know how much uptime you can afford? I certainly didn't, but this article by Itzy Sabo helped me figure it out (it's not that much.)
While I was researching for today’s essay, I ran across this great talk by Jason Lengstorf at SeattleJS Conf last year. It touches on some of the points we discussed today but with an interesting perspective on the importance of tinkering with exciting new technology in our free time—while still choosing boring tech at work.
I really enjoyed this episode of the JS Party podcast with Carson Gross, Alex Russell, and Amal Hussein. It’s not just about HTMX, and I truly learned a lot about the history of the web (and the role of hypermedia) while listening to their conversation. Highly recommended.
That’s all for today, friends! Thank you for making it all the way to the end. If you enjoyed the newsletter, it would mean the world to me if you’d share it with your friends and coworkers. (And if you didn't enjoy it, why not share it with an enemy?)
Did someone forward this to you? First of all, tell them how awesome they are, and then consider subscribing to the newsletter to get the next issue right in your inbox.
I read and reply to all of your comments. Feel free to reach out on Twitter or reply to this email directly with any feedback or questions.
Have a great week 👋