Partie 2 : Le nouveau playbook de Jen
par Pramod Sadalage et Kevin Hartman
Cette série revisite la méthodologie de l'Evolutionary Database Design, vingt ans plus tard. Une contrainte majeure des modifications de base de données en tant que code a toujours été liée au partage des ressources de base de données. Avec le branching par copie sur écriture (copy-on-write) dans Databricks Lakebase, la création en une seconde et sans stockage initial d'une branche d'une base de données de production à l'échelle du téraoctet est désormais une opération O(1). La contrainte qui faisait de la Pratique #4 (chacun obtient sa propre instance de base de données) un simple idéal est ainsi levée. Dans cette série, les auteurs décrivent ce qui change lorsque cette contrainte disparaît : non pas la méthodologie, qui reste valable, mais les pratiques qui émergent pour la première fois, la gouvernance à l'échelle de l'équipe qui devient automatique, l'évolution du rôle de DBA, et la nouvelle capacité que les agents partagent avec leurs homologues humains.
Jen est le personnage de développeur issu de Evolutionary Database Design. Dans cet essai, elle a mis en œuvre un remaniement (refactoring) de base de données, en divisant un champ inventory_code en location_code, batch_number, et serial_number, sous la forme d'une user story classique, illustrant ainsi que les DBA et les développeurs peuvent collaborer, que les schémas peuvent évoluer par petits incréments et que les migrations permettent d'intégrer les changements en toute sécurité.
La série retrouve Jen vingt ans plus tard. La méthodologie qu'elle suit est la même qu'en 2003. La nouveauté réside dans la capacité technique sous-jacente à son flux de travail, rendue possible par l' architecture lakebase : le branching de base de données par copie sur écriture, qui rend les pratiques qu'elle a étudiées opérationnelles à l'échelle de la production. À travers les trois parties de cette série, nous suivons la même Jen à trois niveaux : sa journée (Partie 1), son nouveau guide pratique (Partie 2) et son équipe (Partie 3).
Partie 1 a accompagné Jen dans la réalisation d'une fonctionnalité. Les pratiques qu'elle a suivies ont été décrites dans l'essai 2003 Evolutionary Database Design, approfondies dans le livre 2006 Refactoring Databases, et intégrées au pipeline CI/CD dans le livre 2010 Continuous Delivery (Chapitre 12).
L' essai de 2003 nommait sept pratiques. Cinq d'entre elles présentaient des limites dans leur application jusqu'en 2026.
La technologie introduite par Databricks Lakebase lève les obstacles à la mise en œuvre des pratiques ci-dessus. Databricks Lakebase est une base de données Postgres managée qui utilise la même couche de stockage d'objets (le data lake) que celle sur laquelle repose le reste du lakehouse Databricks. Les données de la base résident dans un stockage partagé et durable – concrètement des buckets S3 ; le moteur Postgres s'exécute en tant que couche de calcul distincte au-dessus de celui-ci. Le calcul et le stockage évoluent indépendamment. Le moteur peut s'adapter à la hausse (scale up) sous la charge, à la baisse lorsque le trafic diminue, et descendre à zéro lorsqu'il est inactif. Lakebase est intégré à Unity Catalog, ce qui permet une gouvernance unifiée sur plusieurs environnements.
Le branching de base de données par copie sur écriture est ce que l'architecture découplée rend pratique à grande échelle. Une branche crée un nouveau pointeur vers le même stockage partagé avec un marqueur de divergence. Tant que la branche n'écrit pas, elle partage toutes ses pages avec son parent. Lors d'une écriture sur la branche, seules les pages modifiées divergent ; le parent reste intact. Le branching est une opération de métadonnées qui ne nécessite aucune copie de données et s'effectue en une seconde environ, quelle que soit la taille du parent. Les branches ne conservent les données que dans les pages modifiées.
Lorsque le coût technique d'une branche est découplé de la taille des données qu'elle contient, la contrainte liée à la Pratique #4 (chacun obtient sa propre instance de base de données) est levée. Les branches par développeur, par PR et par expérimentation deviennent courantes. La couche de compensation supérieure peut être supprimée. Les mocks disparaissent de la boucle de test, remplacés par un véritable Postgres sur une branche dédiée à chaque test. L'environnement de staging partagé cesse d'être le seul endroit pour tester les modifications de schéma. Les substituts de bases de données en mémoire (H2, SQLite) disparaissent de la couche de tests unitaires. La charge DevOps liée à la création de conteneurs Docker pour exécuter des bases de données locales n'est plus nécessaire, et les files d'attente de tickets des DBA pour le provisionnement diminuent car les branches sont en libre-service.
C'est la technologie qui permet d'optimiser la méthodologie et de concrétiser l'objectif des pratiques présentées dans l'article d'origine de 2003.
Le branching de base de données par copie sur écriture de Lakebase lève les limites précédentes des pratiques d'origine et permet d'en développer quatre autres.
Les deux pratiques qui s'améliorent le plus grâce à la capacité fournie par Lakebase sont la n° 4 (chacun dispose de sa propre instance de base de données) and la n° 5 (les développeurs intègrent en continu les modifications de la base de données). Désormais, non seulement tout le monde dispose d'une base de données, mais chaque PR, chaque branche ou plusieurs bases de données par branche peuvent être obtenues à un coût et en un temps négligeables. Le mécanisme peut être automatisé à l'aide de deux modèles de workflow GitHub Actions qui peuvent être intégrés dans chaque projet.
Création de branche par PR. pr.yml se déclenche sur pull_request: [opened, synchronize] et crée ci-pr-<N> dérivée de la branche de base de la PR :
Le même job applique les migrations sur la branche CI et exécute la suite de tests de l'application sur un vrai Postgres. Un exemple complet du workflow est disponible ici : pr.yml
Différence de schéma publiée sur la PR. Le même job pr.yml extrait le schéma des deux branches, formate la différence et la publie sous forme de commentaire sur la PR. C'est ce qui permet au DBA d'effectuer une révision asynchrone comme n'importe quel réviseur de code (Pratique n° 1, réadaptée) :
Le DBA, le réviseur de code, l'équipe et tout agent auteur de la migration voient le même artefact sur la PR.
Nettoyage des branches lors de la fusion. merge.yml détruit la branche de Pull Request CI ci-pr-<N> et la branche Lakebase de la branche de fonctionnalité liée au moment de la fusion de la PR :
Un exemple complet du workflow de fusion est disponible ici : merge.yml Avec autant de branches en circulation, il peut être utile de disposer d'un script de nettoyage hebdomadaire qui supprime les branches orphelines et inutilisées. Un exemple de workflow est disponible ici : cleanup-orphans.yml. Enfin, si la fusion s'effectue dans une branche « multiniveau » (tiered), par exemple utilisée pour le staging ou main/production (ce concept sera plus détaillé dans la partie 3), le workflow peut être orchestré pour créer une nouvelle branche à partir de ce niveau afin de tester les migrations avant d'appliquer la migration finale à tout environnement où des utilisateurs sont actifs et ajoutent constamment des données.
Ensemble, ces workflows garantissent que chaque PR dispose de sa propre base de données et que les branches sont éphémères en tant que propriétés du pipeline, et non comme des disciplines de développeur.
Règle. Le DBA collabore avec les développeurs tout au long du développement de la fonctionnalité, et pas seulement lors de la phase de validation. La collaboration est asynchrone, directement intégrée à la PR, de la même manière que participent les autres réviseurs de code.
Pourquoi est-ce une habitude durable désormais ? Les différences de schéma et les résultats des tests de migration arrivent automatiquement sur chaque PR (voir Comment le workflow s'exécute dans la CI ci-dessus). Le DBA examine un artefact concret selon son propre calendrier. La migration ayant déjà été exécutée sur une branche CI avec de vraies données, le DBA n'a pas besoin de simuler mentalement le changement.
Fonctionnement :
migrations/, db/, répertoires de test de schéma).Anti-pattern. Ne pas inclure le DBA dans le flux de la PR alors qu'il y a des artefacts légitimes à réviser.
Le rôle de DBA gagne également de nouvelles responsabilités en matière d'administration des politiques et de gouvernance à l'échelle de l'équipe. La partie 3 aborde ces aspects.
Règle. Chaque fichier SQL, script de migration et test de schéma réside dans le même dépôt que le code de l'application. Le diff de schéma et les résultats des tests de migration rejoignent l'ensemble d'artefacts en tant que résultats générés au moment de la PR.
Pourquoi est-ce une habitude durable aujourd'hui ? La création de branches ajoute deux nouveaux artefacts à l'ensemble : le diff de schéma par PR et les résultats des tests de migration de schéma par PR. Les deux sont générés par la CI à partir de l'état réel de la branche. Les deux arrivent dans la PR comme des preuves concrètes de ce qui a été modifié et de la manière dont le script de migration des modifications s'est comporté.
Fonctionnement :
migrations/, db/migration/, alembic/versions/, selon le framework).Anti-pattern. Générer le diff de schéma en dehors du flux de la PR (un tableau de bord distinct que le réviseur doit ouvrir). L'artefact doit se trouver là où la révision a lieu, car les modifications de schéma sont liées aux modifications de code et rompre cette dépendance crée des problèmes en aval pour le déploiement.
Règle. Pas de ALTER TABLE manuel sur aucun environnement. Chaque modification de schéma est un script de migration versionné et validé. Les migrations sont idempotentes.
Pourquoi est-ce une habitude durable aujourd'hui ? La règle de la migration en tant qu'artefact n'a pas changé depuis 2003. Ce qui est nouveau, c'est la discipline d'idempotence lors de la rédaction. La même migration s'exécute sur de nombreuses branches tout au long d'une transition, elle doit donc se comporter de la même manière à chaque fois. Une migration qui échoue lors d'une réapplication est un bug.
Fonctionnement :
flyway, liquibase, Knex, Alembic ou d'autres ; ces frameworks gardent une trace des migrations qui ont été exécutées et de celles qui ne l'ont pas été, ce qui permet à l'équipe d'appliquer une commande comme flyway migrate qui applique simplement les modifications non encore appliquées (en suivant les modifications dans une table de métadonnées).Anti-pattern. Une migration qui dépend du fait que le schéma soit dans un état intermédiaire spécifique en raison de modifications locales apportées dans la branche. La migration doit s'appliquer correctement sur n'importe quelle branche parente qui inclut les migrations précédentes.
Règle. Chaque développeur, chaque PR, chaque expérience, chaque exécution de test obtient sa propre branche Lakebase.
Pourquoi est-ce une habitude durable aujourd'hui ? Plus besoin de faire l'effort de créer des conteneurs Docker, d'installer des serveurs de bases de données locaux, d'acquérir des licences ou d'alimenter des bases de données vides avec le schéma existant et des données de test. Une simple commande Lakebase create-branch crée une branche d'une base de données de 1TB en une seconde, tout comme pour une base de données de 1MB. Aucune donnée n'est copiée lors de la création ; seules les pages modifiées consomment du stockage. Les instances par développeur, par PR et par expérience sont désormais courantes.
Fonctionnement :
databricks postgres create-branch ou le flux de création de branche de l'extension SCM.pr.yml), détruites lors de la fusion ou de la fermeture (merge.yml). Voir Comment le workflow s'exécute dans la CI ci-dessus pour les extraits de code de PR et de fusion .Anti-pattern. Partager une base de données de développement au sein de l'équipe « par commodité ». La sérialisation due aux conflits mentionnée dans la Partie 1 réapparaît dès que les branches fusionnent.
Là où l'exemple de Jen va plus loin. Sa branche par développeur a été créée à partir de staging au début de la fonctionnalité. La branche de CI a été créée à partir de staging à l'ouverture de la PR. Ses branches d'exploration A/B (Pratique n°9) ont été créées en parallèle à partir de staging. Quatre branches pour une seule fonctionnalité, le tout en quelques secondes, toutes isolées.
Règle. Chaque PR passe par la CI sur une nouvelle branche Lakebase, avec les migrations appliquées et les tests exécutés sur un vrai Postgres.
Pourquoi est-ce une habitude durable aujourd'hui ? Le pipeline de CI intègre la discipline de migration depuis 2010. Ce qui est nouveau, c'est l'isolation par pipeline : chaque PR obtient sa propre branche, de sorte que l'intégration s'exécute sur des données réelles sans conflit.
Fonctionnement :
lakebase-migrate apply.Anti-pattern. Exécuter la validation de la PR sur un environnement de staging partagé. La sérialisation réapparaît ; la propriété d'isolation par PR est perdue.
Règle. Les modifications de schéma suivent des modèles de refactoring nommés : Split Column, Rename Column, Move Column, Replace Type, et ainsi de suite. Chacun a des mécanismes de transition explicites (conserver l'ancien et le nouveau en parallèle, alimenter à partir de l'ancien, basculer les lecteurs, supprimer l'ancien).
Pourquoi est-ce une habitude durable aujourd'hui ? Le catalogue de 2006 sur databaserefactoring.com répertorie plus de 70 refactorings avec des exemples concrets. Ce qui est nouveau en 2026, c'est un espace économique pour tester les mécanismes de transition : une branche de développeur absorbe la phase de test, la branche de CI vérifie, et la production ne voit que le résultat validé.
Fonctionnement :
Anti-pattern. Une modification de schéma ponctuelle qui ne correspond pas à un refactoring nommé. Le catalogue de plus de 70 cas couvre les situations courantes ; si vous vous trouvez en dehors de celui-ci, vous combinez probablement plusieurs refactorings en une seule migration et devriez les diviser.
Où l'exemple de Jen va plus loin. Sa migration V87 correspond au refactoring « Split Column » (division de colonne) : diviser inventory_code en location_code, batch_number et serial_number. La page du catalogue sur databaserefactoring.com/SplitColumns.html décrit les mécanismes de transition. Sa branche était l'espace de répétition ; l'exécution de la CI de la PR était la vérification.
Règle. Un développeur peut rafraîchir l'état de la base de données de sa branche à la demande : réinitialiser à l'état actuel du parent, créer une nouvelle branche (fork) à partir de la production, abandonner une branche expérimentale, partager une branche avec un collègue. Le tout en quelques secondes.
Pourquoi est-ce une habitude durable aujourd'hui ? « À la demande » en 2026 signifie une seconde, de manière isolée, sur des données conformes à la production. Aucune de ces opérations ne nécessite de consulter les calendriers des opérations ou les files d'attente des DBA.
Fonctionnement :
databricks postgres create-branch --source production.databricks postgres delete-branch.Anti-pattern. Traiter une branche comme durable au-delà de son objectif. La migration est l'artefact durable ; la branche est l'espace de travail.
Règle. Lorsque le rayon d'impact d'une action destructive est nul, les tests destructifs deviennent une option quotidienne plutôt qu'un exercice trimestriel.
Pourquoi est-ce une habitude durable aujourd'hui ? Une branche se réinitialise en une seconde. Tout ce que vous faites sur une branche peut être annulé en en créant une nouvelle à partir du même parent. Les tests destructifs n'ont plus besoin de calendriers d'opérations ni de barrières d'approbation.
Ce qui s'intègre désormais dans un cycle normal de développement de fonctionnalités :
Effet culturel. Lorsque la réinitialisation ne coûte rien, les équipes cessent de traiter la base de données de test comme une ressource précieuse. Les tests peuvent être agressifs. Le nettoyage peut être ignoré, car la branche suivante repart de zéro.
Où l'exemple de Jen va plus loin. Avant d'ouvrir sa PR, elle a pris les données conformes à la production sur sa branche et a délibérément corrompu environ un pour cent des valeurs de inventory_code pour simuler des cas limites (edge cases) : chiffres manquants, espaces intégrés, espaces de fin. Le genre d'artefacts que les données historiques accumulent. Elle a lancé sa migration. Deux lignes ont fait échouer ses calculs de sous-chaîne (substring). Elle a corrigé le script et l'a réexécuté. La branche a absorbé le test destructif. La production ne l'a jamais vu.
Règle. Lorsque deux conceptions sont en concurrence, construisez-les sur des branches parallèles, comparez-les à l'aide de données conformes à la production et conservez la meilleure solution.
Pourquoi est-ce une habitude durable aujourd'hui ? Le coût par branche est presque nul. Explorer deux conceptions de schéma ne nécessite plus d'en choisir une à l'avance, et cela ne requiert plus un processus de provisionnement que la plupart des équipes n'entreprendraient pas pour une simple question exploratoire.
Fonctionnement :
Anti-pattern. Exécuter des prototypes A/B sans consigner par écrit la décision et le raisonnement. Les branches disparaissent en une seconde ; la décision de conception doit être permanente.
Où l'exemple de Jen va plus loin. Elle a envisagé deux conceptions pour la fonctionnalité d'emplacement/lot/série : trois nouvelles colonnes sur la table inventory existante, ou une table de recherche (lookup table) inventory_attributes distincte indexée par inventory_id, anticipant que d'autres attributs seraient ajoutés plus tard. Elle a construit les deux sur des branches parallèles à partir de l'environnement de staging. Elle a testé le chemin de lecture de l'application sur chacune d'elles, mesuré les performances des requêtes par rapport à des données conformes à la production, et analysé comment chaque migration s'adapterait aux volumes de production. La version avec table de recherche a obtenu de moins bonnes performances sur le chemin de lecture standard car chaque affichage d'inventaire nécessitait une jointure (join). Elle a déployé la version avec les colonnes, a supprimé la branche de la table de recherche et a laissé une note dans la description de la PR : Version avec table de recherche envisagée ; rejetée car le chemin de lecture standard devient une jointure. À réévaluer si plus de cinq attributs s'accumulent.
Nous avons listé les sept pratiques de 2003 avec les limites qui faisaient que cinq d'entre elles restaient théoriques, nous les avons reformulées pour 2026 avec l'arrivée du branching (création de branches), et nous avons ajouté quatre nouvelles pratiques rendues possibles par ce dernier. Au total, le nouveau playbook pour le développement évolutif de bases de données (Evolutionary Database Development) compte onze pratiques, dont 9 sont expliquées ci-dessus.
Dans la Partie 1 – L'histoire de Jen : une fonctionnalité, une base de données nous avons vu Jen travailler sur une fonctionnalité : elle a associé une branche de code à une branche Lakebase, a exécuté une véritable migration sur des données conformes à la production en quelques secondes, a effectué des tests sans mocks, a ouvert une PR contenant le diff de schéma intégré, et a fusionné le tout une fois la migration appliquée et les branches éphémères nettoyées. La modification de base de données fait désormais partie du développement normal.
Dans la Partie 3 – L'équipe de Jen à l'échelle, nous examinons le playbook à l'échelle de cinquante développeurs, l'évolution des responsabilités du DBA en matière d'administration des politiques et de gouvernance, ainsi que les agents qui créent des branches aux côtés de Jen. Les pratiques n°10 et n°11 y sont traitées en détail.
Le Guide d'accompagnement : Présentation du plugin présente l'extension SCM Lakebase pour VS Code et Cursor.
Un Lakebase App Dev Kit pour les agents, accompagné d'un e-book pour les utilisateurs humains, sera publié par la suite.
(Cet article de blog a été traduit à l'aide d'outils basés sur l'intelligence artificielle) Article original
Abonnez-vous à notre blog et recevez les derniers articles directement dans votre boîte mail.