Le grand oubli dans l’industrialisation des développements est la base de données, cette chose monolithique et statique qui n’évolue pas aussi vite et aussi aisément que le code. Au même titre que l’intégration continue et les systèmes de gestion de version pour le code source, il existe des outils permettant de fluidifier et d’automatiser le travail autour du schéma physique des données. Travailler avec ces outils permet de compléter une démarche Agile en permettant une réactivité forte face aux changements.
Une première partie de cet article concernera les principes et pratiques autour de ces outils (partie « boss compliant »). La deuxième est orientée technique (partie « geek aware »).
Principes directeurs
Dans son article paru en 2003 intitulé « Evolutionary Database Design », Martin Fowler pose les principes du design évolutif de base de données. Les points clés en sont :
- La base de données évolue en même temps que le code ;
- Il faut donc tester en continu la base de données pour permettre un refactoring sans conséquence, comme on le fait avec le code source ;
- Il faut outiller les processus autour de la base de données afin d’améliorer la productivité des développements et leur industrialisation.
Les outils existants reposent sur les principes suivants :
- Un schéma doit pouvoir être détruit et recréé de manière répétable ;
- La version du schéma doit être identifiable ;
- La montée et la descente de version doivent être automatisées ;
- Les changements appliqués doivent être connus ;
- Un changement doit pouvoir être défait ou annulé ;
- Un changement précédemment appliqué ne doit pas être modifié mais un nouveau changement doit être créé.
Principes techniques
Sur le plan technique, le fonctionnement des outils de migration est simple. Ils se basent sur une table contenant la version de la base de données. La liste des scripts exécutés est conservée ainsi qu’une empreinte de chaque script afin de détecter une altération d’un script déjà exécuté.
A chaque lancement, l’outil de migration compare la version de la base et les scripts existants et propose la mise à jour le cas échéant.
Il est également possible de « descendre de version » le schéma (fonctionnalité disponible dans quasiment tous les outils). Il s’agit de remettre la base de données dans un état cohérent. Deux cas d’usage :
- développement d’une nouvelle fonctionnalité : il est ainsi possible de créer un script et de l’exécuter plusieurs fois (montée de version, test, modification, descente, puis nouvelle montée de version). La descente de version permet ainsi de faire revenir la base de données dans l’état précédent ;
- Ré-alignement automatique du schéma avec le code quand la version de la base de données n’est plus la bonne. Ce cas intervient quand il faut corriger un bug sur la version de production ou au passage à une autre branche de développement, ou encore quand un script a été exécuté puis modifié.
Même si la descente de version est utile, elle a néanmoins deux inconvénients. Le premier est que les instructions de descente doivent être écrites à la main. Les outils les plus simples fonctionnent sur le principe où chaque script contient une partie montée de version et une partie descente (voir l’exemple plus bas avec MyBatis). Seul Liquibase est capable de générer les instructions de descente de version grâce à son DSL.
Le deuxième inconvénient est que certaines montées de version ne sont pas réversibles (suppression de table ou de données). Dans ce cas, la descente ne sera possible que jusqu’à la version incluant ce type de modification. L’alternative est de recréer le schéma de zéro, une fonctionnalité que tous les outils proposent et qui est en fin de compte très rapide.
Bonnes pratiques
Les bonnes pratiques poussées par ces outils sont :
- Scripts (SQL ou XML pour Liquibase) stockés avec le code source
- Une base de données par développeur (réaliste quand la gestion de la DB est automatisée, hors problème de coût de licence) ;
- Une base de données commune à l’équipe qui représente l’état complet et stable ;
- L’intégration continue déroule l’ensemble des scripts à chaque livraison ;
- Un script qui a déjà pu être exécuté ne doit plus être modifié. On risque sinon de désynchroniser les scripts et le schéma La livraison d’un nouveau script est nécessaire dans ce cas. Ce script est un refactoring du précédent. La seule exception est un script buggé qui provoque la perte de la donnée. Il ne faut donc pas que ce script atteigne les autres environnements.
Les outils existants
Liquibase : puissant mais complexe
Liquibase est le plus connu des outils de migration de base de données. Il se base sur les patterns décrits dans le livre « Refactoring database ». À ce titre, il est conçu autour d’une approche théorique par pattern de refactoring.
Le noyau de Liquibase est son DSL basé sur XML qui a les avantages :
- d’être compatible avec plusieurs moteurs SQL ;
- de donner une sémantique aux opérations (on écrira un <renameColumn> plutôt qu’un alter table) ;
- de générer automatique des instructions de rollback (par exemple, un <createColumn> sera compensé par un <dropColumn>).
Liquibase est complet. Il s’intègre à Maven, Grails, Spring et Hibernate et supporte la génération de documentation ou encore la création d’un diff entre schémas.
L’inconvénient principal de Liquibase est une certaine complexité qui ne se retrouve pas dans les autres outils (XML, notion de changelog et de changeset, versionning sur id/auteur/chemin). La courbe d’apprentissage est donc plus élevée que les autres outils se basant purement sur du SQL.
Exemple de changeSet Liquibase :
<changeSet id="1" author="bob"> <createTable tableName="department"> <column name="id" type="int"> <constraints primaryKey="true" nullable="false"/> </column> <column name="name" type="varchar(50)"/> </createTable> </changeSet>
Les pragmatiques
D’autres outils ne vont pas aussi loin que Liquibase en termes de fonctionnalités et d’abstraction mais leur approche est pragmatique et plus simple. Ils visent avant tout à automatiser la gestion des scripts SQL. Les principaux sont MyBatis Schema Migration, DbMaintain et C5 DB Migration.
Le principe de ces outils est assez simple et consiste à lancer une série de scripts stockés dans une arborescence répartie en version. Les actions sont tracées ce qui permet de connaître l’état du schéma.
Exemple d’arborescence organisée pour DbMaintain :
scripts/01_v1.0/01_products_and_orders.sql
02_users.sql
02_v1.1/01_add_barcode_column.sql
02_drop_itemcode_column.sql
Le schéma de base de données est mis à jour en exécutant :
dbmaintain.sh update chemin/vers/les/scripts
Dans le cas de MyBatis, les instructions de montée et de descente de version sont écrites dans le même script SQL. Exemple :
--// create product table CREATE TABLE PRODUCT (ID INT, NAME VARCHAR(255)); --//@UNDO DROP TABLE PRODUCT;
Conclusion
Les outils de migration de base de données permettent une meilleure productivité en levant certaines barrières au changement du schéma des données et ils rendent l’industrialisation accessible.
Les points clés à retenir sont :
- Les outils de migration de bases de données nous permettent de gagner en efficacité lors de la manipulation du schéma de la base de données ;
- Ces outils fiabilisent les traitements en les automatisant et en les intégrants à l’usine de développement ;
- Ces outils apportent de bonnes pratiques permettant un travail en équipe plus efficace ;
- Ces outils sont disponibles, simples à mettre en place et OpenSource.
Par extension, on peut imaginer qu’une application puisse se mettre à jour d’elle-même. En effet, il s’agirait de permettre à l’application de lancer les migrations de schémas quand elle démarre. Cette fonctionnalité réduit le temps de mise en production en supprimant l’étape de passage des scripts par les DBA. Liquibase propose déjà cette fonctionnalité.



