Atomicity and Ratcheting
One of the vital aspects of database transaction is Atomicity, i.e. either it is done or rolled back (during failures or errors) entirely. There is nothing half done. It is like binary, i.e. done or not done.
When I started using Capistrano for deployment, I was impressed by how well it is designed for Atomic deployment. It switches to the new code when everything all deployment steps are successful. And this allows zero-downtime deployments too. And PaaS tools like Heroku applies the same magic too. git push origin heroku, boom, it’s deployed. If something goes wrong, no changes are effected.
Safety
Both atomic transactions and deployments provide safety and reduce the risk when errors occur. And it is simple to use too.
Databases are considered to be one of the high-risk element of an application. How do you bring safety to Database changes?
Say you are renaming a column. And you are deploying the change to production. Something goes wrong during the deployment and code is reverted. Now the schema also should be rolled back.
But rolling back a database change is more costly. It is scary too because we will be in big trouble if we lose data. So how do you make these changes safer?
Or it may be that there are a lot of downstream dependencies (say APIs used by other applications). And a change in column name can result in breaking those applications. So is the only option to wait? Can we do this in small steps than a big-bang change?
Backward compatible schema
For our product, we had a table to capture the membership details. The assumption was there would be one payment for per membership. Later we realised that members at times pay in instalments. So we need to change the schema.
Instead of making the entire change as one step, we retained both the old table structure and new structure. And also added code to make sure that the data in old columns are saved to the new columns. This gave us enough time for us to change all dependencies to migrate to the new schema.
We dropped the old fields once we were sure that all the dependencies are migrated.
Parallel implementation
This technique is called the Split table refactoring. And a lot of similar refactoring techniques exist too.
Similar to atomic transactions and deployments, the refactoring is about safe small steps. And a series of steps results in a significant switch. Each step confirms that the schema is backward compatible.
Branch by abstraction and Strangler pattern helps you to achieve the same for sturdy design and architectural changes. The premise of Continuous Delivery is getting changes to users in a safe, quick, sustainable way. And these techniques help you to achieve the same.
A few posts I had written in the past related to Databases and Continuous Delivery: