Death of the Monolith: microservices

Software was once delivered as monolithic, fear-inducing, complex forklift upgrades, with database schema migrations, application updates, library updates, configuration updates and plenty of downtime. Sometimes, there was a gut-wrenching irrevocable critical step in the process (often a schema update). Today, this is largely a relic and bad memory now, thanks, in part, to Virtualization and Containerization technologies, Network APIs and the move to microservices.

Death of the Monolith

The word monolithic in software authorship circles is (now) usually received as a derogatory remark. Approximately a decade ago, much software was still written and deployed in large, fraught, forklift updates.

These updates often required many software installation, data migration and reconfiguration steps. Usually, large libraries or packages, and sometimes wholesale system upgrade were part of the update process. The logic was to undertake updates infrequently, but take plenty of time in the preparation and testing. Though these updates purported to fix many bugs, introduce features and change behaviour, they could be quite risky and invariably introduced unexpected performance or behaviour changes.

(Anecdotally, I can report experiencing these sorts of releases as a consumer. I often elected to wait until the first or second point release of a piece of software, for example, RedHat-5.2, rather than 5.0 or 5.1. And, RedHat had comparably decent, quality control too; my point is that first releases were often buggy.)

Yes, the industry has improved! Not only are there more and better tools, but the process has also improved. Below, I'll examine some of the long-term trends, many of which converge in our hyper-networked world to support microservices.

At some point during their brief lifetimes, most software experiences teething problems, misses the intended goal, or omits an important feature. Many of the quality problems with software release have been addressed by a move away from monolithic delivery. This post covers trends in open source software delivery and tools for delivering software to infrastructure and distributed systems.

(I.e. this post doesn't treat software intended for installation on an end-user node, like an MacBook, Windows system or Android; though many of the trends affected these target devices and platforms, as well.)

Delivering applications as microservices

The combination of these three long-term trends eliminated need for complex, whole-application-replacing, fear-inducing, forklift upgrades. The emergence of the convenient tooling of containerization has enabled architects, system designers and developers to create discrete sets of network APIs that are intended to be deployed together on a single, independently-managed (container or) node. The general term adopted by the industry for this model is microservices.

Definition of microservices

The choice of the prefix micro simply means small in this context. Nothing fancier. (This prefix gained popularity with the rise of microformats among others.) In short a microservice is

  • a self-contained service providing a clear, versioned API (or multiple versions simultaneously to support migrations and/or older client software)
  • as logical unit of software performing one task; as simple as possible, but as complex as necessary
  • often, horizontally scalable, i.e. many instances can be deployed to handle increased traffic or usage
  • easy to replace with an update package/image
  • often accessible via the network
  • often dependent on another microservice

Here's a good article on microservices. by the fairly well-known Martin Fowler. His discussion also spends more time describing, defining and mapping microservices as an organizational capability, and alludes to the inescapable and well-known Conway's Law.

Containerization is not microservices

Because containerization and microservices have come of age in recent years, many conflate the two, but they are distinct. It is possible to build small, self-contained, individually-scalable services without taking advantage of virtualization and containerization.

Most of us, who have run any Linux system for any appreciable time have had the desire to add a service. How does one accomplish this? I will give a short command-line snippet of how I could do this on a node grabbed somewhat at random:

# apt-cache search jabberd
jabberd2 - Jabber instant messenger server
# apt-get install jabberd2

Now, I have a jabber server running.

Good packaging hygiene has enabled this. This may seem a terribly obvious point; but I stress the benefits of good packaging here.

Ever present needs

Essentially, a microservices model offers operational flexibility for moving software components around and can offer more freedom to the development team supporting a specific service, because everything behind the service is up to the team. Of course, there are the omnipresent needs:

  • each service should support rollbacks, a.k.a. software reversion if something goes wrong in an update, roll it back
  • a practice of decommissioning old, or no longer necessary services
  • monitoring of availability, performance and behaviour an update to service A might tickle a latent bug in B; without monitoring, how would you know
  • strong diagnostic tooling and experience
  • a mechanism to keep the entire stack underneath the microservice up to date
[0]It is precisely this part of the trend that led to the rise of Software as a Service (SaaS) organizations. One good and lasting example is SalesForce.