Bei vielen Ansätzen zur Softwareentwicklung wie agilen Methoden, domänengesteuertem Design und objektorientierter Analyse und Design wird empfohlen, einen iterativen Ansatz für die Entwicklung zu wählen.
Wir sollten unser Domain-Modell also nicht gleich beim ersten Start des Projekts fertigstellen. Stattdessen überarbeiten wir das Modell im Laufe der Zeit, weil wir mit der Zeit ein tieferes Verständnis der Problemdomäne gewinnen.
Abgesehen davon können sich die Anforderungen ändern, auch wenn wir versuchen, ein perfektes Modell im Voraus zu bekommen, von dem ich bereits überzeugt bin, dass es sehr schwierig ist. So , nachdem die Software hat sich auf die Produktion bereitgestellt wurde, können die Endbenutzer feststellen , dass eine bestimmte Anforderung nicht vollständig verstanden wird , oder noch schlimmer, wurde einige Anforderung fehlt.
Der Punkt hier ist, dass wir möglicherweise das Modell ändern müssen, nachdem die Software bereitgestellt wurde. In diesem Fall liegt ein Problem vor: Die Produktionsdatenbank enthält wichtige Benutzerdaten und ist bereits im Format für das alte Modell angepasst .
Das Aktualisieren des Codes kann eine schwierige Aufgabe sein, wenn der Code nicht gut entworfen ist und das System groß ist. Aber es kann mit der Zeit geschehen, wir haben Tools wie Git, die uns dabei helfen, ohne die produktionsbereite Version zu beschädigen.
Wenn sich das Modell ändert, die Eigenschaften von Klassen verschwinden oder was auch immer, sollte sich auch die Datenbank ändern. Aber wir haben ein Problem: Es gibt bereits Daten, die nicht verloren gehen können und die bereits für das alte Modell formatiert sind.
Es scheint, dass eine relationale Datenbank hier ein Hindernis darstellt, das uns daran hindert, iterativ Software zu entwickeln und sogar zu aktualisieren, wenn dies von Endbenutzern gefordert wird.
Ein Ansatz, den ich bereits verwendet habe, war das Codieren einer speziellen Klasse, die alte Datenbanktabellen neuen zuordnet. Diese Klassen wählen also Daten im alten Format aus, konvertieren sie in das vom neuen Modell verwendete Format und speichern sie in den neuen Tabellen.
Dieser Ansatz scheint nicht der beste zu sein. Meine Frage lautet hier: Gibt es bekannte und empfohlene Ansätze, um die iterative Entwicklung mit relationalen Datenbanken in Einklang zu bringen?
quelle
Antworten:
Es müssen keine speziellen Klassen sein, aber ja, Sie benötigen etwas, das die Datenbank im vorherigen Format übernimmt und in die aktuelle konvertiert.
Die Sache hier ist, dass Sie einen Prozess zum Schreiben und Testen dieser Skripte und Disziplin entwickeln müssen, um die Test- und Produktionsdatenbanken nie von Hand, sondern immer von Migrationsskripten zu berühren.
Jedes Mal, wenn Sie eine Änderung an der Datenbank vornehmen müssen, schreiben Sie ein Skript, das dies in SQL oder mithilfe Ihrer ORM-Ebene ausführt, und übergeben es zusammen mit den Änderungen, die das neue Schema erfordern, an Ihre Versionskontrolle. Dann haben Sie ein Steuerungsskript, das die Datenbank aktualisiert, indem alle Migrationsskripten, die noch nicht angewendet wurden, in einer Sequenz angewendet werden.
Und stellen Sie sicher, dass Sie nur freigegebene Entwicklungs-, Test- und QA-Umgebungen ändern, indem Sie die Skripte anwenden und auf eine frühere Version zurücksetzen, wenn sie nicht funktionieren. So können Sie sicher sein, dass sie wie vorgesehen funktionieren, wenn Sie sie für die Produktion freigeben .
Die Neuinstallation erfolgt einfach durch Anwenden aller Skripte. Nach einer Weile werden Sie vielleicht Hunderte von ihnen haben und denken, dass es sehr ineffizient ist, aber tappen Sie nicht in die Falle, wenn Sie versuchen, es zu optimieren. Die Installation ist eine einmalige Aufgabe, die schnell erledigt werden kann.
@ Doc Brown hat bereits Martin Fowler verlinkt : Evolutionary Database Design und /programming/334059/agile-development-and-database-changes , und ich würde Alex Papadimoulis hinzufügen : Database Changes Done Right , was kürzer ist und hat einige Beispiele.
Als gutes Beispiel für die Implementierung eines solchen Prozesses empfehle ich Alembic . Es basiert auf dem Python SQLAlchemy- Framework, kann jedoch mit anderen Sprachen und Frameworks verwendet werden, wenn diese keine eigene Migrationsunterstützung haben. Auf der Wikipedia-Seite zur Schema-Migration sind weitere solche Tools aufgeführt .
quelle
Seltsamerweise ist dies genau das Problem, mit dem mein aktuelles Entwicklungsteam konfrontiert ist. Die Frage enthält mehrere Unterfragen, die unabhängig voneinander beantwortet werden.
Beschränkt eine relationale Datenbank in erster Linie das Datenmodell zu sehr, was Änderungen sehr schwierig macht?
Mit Sicherheit , aber nicht unbedingt aus den genannten Gründen. Leider führt die Vielseitigkeit relationaler Datenbankverwaltungssysteme auch zu deren Untergang. Das RDBMS wurde ursprünglich entwickelt, um eine relativ einfache Datenspeicherplattform anzubieten, die große Datenmengen akzeptiert und auf eine relativ kleine Größe reduziert. Dies erfolgte auf Kosten der Komplexität des Datenmodells und der erforderlichen Rechenleistung. Mit zunehmender Komplexität der Datenbank entstanden gespeicherte Prozeduren, Ansichten, Funktionen und Trigger, mit denen Datenbankadministratoren konsistent und skalierbar mit der Komplexität umgehen können.
Leider ist das relationale Datenbankmodell nicht objektorientiert und kann nicht wie ein Datenmodell auf reale Entitäten abgebildet werden. Das führt uns zu der Notwendigkeit von Mittelsmännern wie objektrelationalen Mappern und dergleichen. Obwohl diese Tools in der heutigen Entwicklungswelt eindeutig einen Platz haben, zielt ihre Verwendung nur auf ein Symptom des Problems der relationalen Datenkomplexität ab und nicht auf die zugrunde liegende Ursache, die eine Fehlausrichtung des Datenmodells zur realen Welt darstellt.
Das führt zum zweiten Teil der Frage, der eigentlich eher eine Annahme war, aber als Frage zu verstehen ist: Sollen wir unser Domain-Modell gleich beim ersten Mal richtig machen?
Ja, bis zu einem gewissen Grad. Wie die Frage zeigte, ist es selten möglich, das Problem vollständig zu verstehen, wenn wir mit dem Entwurfsprozess beginnen. Der Unterschied zwischen einem vollständig inkorrekten Datenmodell und einem Modell, das möglicherweise angepasst wird, wenn wir ein besseres Verständnis der Domäne erlangen, ist jedoch das Modell, das die reale Welt kohärent abbildet. Dies bedeutet, dass wir alle Anstrengungen unternehmen müssen, um ein erstes Datenmodell zu erstellen, das mit unserem Verständnis des Problems in Bezug auf seine realen Entitäten übereinstimmt. Wenn wir beginnen, uns auf die falschen Entitäten zu normalisieren, ist das Datenmodell in zweierlei Hinsicht falsch und die Wiederherstellung wird schwierig.
In vielerlei Hinsicht ist die Umstellung auf "No SQL" -Datenbanklösungen auf die Probleme der Datenmodellinkohärenz zurückzuführen. Verwenden eines objektorientierten No SQL-Ansatzes veranlasst uns, mehr über die Zuordnung zwischen unseren Objekten im Code und denen in der realen Welt nachzudenken Datenbank. Dies führt zu einem besseren Gesamtdesign.
Das führt zur letzten Frage: Stimmt ein relationales Datenmodell nicht mit dem agilen Ansatz überein?
Nein, aber mehr Geschick ist erforderlich. Während es in der No-SQL-Welt trivial ist, ein Feld hinzuzufügen oder eine Eigenschaft in ein Array zu konvertieren, ist es in der relationalen Welt überhaupt nicht trivial, diese Dinge zu tun. Zumindest braucht es jemanden, der in der Lage ist, sowohl das relationale Datenmodell als auch die realen Entitäten, die sie darstellen, zu verstehen. Diese Person ist die Person, die die Aktualisierung des relationalen Modells erleichtert, wenn sich das Verständnis des realen Modells ändert. Es gibt kein Patentrezept, um dieses Problem zu lösen.
quelle
Der wichtigste Punkt ist, nicht so stark umzugestalten, dass sich Ihr Modell bis zur Unkenntlichkeit ändert. Selbst bei iterativer Entwicklung sollten Sie wirklich auf vorhandenen Dingen aufbauen und sie nicht in Stücke überarbeiten.
Auf diese Weise haben Sie zwei Hauptoptionen, um große Änderungen zu bewältigen: Die erste besteht darin, die DB-Ebene als API zu erstellen und gespeicherte Prozeduren zu verwenden, damit sie an den Client angepasst werden können, ohne das zugrunde liegende Datenschema zu ändern.
Die andere Möglichkeit besteht darin, Tabellen durch ein wenig Datenmigration zu ersetzen. Wenn eine umfangreiche Änderung erforderlich ist, erstellen Sie das neue Schema und implementieren eine Reihe von Skripten, um die alten Daten in das neue Format umzuwandeln. Dies ist zeitaufwändig, weshalb Sie sich in erster Linie auf günstigere Methoden zur Änderung des Datenzugriffs (z. B. über SPs) verlassen.
Also: 1. Versuchen Sie, mit dem Design vorauszudenken, damit Sie nichts ändern müssen.
Verlassen Sie sich auf Wrapper oder APIs, um Änderungen zu vermeiden oder sie in einer isolierten Komponente zu verbergen
Nehmen Sie sich die Zeit für ein korrektes Upgrade.
Diese Schritte gelten für alles, nicht nur für Datenbanken.
quelle