I’m Tim O’Hearn and I like microservices.
My preference isn’t a proclamation that the tradeoffs between microservices and monolithic web applications always favor the former, just that I’ve had a better experience implementing microservices for the problems I’ve had to solve at work and with personal projects.
Microservice architecture is a relatively new, relatively groundbreaking approach in that many companies that aren’t serving hyper-performant consumer apps still probably haven’t touched their monolithic codebases. Fundamentally, it’s fine. Objectively, in some cases it’s correct–why change the way things are done just because a couple new grads start on the engineering team and want to break apart legacy codebases?
Microservices gained in popularity as cloud offerings became more fully-featured and the DevOps tools needed to glue everything together rapidly grew in sophistication. Companies ran up against the bounds of Monolithic Architecture. At the end of the day, how you actually implement a microservice is up to you, but for me, Ansible, Docker, and Jenkins are all-but-necessary in helping manage the high complexity of what is a rather modest number of services.
In being a champion of microservices in the office, I also have to be the head evangelist. This means giving presentations, never turning down a question, and writing docs and reports that people actually want to read. I like to do these things. On the more stressful side, I have to frequently fight battles against the guardians of the old way both on the philosophy front and the implementation front.
The reason I’m writing this post is to force myself to think critically about some of the arguments I’ve made and also clear up what I feel are misconceptions about microservice architecture that severely hinder productive discussion.
We’ve all had a bad breakup, whether with a significant other or when we take production systems down when pushing out seemingly-innocuous changes to long-dormant codebases. Maybe both in the same week. In either case, it can be hard to erase that pain. Maybe you don’t date for six months. Okay, do your thing. Chances are that not pushing out major changes at work for six months isn’t an option.
As humans, we often have an aversion to pain stronger than an attraction to pleasure and it’s instinctual to avoid the metaphorical fire that once burned us. However, as a software developer, you have to keep drilling. Too often defaulting to the safe or easy way will lead to the development of bad habits and will impede progress (source: me). So whether a project stalls because people oppose the change or you personally don’t want to cause a major financial loss to the firm, it’s important to ask why. People who have experienced bad breakups may block your progress at any stage, whether making small changes or finally breaking apart a monolith. The hard truth is that 1. You may actually be lacking the knowledge and experience to approach the problem correctly and 2. Your organization may lack the proper organizational process and discipline to enable such work to be completed (within a given threshold of constraints).
What is there to do? Sure, educating people who oppose change can help. Politely documenting every issue that you feel is caused by a service being monolithic also can help. Eventually, you get to a point where you at least have to break a self-identified microservice off from the mothership–there’s no more incremental work. Sometimes, this means a comprehensive re-write. Other times, it can be simple and done via BG deployment. In my experience, the pain often comes from weak integration testing and an incomplete audit of users of a service. Just like when you don’t communicate in a relationship, when you don’t communicate with your end users or support team when refactoring services, things are likely to end badly and you’ll quickly run out of people to blame.
Microservices Are Not Docker
Tracing cause and effect can quickly become a conundrum. When it comes down to it, Docker can become a huge problem if not managed properly. Many companies may be lacking the resources and knowledge to properly take Docker from proof-of-concept to production-viable. My path has been bumpy but I’ve learned quite a bit along the way.
Benefits of Microservice Architecture can be expounded (some would say complimented) by deploying services in containers. Docker makes it easier to release quickly and seamlessly. Using Docker makes it easier to integration test. Docker orchestration (Swarm) is the natural choice for quickly scaling apps in a way that is operating-system agnostic.
However, a dislike for Docker isn’t a reasonable defence. It shouldn’t stall a microservices rollout. Might a Docker toolset (pipeline, whatever) be too primitive to support production microservices? Yes. But monolithic services can use Docker too. As much as they may be tied together, it’s counterproductive to scapegoat microservices when the root cause is an immature implementation of Docker.
Defining a Monolith
What is a monolith? Basically, an entire high-level business operation packed into one application. Nobody ever said that monoliths are bad. In fact, many companies still use this architecture pattern. For companies operating at large scale requiring extreme efficiency (Netflix, Google), migrating to microservices has helped alleviate the shortcomings of monoliths.
It gets confusing because old, tried-and-true monoliths can exist alongside new microservices and be under the ownership of the same team. Likewise, monolithic applications can interface directly with microservices in a hybrid-approach and some microservices can even become monoliths (if not, more vaguely, monolithic).
Neither approach is something to shun but rather to be embraced. If you join the back office team at a bank and during your first month you propose breaking up their monolithic codebase, you’re likely to be labeled an overeager fool. If you go into meetings at a place that has had some success with microservices and respond “monoliths are just fine” to every small failure, that won’t work either. These two approaches can be symbiotic and can both be deemed viable approaches in the generic workplace.
Is Innovation Sacrificed in the Name of Job Security?
In any organization that is trying to blend old with new, the champions of new have to be evangelists as well. Sometimes this is all that’s needed to steadily push the envelope. Other times, being an innovator in a place where innovation isn’t strictly necessary may invite the paranoia that the guardians of old will be trying to silently dismantle your hard work.
Maybe the bearded sages are guarding their jobs and they aren’t so subtle about it. They surely didn’t get to where they are by chasing down every new trend, but they did have to learn how to adapt. There comes a point where the question has to be asked–might some talented people shun new advances like Docker and Microservices because they don’t see how embracement will directly benefit them? The path of least resistance consists of saying no and blocking junior developers whenever possible. Why not?
Such behavior can pay off, as clueless managers who respect senior employee’s skills are going to continue respecting such skills. In fact, being selfish about which new technologies you choose to stay current on means you can allow yourself the luxury of looking good from inception to delivery. Meanwhile, junior developers have little bargaining power. A fact of life is that some battles can not be won. Knowledge is power, but power is also power.