Monoliths on their own aren't a bad thing. Their relative simplicity and resource efficiency can make them an excellent choice if you're keen on getting up and running across a relatively small team. Not only that, but they naturally lend themselves to a monorepo approach which, depending on your existing workflows, can save you time, money, and an untold amount of stress.
Despite O'Reilly's study in 2020—confirming that microservices are reaching maturity with nearly a third of organizations using them and having done so for more than three years—they're still yet to become the default option. When it comes to starting out, monoliths are frequently your starting point. They're easier to develop, deploy, and support.
In the first instance, our integrated development environments (IDEs) are often built to support us building on one application from a single view. This is true of our deployment processes, testing frameworks, and our entire workflows. A single artifact is easy to conceive of until, of course, it isn't.
The one thing that monoliths are terrible at supporting is growth. Monolithic architectures are great at getting you up and running while you determine your market fit, but scalability is not where their strengths lie. As leading tech architect and speaker Randy Shoup notes, "Any architecture meets a particular set of goals or range or requirements and constraints... we've all heard countless stories of how a simple change, under a monolithic, and often legacy-bound architecture can take a matter of weeks." This, in part, could be why monolithic architecture has become almost synonymous with legacy architecture.
Embarking on a modernization journey is by no means an easy task. But if we're treading the same path as the likes of Netflix and Airbnb, there's a sense that we might be on to a winning formula, right? As Sam Newman, the author of "Monolith to Microservices," states when discussing our eagerness to In technology: "We often have a tendency to focus on the activity rather than the outcome". In his book, he recalls speaking to a group of participants in a workshop of his having no clear understanding of why their CTO had been insistent on them migrating to match their inquisition on what microservices are or how they might seek to tackle the task.
There's a whole host of reasons why adopting a microservices-led architecture could be right for you, but how do you know for sure? Here are a few indications on how to know if and when you're ready and some approaches to consider.
How much time do you have?
As anyone in a cross-functional or commercially-led role will know, waiting weeks for a simple change isn't an option. Survival in a competitive market demands speed. In the past three years alone, we've seen the DORA report track elite performing teams shortening their lead time for changes from half a day to half an hour.
The ability to deploy changes at a granular level without waiting for release coordination can give you some real agility as an organization. You'll get the ability to release functionality faster, which is a boon, but as a practice, it comes into its own when coupled with experimentation.
It's often said that there's no production like production. A theory untested is, at best, a hypothesis and, at worst, conjecture. By rearchitecting your systems to enable faster deployment, you'll be able to quickly respond to market pressures, user feedback and anything else that gets thrown at you.
James Lewis, Principle Consultant at Thoughtworks, once famously said that "microservice architectures buy you options, and fundamentally, when you buy into microservice architecture, you're buying into a whole other series of options and choices that you can make.''
If you're at the stage where you've validated your approach and found your market fit, but are now operating with significant levels of competition, microservices might be what you need to give you that extra level of acceleration. The approach provides a good foundation for solving all the problems you'll encounter once you've achieved initial levels of success but are finding it challenging to maintain a sprint.
You're likely ready for this journey if you've completed value-stream mapping exercises to chart the time taken from deployment to the change being live in production and the production pathway. If your pain points are build times and the architecture is the common source of complaints, it might be time.
How many of you are there?
Distributing your systems has the benefit of distributing responsibility, a concept otherwise known as autonomy. Autonomy is a much-discussed goal of the technology industry. From our team composition, right down to the tooling we select, we all inherently understand that achieving autonomy is to empower someone or something.
When we hear about the successes of a microservices-oriented team, we often hear about the services-per-developer ratio. This approach of awarding either individuals or teams ultimate control over particular systems can greatly benefit their personal growth and performance.
In Frederick Brooks's now-famous collection of essays, "The Mythical Man-Month," he comments on how adding more people to a software development project only further delays it due to the tightly-coupled nature of the work.
While this law applies to nearly every aspect of a project, when assessed in a microservices-driven architecture, as Sam Newman notes, independence and minimal interactions are the goals here. While microservices alone won't magically work to decouple the nature of your teams, the clarity when it comes to boundaries between ownership provides an excellent pathway towards sustainable scalability.
By their very nature, microservices seek to limit the level of interaction between one thing and another. While you'll still have to contend with the problem of overarching coordination, aligning your teams and individuals towards service ownership sets you up to multiple the number of developers without simultaneously scaling the delivery contention at play.
Suppose you've got real aspirations of growing out your engineering org and have already begun mapping out your projected headcount. In that case, this might be a good time to rethink your monolith, modular, or otherwise. However, if you're still at the abstract stage of discussions around growth but are already finding that delivery contention results in confusion of ownership, prioritizing autonomy across all of your decisions, architecture included, could cut down on the number of difficult discussions.
How important is uptime to you?
If you're hesitant about changing your service architecture, I don't have to convince you to worry about the monetary costs associated with downtime. If staying online is critical to your business's survival, you've likely employed some level of multi-tenancy or running more than one version of your monolith.
Splitting applications into individual, independent deployable processes aids us in upping the overall robustness of our applications. While it may feel like you're exposing more of your architecture by adopting a loosely-coupled design, opening up your application to increased risks, you're conversely shoring up its ability to handle service outages and network partitions.
This outcome is entirely dependent on the execution of your decoupling. At best, you can create a system with highly-effective fallback paths. If one critical component of your application goes down, your blast radius has a limit. But in the worst-case scenario, you are enlarging your surface area for failure.
While this is a very real fear, it's been largely avoided in the field due to the way responsibility is, in effect, distributed across teams. In a recent paper titled, "Microservices: Architecting for Continuous Delivery and DevOps," Chief Researcher Lianping Chen commented that:
"Microservices make the boundaries between components physical. Each service has its own codebase, its own team, and its own set of virtual machines or containers in which it runs. Therefore, taking shortcuts is considerably more difficult in Microservices. For example, some engineers commented that sometimes, under pressure, they had thought of crossing a boundary but immediately realized that doing so was no longer a shortcut because of the physical boundaries between services. Thus, Microservices provide better protection against the temptation to break boundaries under pressure for short-term implementation convenience."
By creating these boundaries, you'll be improving present resilience while architecting for your organization's future.
Making the jump
A lot of these ideas feel optimistic in isolation; however, to take on this challenge, you'll need to develop a vision and a strategy that captures the attention of more than just your engineering team. During the migration process, it's more than likely that you'll deploy a change that your users might pick up on. Even if it's something small like an increase in load time or an alternative caching technique, to ensure the overarching success of your migration project, you'll need to brief everyone in a customer-facing position on what to expect and why. Getting everyone on the same page understanding the trade-offs and the desired result will become crucial when things start to shift in production.
This process of taking people along with you on the journey doesn't start and end with the sharing of updates. You'll be doing things differently. Working with your team to identify how their skill set should evolve during this process will help them feel included in the change instead of fearing their replacement and the infrastructure.
Starting from something
With all of these considerations in mind, you need to consider the system you're already running. Working with a brownfield system is far preferable as you've already got something substantial to rework. You've got something to decompose and, in the worst-case scenario, fall back to during the migration process. Knowing what good looks like within the context of your business and having an established precedent from which to improve puts you in a strong position.
Ownership versus control
It's easy for ownership to be mistaken for control. While one team might own a particular service, ultimately responsible for its condition, controlling that service need not become siloed. By wrapping each service in a flag, we can distribute control of something being live in production.
There are huge benefits here. You're able to test in production worry-free, with the ability to execute a kill-switch should your service go awry. But more importantly, your engineers won't be the only people with access to the control valves of your release. By decoupling how you deploy and release, you can facilitate complete oversight and control at a team level and manage approvals in the same dashboard.
Growing pains are real
Mistakes are inevitable, and change is rarely easy. Adopting an incremental approach to the migration process will ultimately guarantee that the mistakes you do make remain small and largely reversible. Instilling a set of metrics and regular checkpoints will keep you honest.
Last but not least, remember that you don't need to include "yes and" when mapping out your goals. If you're contemplating moving to microservices, your changes will be technical and organizational. If someone suggests how this could be a good chance to try a new programming language during the exploration phase, they're not wrong, but equally, they're not right.
There are many reasons why adopting microservices will be good for your organization. But doing them just because everyone else is, isn't one of them.