Dans de nombreuses approches de développement de logiciels comme les méthodologies agiles, la conception pilotée par domaine et l'analyse et la conception orientées objet, nous sommes encouragés à adopter une approche itérative du développement.
Nous ne sommes donc pas censés réussir notre modèle de domaine la première fois que nous commençons à travailler sur le projet. Au lieu de cela, au fil du temps, nous refactorisons le modèle parce que nous acquérons une compréhension plus profonde du domaine problématique avec le temps.
En dehors de cela, même si nous essayons d'obtenir un modèle parfait dès le départ, dont je suis déjà convaincu qu'il est très difficile, les exigences peuvent changer. Ainsi , après que le logiciel a été déployé à la production, les utilisateurs finaux peuvent remarquer qu'une certaine exigence n'a pas été complètement compris, ou pire, une exigence qui manquait.
Le point ici est que nous pourrions finir par avoir besoin de changer le modèle après le déploiement du logiciel. Si cela se produit, nous avons un problème: la base de données de production contient des données d'utilisateur qui sont importantes et sont déjà adaptées au format de l'ancien modèle .
La mise à jour du code peut être une tâche difficile si le code n'est pas bien conçu et si le système est volumineux. Mais cela peut se faire avec le temps, nous avons des outils comme Git qui nous aident à le faire sans endommager la version prête pour la production.
D'un autre côté, si le modèle change, si les propriétés des classes disparaissent ou autre, la base de données devrait également changer. Mais nous avons un problème: il y a déjà des données qui ne peuvent pas être perdues, qui sont déjà formatées pour l'ancien modèle.
Il semble qu'une base de données relationnelle soit ici un obstacle nous empêchant de faire du développement itératif et même de mettre à jour les logiciels lorsque les utilisateurs finaux le demandent.
Une approche que j'ai déjà utilisée consistait à coder une classe spéciale qui mappe les anciennes tables de base de données aux nouvelles. Ces classes sélectionnent donc les données dans l'ancien format, les convertissent au format utilisé par le nouveau modèle et les enregistrent dans les nouvelles tables.
Cette approche ne semble pas être la meilleure. Ma question est la suivante: existe-t-il des approches bien connues et recommandées pour concilier le développement itératif avec les bases de données relationnelles?
la source
Réponses:
Il ne doit pas nécessairement s'agir de classes spéciales, mais oui, vous avez besoin de quelque chose qui prendra la base de données dans le format précédent et la convertira dans la version actuelle.
La chose ici est que vous devez développer un processus pour écrire et tester ces scripts et une discipline pour ne jamais toucher les bases de données de test et de production à la main, mais toujours par des scripts de migration.
Chaque fois que vous devez apporter une modification à la base de données, vous écrivez un script qui le fera, que ce soit en SQL ou en utilisant votre couche ORM, et vous le validerez dans votre contrôle de version avec les modifications qui nécessitent le nouveau schéma. Ensuite, vous disposez d'un script de contrôle qui mettra à niveau la base de données en appliquant tous les scripts de migration qui n'ont pas encore été appliqués dans une séquence.
Et assurez-vous de ne modifier que les environnements de développement, de test et d'assurance qualité partagés en appliquant les scripts et en revenant à la version précédente s'ils ne fonctionnent pas, de sorte que vous pouvez être raisonnablement sûr qu'ils fonctionneront comme prévu lorsque vous les libérez sur la production .
La nouvelle installation se fait simplement en appliquant tous les scripts. Après un certain temps, vous en aurez peut-être des centaines et penserez que c'est très inefficace, mais ne tombez pas dans le piège d'essayer de l'optimiser. L'installation est une activité ponctuelle et la maintenir fiable l'emporte sur la rapidité.
@Doc Brown a déjà lié Martin Fowler: Evolutionary Database Design et /programming/334059/agile-development-and-database-changes , et j'ajouterais Alex Papadimoulis: Database Changes Done Right , qui est plus court et a quelques exemples.
Comme exemple décent d'outil mettant en œuvre un tel processus, je suggère Alembic . Il est basé sur le framework Python SQLAlchemy , mais vous pouvez l'utiliser avec d'autres langages et frameworks s'ils n'ont pas leur propre support de migration. La page Wikipedia sur la migration de schéma répertorie d' autres outils de ce type .
la source
Curieusement, c'est le problème même auquel est confrontée mon équipe de développement actuelle. La question contient plusieurs sous-questions, elles seront donc traitées indépendamment.
D'abord et avant tout, une base de données relationnelle contraint-elle trop le modèle de données, rendant les changements très difficiles?
Certainement , mais pas nécessairement pour les raisons citées. Malheureusement, la polyvalence des systèmes de gestion de bases de données relationnelles entraîne également leur chute. Le SGBDR a été initialement développé pour offrir une plate-forme de stockage de données relativement simple qui accepterait de grands ensembles de données et les réduirait à une taille relativement petite. Cela a été fait au détriment de la complexité du modèle de données et de la puissance de calcul requise. À mesure que la complexité de la base de données augmentait, des procédures stockées, des vues, des fonctions et des déclencheurs ont vu le jour pour aider les administrateurs de base de données à gérer la complexité de manière cohérente et évolutive.
Malheureusement, le modèle de base de données relationnelle n'est pas orienté objet et ne correspond pas naturellement aux entités du monde réel comme le devrait un modèle de données. Cela nous amène à la nécessité d'outils intermédiaires comme les mappeurs relationnels-objets et similaires. Malheureusement, alors que ces outils ont clairement leur place dans le monde du développement d'aujourd'hui, leur utilisation vise simplement un symptôme du problème de complexité des données relationnelles, plutôt que la cause sous-jacente, qui est un désalignement du modèle de données sur le monde réel.
Cela nous amène à la deuxième partie de la question, qui était en réalité davantage une hypothèse, mais qui devrait être considérée comme une question: sommes-nous censés faire correctement notre modèle de domaine la première fois?
Oui, dans une certaine mesure. Comme la question l'a souligné, il est rarement possible de bien comprendre le problème lorsque nous commençons le processus de conception. Cependant, la différence entre un modèle de données complètement incorrect, par opposition à un modèle qui peut être modifié à mesure que nous acquérons une meilleure compréhension du domaine, est le modèle qui correspond de manière cohérente au monde réel. Cela signifie que nous devons tout mettre en œuvre pour créer un modèle de données initial qui soit cohérent avec notre compréhension du problème en termes d'entités réelles. Si nous commençons à normaliser sur les mauvaises entités, le modèle de données sera erroné de deux manières et la récupération sera difficile.
À bien des égards, le passage à des solutions de base de données «sans SQL» est le résultat des problèmes d'incohérence des modèles de données. L'utilisation d'une approche No SQL orientée objet nous amène à réfléchir davantage au mappage entre nos objets dans le code et ceux dans le monde réel - et lorsque nous rencontrons une incohérence, cela va souvent de soi car il est impossible à implémenter dans notre base de données. Cela conduit à une meilleure conception globale.
Cela conduit à la dernière question: un modèle de données relationnel est-il incompatible avec l'approche agile?
Non, mais plus de compétences sont requises. Alors que dans le monde sans SQL, il est trivial d'ajouter un champ ou de convertir une propriété en tableau, il n'est pas du tout trivial de faire ces choses dans le monde relationnel. Il faut, au minimum, quelqu'un qui est capable de comprendre à la fois le modèle de données relationnel et les entités du monde réel qu'ils représentent. Cette personne est la personne qui facilitera la mise à jour du modèle relationnel à mesure que la compréhension du modèle du monde réel change. Il n'y a pas de solution miracle pour résoudre ce problème.
la source
Le point principal n'est pas de refactoriser tellement que votre modèle change au-delà de toute reconnaissance. Même avec un développement itératif, vous devriez vraiment vous baser sur des éléments existants et ne pas les refondre en morceaux.
Cela vous donne 2 options principales pour gérer les grands changements lorsqu'ils surviennent: la première consiste à créer la couche DB en tant qu'API, à utiliser des procédures stockées afin qu'elles puissent être modifiées pour convenir au client sans changer le schéma de données sous-jacent.
L'autre façon est de remplacer les tables par un peu de migration de données. Lorsqu'un changement à grande échelle est requis, vous créez le nouveau schéma et implémentez un ensemble de scripts pour prendre les anciennes données et les masser dans le nouveau format. Cela prend du temps à le faire, c'est pourquoi vous vous fiez davantage à des méthodes moins coûteuses pour modifier l'accès aux données (par exemple via des SP) comme premier choix.
Donc: 1. essayez de penser à l'avance avec le design afin de ne pas avoir à changer les choses.
Comptez sur des wrappers ou des API pour que les modifications soient limitées ou puissent être cachées dans un composant isolé
Prenez le temps de mettre à niveau correctement si vous le devez.
Ces étapes s'appliquent à tout, pas seulement aux bases de données.
la source