Part 1 of this series explained the purpose of the microservice architecture and laid out five factors in modern computing that fit well with microservices. This second part looks at the other five factors. In this article, I’ll also describe some of the challenges presented by microservices.
Convenience of Platform as a Service (PaaS)
I mentioned, in the "Defining Microservices" section of the previous article, that developers are consistently striving to reduce the size and complexity of the environment needed to run an application in a microservice. One of the first advances was Platform as a Service (PaaS), a kind of cloud offering that appeared in 2008 in the form of Google's AppEngine. (Google itself credits a slightly earlier company as the first PaaS offering.)
Before PaaS, Amazon and competing cloud services offered simulations of bare metal, called Infrastructure as a Service (IaaS). Within this approach, the customer was responsible for creating an "image" that contained an operating system and all the applications the customer wanted to run. Thus, the customer was pretty much lifting the software lock, stock, and barrel off its on-premises systems and running that software bundle in the cloud.
But most customers didn't run general-purpose systems on their hardware servers in the first place. System administrators found it more efficient to run just a single application, such as a web server, on each hardware system, providing it with a stripped-down operating system. The single-application architecture was simpler to set up and administer and had higher performance than multi-service systems. The simplicity and minimal configuration also made it more secure.
Given this evolution of servers, it became absurd to load down the hardware with multiple copies of a complete operating system and all the general-purpose drivers and libraries it entailed, for each individual application. A very different cloud model made sense. PaaS provided a complete context for running a single function. You could code up your application as a Java function, upload it to the vendor's server, and run it with all the best and latest supporting software that the vendor could put together. PaaS was thus a precursor of microservices.
Efficiency of Containers for Virtual Applications
Microservices are tied to another hot technology called containers, a term slapped recently onto an idea that goes back much further in computing. A container is a lightweight environment for running an application. Each container embodies a single application with the supporting libraries and data it needs. A container is bigger than the extremely lightweight function that runs in a PaaS environment but smaller than a virtual machine, which contains an operating system and all the other software needed to run a computer.
We’ve entered here into a new philosophy for computing. System administrators used to pride themselves on uptime. Some would publicize that their systems had not gone down for a certain number of months, just as construction sites post signs that say "283 days without an accident." Virtual machines, the original basis for cloud computing, created a whole new view of application deployment, and containers took that view even farther. Containers are intended to start up fast and be replaced quickly when they go down for any reason. Containers are fungible and ephemeral. Failure is built-in, along with recovery from that failure.
Until the appearance of Docker in 2013, few developers thought about containers. Docker made GNU/Linux applications so simple to run in the cloud that it catapulted application development into the cloud age. Containers also map excellently onto microservices: both are ideally small, easy to scale, and cloud-friendly.
Applications Moving Online in Software as a Service
Microservices fill a need for a particular type of application. As we've seen, they run in the cloud as part of a large, many-tentacled application that has to scale by creating new instances fast. This is not the type of application people download on their laptop or even run on a server to crunch numbers for analytics. Microservices are really designed for applications offered to visitors over the web, a delivery model that became known in the early 2000 decade as Software as a Service (SaaS).
One of the chief advantages that microservices offer web applications is support for rapid updates. If a bug is fixed or a new feature created, the very next visitor to the website can benefit from the change because the developers quickly upload microservices embodying the changes. This kind of rapid development would be no use to applications running on the users' local systems—nobody wants their computer updated every few minutes.
Microservices carry out the needs of SaaS applications in several other ways. Microservices can be replicated and run anywhere, so they can be loaded onto cloud servers that are geographically close to site visitors. They scale well and are easy to replace in order to achieve high availability. They don't take up cloud resources when they don't have to run, so the company deploying the microservices saves money.
Productivity of Small Programming Teams
Societies made up of small groups of people develop strong cultures and learn to work together well. Programming teams take advantage of this human trait to increase their productivity. There's a downside to a tight, unified culture: it can lead to the exclusion of minorities and alternative points of view in general. Furthermore, the isolation imposed by COVID-19 has put a strain on tightly integrated teams. Nevertheless, projects involving a few people who share common ways of working can move fast.
Because each microservice has a specific task, it provides a small functional footprint that can be covered by a comfortably-sized group of programmers. They can learn the requirements quickly and update the microservice as soon as they hear a need for a change. We'll see later how they can augment their small resources when necessary.
Race to Speed Up Innovation Through DevOps and Rapid Deployment
I've already said that microservices permit rapid development and easy testing. These goals blend well with a practice of rapid development and deployment that earned the name DevOps in 2009. The term DevOps combines the concepts of software development and system operations, which traditionally were done by different groups with different skills.
The rationale behind DevOps can be described as follows: System operations, like an increasing number of processes around the world, are becoming highly automated. Automation requires a kind of formal specification that is most easily implemented as a programming task, so operations become a branch of development.
DevOps automate the process of building applications, testing them, and moving them into deployment when ready. So DevOps provides a great environment for microservices: you need the automation in DevOps to reap microservices' promise of rapid updates.
We've reached the final trend in our list of factors that make microservices a good programming choice. Let's go on to the challenges of using the microservices solution.
Challenges of Microservices
In these articles, I’ve explained how the microservice architecture meets the major requirements of modern computing environments, while combining many recent advances in computing. But microservices aren't easy to implement. I'll list some of the challenges and how organizations are meeting them.
Getting the Design Right
Because microservices draw hard and fast boundaries between the various activities of an application, you'll want to think intensively before starting to define the microservices: What is the domain covered by each microservice? What services should it offer? What inputs does it need, and how are its outputs structured? It’s important to get the design right the first time. Although you could reshuffle your architecture and APIs later, you'd have to recode all the microservices that depend on the old architecture and APIs. That situation negates many of the advantages microservices offer.
Although microservices make it easy to divide and conquer, they ultimately just move the complexity to another level. With microservices, programmers can have trouble finding where something is happening and how the different parts of the application affect each other. After starting to drown in its own microservices, Uber started creating larger modules that they called “macroservices.”
Organization and Training
A move to microservices introduces differences throughout the task of programming: in the structure of the code, in program flow (which is highly parallelized and therefore hard to trace), and even in the libraries used. All this puts a strain on teams used to working on the so-called monolithic applications. Deployment also requires new skills from both programmers and system administrators, who are dealing with distributed systems in far more intense ways than before. So the organization should train its staff in all these skills, and hire some new staff with experience in those skills if possible. Teams may also be restructured around the division of tasks into microservices.
Jesse Anderson, a consultant in data management who reviewed this article, said that the shift from monolith to microservices is sometimes done gradually. Other organizations leave old monolithic applications alone and use the microservice architecture for new ones.
A small team can work efficiently on a small, well-defined system. But suppose their microservice needs a major upgrade or redesign? Can people outside the team come in to help? How can outsiders master the code base, much less pick up the team's style, interactive culture, and processes?
The division into teams can also lead to contending priorities. Perhaps the bicycle team desperately needs a feature from the central transportation team, but the transportation team has different ideas about what problem to tackle.
Many large companies have figured out, by observing how free and open software projects work, how to let one team work on another's code base in an orderly manner. The resulting practices are called InnerSource. It allows a team to set up processes for making changes that other teams study and follow.
The Database Dilemma
I said previously that each microservice ideally manages its own data, which doesn't have to be shown to other microservices. But data is different from other elements of an application: shared data is often the lifeblood of an application. If every instance of every microservice was accompanied with its own instance of a database (MySQL, MongoDB, etc.) the overhead would be significant. Most organizations prefer some element of sharing.
Transactions are classic examples of data sharing. For instance, if one person's bank account must be debited to pay the account of another person, you need a transaction. Some transactions cross the boundary between microservices.
A lot of data also has to be persistent. The microservices may be free to start up and terminate, but the data must be stored in a safe place.
Just as functional programs have to depart from the pure functional model sometimes and tolerate a kind of sharing known as "side effects," microservices have to soften the architectural ideal to use persistent and shared data.
Performance and Guarantees
Like any operations that take place over a network, applications based on microservices suffer from unexpected delays and failures. They make it harder to calculate a reasonable service-level agreement (SLA) or other performance guarantee, and the organization may have to spend a lot on infrastructure and monitoring to meet the guarantee. If a predefined time-out interval is too short, a lot of processes may be restarted unnecessarily. But, of course, a long time-out interval can leave problems unrecognized until they lead to user complaints.
Microservices Are a Stage in Computing Evolution
I have shown in this series that microservices happily bring together several trends in computing from the past couple decades. There are many precedents for each of the traits developers associate with microservices. And these programming tools and processes are sure to evolve further. Microservices may soon join many of the other terms in this article that once larded programmers' discussions, only to be denigrated later as obsolete. But the historic role played by microservices will continue to be recognized.