Expand Contract Pattern and Continuous Delivery of Databases
The premise for Continuous Delivery is helping the business to deliver value continuously. Yes, continuous can be much more continuous than you think and subjective too.
A few years back, we’d worked on interactive T-Shirt design module for an eCommerce application. The design is converted to a PDF and delivered to the printing vendors. We used RGhost, a Ruby wrapper for GhostScript, to generate the PDF files. It worked well until we wanted to support a few Text supporting features. So we decided to move to Latex for implementing this.
It will take longer for us to change the existing features from RGhost to Latex. And the immediate need for us is to implement the new feature than porting the existing ones. So we decided to use the technique Parallel Change using Branch by Abstraction.
Parallel change — aka Expand Contract Pattern — helped us to deliver the new feature without disturbing the existing functionalities. We moved to the new library over a period.
Expand Contract pattern can be applied to databases too. I’d written about the Split table database refactoring technique.
Our product — Good Karma — has a trial class booking module, to allow users to book trial classes at yoga studios. Not everyone who books a trial class attends the same. And those who attend may or may not decide to register with the yoga studio as a member. So this means the status of a booking can be as follows:
- Trial attended and registered
- Trial attended, but not interested in registering now
- Trial attended, but prefer to register in the future
- Didn’t attend the trial
We started with the above, and later realised that we need to split the status field into two:
- Attendance status [Attended, Didn’t attend]
- Registration status [Register now, Register later, Not interested]
Let’s see how approached the same using the split column refactoring:
We’ve got a few entry points in the application using which the status can be updated. So we first rolled out the migration [like a dark launching]. This meant migrating the data to the new fields and also added a trigger to save the data to the new fields when the status field is updated.
After launching the migration, we updated the related parts of the system to reflect the new schema. Once we gained enough confidence about the new schema, we dropped the status column. So, in summary, we expanded it, and then later contracted it to the new schema.
The idea here is to reduce the risk of each release or deployment to the minimum. Small batches always reduce the risk, because it helps to identify the issues quickly and helps us to be more resilient. Techniques such as Dark Launching and Feature Flags help us to be more resilient as these give us hooks to control if and when things go wrong.
Note: I will be speaking at RootConf ‘18 on the same topic.