Revenir au contenu principal
Partenaires

Activation du développement évolutif de bases de données : branchement de bases de données avec Lakebase

Une série (presque) en trois parties

par Pramod Sadalage et Kevin Hartman

Pourquoi cette série existe

La méthodologie décrite dans Evolutionary Database Design et opérationnalisée dans Refactoring Databases: Evolutionary Database Design est claire depuis vingt ans. Les sept pratiques, le catalogue de plus de 70 refactorisations nommées, les mécanismes de transition – tout est documenté, revu par les pairs, enseigné.

Cette méthodologie a atteint CI/CD en 2010 avec Continuous Delivery (Chapitre 12 : Gestion des données). Les migrations sont devenues des artefacts de première classe dans le pipeline de déploiement. La discipline des changements de base de données en tant que code a atteint le mouvement CI/CD plus large. Ce que CD n'a pas résolu, c'est l'isolation par pipeline : les pipelines pouvaient exécuter des migrations, mais ils avaient toujours besoin d'une base de données cible, et cette cible était partagée. La pratique n° 4 – Chacun obtient sa propre instance de base de données – est restée un objectif pour la plupart des équipes, car de véritables bases de données de production pour chaque développeur coûtent du temps, de l'argent et des cycles de DBA. La couche compensatoire qui a émergé pour contourner cette lacune (objets mock, environnements de staging partagés, substituts de bases de données en mémoire, files d'attente de tickets DBA) est devenue une méthodologie fondamentale par défaut, et non par conception.

En 2026, le branchement de base de données par copie sur écriture arrive dans Databricks Lakebase. Une branche de base de données de production à l'échelle du téraoctet, en une seconde et sans stockage initial, est désormais une opération O(1). La contrainte qui maintenait la pratique n° 4 à l'état d'objectif a été levée.

Cette série décrit ce qui change lorsque la contrainte est levée : pas la méthodologie – celle-ci reste – 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 du DBA et le nouveau substrat que les agents partagent avec leurs homologues humains.

Rencontrez Jen

Jen est le personnage développeur de Evolutionary Database Design. Dans cet essai, elle a implémenté un refactoring de base de données – la division d'un inventory_code champ en location_code, batch_number, et serial_number – comme une user story de routine, illustrant que les DBA et les développeurs peuvent collaborer, que les schémas peuvent évoluer par petits incréments et que les migrations transportent le changement en toute sécurité.

La série reprend avec Jen vingt ans plus tard. La méthodologie qu'elle suit est la même qu'en 2003. Ce qui est nouveau, c'est le substrat sous-jacent à son flux de travail : le branchement de base de données par copie sur écriture, qui rend opérationnellement réelles les pratiques qu'elle a lues à l'échelle de la production. À travers les trois parties de cette série, elle est la même Jen à trois échelles – sa journée (Partie 1), son nouveau playbook (Partie 2) et son équipe (Partie 3).

Partie 1 : L'histoire de Jen : une fonctionnalité, un changement de base de données

Pour comprendre comment cela fonctionne, parcourons le parcours d'une développeuse nommée Jen qui implémente une tâche indiquant que l'utilisateur doit pouvoir voir, rechercher et mettre à jour l'emplacement, le lot et le numéro de série d'un produit en inventaire.

Ce qui suit décrit les différentes étapes que Jen doit suivre pour accomplir cette tâche, tout en essayant de comparer comment le flux de travail de Jen change lorsqu'elle travaille avec des bases de données traditionnelles et en utilisant Lakebase qui permet le branchement de base de données à un coût minimal.

Jen commence à travailler sur sa tâche de fonctionnalité

Jen prend en charge ce qui semble être une fonctionnalité simple. L'équipe produit souhaite permettre aux utilisateurs de capturer l'emplacement, le lot et le numéro de série d'un article lors de l'ajout à l'inventaire et de l'utiliser plus tard dans le flux de l'application. De l'extérieur, le changement semble mineur : ajouter un champ à l'écran, enregistrer la valeur, l'afficher dans l'écran d'inventaire d'un article et peut-être l'utiliser plus tard dans une décision en aval.

