It’s interesting how language around service architecture changes as patterns fall in & out of favor.
People who advocated for microservices years ago now refer to them as “nano” services. It seems to get at the costly hassle it can be to integrate with, iterate on, and maintain a service with such a narrow purpose. Something “nano” is annoyingly small, whereas something “micro” is just the product of good design.
On the other hand, “monolith” was becoming an engineering slur. It was less than a pattern; more of a digital junk drawer. You only used the word if you were disparaging a system written by engineers who came before you.
But now, you hear more talk of “modular” monoliths — a more palatable way to describe a similar architectural ethos, but in a way that distances yourself from the poor implementations of the past.
At the same time, the monolithic legend Ruby on Rails is seeing a resurgence as teams are reeling with the tradeoffs of more tumultuous architectures, and Laravel continues to explode, even catching notable attention from other communities (despite PHP being dead — incredible).
Regardless of what architectural trends look like at a given moment, the language around them attempts to get at the same thing: how well-suited an architecture is to meet a need.
But being how consistently inconsistent they are, I wonder if the underlying patterns we use are as critical to an effective system as much as we seem to think.
I’m not old or wise enough to definitively know why these shifts occur like clockwork every few years, but it's fun to speculate. Let’s imagine:
You’re on a team that owns a monolithic service. It’s relatively new, but given a little time, the system starts to show its cracks. They’re not a problem at first; easy enough to walk over without really noticing. Maybe it’s the occasional bug dismissed as an edge case. Or perhaps a small change that took too long to ship, but that was shrugged off because you have new engineers who are just unfamiliar with the codebase. Nothing's on fire and there's no negative impact to business or productivity. Stuff like this just happens (and really, it does).
But eventually, those cracks swell. It's harder to walk, and your team finds itself outright tripping more frequently. The stumbles are mostly just annoying, but quickly enough, crippling. The pipeline is consistently blocked, and you’re playing Whack-a-Bug every time you do get around to shipping something (which seems to rarely happen nowadays anyway).
It’s clear that you can no longer afford to work with the status quo. So, you take inventory of the pain. Some of it can be eased with operational tweaks, but a long-term fix needs to go deeper. You want to get at the root of the problem. Uprooting the tree altogether certainly does that (sorry for switching metaphors here).
But you’re not naïve. You know that the old system was, at one point, built from scratch too. So, you’ll do it differently. And conveniently, the biggest pain points can be neatly grouped under a single heading: the architecture.
- The pipeline's always clogged because teams are competing for stage time in a single monolithic application!
- Bugs keep popping up because there's so much intertwined code shoved into a monolithic application!
- It takes so long to build a feature because there's a different convention used in every corner of this monolithic application!
The core problem seems obvious, despite only really looking where the light is. And the solution is to adopt a well-organized, scalable, microservice architecture. And so, you're off to build it a better way, free of the baggage of the past, and filled with a renewed sense of confidence.
We know how the story goes from here. The cycle continues, and some version of the same story repeats itself, just with new characters on a different stage.
Bob Martin touches on this cycle in Clean Architecture: "The same overconfidence that led to the mess is now telling them that they can build it better if they can start the race over." Been there, by the way. Many, many times.
In fairness, blowing it up and pivoting to a new architecture might be a legitimately good decision. But it's a costly one, and it risks overlooking more subtle, meaningful problems we didn’t (want to) identify when the pain was fresh. A few come to mind: poor testing habits, squishy pattern standards, siloed relationships between stakeholders and engineers, uninvested team members, an otherwise unhealthy engineering culture, etc. Some of these are pretty boring, but they’ll cause a system to rot no matter how immaculate the architectural vision is.
All that said, think of this as another reminder of how important it is to be really clear on what it is we’re trying to solve, and why we think massive undertakings (like an architectural migration) have a realistic chance of helping. And when you hear that case being made, consider it your responsibility to press into it. Ask questions. Question assumptions. Leave no doubt that there aren’t other avenues more appropriate to explore, at least first.
It could end up being the right move. But at least not because we’re just eager to ride the pendulum as it swings to the other side (sorry, another metaphor).