“It may not be the right way to do things, but it’s how we do it.”
How many of us, as junior developers, wide-eyed and full of wonder, have heard something like this from a manager or tech lead?
I remember hearing this early in my career and responding with a furrowed brow and a harrumph. My boss was trying to explain the facts of life to me, and I was ill-prepared to hear them.
And what are the facts of life for a software engineer?
The facts are that someone probably taught you how to program, and they probably tried to instill in you — for lack of a less barf-worthy term — best practices. One of these might have been a central engineering principle, namely modularity: systems should be modular, made up of reusable components that do useful things in a generic way.
We’re talking about software, but this applies in lots of areas: you don’t have to replace your car’s engine every time you change the oil. And there was even a time this applied to computer hardware. I’m still using my late-2011 MacBook Pro because it has a removable memory card. This meant that I could swap out the 4 GB it came with for 16 GB from Crucial, which is twice what Apple would sell you from the factory. The equivalent model today comes with the memory soldered to the logic board, so you’d have to replace the whole board to upgrade it.
What does this have to do with software?
At that same job where I learned the facts of life, one of my responsibilities was to manage a web application that ran on a Java EE application server. It was the type of monolithic enterprise application that the denizens of container land and the microservices archipelago love to excoriate, and for good reason.
This thing was a monstrosity. A consulting team had built and abandoned it at some point in the hazy, ancient past, at least 4 years prior to my arrival. It basically worked, but it did weird things sometimes. I would occasionally have to change some config and restart it, and it usually came up. Usually. Eventually.
I came to regard it as a sleeping dragon. Occasionally I would tiptoe around it to implement a Servlet filter to do something small and unambitious, but mostly I tried not to disturb its fragile equilibrium. Needless to say, when I heard tech evangelists denouncing monolithic applications in fervid sermons, I was an easy mark. I had swallowed untold ibuprofens and drowned my weariness in oceans of coffee while toiling under the heel of a monolithic enterprise app.
I needed deliverance.
Microservices were an idea that I was ripe for. Everything should be a free-standing service that exposes its data over RESTful APIs that anyone can consume in standardized ways. This felt like the triumph of HTTP and the web, and the triumph of Doing Things Right. Docker containers would help us carve our VMs up into bundles of micro-VMs that would house our microservices. It was a heady experience diving into this brave new world.
And yet…. There were some problems.
So you’re going to carve that monolith up into, say, a dozen microservices. What languages, frameworks, and runtimes are you going to use for those services? Are you prepared to learn and build 12 different stacks? Probably not. So that means using the same stack for multiple services. What happens if your stack has a security vulnerability? Are you going to patch each microservice manually? If not, assuming, they’re running in Docker containers, how are you going to automate this process?
No problem, says a team from Google. We’ve been doing this for years, and we have a solution called Kubernetes. The new buzzword is orchestration: Kubernetes will orchestrate your container environment. What does that mean, exactly? Orchestrate sounds lofty, almost god-like, with Kubernetes as the divine puppet master of your containers, and by extension, microservices. But really it just means that it automates a lot of the annoying stuff you have to do by hand if you don’t have an orchestrator.
Automation saves time, and it also standardizes tasks so that they happen the Right Way every time. Computers are bad at a lot of things, but one thing they do way better than humans is repetitive tasks. So it almost always makes sense to let them do anything you have to do more than once or twice.
Okay, so we have an orchestration layer. We can automate the full lifecycle of our microservice containers. But we now have this big, unwieldy thing to manage. We have a bunch of microservices, and they form a complex mesh of interdependencies that makes troubleshooting extremely difficult. What we need is monitoring, logging, traffic management. We need a way to know and manage what’s going in this mesh.
No problem, says a team from Google. We’ve been doing this for years, and we have a solution called Istio. It’s a service mesh that does exactly everything you’re talking about. It makes your complex environment of microservices manageable. All you have to do is install this thing on your Kubernetes cluster and hook your microservices up to it and voila! Your mesh is manageable.
Except that now I’ve tied together all of these microservices with multiple layers of automation, so now they’re not all that independent anymore. Automation seems to have led me right back to a monolith.
So what happened? Well, the world happened. Meetings happened. Your boss’s pet project that will never go anywhere happened. Weekends happened, vacations happened, Pokemon Go happened. Those five open personnel reqs that you can’t seem to fill happened.
Recall that Java EE and SOA promised us modularity. And they delivered! But ultimately tech decisions are made by human beings in response to human needs. And so our best-laid theories about Doing Things Right often run aground on the rocky shores of tired, overworked engineering teams.
The thing is, I love Kubernetes. It’s nothing short of an engineering marvel. I love it in the way I love Linux — in a deep, primordial, pre-verbal way. I even find it aesthetically gratifying, which, for all its virtues, is not something I’ve ever said or heard anyone else say about Linux. It’s an immensely elegant and practical approach—and how often do ever achieve both of those things: it’s beautiful and it works—to some very sticky problems.
And it has something else that we techy people don’t like to talk about, and that’s compassion for the people who have to implement and use it in their daily work. They’re designed by people who carried beepers and just wanted them to shut up so they could enjoy a day at the beach with their family.
The lure of the monolith is the lure of life, of the outdoors, of the great, wide world that lots of us hope to make better with the technology we work on.