The 10 Commandments of Changing a Microservice
- 1. You Shall Not Take the Name of Tests in Vain
- 2. You Shall Not Tackle the Whole Change in a Single Step
- 3. Honour the Main Branch
- 4. You Shall Not Avoid Live Promotions
- 5. You Shall Use Scaffolding
- 6. You Shall Use Feature Toggles
- 7. You Shall Increase Your Test Coverage
- 8. Remember to Clean Up the No Longer Needed Code
- 9. You Shall Change Your Clients Before Doing a Clean-Up
- 10. You Shall Ensure Nobody is Using the Old Code
- Following the Commandments: The Path to Safe Migrations
Microservices as a term has become increasingly popular in recent years, and is used to describe a variant of the SOA architectural style that creates an application as a collection of loosely coupled services. Every microservice has its own purpose, and will implement different interfaces or communication protocols. Therefore, any problems within a microservice will require a different, ad-hoc solution.
In my previous teams, building microservices has provided us with a set of industry standard practices and techniques to help us ensure successful, seamless transitions when it comes to a big refactor or incremental changes. Trying to provide instructions on how to tackle every single change is challenging, so we have decided to turn our knowledge into a useful guide: our 10 commandments of changing a microservice.
Without further ado, here are our 10 commandments — follow them closely!
1. You Shall Not Take the Name of Tests in Vain
Before starting a big change, failing to do so without good test coverage (from a unit and/or integration perspective) is highly risky. Are you sure your changes won’t break anything if you can’t define with tests what ‘anything’ means? You should have your expectations defined and automatically controlled in advance. The importance of good testing beforehand cannot be understated!
Modern testing frameworks like Vitest, Jest, Pytest, or JUnit make it easier than ever to build comprehensive test suites. Beyond unit tests, consider implementing integration tests and contract tests using tools like Pact to validate your microservice’s behavior.
2. You Shall Not Tackle the Whole Change in a Single Step
A famous saying applies here: Q. How do you eat an elephant? A. One bite at a time. Attempting to make a massive change at once is risky, messy and prone to error. Don’t let deadlines or pressure cloud your thinking. Patience and discipline are key here: plan your strategy as a set of micro changes instead. Every small commit will be an extra step towards success. One bite at a time.
3. Honour the Main Branch
Make several changes, make them small and commit them into main. That way you will think about making your changes harmless and ready to go live as soon as possible. It’s better to go live with unfinished, safe code than to branch out with a time bomb. Also, committing in main will make your teammates aware of what you’re doing.
This approach aligns with trunk-based development, where developers integrate changes frequently into the main branch, avoiding the integration hell of long-lived feature branches.
4. You Shall Not Avoid Live Promotions
Following the previous commandment will allow you to commit smaller, safer changes and put them live with minimal risk. It’s better to perform staggered releases, since this will add value quicker and minimise the risk that comes with a big reveal. Live promotions allow you to slowly make changes, and can give you tangible improvements as you go.
5. You Shall Use Scaffolding
Scaffolding is the process of adding temporary code to keep the application working while you are changing something else. You wouldn’t try and fix your roof without scaffolding. The same is for microservices — for example, in the case of a new API you’d create new routes to support the new API whilst serving requests to the old one, so you don’t break any clients. In other words, make your microservice backwards compatible with the ongoing change.
6. You Shall Use Feature Toggles
If you can control the behaviour of your microservice by configuration, then you will add a lot of flexibility to your change process. With feature toggles, you could enable your changes for every environment, for example (so you could test your changes before going live). You may also configure your microservice to support switching between versions by http, so an external entity could change your code version based on certain criteria.
Another possibility is to make your microservice a bit smarter and allow your feature toggle to be enabled/disabled based on health check metrics: this would allow you to roll back to the older version automatically if metrics reported lots of errors with the new one. Finally, with a more sophisticated feature toggle you could even specify different levels of granularity (for example, you could enable the new version only for certain users in a given environment, or from an individual country using a certain device).
The Dark Side of Feature Toggles
Nonetheless, feature toggles have a dark side: if you have too many, or if they are too fine grain it will be hard to test, as the code would behave differently according to a number of combinations. Try keeping a balance. Modern platforms like LaunchDarkly or Split.io help manage this complexity, but remember: feature toggles are technical debt—clean them up once the migration is complete.
7. You Shall Increase Your Test Coverage
If you have followed the previous commandments, then you will have ended up with backwards compatible versions of the code — which means you will have an older version and a newer one. You should have started with tests for the old behaviour, but now you should also add test coverage for the new one. This is what will remain after you complete your changes, so you should ensure it will be safe.
8. Remember to Clean Up the No Longer Needed Code
Not cleaning unused or redundant code is one of the reasons to consider a refactor, so save some time now while the context is fresh in your mind. Kill the old code and all the scaffolding after you ensure using the new changes is safe. Don’t leave garbage in your services, it’s confusing and forces people to spend more time reading through the code. Getting into the habit of ensuring your code is clean will pay dividends in the long run.
9. You Shall Change Your Clients Before Doing a Clean-Up
As obvious as it is, your service will be used by many different clients. If for example you’ve created a breaking change requiring the use of a new API or a new routing key, you will need to make all clients start using the new version before removing the old one, or they will start failing and report errors. This commandment can seem simple, but to avoid problems with clients, make sure that you do things in the right order.
The proper sequence:
- Deploy the new version alongside the old
- Migrate clients to the new version
- Monitor usage of the old version
- Remove the old version when usage drops to zero
10. You Shall Ensure Nobody is Using the Old Code
Since microservices are agnostic as to who is using their API, there’s no obvious way to tell whether removing the old version of the code is totally safe or not. However, you could put some monitoring in place, use some logging or send metrics over a reasonable time period to watch the use levels of these old functions. That way, you can ensure you can kill the old code if no clients are making use of the old version.
Observability tools like Prometheus, Grafana, or cloud-native monitoring solutions (CloudWatch, Azure Monitor) make this straightforward. Wait at least a full business cycle before declaring the old code completely unused.
Following the Commandments: The Path to Safe Migrations
Microservices, and their changes, can be difficult obstacles to tackle. Creating an ad-hoc solution can be challenging and it’s important to follow a set of guidelines and principles whilst making changes to ensure the result is as desired, for both yourself and the client.
These 10 commandments are battle-tested practices that have helped teams successfully evolve complex microservice architectures without breaking production. The key is discipline: follow these principles even when under pressure, especially when deadlines loom. Taking shortcuts might seem tempting, but the cost of fixing a broken production system far outweighs the time saved by rushing through a migration.
Remember, changing microservices is not a sprint—it’s a carefully choreographed dance between old and new, between stability and progress. Your migrations will be smooth, safe, and predictable if you commit to these commandments.