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. Extract all the code from the base (except the API) into a single "monolithic" component:
4. 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 "monolithic" component:
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.
Microservices is an architecture consisting of many small Monoliths. This means that migrating to Polylith is as simple as performing the Monolith migration steps on each service:
Once the initial migration of all our microservices to Polyliths is complete, then we can start to refactor.
It's likely that there are a number of common components that can be shared across multiple services. Resuing components in this way, make our codebase DRY and easier to maintain.
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.
Serverless is an architecture consisting of many Lambda functions. This means that migrating to Polylith is as simple as performing the Monolith migration steps on each Lambda:
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.