Database Continuous Integration – The iXTS way?

von Alois Flammensboeck, 22. August 2013

DB_CI

Neue Projekte bedeuten immer auch neue Herausforderungen. Die Aktuelle lautet, dass bei zukünftigen Projekten nun auch die Datenbank mit in der Continuous Integration Toolchain berücksichtigt werden soll. Da es an einem Freitag  bei einem kollegialen Mittagessen zu wirren Diskussionen kam wie diese Challenge gemeistert werden kann, möchte ich das hier noch einmal konsolidieren.

Zuerst einmal müssen natürlich die Anforderungen geklärt werden, die wir an unsere DBCI haben:

  • Änderungen am Datenbankschema sollen in Versionsverwaltung erfasst werden
  • Konkurrierende Veränderungen am DB-Schema müssen erkannt werden
  • Der Build Server soll Datenbank-Updates automatisch ausführen/testen können
  • Die Daten sollen bei einem Datenbank Update nicht verloren gehen, sondern ggf. migriert werden
  • Der Gesamtprozess soll unabhängig vom verwendeten DBMS sein
  • Der Gesamtprozess soll möglichst bei Projektstart schon eingehalten/durchgeführt werden können

Zusätzlich standen noch folgende Anforderungen für ein aktuelles Projekt mit im Raum:

  • Die Datenbasis soll jederzeit zum Zwecke von Backup und Archivierung exportiert werden können
  • Die so erzeugten Exports sollen jederzeit in die Software einer Version größer oder gleich der Version mit der exportiert wurde wieder importiert werden können

Bezüglich Versionierung waren sich die Diskutierenden recht schnell einig. Vor kurzem haben wir beschlossen die Software Dezign for Databases für die Modellierung von Datenbanken einzusetzen. Diese Software speichert ein Datenbankmodell in einer XML-Projekt-Datei und diese Projektdatei kann dann in die Versionsverwaltung aufgenommen werden. Daraus ergibt sich unter der Voraussetzung, dass DB-Modell-Änderungen nur noch in diesen Datenbankprojekt durchgeführt werden die Erfüllung der ersten beiden Anforderungen:

okÄnderungen am Datenbankschema sollen in Versionsverwaltung erfasst werden
okKonkurrierende Veränderungen am DB-Schema müssen erkannt werden

Für die Anforderung, dass der Build-Server die Updates automatisch ausführen und testen können soll hat man zumindest schon mal das erfüllt, dass die Datenbank in der jeweiligen Version des Trunks erzeugt werden kann.

Jetzt wird es allerdings schwierig. Zur Diskussion standen folgende Möglichkeiten

Methode 1: SQL-Update-Scripts welche vom Build-Server ausgeführt werden können

Der erste Vorschlag war, dass die Entwickler dafür zuständig sind, dass zu jedem Zeitpunkt die nötigen Update Scripts im Repository sind um die Datenbank auf die aktuelle Version zu bringen. Zum besseren Verständnis ein kleines Beispiel:

Angenommen Version 1 einer Datenbank ist aktuell im Trunk. Die Datenbank enthält eine Tabelle mit Metadaten welche unter anderem auch die Versionsnummer in diesem Fall 1 enthält. Ein Entwickler möchte gerne eine weitere Tabelle zur Datenbank hinzufügen. Wie geht er vor:

  1. Update der aktuellen Workingcopy
  2. Öffnen des Dezign for Databases Projekts
  3. Sicherstellen, dass die aktuelle Version 1 auch als Version in Dezign angelegt ist
  4. Hinzufügen der Tabelle im Dezign Projekt
  5. Export des SQL-Update-Scripts aus Dezign und Ablage des Scripts in einem vordefinierten Verzeichnis mit vordefiniertem Dateinamen-Schema (z.B. Update-2.sql)
  6. Test des Update Scripts in der eigenen Datenbank und ggf. so lange Anpassungen bis es passt und die erforderlichen Migrationen durchgeführt werden
  7. Anpassen des Quellcodes, solange bis dieser wieder zum neuen DB-Schema passt
  8. Einchecken des Dezign Projekts und des Update Scripts

Was passiert nach dem Check-In?

Angenommen es existiert eine Datenbank in Version 1, welche vom Build Server auf die aktuelle Version gebracht werden soll. Der Build-Server checkt die aktuelle Version aus und führt dann ein DB-Update-Tool aus, welches folgende Schritte durchführt:

  1. Es liest die aktuelle Version aus der Tabelle mit Metadaten der aktuellen Datenbank aus und erkennt somit, dass Version 1 installiert ist
  2. Es schaut in das Verzeichnis mit den Update-Scripts und ermittelt welche Updates installiert werden können. Nachdem dort die Datei Update-2.sql liegt, ist klar, dass dieses Script noch ausgeführt werden muss
  3. Das Script Update-2.sql wird ausgeführt und somit die DB auf den aktuellen Stand gebracht

