Microservice Versioning
The version 2 blues
If multiple clients are consuming your API, and you’re regularly making changes, then at one point, a new version will become a topic of conversation. But what do these new versions look like?
Let’s assume your first version has a layout similar to the below:
- Controller Layer (The layer that exposes the REST endpoints)
- Service/Business logic Layer
- Data layer (Where data is accessed and/or persisted)
A common pattern I see encouraged regularly is to create a new controller layer. This is where your newly perfected endpoints and DTOs sit, and where the new DTOs are translated into the original business objects, which will then be used by the existing business logic layer. This is great! There’s barely anything to do; after all we are only changing what the API looks like, and everything else remains the same.
Sadly (most of the time) this is a very wrong assumption. If you can say your business logic is never going to change, then sure this pattern may be okay. But our microservices are often not so micro with the business logic they encapsulate. Our business logic is ever changing, so how does this complicate things?
Well the ‘backwards compatible’ problem has just been buried to the business logic layer and for any change to your new version you will always have to ask “is this breaking anything in version 1?”. Remember one of the main reasons for making a new version is to get away from this backwards compatibility.
There are going to be changes in your new version that will have to break the older version. This is inevitable if you have an ever-transforming business. When this happens, prepare for code that looks like this:
if (version == V1) {
//do this
} else if (version == V2) {
//do something else
}
From the perspective of the API, this isn’t obvious. At least that has been cleaned up; you have a sexy new API with perfectly RESTful endpoints, but your code is going to get consistently more complicated. You have pushed the ugliness of your API into the business logic, and as a result slowed development time and forced engineers to write horrendous work arounds like the one above.
You might be able to say you can get clients of your old versions which will give you the freedom you so crave. When saying this, you should keep in mind how hard it is to convince your own team/business, to allow time to work on tech debt. Imagine how hard it’s going to be to convince another business/team to move to a new version. In any case these clients should not have to worry about helping you with your tech debt. It won’t happen and shouldn’t happen.
Hopefully this has convinced you that there is a problem with the easy approach, but what’s the alternative?
If you want freedom when you rewrite your services or make changes in your new versions, do not be scared of starting things again. I’m not saying start from scratch; I’m saying what is so bad about copying your old one, upgrading dependencies, and cleaning some the mess you have made in version 1. There is a lot of fear around copying, but remember, with microservices, you probably have copies of DTOs, translators, security and all sorts of things. Don’t be scared of copy paste.
This approach means create a new code base and new API from the old version. This code base can be changed independently to your old version, meaning you can do all the refactoring and clean up you want, without having to tiptoe around existing code.
Of course there are negatives to this solution. Obviously this requires some architectural work such as new hosts for the new version. And you will debate what you call this new API, because we all know that’s very important. There is also the possibility of having to change things in two places if such a change is required to common part of the service.
Managing multiple code bases and services could be a problem but now at least there is an opportunity and possibility of deprecating one of them completely.
The only real negative to this solution is time. Doing this is going to take longer short term, but good things don’t come quickly. In the long term you have rid yourself of many mistakes you made in your old version and most importantly you don’t have to ask yourself, “is this backwards compatible?” (at least for now).