Introducing microservices and their evolution
Before we thoroughly jump into introducing and defining microservices, it will be helpful to know how microservices have evolved. In the late 1960s, Alan Kay coined the term object-oriented programming. Though it was a definitive idea, later it birthed the four pillars for building software solutions using object-oriented programming:
- Encapsulation
- Inheritance
- Polymorphism
- Abstraction
In a short mnemonic, it's known as EIPA. Since the inception of these four pillars, the software industry has seen the rise and fall of many programming languages, frameworks, design patterns, and so on. With each such adaption and idea, thinkers and tinkerers have tried to come closer to EIPA by keeping a modular design and loosely coupled yet tightly encapsulated application components. Over the last few decades, software teams have moved away from the art of object-oriented programming toward the science of object-oriented programming by systematically adopting these key pillars. This iterative journey is the evolution of microservices.
In the late 1980s and early 1990s, almost every enterprise application was exposed as either a command line or native desktop software. Applications were tightly connected to databases and it was almost as if the end user was directly interacting with the database with the application as a thin façade in between. It was the era of monolithic applications or client/server architecture.
In the proceeding diagram, we can see how users interacted with a monolith application:
As depicted in Figure 1.1, in monolithic client/server architecture, the application is tightly coupled to the database and the user interacts through a terminal façade or desktop application. In this architecture, it was painful to maintain good service-level agreements (SLAs). Almost all the key non-functional factors such as scalability, high availability, fault tolerance, and flexibility underperformed or failed.
To address some of these aspects service-oriented architecture (SOA) came into existence. In the 2000s, SOA was formalized in the industry with the definition of some standard protocols such as Simple Object Access Protocol (SOAP). Web Services Description Language (WSDL) was also created during this period. Web 2.0 applications were popular with Asynchronous JavaScript And XML (AJAX). Enterprise service bus and messaging systems were highly used in enterprise applications. Advancements in SOA catalyzed a new paradigm of delivering software solutions to end users: Software as a Service (SaaS). Instead of desktop applications and terminal clients, software solutions were delivered to end users over HTTP as hosted online services. In the proceeding diagram, we can see how users interacted with an SOA-based application:
As shown, SOA brought in some decoupling by separating the concerns between the web application, web server, and app server. App servers or enterprise service buses (ESBs) usually interact with the database and the user interacts with the application by accessing it on web browsers (SaaS solutions). Though SOA brought some relief, the adoption of SaaS left scalability and flexibility as key unhashed puzzles.
Post-2010, the technology world started to move much faster than it did in the previous two decades. With the introduction of containers, the cloud, big data, and machine learning, everything started moving rapidly in architecture design. It is the era of Uber, Airbnb, Netflix, and freemium/premium applications. Applications are designed for distributed computing and scalability. With the microservices architecture, the application is decomposed to loosely coupled microservices where each microservice owns its database. In the proceeding diagram, we can see how users interact with a microservices-based application:
In the previous diagram, we can see a fully realized microservices application where each microservice interacts with and owns its database. The user interacts with a single-page application through a modern browser. Any incoming requests from the web server are routed to the respective microservice. The full realization of microservices architecture is to address key factors of scalability, fault tolerance, high availability, and flexibility.
To put it simply, microservices or microservices architecture componentize an application into a collection of interacting services. Each service could be developed, tested, deployed, and maintained independently. Thus, each smaller (micro) service has its own unique life cycle. Furthermore, since each service is loosely coupled (interacting with other services using HTTP/HTTPS), we can do the following:
- Scale up or scale down (based on the service traffic).
- Address any runtime faults (boot up the service backup).
- Make new changes (change impact is limited to the service).
Therefore, through the complete realization of decoupled architecture in the microservices, we address key issues of scalability, fault tolerance, high availability, and flexibility.
So far, we have learned about microservices and their evolution and how they have been transformational in addressing the unique, rapid, and agile needs of today's world. This understanding is a good preface to realizing the potential of microservices. In the next section, we will dive into the microservices design patterns.