In the ever evolving and dynamic world of software architecture, you will hear new buzz words every other month. Microservices is the latest of them, though not as new as it appears, it has been around for some time now in different forms.
Microservices – The micro of SOA?
“… the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies.” that Fowler guy.
So, to break it all down, microservices is a form of fine-grained service oriented architecture (SOA) implementation that could be used to build independent, flexible, scalable, and reusable software applications in a decoupled manner. This relies heavily on separately deployable and maintainable sub systems/ processes that can communicate over a network using technology-agnostic protocols. That in turns, pave way for DevOps and Continuous Deployment pipelines.
Principia Microservices – nutshell
You would not find a defined set of characteristics of a microservices based system. A formal definition is still missing, though we can outline the basic and mostly mentioned pointer.
– The services are small fine-grained representation of a single business function.
– Designed and maintained around capabilities.
– Flexible, robust, replaceable, and independent of each other in nature.
– Designed to embrace faults and failures. An unavailable service cannot bring the system down. Emphasis on monitoring and logging.
– Advocates the practices of continuous improvement, continuous integration and deployment.
Services as Components
Defining software systems as a set of smaller, independently maintainable components has always been a craving of well-define architectures. The current programming languages lack the mechanism of explicit boundary definitions for components and often, it’s just documentation and published best practices/ code reviews that stops a developer in mixing logical components in a monolithically designed application.
This differs a bit from the idea of libraries. Libraries are in-process components of an application that, though logically separate, cannot be deployed and maintained independently.
In microservices, components are explicitly defined as independent and autonomously deployable services. This enables continuous processes (CI & CD) and enhances maintainability of individual components, increases reusability and overall robustness of the system. It also enables a better realization of business processes into the application.
Built for Business
Most of the time, organisations looking to build a decoupled system focuses on technical capabilities. This leads to teams of UI devs, backend devs, DB devs etc. This leads to siloed architectures and applications.
Microservices does things differently. The organisation splits teams as per the business capabilities. This results in cross-functional, dynamic and independent teams with full technical capabilities.
A consequence of a monolithic design is central management and support of the whole system. This create problems in scalability and reusability. These systems tend to favour a single set of tools and technologies.
Microservices advocates “you build it, you run it” approach. The teams are designed to take end-to-end responsibility of the product. This disperse the capabilities across the teams and helps tie up the services with business capabilities and functions. This also enables selection of underlying technologies based on needs and availabilities.
Designed for Failure
A failure in monolithic design could be a catastrophe, if not dealt with gracefully and with a fall-back approach. Microservices, however, are designed for failure from the beginning. Because of their independent and granular nature, the overall user experience in case of a failure tends to be manageable. Unavailability of one service does not bring the whole system down. It is also easier to drill down in microservices to identify the root cause because of their agility and explicit boundaries. Real-time monitoring and logging and other cross-cutting concerns are easier to implement and are heavily emphasized.
“If we look at the characteristics of an agile software architecture, we tend to think of something that is built using a collection of small, loosely coupled components/services that collaborate together to satisfy an end-goal. This style of architecture provides agility in several ways. Small, loosely coupled components/services can be built, modified and tested in isolation, or even ripped out and replaced depending on how requirements change. This style of architecture also lends itself well to a very flexible and adaptable deployment model, since new components/services can be added and scaled if needed.” — Simon Brown
Microservices architecture tends to result in independent products/ services designed and implemented using different languages, databases, and hardware and software environments, as per the capabilities and requirements. They are granular, with explicit boundaries, autonomously developed, independently deployable, decentralized and built and released with automated processes.
Issues – Architecture of the wise
However, there are certain drawbacks of microservices as well; like higher cost of communication because of network latency, runtime overhead (message processing) as oppose to in-process calls, and blurry definitions of boundaries between services. A poorly designed application based on microservices could yield more complexity since the complexity will only be shifted onto the communication protocols, particularly in distributed transactional systems.
“You can move it about but it’s still there” — Robert Annett: Where is the complexity?
Decentralized management, especially for databases has some implications related to updates and patches, apart from transactional issues. This might lead to inconsistent databases and need well defined processes for management, updates, and transactional data consistency.
Overall system performance often demand serious considerations. Since microservices targets distributed applications in isolated environments; the communication cost between components tends to be higher. This leads to lower overall system performance if not designed carefully. Netflix is a leading example of how a distributed system based on microservices could outperform some of the best monolithic systems in the world.
Microservices tends to be small and stateless; still business processes are often state-full and transitional in nature so dividing business processes and data modelling could be challenging. Poorly parted business processes create blurry boundaries and responsibility issues.
Potential of failure and unavailability rises significantly with distributed systems based on isolated components communicating over networks. Microservices could suffer with the same because of high dependence on isolated components/ services. Systems with little or no attention to Design for Failure could lead to higher running cost and unavailability issues.
Coping with issues of distributed systems could lead to complexities in implementation details. Less skilled teams in this case will suffer greatly, especially when handling with performance and reliability issues. Therefore, microservices is the architecture of the wise. Often building a monolithic system and then migrating to a more distributed system using microservices works best. This also gives the teams more insights about business processes and experience of handling existing complexities which comes handy in segregating processes into services with clearer boundaries.
When we have multiple isolated components working together in a system, version control becomes a problem, as with all the distributed systems. Services dependencies upon each other create issues when incorporating changes. This tends to get bigger as the system grows. Microservices emphasises on simpler interfaces and handshakes between services and advocates immutable designs to resolve versioning issues. This still requires managing and supporting multiple services at times.
There is no zero-one choice between monolithic and distributed systems. Both have their advantages and shortcomings. The choice of an architecture heavily depends upon the business structure, team capabilities and skill set, and the dispersed knowledge of the business models. Microservices does solve a lot of problems classical one package systems face but it does come up with a cost. More than the architectural choices, it is the culture of the team and the mindset of people that makes the difference between success and failure – there is no holy grail.