Migrating an existing system towards microservices is very different from building a new system, Joris Kuipers, claims in a presentation describing an ongoing process of refactoring a large monolithic application towards a more distributed or microservices-based architecture.
Kuipers, architect at Trifork Amsterdam, describes the application as an electronic patient record system for health care, created six years ago, that for the first two years was a single monolithic application with a few business-to-business (B2B) integrations. From the very beginning it has been based on Command Query Responsibility Segregation (CQRS) using Axon, an open source framework developed by Trifork. It worked very well but as the system and number of customers grow, new requirements came along, including a requirement for insurance expensing that had to be a separate application but still requiring data from the current application. This was a significant change since they now had to move towards multiple applications that is sharing state.
Today the core application is still relatively large, surrounded by three separate applications for insurance expensing, together with almost 40 third-party integrations implemented in a dozen of deployable applications. It hosts about 65 tenants and 12,000 users.
A lot of the integrations have a much shorter lifecycle than the core application, so their major reason for moving to microservices was the need to scale their development to be able to adapt to these different lifecycles. Scaling the development teams and scaling the pace of development was the real drivers for the move.
Since they had an application based on CQRS and events when starting with the refactoring, they decided to use events as a point of integration and broadcast all events through a message broker to other interested applications. They extracted all the existing B2B integration-related code into separate applications and connected them to the broker to get all emitted events. For extracted applications with a need to communicate back to the core application, they are using the CQRS commands already present in the core.
A typical example of the flow of data is when a user is using the core application making a change to some data. This change will result in events published which the integration applications are reading asynchronously, and based on the logic this may trigger a notification sent to an external partner. Kuipers sees this as a hub and spoke architecture with their core application being the hub, surrounded by several smaller applications. He notes that this type of decomposing, by consumers, is a way of moving towards microservices that fits them very well.
For Kuipers, events are a huge help in splitting up a system because they are asynchronous by nature, describes something that has already happened, and is something that other systems can listen for and react to. He notes that using events also introduces some challenges, especially important to think about when events becomes the backbone for integration:
- They may create coupling since they are a shared data structure
- Some events may need to be private within an application or a service
- Granularity of types and the amount of data needed to prevent an event handler from having to request more data
- How events evolve over time without breaking clients
In conclusion, Kuipers notes that they are now able to quickly develop and deploy new integrations in isolation from the core application, which also means a reduced risk since the core systems can be left untouched, all of which Kuipers claims have given them an important and competitive advantage.