Refactorisation ou mise à niveau des bases de données pour gérer de nouvelles fonctionnalités

9

Plusieurs réponses à une question de schéma de base de données ont suggéré une table supplémentaire pour normaliser une base de données pour une fonctionnalité qui ne fait pas partie des exigences actuelles (une table UserDepartment pour permettre une relation plusieurs-à-plusieurs entre les employés / utilisateurs et les différents services qu'ils peuvent utiliser appartenir à.).

Pas contre la normalisation. On dirait qu'en matière de conception de base de données, il y a une forte pression pour inclure des fonctionnalités dont ils sont «sûrs» que quelqu'un voudra à l'avenir. Est-il si difficile d'ajouter des tables / champs à la base de données pour tenir compte des fonctionnalités qu'il y a une tendance à sur-concevoir? Ne seraient-ils pas refactorisés ou mis à niveau comme le reste de l'application si nécessaire? Refaire des choses n'est jamais amusant, mais déplacer des données d'une table vers une nouvelle peut être fait. Je ne sais pas où cette ligne de pensée se terminera.

Edit: Il y a tellement d'aversion à cela, je me demande combien de projets finissent par ne pas ajouter une fonctionnalité qui nécessite un changement radical de la base de données ou des approches non normalisées sont prises comme l'ajout d'un champ DepartmentID2 au lieu d'une nouvelle table. La nécessité de plusieurs départements pour un employé est un problème de domaine commun. Je n'ai tout simplement pas remarqué de nombreux schémas de base de données jonchés de relations plusieurs-à-plusieurs.

JeffO
la source
1
+1 Merci d'avoir posé cette question. J'ai beaucoup appris en lisant les réponses à ma question d'origine, et c'est également un fil conducteur.
Jim

Réponses:

3

Il y a un livre entier écrit sur le refactoring de base de données. Tout comme avec le refactoring de code, il existe des moyens standard de refactoring de base de données. La seule différence est que lorsque vous effectuez une refactorisation de code, vous n'avez pas à prendre en compte l'état de l'objet / du code, tandis que dans les bases de données, vous devez prendre en compte les données, car la perte de données n'est pas bonne pour les utilisateurs (ou pour quiconque, en fait ).

Vous pouvez en savoir plus sur la refactorisation de la base de données ici .

Pramod
la source
Ce site est ce qui a suscité la question en premier lieu;)
JeffO
14

La refactorisation du code est facile - vous changez simplement le code et exécutez vos tests de régression.

La refactorisation des bases de données est difficile - vous devez déplacer (une quantité potentiellement énorme) de données, assurez-vous qu'aucune d'entre elles n'est supprimée, assurez-vous que les contraintes sont maintenues dans le nouveau schéma. Et, si vous avez des exigences d'audit sur les données, vous devez être en mesure d'expliquer pourquoi elles sont organisées différemment et de faire correspondre les données pré-refoctor avec les données post-refactor. De plus, aucune de vos anciennes sauvegardes ne correspondra au nouveau schéma, ce qui représente un autre risque.

Des trucs effrayants.

Matthew Flynn
la source
Les tests de base de données ne devraient pas être différents. Toutes les modifications nécessitent un audit et affectent les sauvegardes. Combien de données allez-vous accumuler avant de reconnaître ce besoin? Si vous avez converti des données, cette fonctionnalité serait encore plus évidente.
JeffO
8
+1 pour @Mathew Flynn. Combien de données allez-vous accumuler avant de reconnaître ce besoin? Des millions de rangées. Un autre problème est que votre application n'est souvent pas la seule à utiliser la base de données. La base de données peut contenir de nombreuses applications et vous ne savez peut-être même pas qu'elles existent (par exemple, des applications "BI" sauvages). Les changements dans les schémas de base de données sont effrayants.
Angelo
2
Parfois des milliards de lignes
HLGEM
1
Si vous avez affaire à des milliards de lignes, vous feriez mieux de savoir comment les déplacer
JeffO
3