Pour Jen, le changement d'application est facile à imaginer. Elle sait où se trouve le formulaire. Elle sait quel service gère la requête. Elle peut voir l'objet modèle qui a besoin d'attributs supplémentaires. Mais au moment où elle retrace le changement jusqu'au bout, elle voit la vraie dépendance, la base de données doit aussi changer.

Certaines nouvelles colonnes sont nécessaires, les données existantes dans l'environnement de production doivent être préservées et doivent être sémantiquement correctes. L'application doit gérer les données anciennes et nouvelles en toute sécurité et elle doit ajouter des tests pour prouver que les nouveaux champs sont stockés, lus et affichés correctement. Ce qui semblait être une simple fonctionnalité est maintenant un changement coordonné de l'application et de la base de données, avec la responsabilité supplémentaire d'assurer la migration du schéma et des données de production existants vers le nouveau schéma.

Base de données partagée

Jen crée une branche de code pour le travail qu'elle s'apprête à entreprendre, et comme ils utilisent une base de données partagée et que le reste de l'équipe utilise la même base de données pour le développement, elle commence immédiatement à penser à tous les changements qu'elle va introduire dans la couche de base de données qui pourraient affecter d'autres utilisateurs de la base de données partagée et commence à planifier comment elle peut la rendre sûre pour les autres. Pourrait-elle exécuter le changement d'application localement et être capable d'exécuter ses tests unitaires et d'intégration ? Chaque option a un coût. Elle peut attendre. Elle peut demander à l'équipe de coordonner. Elle peut configurer sa propre instance Postgres locale dans Docker, l'amorcer avec des données obsolètes datant d'une semaine et espérer que les différences n'ont pas d'importance. Elle peut se rabattre sur l'exécution d'une base de données locale dans un conteneur ou sur une base de données en mémoire H2 ou SQLite qui s'exécute rapidement mais utilise le mauvais dialecte, de sorte que ses tests réussissent localement et révèlent des échecs inconnus sur Postgres réel. Peut-elle même tester ses scripts de migration de schéma et de données ? Cette peur de déranger les autres la ralentit et, en même temps, ne lui permet pas d'expérimenter plusieurs options de construction de la fonctionnalité.

Fig 1 : Montrant une base de données partagée avec tous les types d'utilisateurs accédant à la base de données de développement.

Dans une base de données partagée, un développeur peut tester un changement de logique métier, un autre débogue une migration de données, quelqu'un d'autre a créé des données de test que Jen ne comprend pas. Si Jen applique son changement de schéma à la base de données partagée, elle risque de casser le travail de quelqu'un d'autre. Si quelqu'un d'autre modifie le schéma pendant qu'elle teste, ses résultats peuvent ne plus être fiables. Si elle ajoute des données de test, cela peut interférer avec les hypothèses d'un autre développeur.

Jen peut attendre que la base de données partagée soit libre, ce qui protège l'équipe des collisions, mais cela transforme une petite fonctionnalité en un problème de planification et une perte de productivité. Elle peut coordonner manuellement avec les autres développeurs : « Est-ce que tu utilises dev en ce moment ? » « Puis-je exécuter une migration ? » « S'il te plaît, ne réinitialise pas les données pendant la prochaine heure. » quelque chose comme un témoin dans une course de relais. Cela fonctionne pendant un certain temps, mais cela ne passe pas à l'échelle, surtout avec une équipe à distance ou dans plusieurs fuseaux horaires.

Jen pense à une autre option, utiliser une base de données locale en mémoire. Elle sait que cette configuration ne correspond pas à l'état de la base de données utilisée par le reste de l'équipe, ce qui signifie qu'elle n'aura pas confiance en sa solution car le changement peut fonctionner localement et échouer plus tard lorsqu'il rencontrera les données et le schéma réels dans des environnements supérieurs comme staging et production.

Le vrai problème que Jen rencontre est celui d'un retour d'information plus lent . Elle peut apporter le changement, mais découvrir si le changement fonctionne, mais un retour d'information rapide et réaliste, et sans ce retour d'information, le changement de base de données devient quelque chose que l'équipe traite avec soin et finit par choisir la première solution qui fonctionne et n'expérimente jamais ou n'essaie jamais plusieurs solutions, conduisant ainsi à des solutions sous-optimales, une productivité réduite et des développeurs insatisfaits.

