I wouldn't necessarily call this approach simple, but it was incredibly safe and rollbacks was always a none event.
We got really good at data migrations and it was no big deal - but we only got serious about this after we had a major DB and functionality update that went wrong and took us down for 2 days.
* test of a rollback procedure,
* developers thinking about backwards compatibility and rollback procedure.
The main issue I see with this approach is that the test of the rollback is only partial. Just because the schema is usable by the previous version of the application does not mean the new data that is going to be put by the application will perform the same way.
Another issue I am seeing is that it is not a separate testing event but essentially happening live when the application is turned on on production. Not nice.
On the pros, this is very useful when you want to have more than one version of the application code to coexist at the same time. But I would not rely on learning about incompatibility when I start deploying the application, I would want to know that well before then.
It's a testing event if you make it a testing even. The team I'm referring to regularly makes a dump from production, run it through a PII anonymizer and performs migration test on that.
The typical example is the renaming of a column, which needs to be done in several steps:
1. Create the new column, copying the data from the old column (DB migration) both columns exist, but only the old one is used
2. Deploy new code that works with both columns, reading from old and writing new and old
3. Deploy data migration (DB migration) that ensures old and new columns has the same values (to ensure data consistency). At this point, there are no “old column only” writes by the code deployed in previous step
4. Deploy new code using only new column. Old column is deprecated
5. Delete old column
At any given point, code versions N (current) and N-1 (previous) are compatible with the DB. Any change on the DB is done in advance in a backwards compatible way.
And these DB migrations, did your team keep a history of them? If so, did you manage them yourselves, or did you use some tools like flyway?
I'm asking because I'm starting a project where we will manage the persistence SQL layer without any ORM (always did it so far with Django's migrations), but might consider some third party tools for DB migrations.
There shouldn't be any reason that you can't do it with Flyway, but I would be concerned about fighting Flyway a bit. I use Django a fair bit and I honestly don't see a good way to make this approach work for Django, not suggesting that you can't, but you would be fighting Django a fair bit, it's not really how it's designed to work.
If you don't have en ORM, then this is actually much much easier to do right. I'd design the initial schema, either by hand or using some pgAdmin, TOAD or whatever you database has. For there on everything is just hand written migrations.
Here we never drop columns, only add new colunms, also never change column types.
When it comes to constraints (not null or something else) we double check about backwards compatibility.
Changing data is not a robust rollback.
I'd argue that because you're making the migrations from the model, it's also easier to do accidentally create migrations that are not independent of the code version.
(You could in theory remove the column but not merge the migration if you wanted to show your code worked fully without that column in your ORM model before removing it from the DB as well?)
renaming stuff with that gets a little bit tricky, but you can workaround that with database triggers if you really need to rename things.
You just end up with weird, unpredictable DB states that don't reflect production at all. Especially when you're dealing with old versions of MySQL and the character encoding and collation are all over the place.
If you can roll back and forward events, good for you but for most of us rollbacks are actually a new build, deployment, and a new set of tests. Every single time.
This is why I've never used or understood the value of the "downgrade" feature in some database migration tools. If you need to revert, make a _new_ migration that fixes the problem. Your tooling/code/logs should reflect the true history of the system without cooking the books.
Of course usually it would be followed by something that fixes it 'properly' - applying the original 'upgrade' again but with some correction, but typically that'll take longer than reverting to the previous version, and given it's gone wrong you'll probably want to take longer with it, test more, restore confidence.
Forward migration: add date column, set = date(day, month, year) for existing records, drop is valid date constraint, drop day/month/year columns
Down migration: add day/month/year columns, add is valid date constraint, set day/month/year = appropriate datepart of date, drop date column
for trivial example.
It's technically a roll forward, while to most users it's more nature to say rollback/revert
Completely reverting all the state to some point in the past is easy and have been a solved problem for quite a while.
The actual problem is undoing states changes related to the code change, while not losing state changes related to normal system activity.
If I add some new fields to how my web forum records posts, and then find out that it's eating every tenth post and need to revert, it'd be good to not lose and posts made in the meantime.
You're right though. Systems in the social media space dealing with users appending to a database typically don't have this requirement to be easily reproducible, so the local snapshots are the right choice.
Having flags push separately adds another problem on top of data corruption.