Monolithic systems are easier to build and reason about in the initial phases of development. By including every aspect of the entire business domain in a single packaged and deployable unit, teams are able to focus purely on the business domain rather than worrying about distributed systems concerns such as messaging patterns and network failures. Best of breed systems today, from Twitter to Netflix to Amazon, started off as monolithic systems. This gave their teams time to fully understand the business domain and how it all fit together.
Over time, monolithic systems become a tangled, complex mess that no single person can fully understand. A small change to one component may cause a catastrophic error in another due to the use of shared libraries, shared databases, improper packaging, or a host of other reasons. This can make the application difficult to separate into services because the risk of any change is so high.
Our first order of business is to slowly compartmentalize the system by factoring out different components. By defining clear conceptual boundaries within a monolithic system, we can slowly turn those conceptual boundaries—such as package-level boundaries in the same deployable unit—into physical boundaries. We accomplish this by extracting code from the monolith and moving the equivalent functionality into services.
Let’s explore how to define our service boundaries and APIs, while also sharpening the distinction ...