Art Of Breaking A Monolith To Microservices
Let's do this thing!
Join the DZone community and get the full member experience.Join For Free
The two important aspects of software development in enterprise web applications are architecture and software design. There is not a clear distinction between architecture and software design. Software architecture exposes the structure of a system while hiding the implementation details.
You may also like: Top Three Strategies for Moving From a Monolith to Microservices
Architecture also focuses on how the elements and components within a system interact with one another. Software design delves deeper into the implementation details of the system. Design concerns include the selection of data structures and algorithms or the implementation details of individual components.
Often monolithic is the right architecture for the system. Exactly once a need to quickly have a system to focus on business logic and prevent initial over design which is suitable for small teams, they can manage changes easily and also less debugging time. It is not the whole story, as the system grows you need more developers and business logic gets more complicated.
Deployment gets harder and most of all independent scaling is not an option anymore. For example, if part of the app needs more resources, the resource of all apps should be improved. In this case, the monolithic system will not work anymore and a microservice architecture has shown to be a promising solution.
Microservice is an architecture to developing a single application as a suite of small services, each running in its process. Indeed, a microservice decomposes a monolithic application into a collection of individual, loosely coupled services, to encapsulate business capabilities in a particular domain to fill objectives and responsibilities.
These services are built around independently deployable by fully automated deployment machinery. Basically, instead of developing software as a set of functionality to be completed. Microservice philosophy is design and bound around business capabilities. Microservices are very beneficial, some of the important benefits of using microservice are listed:
- Onboarding new members on the system are much easier.
- It can have different tech stacks such as python and java.
- Business logic can be reused, whenever they are needed by other parts of the system.
- Each part can deploy independently
- Easier to scale and distribute.
- Accelerating the pace of change and escaping the high cost of change.
Microservice architecture lets you split applications into distinct independent services, each managed by individual groups within your software development organization. They support the separation of responsibilities critical for building highly scaled applications, allowing work to be done independently on individual services without impacting the work of other developers in other groups working on the same overall application.
How To Break?
As you conclude a monolithic system is not applicable anymore. It's time to migrate, but what should you do exactly? what is the right way to split up? Actually, decoupling capabilities from the monolith are hard. Mostly it is like organ surgery. Extracting a capability involves carefully extracting the capability’s data, logic, user-facing components and redirecting them to the new service.
The first thing that might come to mind is the size of each microservice, There is a concept service granularity that is essentially referred to as the size of service. There is no fixed size for it, it depends on infrastructure and technical stack. Consider how much overhead is associated with a new service (source control management and deployment requirements). Also, if creating service needs time more than implementing it. this indicates how small is your microservice.
In continue, make sure you understand your monolith thoroughly. I mean finding the core use case and searching for keys in the domain. The most important thing you should care about is what to break out of the monolith. Basically, language boundaries and understand the dependencies of your monolith. You need to enforce linguistic boundaries to protect the validity of a domain term.
In this case, Words and phrases are very important. If a search for one has a different meaning in the same model, the model should be split into at least two microservices. Also, you need to find out service endpoints, usage and behaviors of your dependencies. If you have strong dependencies on a backend service such as a database or an external service, make sure to factor this into any decisions when breaking out that implementation from your monolith.
Sometimes domain expert defines new capabilities or fixes your current. For example, I remember I try to break a monolith system of geography organization. I decide to put humidity range in weather microservice, domain expert corrects me and told me that it must be in soil microservice. Sometimes current organization structure is an indicator to create your microservice base on them.
In fact, splitting up into services organized around business capability. Also, Your new service potentially runs in a different environment, maybe even in the cloud and you should consider dependencies that will potentially impact the services and applications that are depending on you and those you are depending on.
By now we have a better understanding of what to break out of the monolith, the next step is where you should break the monolith? I think entry points are a good place to start, my approach to finding good candidates of current methods, classes or modules to break out of your monolithic codebase is to learn which code gets executed when your endpoints are called and more important: what is the first method that gets called in your own custom code in a certain module.
For breaking up critical systems, Martin Fowler proposes to merge a new microservice with the monolith and do not let it live on its own. The most important reason to apply this pattern is the reduction of risk by monitoring the progress of the microservice more carefully. Until the point in time, the microservice is stable enough to take over the entire workload of the monolith’s functionality. Martin Fowler describes the Strangler Application:
One of the natural wonders of this area is the huge strangler vines. The seed in the upper branches of a fig tree and gradually work their way down the tree until they root in the soil. Over many years they grow into fantastic and beautiful shapes, meanwhile strangling and killing the tree that was their host.
Actually, in strangler pattern, you build small replacement pieces of an old system that do not have a dependency on the vendor and you kill old pieces that you have replaced. Eventually, the old system is strangled, replace piece by piece in a new system. you get feedback along the way if some use case is broken anyone of changes. we apply the strangler pattern to control the evolution of the microservice.
This requires updating the legacy code to call the new microservice. Your new microservice must have minimized dependency on your monolith else it prohibits having a fast and independent release cycle. Often the main motivation for moving away from the monolith is the high cost and slow pace of change of the capabilities locked in it, so we want to progressively move in a direction that decouples these core capabilities by removing dependencies to the monolith.
In order to migrate truly, you should split the sticky capabilities of the monolith as soon as possible. Whenever sticky capabilities are left in the monolith, this will limit the further move to microservices. That’s because there will always be this dependency back to the monolith for a particular capability and the team needs to identify the sticky capability, deconstruct it into well-defined domain concepts, and then further divide these domain concepts into standalone microservices.
The migration of a monolith to microservices has a strong impact not only on the code base but also on the schema of the legacy database. Keeping all the data in the same datastore is counter to the Decentralized Data Management characteristic of microservices. Basically, without decoupling the data, the architecture is not microservices.
Often it is required to retrieve data from the monolithic database as well as from the database that belongs to the service. To work with these two data sets in a joint manner, we will use a data virtualization technique temporarily during the process of the migration. Data virtualization is the provision of an abstraction layer so the data consumer does not have to know the physical location or format of the original data.
I worked with a team who prefer to use feature flags for strangler pattern like migration. It allows controlling the integration of the new service without redeploying the monolith. Actually, Feature Flag is a tool to turn some functionality of your application off, via configuration, without deploying new code. In general, I do not recommend to use a feature flag. It creates a really tight coupling between microservices. Then your microservices would not be autonomous, which goes against the ideal conditions for a microservice.
As you see the art of breaking a monolith to microservice is the art of aligning business capabilities to technical capabilities.
Opinions expressed by DZone contributors are their own.