2 min read

Avoiding some troubles in DB schema changes

How and why splitting db schema migrations and the code changes related to them.
Avoiding some troubles in DB schema changes
Photo by Jo Coenen - Studio Dries 2.6 / Unsplash

Many fullstack frameworks such as Ruby on Rails and Django (just to name  2 of them) come with a way to handle changes in the DB schemas through "migrations". This is a great feature, yet, when deployment time is reached ...  making those changes real in the production DB requires a bit of a careful dance.

Risking it all

When a code change is pushed to production it will usually be done by starting up a new release of the application on a server. As the application is loaded it will reconnect to the database and start to proceed with treating what ever requests come in. If those code changes make use of new columns or tables added in the database within a schema migration included in the patch that composes that release ... This might create a big issue and crash the application.

Depending on how the deployment and running of scripts related to a deployment is done ... the changes in the database might not be live yet. So the code might be looking for a table or column that doesn't exist.

Limiting the risk

We have a way to limit that risk: splitting the release in two: one part to handle the DB schema changes, the other part to handle the code changes. Depending on the type of DB schema change the order of deployment of the two is different.

In the past, depending on how the deployment and running of the scripts for the migrations is done my teams would request specific heads up from the software engineers to run the DB migrations with the new release. In other cases the CD process would include the step.

If you add a table or a column you need to pass the migration of the DB schema ahead of the code changes. So 2 patches, 2 releases: first the schema changes, then, once we are sure it went through, the code change relying on that new table or new column.

If you remove a table or a column you need to pass the migration of the DB schema after the code changes have been deployed. First you remove all references to the table or column and then you remove the table or column. 2 releases again: first the code change, then, once we have no more calls to that table or column, we can pass the schema changes.

If you rename a column or table: well you don't rename, first you add a new column or table (1st patch), figure out a way to copy the data into the new column or table (2nd patch), point the code to use it (3rd patch), and then clean up (4th patch). In effect, that a mix of the previous two steps.

Reasons

Most developers don't see the point of this dance, it slows down the development process by adding steps, yet: it removes the strong tie to schema change and code change within a deployment. If one or the other fails you can rollback in a safer manner.

This is a great way to avoid issues upon deployment and gives an extra moment to proceed with rollbacks. It saves time in the end.