Transitioning to Polylith
How much will Polylith affect our current codebases and deployment experience?
Let's say that we have twelve Microservices in our current solution. After we complete the initial stage of a migration to Polylith, then we'll still have twelve Microservices, but each will be a Polylith service.
Let's take a look at the steps involved in transitioning from each type of architecture.
1. Create a new workspace, and add a new project, with an empty base. 2. Copy all your Monolith's code, including its API into the base, and add all the libraries to the project.
3. This is where the real fun starts, because now we can refactor the code to increase the modularity of the project. We start by teasing out one component at a time from our base:
When we've finished extracting all the components, we'll have a project that's in much better shape:
Some components will handle a specific part of our domain, some might manage integration with external systems, and others will be responsible for infrastructure features such as logging or persistence.
Once the initial migration of all our microservices to Polyliths is complete, then we can start to refactor.
We might also discover that we had prematurely optimized our Microservice architecture for scalability and/or single responsibility. In other words, we have more services than we actually need to achieve the scalability we require.
Those additional services come with a hefty complexity cost, so we'll be able to make our life much simpler by combining them into fewer Polylith projects. Whilst still maintaining the architectural benefits of separating our code into single responsibility components.
As with Microservices, we are not forced to migrate all our Lambdas at the same time. If we have many Lambdas this is especially good news, because it allows us to migrate in small and controlled steps.
If we have extracted shared functionality into internal libraries that we maintain, then Polylith gives us the opportunity to defrost them into living code. Libraries are created by freezing code in time, which leads to friction in the development experience. By defrosting them into components, we get living code that is easy to change and which is always in sync with the rest of our codebase.