Scaling a growing organization by rearchitecting the monolith

During this year's QCon conference held in New York, I attended a full-day workshop on the scalability challenges a growing organization faces, hosted by Randy Shoup. In my previous post, I elaborated on Randy's classification system to illustrate the phases of a growing organization and how that affects technology. In his opinion, facilitating an organization that enters the scaling phase means re-architecting the monolith.

About Rearchitecting

In his words, rearchitecting is the act of re-imagining the architecture of an existing system so that there's a path to meet the requirements of the organization in its current form. As I said before, rebuilding a system is not an option, particularly not in the scaling phase. By that time, you'll have way too many clients that need new features and other improvements. On the other hand, you will very likely suffer from typical monolithical symptoms like lack of isolation in the code base, teams that are stepping on each other's toes, new engineers that need months to get a decent understanding of the code, painful and slow releases, etc., etc. Instead of that, you want to be able to have components which lifecycle is independent of others and that are deployed in an automated fashion. Sounds familiar? Enter microservices…

According to Randy, microservices are the perfect solution to rearchitect an existing monolith. Each service is simple, can be independently scaled, tested and deployed and allows optimal tuning without affecting any of the other services. The tooling, platform and practices have evolved considerably since people started talking about microservices two years ago. Building them is a lot less of a challenge then it used to be, but it still comes with a cost. You'll end up with lots of small source code repositories as well as the organizational structure to support all that (e.g. who owns what repo). Finding the repo that belongs to a particular micro-service requires naming conventions and tools not provided by the current online providers. On a technical level, you need to consider the network latency and the availability of a service. You'll also need sophisticated tooling to track, manage, version and control dependencies between the services. As many QCon sessions have demonstrated, a lot of tooling has emerged. But just like the wave of JavaScript frameworks and libraries that occurred when React became popular, I suspect it'll take a while until the dust has settled.

From monolith to microservices

So now that we've established the decision to re-architect the monolith into microservices, how are we going to do that? Well, if it's up to Randy, he wants you to start carving up the monolith by finding a vertical seam that allows you to wall off a functional feature behind an interface. This is obviously the hardest part since monoliths typically don't expose a lot of cohesion. The logic related to a feature is spread out over the codebase, sometimes crosses layers and involves way too much coupling. The next step is to write automated tests around that interface so you can replace the implementation with a remote microservice without causing breaking changes in the semantics of the feature involved. As you can see, this is anything but a big bang approach, and can be done in relatively small and riskless steps. However, Randy shared that in his own experience, it is very bad to combine a migration like this with the introduction of new features. He stressed the importance of first completing a migration of an existing feature so that it can serve as the basis of a new microservice and then add the additional functionality. Doing both at the same time is simply too risky and may blow up the project.

Now, he doesn't want you to become too overzealous and just start carving like crazy. Instead, he advises you to start with a pilot implementation. The pilot should represent an end-to-end vertical part of the system's experience, something significant enough to be representative for the monolith's complexity. Such a pilot provides an opportunity for the team to learn and use that experience to manage expectations. At the same time, it can be used to demonstrate the feasibility to the stakeholders.

When the pilot is deemed to be successful, it is time to continue the migration on a larger scale. However, Randy advices to prioritize future candidates for a migration to microservices based on their business value. In other words, prefer those parts of the monolith that give you the highest return-of-investment. If that doesn't help you, focusing on the the areas with the greatest rate of change. I mean, that was the whole premise of switching to microservices; being able to work and deploy in isolation. And finally, as you would approach any technological task with a lot of uncertainty, consider solving the hardest problems first.

Anti-Patterns

He also identified a couple of anti-patterns while working on his own migration projects. For instance, the Mega-Service, similar to the God class, is a microservice that is not focusing on a single feature. If you're practicing Domain Driven Design, I think aligning a microservice with a single bounded context makes sense. Smaller, like a couple of domain Aggregates is probably fine too. But a microservice that crosses multiple domain boundaries is very likely a bad idea.

Another anti-pattern, the Leaky Abstraction Service, deals with the subtle issues of growing a microservice from its implementation rather than defining the consumer's contract first. Randy is clearly adamant about making sure microservices are designed from a consumer-first approach. He believes that the usage of a microservice is the true metric of the value of such a service. So a service that is designed without any particular business client, the so-called Client-less Service, is obviously an anti-pattern as well. One final anti-pattern he mentioned that day is the Shared Persistence anti-pattern: two or more microservices that share their data store. As microservices are supposed to be independent, introducing any kind of coupling is always a bad idea.

Well, that's all I got on technology from that day. Next time, I'll talk a bit on the people side of his story. What do you think? Are microservices the next big thing to move away from monoliths? And do you agree with his migration approach? Let me know by commenting below. Oh, and follow me at @ddoomen to get regular updates on my everlasting quest for better solutions.

Share on

Leave a Comment

You May Also Enjoy

Transient vs non-transient exceptions
If I have to name the single biggest flaw in adopting Event Sourcing, it must be our decision to rely on the synchronous dispatching pipeline of NEventStore. It is based on the idea that every event will be processed by all projectors in a synchronous manner....

I thought we didn’t need OR/Ms anymore?
A common advantage of adopting Event Sourcing is that it solves the impedance mismatch between object oriented code and the relation database model. And because of that, Object/Relational Mappers (OR/Ms) have become obsolete. While I agree with the first st...

The characteristics of a great projection implementation
Over the course of the last two years I’ve written numerous articles on the good, the bad and the ugly of Event Sourcing as well as on our experiences building and maintaining a distributed enterprise-class based on this increasingly popula...

Over the last couple of months I’ve heard and read quite a few statements that say that Dependency Injection frameworks are bad things that you should avoid like the plague. In my opinion that’s just a result of rejecting something because it has been misused too long. Don’t get me wrong. I’ve be...