From Monoliths to Microservices Using Feature Flags

erik | September 29, 2017

I’m sure that you’ve heard the term “microservices” by now.  How could you not?  After all, it’s everywhere.  Gartner catalogs waves of hype in what they call their hype cycle research.  And, for 2017, they have microservices at peak hype.  But let’s look past the hype and to the actual, substantive principle at the core of things.

Microservices let you break large, complex problems into simpler, smaller ones.

Oh, don’t get me wrong.  You must still manage this complexity somehow (usually through a concept called orchestration).  But microservices let you move away from a world where you ball all of the complexity in your entire problem domain into one gigantic thing that you plop into production and tweak later.

The Pain of the Monolith

In the world of application development, people that write architecturally sound code abide by a principle known as the interface segregation principle.  Simply put, don’t make people depend on things they don’t need.

Want a quick example?  Imagine logging into your bank account online to pay some bills.  Except, you can’t login because there’s a glitch in the section of the bank’s site dealing with auto loans.  “But I don’t have an auto loan!  So what do I care about that?”  Exactly.

In the world of software, architectural monoliths run afoul of this principle.  That bank’s site has everything coupled together, so a problem in one area affects unrelated areas.

In the past, when the world accepted yearly software releases, this wasn’t such a big deal.  In a 2017 world of agile software development, continuous delivery, DevOps, and generally more nimble software delivery, it’s a very big deal.  So companies scramble to decouple, and they move toward microservices.

The Irony of Moving from Monliths

All too often, when companies commence this scrambling, they do so in a very non-strategic way.  In fact, it’s downright ironic.  They decide to get flexible by moving toward microservices, and then they orchestrate that move in the most dated, inflexible, monolithic way imaginable.  They go for the forklift upgrade.

I’ve written before about the mistake of doing a forklift upgrade. That was on a different post about reducing database migration risk with feature flags.

It involves first deciding that you need to replace a piece of software.  You then set about doing so by developing a parallel system over the course of months or years.  Once that system is finally already and tested, you perform a grand switcheroo from old to new.

I’ve never seen this go well.  Really, it’s a question of whether you spend a few harrowing weeks of late nights getting things working, or whether it’s a complete disaster and you roll back.  But nobody ever just pulls that switch and watches things go smoothly.

The irony of this whole thing has to do with risk.  Moving from a monolith to microservices allows the bank not to anger its banking customers when the mortgage system goes down.  It isolates risk vectors and thus minimizes them.  But all too frequently, companies move toward that reduced risk situation in the riskiest way imaginable: all or nothing.

Slaying the Monolith Without the Risk

Alright, so the big bang cut-over isn’t the way to go.  If not that, then what should you do?  Well, let’s consider what that might look like.

Conceptually, you do it one piece at a time.  Your monolith, after all, isn’t a perfect spheroid of uniform density and consistency, like a pool ball.  Some of its functionality is tightly woven into the core, but some of it exists more loosely, at the edges.  You start, then, by picking something at the edges and migrating it out of the monolith and into its own orbit as a stand-alone microservice.

Think of untangling a complicated knot of interconnected cords behind your television.  You don’t simply throw all of your equipment out and start over.  And you don’t wave a magic untangling wand and get magic.  Instead, you start carefully and determinedly, and you untangle the least tangled cord first, working your way gradually inward.

And, as you do this, one of your most potent tools will be the feature flag.

Migrating to Microservices: First, Build a Microservice

Let’s return now from metaphors to the world of software development.  What does this look like, more tangibly?

It starts with identifying a candidate microservice within your monolith.  Make it something peripheral.  For instance, say that you have an e-commerce platform that allows people in a niche to buy and sell from one another, a la eBay.  Core functionalities include account management, bidding, buying, selling, and negotiating the money.  But you’ll also have conceptually fewer core functionalities, such as emailing your users.

In a monolith, emailing happens in procedural fashion.  Right after your code that writes a new user to the database, you have the code that dispatches a welcome email.  But does that really need to be there, tightly coupled?  If you issue an update with changes to the emailing logic, do you really want to run the risk that it stops new users from signing up?  Of course not.

So you’ve identified a candidate microservice.  Now, you just need to build it.  I make that sound easy, and that’s because it should be.  Microservices are very simple, very focused utilities.  So you build a little back-end utility that accepts, say, JSON with details about an email and then dispatches that email.

That’s easy to write, easy to test, and easy to stand up.  So go do it.  And then test it and ship it to production with a dark launch.

Next, Introduce a Feature Flag

Now you have a production email dispatching microservice.  No one is yet using it, but that’s by design.  And, no worries, they’re about to start.

With your email service quietly awaiting its users, you get to work on your monolith.  Go to the application code concerning emails and introduce the concept of feature flag management.  You’ll put conditionals around the email functionality that correspond to configurable settings.  The logic is simple: if the feature flag is configured to be true, you use the new service. Otherwise, you use the monolith’s old code.

With those changes in place, you issue an update/patch to your monolith.  The risk of this is very minimal since the code is exactly the same until you turn on the feature flag.  Once you’ve rolled that into production and confirmed that everything is stable, you enable the feature flag for a tiny trickle of new users.  Then you watch carefully, making sure that everything goes well with the new microservice version of the emailing.

Build On Your Success

If all goes well with that trickle of users, you crank up the traffic using your feature flag management.  Turn that trickle into a flow, then a stream, then a flood, validating at each step along the way.

Eventually, all of your users will be on the new email microservice, which is great.  You’ve now struck the first blow in slaying your monolith.  But don’t get complacent.  The next important step is to remove the flag for that microservice and the old functionality.  The last thing you want is old, duplicated cruft hanging around when your whole goal is to get leaner and simpler.

Once you’ve done that, you’ve successfully pulled a tiny chunk of monolith into a microservice.  Now you just have to do this over and over again until you’ve pulled all peripheral functionality into its own microservices and left a core of whatever size and complexity you deem suitable.

The Whole Cloth Process

That’s the overall gist of using feature flags to reduce your risk in migrating to microservices.  Here’s a quick, bullet-list recap of what that looks like.

  1. Identify a peripheral piece of functionality in your monolith to migrate to a microservice.
  2. Implement that microservice, test it, and stand it up quietly in prod.
  3. Add feature flags to your main application around that functionality and then issue a release/patch.
  4. Experiment by using the flag to send a few users to the new microservice.
  5. If that goes well, keep sending more and more users until all are using the microservice.
  6. Retire the feature flag and delete the old application code in your next patch/release.
  7. Keep repeating until you’ve broken off all of the microservices you want.

Laid out like this, it’s truly not all that complicated.  It’s not nearly as complicated as the grand rewrite in which you deconstruct the monolith into an ideally orchestrated suite of microservices.  And that simplicity is really the point.  It lets you evolve your architecture without waste, even as you continue to serve your users.  And feature flagging lies at the core of this.

So, by all means, take advantage of the microservices paradigm.  Lots of hype or not, it’s a great way to ship software with much less risk.