Was jetzt noch fehlt ist, die Möglichkeit das durchgeführte Update auch zu überprüfen. Nachdem das Datenbankschema in Form einer XML-Datei (Dezign for Databases) vorliegt könnte ich mir vorstellen, dass man sich entsprechende Integrationstests aus diesem Modell generieren kann.

Sind nun alle Anforderungen erfüllt?

okDer Build Server soll Datenbank-Updates automatisch ausführen/testen können

Der Benutzer erzeugt die Update Scripts, welche vom Build Server ausgeführt werden. Automatische Tests sind möglich, wenn man z.B. Test-Code aus der Dezign XML-Datei generiert.

okDie Daten sollen bei einem Datenbank Update nicht verloren gehen, sondern ggf. migriert werden

Der Entwickler hat sicherzustellen, dass die Migrationen alle durchgeführt werden. In einem weiteren Schritt könnten Integrationstests geschrieben werden, welche die erfolgreiche Migration überprüfen.

okDer Gesamtprozess soll unabhängig vom verwendeten DBMS sein

Dezign for Databases unterstützt alle gängigen Datenbanken. Das Update-Tool ist eine Eigenentwicklung und kann somit für weitere DBMS angepasst werden

okDer Gesamtprozess soll möglichst bei Projektstart schon eingehalten/durchgeführt werden können

Aufgrund der Tatsache, dass hier ein generischer Ansatz gewählt wurde kann diese Vorgehensweise für alle zukünftigen Projekte unter Zuhilfenahme derselben Tools sofort bei Projektstart umgesetzt werden.

Der Punkt bzgl. Export und Import wird hier bei natürlich nicht berücksichtigt. Das bedeutet, dass die Migration von alten Exports für die Verwendung in neueren Softwareversionen noch einmal separat implementiert werden müssen.

Methode 2: Export der Daten, neues Schema einspielen, Import der Daten

Nachdem erkannt wurde, das hier das DRY (Don’t repeat yourself) Prinzip nicht eingehalten wird, kam der Vorschlag, dass man den Export und Import dann doch auch für die DB-Migrationen über die Versionen hinweg verwenden könnte.

  1. Aktuelle Daten exportieren
  2. Datenbank komplett löschen
  3. Neues DB-Schema einspielen
  4. Daten wieder importieren (und dadurch automatisch migrieren)

Das hört sich erstmal sehr gut an, weil die Migration von Daten nur an einer Stelle durchgeführt und implementiert werden muss, erfüllt aber nicht alle Anforderungen:

Der Gesamtprozess soll möglichst bei Projektstart schon eingehalten/durchgeführt werden können

 

Es muss bereits der gesamte Export-Import-Mechanismus implementiert sein, um den Prozess so umzusetzen zu können. Dadurch kann der Prozess bei Projektstart noch nicht eingehalten werden.

Weitere Nachteile:

  1. Gerade der Import kann nicht generisch implementiert werden und muss somit mit jeder kleinen DB-Änderung angepasst werden
  2. Der Import ist schwierig und langwierig zu testen. Ein häufiges Anpassen des Imports führt zu häufigen und unnötigen Test-Schleifen

=>Der Export-Import sollte jeweils kurz vor der Veröffentlichung eines Produktiv-Releases angepasst werden. Dadurch können unnötige Schleifen vermieden werden und Tests ausführlicher durchgeführt werden (z.B. Exports aller vorhergehender Versionen im Import testen). Klar, man könnte natürlich auch „nur“ die Tests an das Ende eines Produktiv-Inkrements stellen, aber m.E. würde trotzdem die Qualität des Imports darunter leiden, weil sich niemand an geeigneter Stelle nur einmal Gedanken macht, was bei einem Import der älteren Version nun alles migriert werden muss.

Fazit

Obwohl das DRY-Prinzip bei Methode 1 nicht eingehalten wird erscheint diese doch als die Bessere. Vor allem der Nachteil, dass bei Methode 2 bereits jede Menge implementiert sein muss, damit sie angewendet werden kann wird zum Killerkriterium. Wir werden also vorerst darauf setzen und dies in einem nächsten Projekt genau so umsetzen.

 

 

 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *