Migrations d’oie pour des changements de base de données en douceur

Bonjour, mon pote !

Aujourd’hui, parlons de ce que sont les migrations de base de données et pourquoi elles sont si importantes. Dans le monde d’aujourd’hui, il n’est pas surprenant que tout changement apporté à une base de données doive être effectué avec soin et selon un processus spécifique. Idéalement, ces étapes seraient intégrées dans notre pipeline CI/CD afin que tout fonctionne automatiquement.

Voici notre agenda :

  1. Quel est le problème ?
  2. Comment le résoudre ?
  3. Un exemple simple
  4. Un exemple plus complexe
  5. Recommandations
  6. Résultats
  7. Conclusion

Quel est le problème ?

Si votre équipe n’a jamais traité de migrations de base de données et que vous n’êtes pas tout à fait sûr de leur nécessité, clarifions cela. Si vous connaissez déjà les bases, n’hésitez pas à passer à la suite.

Défi principal

Lorsque nous apportons des changements « planifiés » et « fluides » à la base de données, nous devons maintenir la disponibilité du service et respecter les exigences SLA (afin que les utilisateurs ne subissent pas de temps d’arrêt ou de latence). Imaginez que vous souhaitiez changer le type d’une colonne dans une table contenant 5 millions d’utilisateurs. Si vous le faites « de front » (par exemple, en exécutant simplement ALTER TABLE sans préparation), la table pourrait être verrouillée pendant un temps significatif — et vos utilisateurs seraient privés de service.

Pour éviter de tels maux de tête, suivez deux règles :

  1. Appliquez les migrations d’une manière qui ne verrouille pas la table (ou au moins minimise les verrouillages).
  2. Si vous avez besoin de changer le type d’une colonne, il est souvent plus facile de créer d’abord une nouvelle colonne avec le bon type, puis de supprimer l’ancienne par la suite.

Autre problème : contrôle de version et retours en arrière

Parfois, vous devez revenir en arrière sur une migration.

Le faire manuellement — en accédant à la base de données de production et en manipulant les données — est non seulement risqué, mais aussi probablement impossible si vous n’avez pas un accès direct. C’est là que les outils de migration dédiés sont utiles. Ils vous permettent d’appliquer proprement des changements et de les annuler si nécessaire.

Comment résoudre ce problème ? Utilisez les bons outils

Chaque langage et écosystème a ses propres outils de migration :

  • Pour Java, Liquibase ou Flyway sont courants.
  • Pour Go, un choix populaire est goose (celui que nous examinerons ici).
  • Et ainsi de suite.

Goose : ce que c’est et pourquoi c’est utile

Goose est un utilitaire léger en Go qui vous aide à gérer les migrations automatiquement. Il offre :

  • Simplicité. Des dépendances minimales et une structure de fichiers transparente pour les migrations.
  • Polyvalence. Prise en charge de divers pilotes de base de données (PostgreSQL, MySQL, SQLite, etc.).
  • Flexibilité. Écrivez des migrations en SQL ou en code Go.

Installation de Goose

Shell

 

Comment ça fonctionne : Structure de migration

Par défaut, Goose recherche les fichiers de migration dans db/migrations. Chaque migration suit ce format :

Shell

 

  • NNN est le numéro de migration (par exemple, 001, 002, etc.).
  • Ensuite, vous pouvez avoir un nom descriptif, par exemple init_schema.
  • L’extension peut être .sql ou .go.

Exemple d’une migration SQL

Fichier : 001_init_schema.sql:

SQL

 

Notre premier exemple

Changement de type de colonne (String → Int)

Supposons que nous avons une table users avec une colonne age de type VARCHAR(255). Maintenant, nous voulons la modifier en INTEGER. Voici à quoi ressemblerait la migration (fichier 005_change_column_type.sql) :

SQL

 

Ce qui se passe ici :

  1. Migration vers le haut

    • Nous changeons la colonne age en INTEGER. La clause USING (age::INTEGER) indique à PostgreSQL comment convertir les données existantes en nouveau type.
    • Notez que cette migration échouera s’il y a des données dans age qui ne sont pas numériques. Dans ce cas, vous aurez besoin d’une stratégie plus complexe (voir ci-dessous).
  2. Migration descendante

    • Si nous revenons en arrière, nous ramenons age à VARCHAR(255).
    • Nous utilisons à nouveau USING (age::TEXT) pour convertir de INTEGER à texte.

Les cas deux et complexes : migrations multi-étapes

Si la colonne age pourrait contenir des données désordonnées (pas seulement des nombres), il est plus sûr de le faire en plusieurs étapes :

  1. Ajouter une nouvelle colonne (age_int) de type INTEGER.
  2. Copier les données valides dans la nouvelle colonne, en traitant ou en supprimant les entrées invalides.
  3. Supprimer l’ancienne colonne.
SQL

 

Pour permettre un retour en arrière correct, la section Down reflète simplement les actions à l’envers.

L’automatisation est essentielle

Pour gagner du temps, il est vraiment pratique d’ajouter des commandes de migration à un Makefile (ou à tout autre système de construction). Voici un exemple de Makefile avec les principales commandes Goose pour PostgreSQL.

Supposons :

  • Le DSN pour la base de données est postgres://user:password@localhost:5432/dbname?sslmode=disable.
  • Les fichiers de migration se trouvent dans db/migrations.
Shell

 

Comment l’utiliser?

1. Créez une nouvelle migration (fichier SQL). Cela génère un fichier db/migrations/002_add_orders_table.sql.

Shell

 

2. Appliquez toutes les migrations. Goose créera une table schema_migrations dans votre base de données (si elle n’existe pas déjà) et appliquera toutes les nouvelles migrations par ordre croissant.

Shell

 

3. Annulez la dernière migration. Annulez simplement la dernière.

Shell

 

4. Annulez toutes les migrations (utilisez avec prudence en production). Réinitialisation complète.

Shell

 

5. Vérifiez l’état des migrations.

Shell

 

Exemple de sortie:

Shell

 

Résumé

En utilisant des outils de migration et un Makefile, nous pouvons:

  1. Restreindre l’accès direct à la base de données de production, en apportant des modifications uniquement par le biais de migrations.
  2. Suivre facilement les versions de la base de données et les annuler en cas de problème.
  3. Maintenir un historique unique et cohérent des changements de base de données.
  4. Réaliser des migrations « fluides » qui ne perturberont pas un environnement de production en cours d’exécution dans un monde de microservices.
  5. Obtenir une validation supplémentaire – chaque changement passera par un processus de PR et de revue de code (en supposant que vous avez ces paramètres en place).

Un autre avantage est qu’il est facile d’intégrer toutes ces commandes dans votre pipeline CI/CD. Et n’oubliez pas – la sécurité avant tout. 

Par exemple:

YAML

 

Conclusion et Conseils

Les idées principales sont si simples :

  • Gardez vos migrations petites et fréquentes. Elles sont plus faciles à réviser, tester et revenir en arrière si nécessaire.
  • Utilisez le même outil dans tous les environnements afin que le développement, la mise en scène et la production soient synchronisés.
  • Intégrez les migrations dans CI/CD pour ne pas dépendre de la personne qui les exécute manuellement.

Ainsi, vous disposerez d’un processus fiable et contrôlé pour modifier la structure de votre base de données — un processus qui ne casse pas la production et vous permet de réagir rapidement en cas de problème. 

Bonne chance avec vos migrations!

Merci de votre lecture!

Source:
https://dzone.com/articles/goose-as-crucial-tool-for-your-service