You’re an API developer, say at Spotify or Twilio. Your API’s v1 is out there in the wild being used by devices. It’s been a few years since you released v1 and now you need to make significant improvements and release a v2. If the changes are minor and you can keep them backward compatible, everything is good. But, if the changes are major and hard to keep backward compatible you have a problem. All those devices calling into v1 will not be upgrading. You can’t just retire v1. You have to maintain both versions.
How do you do that?
A common way people solve this problem is powering v1 and v2 from the same instance of a single microservice. Any v2 specific logic is then controlled via permanent feature flags that are sitting right below the API layer.
This is a bad use of feature flags.
- It creates a permanent if-else statement in your code that, depending on the scale of difference between v2 and v1, makes the code hard to read.
- A well-intentioned engineer can destroy the logic in a refactor 6 months down the road and now all your clients of v1 are breaking.
- As you release v3, v4, and vn of your service, the code will only get more unmaintainable.
So, if feature flags are not the right solution, what is?
A better solution is to create a new microservice for v2 which is deployed separately from v1. This way engineers developing v2 do not have to worry about the needs of v1 clients. Any code that is still shared between v2 and v1 can be pulled out into a shared library.
Of course, this is only possible if your team has the discipline to keep microservices “micro”. Large sprawling monoliths will struggle with this approach.
Also, just to reiterate: this solution is best when v2 is significantly different than v1.
So, there you go. Feature flags are great. Just be aware that they are not the ideal solution for every problem. Use the right tool for the right job.