We tend to depict the microservice and the monolith as two polar opposite styles of software architecture — the natively decomposed versus the self-contained, the fluid versus the solid, the mercurial versus the integral. And because “New” is the second word in our masthead, we tend to draw a parallel vector leading from the archaic to the modern, when we discuss the virtue of full-scale containerization, encompassing microservices, serverless staging, asynchronous signaling, and statelessness.
Microservices, wrote software architect Vivek Juneja for The New Stack in 2016, enables “a new, more agile world in which developers and operations teams work hand in hand to deliver small, loosely coupled bundles of software quickly and safely. Instead of a single monolithic system, functionality is carried out by a smaller set of services coordinating their operations.”
It has often sounded utopic, like the ousting of a totalitarian regime by an egalitarian republic. Microservices, as has often been stated, enables not only scalability but flexibility in the way applications are managed.
But have we been unrealistic about all this?
“I think I have personally never seen an engineering team plan out an application using microservices, from the first step, and have it be successful. One hundred percent failure rate,” stated Laura Frank, the director of engineering for commercial Jenkins platform producer CloudBees.
“There is value in that yoking to oneself because the abstractions and their disintegration points will reveal themselves to you over time,” Frank continued, referring to a kind of illustrative image similar to how a marble sculptor sees in her mind the chunks she needs to chisel away. “Every monolith starts as a microservice, really, if you think about it. As you keep adding on and tacking on, it becomes a monolith. And where the monolith gets a bad reputation is when it’s not revisited, and those abstractions aren’t acted upon.”
Since most applications are built up like clay busts from the inside out, as she perceives the two concepts, a microservice is a primordial monolith. Her perspective is backed up by industry observer Martin Fowler, which The New Stack cites as having coined the microservices concept in the first place.
In a 2015 essay, Fowler wrote, “Any refactoring of functionality between services is much harder than it is in a monolith. But even experienced architects working in familiar domains have great difficulty getting boundaries right at the beginning. By building a monolith first, you can figure out what the right boundaries are, before a microservices design brushes a layer of treacle over them.”
In that same essay, Fowler suggests that a reasonable method for arriving at a microservices system is to begin with a monolith and peel away microservices individually and carefully. CloudBees’ Frank takes that assertion to the next step, stating that this peeling away may actually be the only rational method for any organization (at least, outside of Netflix) to attain scalability and cross-cloud portability.
“We often mix up lines of code with business logic,” said Frank. “And it’s very possible to have a very tiny monolith that has lots of business logic in it, but probably not many lines of code, or maybe not using that much infrastructure resources. Likewise, I think it’s easy to have a big ol’, fat microservice that’s a ton of lines of code, that’s maybe only responsible for one business decision. It’s a sliding scale. ‘Microservice’ is on one extreme end and ‘monolith’ is on the other extreme end, when it comes to business logic. We never talk about the middle part anymore. I don’t know why that is, but I found that middle part to be pretty successful for lots of engineering teams across many different industries. That middle part is really, I guess, the typical service-oriented architecture.”
The Child Disclaims the Parent
Frank’s assertion is that the scale is bookended by a pair of models in opposition to one another, neither of which accurately depicts the state of affairs in any enterprise. As I told her, most practitioners of Service-Oriented Architecture (SOA, the “parent” of microservices) whom I’ve met, uphold such a model as the ideal state of the organization — effectively a fully annotated business that is acutely aware of each discrete function it performs, and which has built software code around each function.
Some software architects have referred to this model of SOA by way of arguing that microservices are, to put things more succinctly, services. But in a webinar last November, Event Store architect James Nugent pointed to a critical difference between the two concepts: The parent SOA advocates the creation of a single organizational domain model that represents the business model for all the code (analogous to how a schema represents the elements of a business for a database). But the child, microservices, would eschew such a global model.
If you think about it (and with a topic this esoteric, it’s difficult not to), microservices would seek to do the unfathomable: model a business while simultaneously forgoing the use of a model. We’ve seen before, South American ants building bridges from their own interlocking bodies without blueprints. It’s amazing. But perhaps it’s not advisable.
“There already is a very rich landscape of business logic that something needs to be built out of,” she explained to The New Stack. “And I think that assembly of business logic is a monolith in and of itself. It has already gotten to a point where there are clear abstraction layers, and the decision could be made to say, ‘We need this component, and we need to build it this way, because we understand the world around us.’ I think what’s not successful is a total greenfield project without that richness of business baggage behind it, where the decision is like, microservices for microservices’ sake. That where I think people fall into that hole.”
The Second System Effect
Last September at the Open Source Summit in Los Angeles, some of the major practitioners of cloud-native applications development appeared to be leaning in Frank’s direction. At one session, Cloud Native Computing Foundation Executive Director Dan Kohn spoke out in favor of a kind of lift, shift, and adjust approach for transitioning monolithic applications into cloud inhabitants.
“You have this very old application that’s conducting, in many cases, billions of dollars of commerce. And you say, ‘Well, how can I evolve that?’” explained Kohn. “The obvious answer is, ‘Okay, I’ll rewrite it.’”
But Kohn cited a 1975 volume of essays on software engineering by Frederick Brooks entitled “The Mythical Man-Month,” which referred to a concept called the “second system effect.” In one essay, Prof. Brooks proposed that a first effort at a systems architecture is “spare and clean,” mainly because the architect is learning as he goes along. But later on, the inevitable sequel is likely to have been overthought, becoming a “big pile” of functions, only half of which will ever be regularly used.
“The existing system has to keep evolving,” explained Kohn, citing Brooks’ work, “to new requirements and new demands on it, and fixing bugs and other sorts of things. And it often evolves faster than the second system can go and catch up. So if a rewrite is not going to work, and you have this monolith, and it’s the antithesis of cloud-native — it’s inflexible, it’s tightly coupled, it’s brittle — then how can you get to this new world?”
The first step Kohn advised was to “stop digging” — to cease adding new functionality to the monolith. Next, begin adding APIs around the existing system, and literally “lift and shift” it into a single container. “You can actually take essentially any piece of software ever written, and you can wrap it in a container.”
Later that same day at the conference, Tibco Software director of product management and strategy Rahul Kamdar specifically cited Kohn’s “lift-and-shift” methodology as #4 in his list of “10 Pitfalls in the Transition to Cloud-Native Integration” (PDF).
Kamdar conceded that lift-and-shift does have the advantage of expediting a project. “But it has a lot of risk, a lot of costs in the medium- to long-term,” he said, “a lot of operational overhead.” Tibco learned this lesson from direct experience, he added. “If your apps are already horizontally scalable, if they have a very fast startup time, if they have a significant number of services going up and down, then sure, you could do a lift-and-shift. But that’s not the reality for most traditional ESB [enterprise service bus] apps.”
Applications designed to use ESBs as their cross-component signaling mechanism, Kamdar went on, simply cannot be lifted and shifted into a single container and decomposed from there. By design, such an application maintains its own session state — that’s what the ESB is for. From his perspective, decomposing such an application into stateless services running alongside a stateful session makes it impossible at best, and ridiculous at least, to continually and intentionally maintain dichotomy by design.
CloudBees’ Laura Frank (whose Codeship CI/CD platform is now a CloudBees service) sees precisely the opposite development pattern. By leaving the monolith on life support as it’s being decomposed, Frank argues, an organization does not need to concoct a new deployment strategy during the transition process.
“For example, we have a new API, and we wanted it to be an independent microservice,” described Frank, “but guess what? All the business logic that this API relies on is in this monolithic Rails application. To abstract it out at that level was way more overhead, for not enough return on investment. So it made sense to keep it in the same place. It made deploying it easier; it made testing it easier. There are definitely advantages and solid business reasons that companies find themselves looking at either chasing down this horizon of cloud-native and microservices, or keep doing what they’re doing and take a more pragmatic approach, and have that be the better business decision.”
Way too often with our technology and architecture debates, we close with a professorial note that the final solution is something in-between. This time, we may not have that luxury. It’s the state of being in-between, of perpetual flux, whose value is being debated. And both parties to the argument appear to have evidence, history, and experience on their side.
Feature image: An active termite hill in the middle of an open, green field by Paulgotoo, licensed under Creative Commons 4.0.