How Koble is transitioning from MVP to enterprise-scale
by Àlvar Pérez
In the last decade, everyone has heard about microservices and how amazing they are. But microservices, domain-driven design (DDD), and other techniques for building loosely-coupled software are not only buzzwords that allow us to be the coolest-looking company out there. We have statistical proof that they enable low- and mid-performing teams to be high performers, being highly focused on their goals, and achieving superior business results.
If we achieve a loosely coupled, well-encapsulated architecture with an organizational structure to match, two important things happen. First, we can achieve better delivery performance, increasing both tempo and stability while reducing the burnout and the pain of deployment. Second, we can substantially grow the size of our engineering organization and increase productivity linearly — or better than linearly — as we do so.
Nicole Forsgren, Accelerate, 2018
Why do we build monoliths?
Knowing how beneficial it is for our project to have a loosely coupled architecture, why do we keep building monoliths? When building an MVP, you don’t always need software that will scale massively. As the name says, a minimum viable product is a bare minimum that will generate value and test an idea with the market. The faster we validate the idea, the better. This makes us frequently implement services through transaction scripts, procedurally handling our logic. Although transaction scripts can be a very valid and technically efficient architecture pattern, it drives us away from our ideal of decoupled software due to its lack of events and abstractions.
Procedurally building our software, due to the natural time-pressure of launching MVPs to the market, leads us to tightly-coupled solutions that are difficult to change. The problem with these solutions is that they will often take us to a point where tech teams cannot fulfill product requirements without significant rework, leading to longer cycle times. This is when we know that we will need to switch the approach to a well-encapsulated modular architecture. But how can we move towards a hypothetical service-oriented architecture with a very young product?
Domain-driven design as a product modeling tool
At this point, a domain-driven design approach can be extremely helpful because it not only allows us to decouple our idea and model our product better, it also tends to bridge the gap between the problem domain and the solution space, that is, the business problems that we are trying to solve and how we solve them.
One of DDD's main benefits is establishing a common language (ubiquitous language) that brings the communication gap between tech teams & businesses to nearly-zero. To abstract, the problem domain (business needs), a very effective approach is to hold event storming sessions, in which we start with the events that our application has. We go back to how we generate them, allowing us to quickly find what is happening in our business, uncover the ideas we have, and map them between them, shaping our product. If you want to know more about them, I encourage you to read this article for more information.
Through this work of remodeling and refactoring, we can improve our dynamics to a place where both business and tech teams are fully aligned on what is needed and how it has to behave. This dynamic is achieved by creating a common language and having all the software modeled into small blocks that are independent (bounded contexts), achieving the goal-state of loosely coupled software. Ideally, also the communication of these blocks would be through events (see domain events). Thanks to these changes, we will improve our time to market, meeting business expectations about timings and reducing the amount of time invested on refactorings.
Why do we need SOA & Microservices?
When teams grow and start having multiple squads, a mono-repo modular approach can be limiting, making our different teams codependent and reducing autonomy. However, if we have already started identifying our subdomains and bounded contexts, we already have half of the path done towards microservices. Through domain-driven design, we would have already created independent sub-products that can be extracted into different services to maintain event-based communication.
Right now, at Koble, we are moving towards a microservices architecture due to our own growth. Handling growth with this new architecture will avoid dependencies or blockers between teams, enabling fully-autonomous squads that focus their work in specific domains. These domains are fully aligned with the business, and, thanks to this, the transition will be a lot less painful.