Branches de base de données individuelles

En utilisant Lakebase, Jen a la possibilité de créer une branche de base de données pour son usage individuel et cette capacité change complètement sa façon de travailler.

Au lieu d'attendre que la base de données de développement partagée soit disponible, Jen crée une branche de base de données databricks postgres create-branch pour sa fonctionnalité ou utilise une extension VS Code / Cursor. Cela modifie immédiatement la forme du travail. Elle ne demande plus à l'équipe une fenêtre de temps libre. Elle ne négocie plus avec d'autres développeurs sur qui peut exécuter quelle migration et quand. Elle n'essaie plus de protéger sa modification à moitié terminée des modifications à moitié terminées de tous les autres. Elle dispose de son propre espace de base de données isolé, créé à partir du même type d'environnement de base de données que l'application utilisera finalement en production.

Fig 2 : Chaque membre de l'équipe obtient sa propre base de données et peut en obtenir plusieurs si nécessaire.

La branche donne à Jen une copie rapide de l'état de la base de données sur lequel travailler. Elle dispose désormais du même moteur Postgres, du même schéma, des mêmes politiques de gouvernance et des mêmes données mises en forme pour la production qu'elle obtiendrait si elle interrogeait la production directement. La seule différence : cette branche peut être modifiée, supprimée ou recréée sans affecter aucune autre charge de travail. Elle ne teste pas sur une base de données locale simplifiée qui se comporte différemment de la production. Elle travaille avec le même type de base de données que l'équipe utilise en production, avec les mêmes types de règles de schéma, de contraintes, d'index, de données de référence et d'historique de migration qui font que les modifications de base de données réussissent ou échouent dans le monde réel. Ce réalisme est important car de nombreux problèmes de base de données n'apparaissent pas dans des tests unitaires isolés. Ils apparaissent lorsqu'une nouvelle migration rencontre la structure existante, les données existantes, les hypothèses existantes et le comportement de l'application existant.

Maintenant, Jen peut considérer la modification de la base de données comme faisant partie de la conception, et pas seulement comme une étape de déploiement. Elle peut essayer la version évidente en premier : ajouter les nouvelles colonnes, définir une logique par défaut pour diviser la colonne existante, créer un script de migration de base de données, mettre à jour l'application et exécuter les tests. Ensuite, elle peut poser de meilleures questions. Ce script de migration doit-il fonctionner pour les volumes de données de production, la qualité des données en production est-elle telle que ses scripts s'attendent à ce qu'elle soit ? Un script de migration de données cache-t-il des informations commerciales manquantes ? La préférence doit-elle être modélisée comme de simples colonnes, une table de recherche ou une table item_information distincte car plus d'informations sont susceptibles d'arriver plus tard ? Le modèle de requête nécessitera-t-il un index ? Cette conception facilitera-t-elle ou rendra-t-elle plus difficile le reporting en aval ? Dans l'ancien flux de travail, ces questions sont souvent compressées car la modification de la base de données est coûteuse.

Fig 3 : Flux de travail de Jen lors du traitement des tâches, avec la capacité de créer des branches de bases de données

Dans le flux de travail basé sur les branches, Jen peut les explorer pendant que la fonctionnalité est encore en cours de définition. Le DBA peut faire équipe avec elle pour la guider sur les nuances de production et les volumes de données, fournissant ainsi des commentaires précieux sur la conception de la solution au lieu d'être un réviseur après coup.

Faire évoluer l'application et la base de données ensemble

Jen écrit le script de migration. Quel que soit l'outil utilisé par son équipe – Flyway, Liquibase, Alembic, Knex, Prisma – le script se trouve dans le référentiel de code, aux côtés des modifications de l'application. Le schéma et la migration des données voyagent avec le code.

(Il s'agit du refactoring Split Column – l'un des ~70 modèles répertoriés dans Refactoring Databases, le livre qui a opérationnalisé les sept pratiques.)