[...] [Article publié initialement sur le blog d'Octo] [...]
Content de voir (enfin) un article sur cette « grand oubliée ».
J’aime beaucoup le chapitre sur les bonnes pratiques.
Autre chose : toujours laisser à dispo dans un répertoire commun un backup de la BDD. Afin que si un développeur crashe sa base il a un backup à dispo. Ou si un nouveau arrive il peut tout de suite commencer avec une version à jour pour le développement de la DB
Personnellement, j’ai mis en place un process basé sur
- un backup de départ qui est la BD de référence
- une série de scripts sql
- un gros script pour lire le sql et mettre à jour la BDD de référence et créer un backup de référence pour le développement
La question de l’ordre d’application des scripts sql est importante. Notamment quand on n’utilise pas d’outil
[...] gestion incrémentale des bases de données, longuement décrite dans cet article, existe nativement dans Rails. Et par exemple, si l’un de vos coéquipiers livre du code [...]
[...] Le code source et la base de données sont les éléments fondamentaux d'une application web. Pourtant le premier est bien plus simple à maintenir que la seconde. Faire évoluer de manière structurée sur plusieurs environnements une base de données demande de la méthode et de la rigueur. Heureusement, il existe des outils pour simplifier cette tâche. [...]
L’automatisation est critique effectivement, mais il ne faut pas oublier le versioning de la base de données. L’ensemble des outils cités prennent en charge plus ou moins bien l’automatisation du déploiement, mais n’adressent pas la génération des scripts (SQL ou XML) initiaux. Ni d’ailleurs la gestion du merge entre 2 branches de développement parallèle.
Liquibase est très puissant, mais l’écriture de tels scripts est très consommatrice en temps.
C’est pour adresser l’industrialisation dès la phase de conception / développement que nous avons mis en place neXtep designer : un produit gratuit sous licence GPL qui propose le versioning de vos bases de données. Il s’agit d’un environnement de développement dans lequel votre structure (et bientôt vos données) sont sous controle de version : vous travaillez directement sur le modèle, l’outil se charge de générer les scripts de delta automatiquement. L’IDE est basé sur eclipse et propose des diagramme de modèlisation CASE, la gestion des dépendances, un puissant éditeur SQL, la synchronisation directe ou reverse, la génération de SQL à partir de n’importe quel delta de version, etc.
Nous songeons à travailler avec le projet liquibase pour proposer des générateurs de changeset XML dans une future version. Nous sommes en discussion avec Nathan sur ce point.
Bref, pour en savoir plus :
http://www.nextep-softwares.fr
La présentation des concepts est plus détaillée sur le wiki :
http://www.nextep-softwares.com/wiki
Pour ma part j’utilise doctrine migrations ( http://www.doctrine-project.org/projects/migrations ) qui permet de versionner sa BDD et de faire des updates assez simplement et rapidement.
C’est intéressant de parler de cette partie d’un projet car bien souvent elle est oubliée dès le début ce qui peut poser quelques problèmes par la suite quand les besoins évoluent.