In my previous article, I covered the challenges and design of an application that uses zero downtime deployments with breaking schema changes to a database. In this article, I cover the implementation details.
The current state of our database table is shown below.
We will be renaming the LastName field to SurName.
The user interface will also need to change.
The implementation for the user interface ensures that a value is entered for LastName. This will be implemented for SurName as well.
We will be using diagrams like the one shown below to step through the implementation. The database version is shown above the database element. We start with 2.0.0.
Under the database element, we see the fields involved. We start with the current database with LastName that does not allow nulls.
Application 2.2.2/Database 2.0.0
The current production version of the application is 2.2.2 and is compatible with database version 2.0.0. The previous version, 2.2.1, is in the staging environment and is also compatible with database version 2.0.0.
Application 2.2.2/Database 2.01
The first thing we need to do is add SurName to the table. It is set to allow nulls so both versions of the application will operate. Remember, the user interface validates the entry of the data. The database reinforces this rule. This brings our database version to 2.0.1.
No application code is changed, but the compatible database version is changed. As new rows that contain LastName are added, null SurName fields will be present. The database change needs to be tested carefully in the QA environment since no easy rollback is available when deployed to production.
Application 2.2.3/Database 2.0.1
Version 2.2.3 of the website implements the SurName field in the user interface. Front-end validation ensures that the SurName field has been entered.
To support a possible rollback, we also need to maintain the LastName field. This application uses the Entity Framework and the Repository Pattern.
A screenshot of the code changes for the SaveCustomer method is shown below.
We need a postdeployment script that updates the SurName field with the LastName values.
Below, we see the implemented SurName field. All of the LastName values are now also in the SurName field. As the user operates the application, the LastName field is also updated.
Rollback - > 2.2.2
If something goes wrong with 2.2.3, we can roll back to 2.2.2. As we are fixing 2.2.3, users will be using 2.2.2. As they do, only the LastName field will be updated. When we deploy the fix to 2.2.3, we need to rerun the postdeployment script.
Application 2.2.4/Database 2.0.2
2.2.4 removes LastName from the application codebase, but we need to keep LastName in the database and change it to allow nulls. As new rows that contain SurName are added, null LastName fields will be present.
Rollback - > 2.2.3
If something goes wrong with 2.2.4, we can roll back to 2.2.3. As we are fixing 2.2.4, users will be using 2.2.3. As they do, the LastName field will still be maintained.
Application 2.2.5/Database 2.0.3
Version 2.2.5 of the application depicts the implementation of some other new feature and the completion of the SurName implementation.
Final database changes are made, and the LastName field is replaced with the SurName field.
Rollback - > 2.2.4
Version 2.2.5 implements some other feature. If something goes wrong, we can roll back to 2.2.4, which contains the final application code for the SurName change.
This trivial change represents a worst-case scenario for a database change. To support rollbacks, we basically need to support both the LastName and SurName fields and gradually remove the LastName field.
In my development cycle, I used a separate local development SportsStore database. This is necessary because I needed to carefully test the database deployments. I also carefully made backup copies of the local database so I could restore and retest the deployments.
In a real-world example, careful thought, planning, and testing need to be completed to achieve true zero downtime deployments with rollback.