Backward compatibility and making changes with less risks
===============================
Goal of this document is to estabilsh some principles and ideas around
reducing risks of applying changes.
Everybody breaks things, but there are few things which might reduce problems.
## Deployment and BC between releases
Let's check simplified deployment diagram to illustrate a problem. There is two apps which deployes at the same time: API and provider app SPA.

Sequence of actions is following:
- Start new container from new image and run DB migrations
- Update API container
- Update SPA
So here we have two things:
- while we updating changes for new version of API older version still operating and should not break.
- Provider could load SPA in his browser before we deploy new version. So provider app *v41* will rely on new version of API.
Each step requeres previous to be successful. In reality there could be blue/green deployment, cannary deployments and so on. Both new and old versions of API will work at the same time.
Because of that we must garantie backward compatibility between this two versions:
- All DB migrations should be backward compatible at least between two versions.
- All API requests/responses should be backward compatible at least between two versions.
Potentially you could break BC by:
- Adding mandatory field in API
- Removing things which still could be used by older version of app
- Renaming things
### DB Migrations
with DB migrations there are also few other things which could cause problems. One of it is table rewrites when performing some of the schema changes. Here is a list of safe-to-use SQL to modify schema:
- `ALTER TABLE ... ADD COLUMN` without a default and allowing the column to be NULL.
- `ALTER TABLE ... DROP COLUMN`
- `CREATE INDEX ... CONCURRENTLY`
- `DROP CONSTRAINT`
- `ALTER TABLE ... ADD DEFAULT`
**Note**: with assumption that there are no long running transactions in application. You could check more deltails here: http://www.joshuakehn.com/2017/9/9/postgresql-alter-table-and-long-transactions.html
There are also notion of idempotent migrations. i.e. instead of `down` migration scripts, you write all of your migrations in a way that it's safe to apply them twice.
```
ALTER TABLE settings ADD COLUMN IF NOT EXISTS some_id UUID
```
See more details here: https://dzone.com/articles/trouble-free-database-migration-idempotence-and-co
### Multi step schema changes
Adding new things in database should be safe, since old code can't rely on it.
Removing things - only safe if you already checked that no one rely on this things.
More complicated thing is renaming tables/columns, moving columns from one table to another. Changing types of columns and so on. This kind of changes are not backward compatible and will cause problems.
Simplest solution would be to replace "change" operation with combination of "add" and "remove" in several steps.
For example, let's check how process of renaming a column `foo` into `bar` would look like. We will do this in three deployments:
1) First deployment
- In migrations, add nullable column `bar` in database
- New version of application starts writting in both `foo` and `bar`. **Important** to mention that code should only populate value for `bar`, but should not use it.
3) Second deploymennt
- In migrations, provide value for old records: `UPDATE table SET bar=foo`
- Code should stop rely on `foo` and start work only with `bar`.
4) Final deployment
- Remove unused column `foo`
Changes for first deployment, since it contains only new things, is safe to add to release branch, so it can be deployed as soon as possible.
Changes for second deployment should be added to master.
Changes to cleanup unused things could be scheduled to next sprint (or at a time when new release branch, which already includes changes for second deployment, will be created).
We could even schedule all cleanup activities to next sprint in a single task, so it would be easier to manage.