Il y a une frontière fine entre passer beaucoup de temps à sur-concevoir et investir un peu de votre temps pour ajouter juste assez de fonctionnalités pour vous faire gagner beaucoup de temps à l'avenir.

0x4B1D
la source
1
Vous pourriez faire cet argument pour une instance isolée ou deux, mais quand les «bits» de temps s'additionnent-ils trop?
JeffO
D'après ma propre expérience, c'est en fait le cas pour la grande majorité des projets. Mais je suppose aussi que cela vient avec l'expérience et est très subjectif :) Je serais surpris si quelqu'un pouvait vous donner une recette exacte (d'où la «ligne fine»).
0x4B1D
@Jeff O: Ce ne sera pas des «bits». Un investissement de 10% ou 20% du temps de développement dans le durcissement est nécessaire car le système peut durer à la fois le délai initialement prévu et votre emploi.
rwong
3

Je pense que la théorie est que si vous incluez une table de liens pour prendre en charge une relation plusieurs à plusieurs entre 2 tables, alors même si vraiment seulement plusieurs relations à un existent dans les données, tout le monde écrira le SQL de telle sorte que si jamais un plusieurs à plusieurs est pris en charge tout fonctionnera "tout simplement".

Dans la pratique, je n'ai pas l'habitude de constater que cela est vrai, mais je suppose que le SQL est plus proche de ce qu'il doit être pour prendre en charge le plusieurs à plusieurs qu'il ne l'aurait été autrement.

Mais pour répondre précisément à votre question, il y a en fait beaucoup de peine à convertir une relation de 1 à plusieurs en plusieurs à plusieurs. La raison en est que SQL n'est pas conçu avec les mêmes types d'objectifs d'encapsulation que les objets, et la plupart des requêtes utilisent plus de tables sur la couche de base de données que les gens ne seraient à l'aise avec la visibilité d'un objet dans la couche métier.

Par conséquent, la modification d'une relation plusieurs à plusieurs affectera chaque requête impliquant les 2 tables d'origine, souvent un effet de cascade beaucoup plus large que celui qui se produira sur la couche métier. Donc, les gens mettent tout en œuvre pour empêcher que cela se produise.

À mon humble avis, cela ne serait pas nécessaire si nous avions un meilleur langage que SQL pour spécifier l'algèbre relationnelle. S'il était possible de créer une requête SQL pièce par pièce par des objets qui n'avaient pas besoin de visibilité pour chaque table de la requête, cela ne se produirait pas. Des choses comme LINQ (pour SQL ou pour les entités) tentent de résoudre ce problème, mais c'est une solution très complexe et difficile à optimiser (et je suis allé dans des groupes d'utilisateurs DBA où LINQ est mentionné et un grognement collectif monte à chaque fois). Je rêve d'un langage de base de données universellement pris en charge avec des fonctions d'algèbre relationnelle de première classe ...

En attendant, oui, vous pouvez refactoriser de 1 à plusieurs à plusieurs à plusieurs, mais cela peut demander beaucoup de travail.

psr
la source
Tu ne vas pas transformer chaque relation en plusieurs à plusieurs?
JeffO
@Jeff O - Je ne suis pas sûr de comprendre votre question. En cas de doute, je modélise en plusieurs pour éviter les pièges mentionnés dans les différentes réponses à votre question initiale. Je me suis un peu plus méfié de cela après avoir maintenu des bases de données qui faisaient vraiment presque toutes les relations plusieurs à plusieurs, car elles avaient fini par faire des choses comme créer des vues qui faisaient apparaître les relations de un à plusieurs (ce qui, en pratique, ils l'étaient tous). Ils avaient donc le pire des deux mondes. Je ne l'ai jamais vu sur mes propres créations, mais c'est là un récit édifiant.
psr
3

Je l'explique généralement de cette façon aux PHB - le code est les murs et le toit, la base de données est le fondement.

Il est possible de déplacer les murs et de changer le toit. Changer la fondation autour nécessite beaucoup de creuser et de reconstruire les murs et le toit.

Ce que les développeurs inexpérimentés (et les professeurs d'université) disent qu'il s'agit de "suringénierie" est ce que les développeurs expérimentés appellent "l'épreuve du futur". Malgré ce que dit la spécification, vous savez ce qui changera probablement au cours de l'ALM ou où les problèmes de performances se produiront, vous devez donc commencer par structurer votre table.

Déployer des scripts de mise à jour sur les serveurs des clients est un projet non trivial et chacun des administrateurs de base de données des clients est partout, vous souhaitant tout vérifier. Certaines colonnes et tableaux supplémentaires ne sont pas si mauvais après tout.

jqa
la source
1

La règle générale est que si une relation est un à un mais peut à l'avenir être plusieurs à plusieurs, elle devient alors plusieurs à plusieurs.

L'employé / service est un exemple classique. Dans la plupart des petites entreprises, il s'agit généralement d'une relation un à plusieurs la plupart du temps . Cependant, il y a presque toujours une situation où cela devient plusieurs à plusieurs - l'un de vos ingénieurs prend la direction, mais il est toujours responsable du support d'un produit qu'il a développé pendant qu'il était ingénieur, ou l'un de vos vendeurs a déménagé le développement de produits, mais, comme il a une relation étroite avec un client important, il est toujours le vendeur principal de ce client.

Cela ne coûte pas beaucoup plus si un à plusieurs est implémenté en plusieurs à plusieurs - mais la refactorisation d'une base de données et d'une application pour prendre en charge plusieurs à plusieurs est coûteuse et lourde de difficultés.

James Anderson
la source
Je suis d'accord qu'il existe de nombreux domaines matures (comme les ressources humaines) où le client n'anticipe pas le besoin, mais vous savez que cela arrivera forcément.
JeffO
0

Il existe deux façons d'envisager la conception d'un logiciel (et probablement bien d'autres choses) - une vue tactique ou une vue stratégique. Chacun a ses propres avantages et inconvénients.

Même avec les modifications du logiciel OO, c'est toujours une douleur, non seulement la partie codage est difficile, mais le processus de promotion d'un changement de production dans un environnement de réclamation (compte tenu de l'état actuel de la technologie) est irréel pour les grands systèmes qui sont censés être travailler 24/7.

Je suis mon principe qui dit: " Lorsque cela est possible, concevoir des artefacts logiciels partagés de manière stratégique " - Cela peut sembler aller à l'encontre du principe YAGNI d'une certaine manière, cependant, c'est mon avis. Cette approche garantit moins de retouches sur le coût de la complexité et des ressources.

Dans votre cas, les activités requises pour ajouter une nouvelle table de jonction incluraient: conception, approbation de conception, modification du schéma, réécriture de plusieurs méthodes pour CRUD pour 3 tables (à l'exception de certaines lectures), construction d'index, création d'une interface graphique pour le CRUD pour la nouvelle table, pour permettre à l'utilisateur de sélectionner les PK dans la création, la mise à jour de la nouvelle table, etc. Oh, et en passant, n'oubliez pas les tests unitaires, les tests d'acceptation des utilisateurs, les tests du système et la promotion de la production.

Si cela ne suffit pas, le vrai cauchemar vient de la perte d'informations. Si vous ne disposiez pas de la table de jonction au départ et que vous avez décidé de capturer les dates auxquelles l'association / la séparation entre un employé et un service s'est produite, vous ne pourrez pas remplir automatiquement la date sur la table de jonction. Vous devez les entrer manuellement (si vous avez les données).

Il est donc préférable de prévoir cela dès le départ.

Aucune chance
la source
Tout est préférable de prévoir dès le départ.
JeffO
0

Comme Matthew l'a dit ci-dessus, la refactorisation / modification des bases de données est souvent plus impliquée que les logiciels, car la gestion des données doit également être prise en considération. Il existe des techniques qui peuvent vous aider, par exemple, à vous assurer que vous disposez d'une suite appropriée de tests unitaires de base de données, à dissocier les applications clientes de votre schéma de base en utilisant une 'API DB' - sprocs / vues, etc.

mbaylon
la source