As we continue exploring breaking apart the monolith into smaller chunks, we will start to find edges that are not clear. The easy and trivial edges are done, and now we face the hard edges.
Defining the Boundary
These pieces require even more code archaeology than before. We need to really dig in and understand the code. This time we are looking for the boundaries of the functionality. We no longer have nice clear boundaries defined for us, so we need to make them. There will be hints and good starting points. The code was (probably) not intentionally built poorly in the monolith. But years of use and abuse have caused API boundaries to become slack.
Use cases have grown since the original conception of this solution, and the various additions that have been added over the years have not maintained crisp boundaries. Our job now is to fix that. Before we can pull anything more out of the monolith, we need to wrap it in a tight boundary. This includes everything from the code down to the database.
Transaction boundaries are going to be the hardest piece to get right. ORM tools are great, but they can make it very easy to blur what should be distinct modules. Need a budget decremented when a time card is approved? No problem. Need notifications to be sent when the system takes an action on an object? That is easy in a monolith. But we will need to find new ways of solving these problems in a distributed system.
Boundary Tricks and Tips
Those architecture diagrams and metrics will come in handy at this point. Those numbers that we rarely care about (or even understand) before now can give us invaluable insight into where the boundary lies. Number of module/package dependencies, backward dependencies, cyclicity, etc. If tools that provide these metrics are not already running over the source code, add them. These will also provide nice metrics for presentations on how much “progress” is being made from our efforts. How much better the code is now, and how far we may still need to go.
Extraction
Once the boundary is defined, it is time to actually pull the newly defined module out. At this point it looks much more like one of the easy or trivial moves from before, and we know how to deal with that. Once again, still keep track of those pesky transaction boundaries, because even with the new module wrapped up nicely, it living in the same memory- and process-space with the rest of the monolith can still allow leakage that we couldn’t find before.