3 ms·
One of the very best development teams I worked with had an interesting take, they always did database migrations first. Any new state that was to be added to t
by mrweasel 3y ago
One of the very best development teams I worked with had an interesting take, they always did database migrations first. Any new state that was to be added to the system could only be done so by first adding the new database fields or tables. This ensure that version 1 of the code would work with version 1 and 2 of the database. They would then roll out version 2 of the code, but have the new features hidden behind a feature flags (in the database), ensuring that version 2 could run, without using the new database schema. Once they where confident that everything was still running on version 2 of the code and database they'd enable the new feature. Later the feature flag could be migrated from the database to a properties file, saving the database lookup.
I wouldn't necessarily call this approach simple, but it was incredibly safe and rollbacks was always a none event.
- steffres 3y agoThat sounds reasonable. But what about the case where the DB migration of version 2 would be incompatbile with code version 1, e.g. a column was dropped?
- jaimebuelta 3y agoYou NEVER do that in one go, you need to split it in several deployments. Dropping a column is relatively straightforward, in two steps. First deploy a version of the code that doesn’t use the column, then release the migration dropping the column. 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.
- steffres 3y agoI see. Thanks for the clarifications. 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.
- merb 3y agobtw. it's also bad to drop a column if you have multiple people in a team when they switch between branches. it's always a headache, so the best thing is to delay dropping/deleting. renaming stuff with that gets a little bit tricky, but you can workaround that with database triggers if you really need to rename things.
- ljm 3y agoThe problem I've seen a lot, particularly with Rails, is when migrations generate a schema dump after running them, which can get really messy if people blindly commit the diff or if you rely on running several years of migrations in your local environment from scratch (many of which may have been edited or removed if they directly referenced application code). Given the migrations are executed through a DSL and the dump is just a structural snapshot of the DB at the end of the run, they're not quite as reproducible as plain SQL migrations. 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.
- mrweasel 3y agoThe way I've seen it work is hand written SQL for the migrations, numbered and tracked in Git. 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.
- nicoburns 3y agoYou do it in two stages. Add as new column, deploy code that uses it and no longer use the old column. Then later drop the column once nothing is using it anymore.
- QuercusMax 3y agoI learned this as standard practice at Google back in 2015. 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.
- onetimeuse92304 3y agoNot saying it is a bad idea, but the way it works is it ensures certain things happen that you would normally want to happen, namely: * 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.
- mrweasel 3y ago> 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. 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.