Elle applique la migration à sa branche en utilisant flyway migrate. L'outil s'exécute en moins d'une seconde sur des données réelles. Elle met à jour le code de son référentiel pour lire et écrire les trois nouvelles colonnes. Elle exécute sa suite de tests. Les tests réussissent sur du vrai Postgres, sans mocks, sans substituts en mémoire.

Si elle souhaite une ardoise vierge pour essayer une approche différente, elle supprime la branche et en crée une nouvelle à partir de la production. Une seconde de plus. Pas de tickets de nettoyage. Pas de DBA impliqué.

Même Jen. Même refactoring. Ce qui a changé, c'est la capacité.

Espace pour échouer plus rapidement

La capacité d'expérimenter est importante. La conception et le développement évolutifs ne consistent pas seulement à parcourir rapidement une liste de contrôle prédéfinie. Il s'agit également d'apprendre à mesure que le travail devient plus concret. Jen peut découvrir que la première conception de schéma fonctionne mais crée une logique d'application maladroite. Elle peut découvrir que la deuxième conception est plus propre mais rend la migration des enregistrements existants plus compliquée. Elle peut découvrir qu'une petite décision de normalisation maintenant faciliterait les changements futurs. Le premier script de migration qu'elle a écrit, les index SUBSTRING sont décalés d'un. Le DROP COLUMN destructeur s'est exécuté avant qu'elle ne puisse vérifier que les nouvelles colonnes ont été correctement remplies. Parce qu'elle a sa propre branche, ces découvertes sont peu coûteuses. Elle peut appliquer une migration, exécuter l'application, inspecter les données, avancer avec une autre migration, ou réinitialiser et essayer un chemin différent.

La branche change également la posture émotionnelle du travail. Jen n'a pas à être trop prudente car quelqu'un d'autre pourrait dépendre de la base de données de développement partagée. Elle n'a pas à annoncer chaque expérience à l'équipe. Elle n'a pas à nettoyer les données de test immédiatement car un autre développeur pourrait trébucher dessus. Sa branche est un endroit sûr pour les réflexions inachevées. Elle peut contenir des tables temporaires, des tentatives de migration échouées, des données de test maladroites et des conceptions à moitié formées sans créer de bruit pour personne d'autre.

Dans le même temps, l'isolement ne signifie pas un détachement des normes de l'équipe. Jen écrit toujours des scripts de migration. Elle maintient le code de l'application et la modification de la base de données ensemble. Elle exécute toujours des tests. Elle s'attend toujours à ce que la conception finale soit examinée. La différence est qu'elle peut faire la partie désordonnée du travail en privé et rapidement avant de demander à l'équipe de raisonner sur la version polie. Au moment où elle ouvre une pull request, la conversation peut se concentrer sur la justesse de la conception, et non sur le fait qu'elle ait eu un endroit sûr pour la tester.

C'est le changement clé : la branche de base de données donne à Jen un retour d'information rapide, réaliste et isolé qui peut également être examiné par ses chefs techniques ou ses DBA, en leur montrant sa branche de base de données. Rapide signifie qu'elle peut créer l'environnement quand elle en a besoin, pas quand quelqu'un le lui provisionne. Réaliste signifie qu'elle teste avec le même type de comportement de base de données qui compte en production. Isolé signifie que ses expériences n'interrompent personne d'autre. Ensemble, ces trois propriétés transforment la modification de la base de données d'un goulot d'étranglement en une partie normale du développement de fonctionnalités.

Jen peut maintenant faire avancer l'application et la base de données ensemble. Sa branche de code et sa branche de base de données deviennent deux faces de la même tâche. L'une contient les modifications de l'application. L'autre lui fournit une base de données réelle pour vivre. Au lieu d'attendre, de coordonner ou de faire semblant avec une configuration simplifiée, Jen peut concevoir, tester, réviser et apprendre. La fonctionnalité est toujours petite, mais maintenant la base de données n'est plus ce qui la ralentit.

Ouverture de la pull request

Jen valide à la fois le code de l'application et le script de migration. Elle ouvre une PR.

