History: From Mud to Microservices

Monolithic software systems are the common result of how software has largely been built for decades since computers were born in academia and the military and then matured into mainstream commerce. Monoliths are hard to scale up technologically and organizationally because it is one code base, one shared database, sometimes one application process, generally one deployment unit, and often one team. A small change in one part of a monolith like a shared library or domain model might ripple to other parts, thus requiring coordinated changes across the system. Re-deployment of the entire monolith could take hours if it ran background jobs or had very long startup/stop times due to the libraries that loaded at run-time. On-boarding new hires could also be troublesome because digesting the large monolithic code base was daunting, and its size often strained the IDE. Furthermore, scaling the system often meant scaling vertically by increasing hardware resources for compute and storage at the application and database layers; one could scale horizontally, but often at greater cost per CPU cycles, memory bytes consumed, and disk storage utilized since not all the system components needed the resources uniformly. All these characteristics of monoliths result in a slower, more expensive rate of technology change that put the business at risk in a competitive ecosystem where there is a premium on innovation. The metaphor for monoliths is the Big Ball of Mud. Unfortunately, the mud slinging still happens all too often.

Some of the earliest principles to improve software architecture and design were encapsulation, information hiding, modularity, and separation of concerns. These concepts go back to the late 1960’s and early 1970’s, and they are still alive and well today. As object-oriented languages grew in popularity thanks to Smalltalk, C++ and Java, design patterns surfaced in the early 1990’s for designing maintainable OO-oriented software systems based on these original principles. Then, along came the Service Oriented Architecture (SOA) movement of the mid-1990’s based on Application Middleware (e.g. BEA WebLogic, IBM WebSphere, Red Hat JBoss, Microsoft BizTalk and Tibco Rendezvous), Remote Procedure Call protocols such as SOAP, CORBA, and DCOM, and Message Oriented Middleware. While SOA was a step in the right direction, it was too middleware focused, some of the protocols such as SOAP and CORBA were too heavy and slow, and often the services were still coupled to one another.

In the 2000’s microservices became increasingly possible through the combination of cloud computing, Docker, and a renewed emphasis on Agile and DevOps. These technologies and processes support the microservices approach to architecture. Microservices should be independent services each within a Bounded Context Domain that are supposed to do one thing well. Each service must surface API contracts for interaction with other services through either synchronous methods (e.g. RESTful web) or asynchronous means (e.g. RabbitMQ, Amazon SQS, Azure ServiceFabric Queues). The services can be built using the most appropriate polyglot technologies (e.g. language, compute, storage, database) for the use case and organization. Microservices do have several theoretical benefits over Monoliths including agility, deployment, innovation, modularity, scalability, and testability. Instead of decomposing a system into horizontal layers, the architecture becomes cut into vertical slices related to the narrower domain and set of use cases. Smaller teams usually no larger than the size of two pizzas (e.g. 6–8 people) own that vertical slice, are empowered to work independently, and use build, test, deployment, and infrastructure automation to further shorten cycle times and improve release reliability; as a result, organizations can benefit from higher aggregate throughput. Since each decentralized service can be optimized for its domain, services can be scaled both horizontally and vertically for performance, and it allows innovation to flourish across the teams and within the federated system.