Microservices architecture has caught the fancy of software developers and architects and is now seen as more appealing for modern application development. Even though inter-process communication is not a new thing, popularity of the architecture since it came in reckoning in 2011 has got pronounced in the last two years with cloud-native application development picking up pace. Microservices architecture and its benefits are fairly well-known. However, architects have been in a dilemma of when to implement it (or rather when not to) in an application’s development journey. I am putting forth my views on this through this article in a bid to help architects decide.
Teams working on new applications these days have a common charter, i.e., to build cloud-native applications and to be able to utilize cloud features, as well as for a faster turnaround.
Building a cloud-native application does not necessarily mean starting with microservices itself. Saying that all cloud-native applications follow the microservices-based architecture is incorrect.
Monoliths can also be cloud-native by following 12-factor principle. My recommendation is to consider building monoliths in absence of all the prerequisites and following a modular approach for development.
However, you need to take care that each component has well-defined boundaries and a clear scope of what it does or does not need to do. This will help when you refactor your application later in order to adopt the architecture. In fact, I will go a step further and recommend starting building always with a monolith and when you are ready to adopt, refactor the existing components into microservices, and design the new functionalities as microservices.
Prerequisite 1 - The application should have been modelled based on the business domain it is a part of with a strong understanding of the same. Thanks to object-oriented programming that we all know well, we already know what this signifies.
But we need the right boundaries, defining the application components that should be modelled around different business capabilities.
There should be a definite scope of each component and the interfaces that it would serve, as well as require. Loosely defined interfaces and the lack of clarity on scope and boundaries do not bode well for a microservice.
Prerequisite 2 – The components should be highly mutable. As an application evolves, its components would need continuous changes in architecture and deployment.
Prerequisite 3 – You have all the intentions to structure your team per the application model. Your teams need to be self-contained in terms of DevOps support, including business analysts who are able to identify the bounded context(s), as well as support for monitoring and testing, i.e., you have a strong DevOps culture in your organization.
Prerequisite 4 – You are okay to support multiple databases in your application, including different types of databases with varied kinds of data stores.
Prerequisite 5 – You are okay to shift the pH of distributed transaction processing or consistency model from ACID to BaSe form. This is because every microservice will have its own database with different types of data stores or polyglot persistence.
Prerequisite 6 – Your team possesses skills of adding and maintaining ReST and/or messaging-based communication layers.
Essentials for running
I will also mention here a few things that need attention for running the microservice-based implementations.
Setup a choreography of microservices architecture– Client-side load balancing, registry, discovery, and circuit-breaker patterns are required.
Consider using a gateway to keep away from direct chats to avoid coding and refactoring complexities, as well as to ensure protocol compatibility.
Your testing strategy should be comprehensive - Unit, integration, contract, end-to-end, and performance.
Take only what is required as a client – Nothing more than what you require to minimize risks associated with the later changes in definition.
Keep an eye on latency that you introduce with microservices. Abort it if a functionality is performance critical, hugely transactional across application boundaries and if any discontinuity occurs because of communication across boundaries.
Be cognizant of the fact that you cannot have services defined right always and may have to change their definitions a lot of times before you could finally have well-defined services with zero or minimal overlap.
Depending on perceived frequency of changes, business capability(s) being tried to address, clarity in definition of interfaces, and dependencies and overlaps in functionality and data being stored, you may also have to merge two services into one.
As a concluding note, I wish to reiterate that without the prerequisites being met, please do not implement microservices architecture for the sake of having cloud-native applications as it will lead you to bigger problems. Architects need to give a serious thought on their readiness before venturing into the world of microservices.