La CI fait ce que Jen vient de faire, mais pour l'équipe : elle crée sa propre branche Lakebase temporaire, applique la migration, exécute la suite de tests de l'application, exécute des tests de base de données sur le schéma migré, valide la migration elle-même (s'applique proprement, idempotente, réversible) et publie un commentaire schema-diff sur la PR montrant exactement quels objets de base de données ont changé.

Le réviseur peut maintenant voir ce que fait la modification du schéma en ligne avec le code qui l'utilise, changeant sa compréhension contextuelle d'abstraite à concrète.

Capture d'écran de la vue de résumé des différences de branche de l'extension Lakebase SCM Extension

Revue de la modification

Dans l'ancien flux de travail, la question de la revue de base de données était "cela va-t-il casser la base de données ?" – contrôlée par un DBA qui devait examiner chaque modification isolément, car chaque modification avait des conséquences à l'échelle de la production si elle se débridait. Les revues étaient synchrones. Les plannings entraient en collision. Le calendrier du DBA devenait une file d'attente et parfois le DBA était ignoré pour des raisons de "délai de mise sur le marché".

Dans le nouveau flux de travail, la question est "est-ce la bonne conception ?" Le DBA a déjà vu la différence de schéma publiée par l'intégration continue (CI). Il a déjà vu la migration s'exécuter avec succès sur une branche de données réelles. Jen peut également solliciter le DBA pour une discussion, pour lui montrer ce à quoi elle pense et toutes les autres options qu'elle a essayées. Le DBA peut réviser selon son propre calendrier, pas celui de Jen. Il peut fournir une revue beaucoup plus tôt dans le cycle de développement de la solution et améliorer la solution en matière d'intégrité des données, de stratégie d'indexation, d'extensibilité future ou de maintenabilité à long terme, plutôt que sur le contrôle de protection qui prenait tout son temps.

L'équipe examine le code et la base de données ensemble. Une seule PR. Une seule conversation. Même fenêtre.

Fusionner en toute confiance

La migration a déjà été testée sur une branche de données réelles. L'application a déjà été exécutée avec le schéma modifié. La migration du schéma a été revue. La construction CI a exécuté exactement les mêmes étapes et est restée verte pendant une heure.

Lorsque Jen fusionne, la migration s'applique à l'environnement suivant, les branches de base de données et de code pour l'environnement CI et Jen sont nettoyées. Assurant ainsi que la modification de la base de données n'est plus une surprise le soir de la mise en production.

Ce que Jen vient de faire est la cinquième pratique de l'essai de 2003 : intégration continue des modifications de base de données.

Ce que le parcours de Jen montre

La modification de la base de données fait partie du développement normal. Le branchement réduit l'attente, le risque et les frais de coordination. La boucle quotidienne de Jen lui donne maintenant un retour d'information rapide et isolé au niveau de la base de données.

Dans la Partie 2 – Le nouveau playbook de Jen, nous expliquons ce qui a été soulevé et pourquoi la couche de compensation autour de laquelle Jen a travaillé toute sa carrière peut être supprimée : le branchement en copie sur écriture (copy-on-write), l'architecture qui le rend possible et les optimisations méthodologiques qui en découlent.

Dans la Partie 3 – L'équipe de Jen à grande échelle, nous examinons à quoi ressemble l'histoire de Jen lorsqu'elle fait partie de cinquante développeurs, ou peut-être qu'elle travaille sur un produit en marque blanche, ou qu'elle travaille sur un monolithe modulaire avec de nombreux domaines à l'intérieur – la gouvernance lors de la création de branches, le nouveau rôle du DBA, l'agent dans la boucle (agent-in-the-loop) et le travail de conception de plateforme qui s'ouvre lorsque le calendrier du DBA n'est plus une file d'attente de tickets.

Pour les lecteurs qui souhaitent découvrir les outils IDE que Jen a utilisés dans cet article, il y a le Compagnon : Présentation du plugin – l'extension Lakebase SCM pour VS Code / Cursor, de bout en bout.

Enfin, un kit de développement d'applications Lakebase (Lakebase App Dev Kit) destiné aux agents et accompagné d'un ebook pour les humains sera bientôt publié.

(Cet article de blog a été traduit à l'aide d'outils basés sur l'intelligence artificielle) Article original

Recevez les derniers articles dans votre boîte mail

Abonnez-vous à notre blog et recevez les derniers articles directement dans votre boîte mail.