Photo by National Cancer Institute on Unsplash
The growth of microservice adoption has caused a resurgence in popularity of some previously-overlooked software design patterns. Many of these patterns have been mined from Eric Evans’ Domain Driven Design, a book that’s as much about team structure as it is about software architecture.
And of these patterns, the Bounded Context is perhaps the most important to understand. As engineers, we have come to consider the Bounded Context to be a software architecture design pattern. But that’s because we’ve co-opted it a bit from its original usage. As used by Evans, the Bounded Context is as much an organizational pattern as it is a technical one.
That’s why I’ve come to view the Bounded Context pattern as a lynchpin in understanding microservices. Not just how to build them, but really why we build them in the first place, and how they can make our organizations more successful. If we understand what Bounded Contexts are — if we adopt the Bounded Context mindset both technically and organizationally — then we can truly be successful in building our microservices architecture.
To begin, let’s perform a little exercise. Ask yourself this question: Why do we build microservices in the first place?
Take a moment to think about it. What are the benefits that first come to mind? What are the main problems we should hope to solve? Jot down some answers, just to keep yourself honest.
Do you have your answer? Good. Read it back to yourself. Did you hit the standard technical benefits? Continuous delivery, scalability, polyglot environments, containers and clouds, and all of that good stuff? Great.
But did your top answer include anything about enabling your organization to operate more efficiently? It should. Because building microservices isn’t about realizing technical benefits. Really, it’s about gaining organizational benefits. Everything else is an implementation detail.
As our monoliths grow bigger and bigger, productivity starts to wane. There are at least two major reasons for that.
First, every engineering team is contributing to one giant codebase. As such, teams face an ever-growing likelihood that their code will conflict with others’ code. To help mitigate the potential issues this could cause, we institute procedures — code freezes, QA testing periods, release trains, etc. — that are literally designed to slow down our productivity.
Of course, these procedures keep features and improvements from being deployed in a timely manner. They also wreak havoc on engineers’ ability to focus on their teams’ priorities. If a bug is found during a testing period, the responsible team must context-shift and focus on resolving that bug. If a severe bug is found in production, the team has to not only fix the bug, but also jump through hoops to get it deployed by the next release train.
On-call duty becomes a boondoggle. If something goes wrong with our monolith, someone needs to be available — day or night — to resolve the issue. But who? Large organizations with large monoliths are generally faced with two choices: