Do you know the difference between continuous integration, continuous delivery and continuous deployment?

Probably every common agile developer has heard these terms. But have you ever thought about the difference between them. I have really been wondering about this question and after some investigation I would like to share all information on this topic i have gathered.

To be able to understand continuous deployment it can be helpful to define its predecessors first – continuous integration and continuous delivery. Continuous integration (CI) usually refers to integrating, building and testing code within an integration environment. It assumes frequent integration of developers code into a shared repository, at least once a day. This makes sure that the local version of every individual developer doesn’t differ too much. Weiterlesen

08.12. Agilere Datenbankentwicklung

Agile Entwicklung ist gescheitert.
Jedenfalls auf Datenbankseite.

Agile Entwicklung ist mehr als nur Scrum, hierzu kommen in den meisten Projekten noch weitere Tools und Vorgehensweisen zum Einsatz, um schnell auf neue Anforderungen zu reagieren.
Hierzu zählen in der eigentlichen Entwicklung Continuous Improvements, also das stetige Verbessern des Quellcode innerhalb eines Projektes, welche zum Beispiel durch Code Reviews und Refactorings unterstützt werden können.

Bedingt durch die sich schnell ändernden Anforderungen ändert sich auch der Code schneller und häufiger.
Um sich dennoch abzusichern, kommen hier Tools wie automatisierte Unittests, ausgeführt Beispielsweise in einer Continuous Integration Umgebung zum Einsatz.

Inzwischen haben viele Projekte zudem erkannt, dass die kurzen Entwicklungszyklen, die mithilfe, eben genannter Techniken möglich werden, entsprechend kurze Releasezyklen erfordern.
Im Idealfall führt dies zu einem Continuous Deployment, also der Fähigkeit ein Feature sofort nach der Fertigstellung zu releasen.

Ein Prozess ist jedoch immer nur so gut, wie seine Teilprozesse.
An dieser Stelle sollten wir unseren Blick auf die Datenbank lenken.

  • Wie läuft hier die Entwicklung?
  • Wie automatisieren wir Datenbankupdates?
  • Was für einen Stand hat unsere Datenbank auf Produktiv? Auf Staging? Auf dem Previewsystem?
  • Wie sichern wir Datenverluste bei nachträglichen Änderungen ab?

Bei uns lief es im Projekt bis vor kurzem so, dass vor einem Update der Datenbank händisch geprüft werden musste welche Änderungen noch nicht in der Datenbank existieren um dann entsprechende SQL Dateien zusammenfügen zu können, die die neuen Änderungen enthielten.
So ein Vorgehen ist nicht nur Fehleranfällig sondern auch Aufwendig.
Am stärksten Bemerkbar machte sich dies, beim migrieren von Daten, was bedeutete, dass die Reihenfolge von SQL Dateien und Migrationsskripten strikt beachtet werden musste.

Refactorings hingegen liefen so ab, dass die neue Datenstruktur in Form von neuen Tabellen angelegt wurde, die Daten mithilfe von Migrationsskripten überführt wurden und die ursprünglichen Tabellen erst beim nächsten Release vollständig gelöscht wurden, sofern dies nicht vergessen wurde.

Dieses Vorgehen kostete viel Zeit und Nerven, weshalb eine Alternative gesucht wurde.

Vor kurzem haben wir als Team ein neues Tool gefunden welches uns viel Arbeit abnimmt und vor allem zusätzliche Sicherheit auf Datenbankseite gibt.

Dies ist Liquibase, ein in Java geschriebenes Tool zum Refactoring und automatischen Update der Datenbank, welches unter der Apache 2.0 Lizenz zur freien Nutzung zur Verfügung steht.

Liquibase bringt eine eigene Beschreibungssprache für Datenbankänderungen mit, die auf XML basiert.
Durch diese abstrakte Beschreibung der Änderungen in XML wird Datenbankunabhängigkeit ermöglicht.
So kann Liquibase mit jeder Datenbank umgehen für die ein JDBC Treiber verfügbar ist, so zum Beispiel MySQL, Microsoft SQL Server, Oracle, PostgreSQL, SQLite, Apache Derby und vielen weiteren.

Definiert werden die Änderungen als sogenannte Changesets, die in beliebiger Anzahl innerhalb eines DatabaseChangelogs vorkommen können.
Jedes Changeset setzt die Angabe eines Autors und einer Id voraus, wobei die Id nur innerhalb des DatabaseChangelogs eindeutig sein muss.

Ein einfaches Changelog, der eine einzelne Tabelle mit 2 Spalten, id und name, anlegt sieht wie folgt aus:


Ausgeführt werden kann dieses Changelog entweder innerhalb eines vorhandenen Buildsystems, hierfür gibt es Tasks in ANT, Maven, Grails, Spring und in Phing als Erweiterung unter https://github.com/bitExpert/liquibase-phing, oder über die Kommandozeile:


Bei diesem Aufruf wird der Treibertyp, in unserem Fall JDBC MySQL, das Verzeichnis des Treibers, der Pfad zum auszuführenden Changelog, sowie URL der Datenbank, Nutzername und Passwort angegeben und der Befehl update, um Liquibase zu veranlassen, dass alle Änderungen eingespielt werden, die noch nicht in der Datenbank sind.
Am Rande sei hier bemerkt, dass der JDBC Treiber für die jeweilige Datenbank nicht Teil von Liquibase ist, ergo separat heruntergeladen werden muss.

Wer sich jetzt fragt, woher Liquibase wissen kann, was bereits in der Datenbank vorhanden ist und was geupdatet werden muss, dem möge folgende kurze Erklärung dienen:
Liquibase speichert in der Tabelle DATABASECHANGELOG Metainformationen zu jedem erfolgtem Update ab.
Hierzu gehört für jedes ausgeführte Changeset der Autor, die Id, das Ausführungsdatum und eine Hashsumme des Changesets.
Die Hashsumme wird bei jedem neuen Update für alle bereits vorhandenen Changesets geprüft, so dass nachträgliche Änderungen an einem bereits ausgeführten Changeset nicht mehr möglich sind.
Es gibt zwar die Möglichkeit mit dem Kommandozeilenbefehl clearChecksums alle Hashsummen zu löschen, jedoch ist die saubere Vorgehensweise bei einem Fehler ein neues Changeset anzulegen, welches den Fehler behebt.

Der größte Vorteil, den man mit echten Changesets gewinnt, sind die Rollbacks.
Für alle Änderungen die neue Tabellen, Spalten oder ähnliches anlegen, oder bestehende Verändern, bietet Liquibase automatische Rollbacks.
Diese werden wichtig, sobald beim updaten etwas schief geht, denn dann wird der Rollback ausgeführt, so dass eine inkonsistente Datenbank verhindert wird.
Jedoch sind die Rollbacks auch in der Entwicklung sehr nützlich, da jederzeit zu einem bestimmten Stand der Datenbank zurück gekehrt werden kann.
Dies ist Changesetabhängig möglich, mit rollbackCount n, welches die letzten n Changesets zurück nimmt, Datumsabhängig mit rollbackDate <date>, welches alle Changesets die neuer als das angegebene Datum sind zurück nimmt und Tag abhängig.
Letzteres kehrt dabei zu einem in Liquibase gesicherten Stand der Datenbank zurück, einem sogenanntem Tag.

Für alle Rollbacks, die nicht mit einem Automatismus abgedeckt werden, kann auch manuell ein Rollback definiert werden.
Dies ist zum Beispiel der Fall wenn das Löschen einer Tabelle fehlschlägt und darauf entsprechend reagiert werden soll.
Das Definieren geschieht innerhalb des entsprechenden Changesets, indem nach der eigentlichen Anweisung eine oder mehrere Rollbackanweisungen geschrieben werden, die alle innerhalb des Tags <rollback> stehen müssen.

In den meisten Teams ist Dokumentation nicht gerade beliebt, jedoch ein notwendiges Übel um neuen Teammitgliedern den Einstieg zu erleichtern und nachvollziehbar zu machen, welche Änderungen wann gemacht wurden.
Auch hier Unterstützt uns Liquibase.
Mit dem Befehl dbDoc und einer nachfolgenden Pfadangabe ist es möglich, eine Dokumentation aller Änderungen zu generieren, die mit dem angegebenen DatabaseChangeLog durchgeführt werden würden.
Die dabei entstehende Änderungsdokumentation ist dabei stark an Java-Doc angelehnt.

Am meisten Zeit bei der Datenbankentwicklung mit Liquibase verschlingt das Schreiben der Changesets.
Zum Glück stellt auch hier Liquibase ein Tool bereit.
Die Methode diffChangeLog generiert anhand der Unterschiede zwischen zwei Datenbanken die entsprechenden Changesets.
Der Kommandozeilenaufruf dazu sieht ähnlich aus, wie beim updaten der Datenbank, jedoch werden zusätzlich die Daten der zweiten Datenbank angegeben, gegen welche geprüft wird:


Die neuen Changesets werden im angegebenen changeLogFile gespeichert.
Dabei werden sowohl Stored Procedures und Functions, als auch Trigger und Check Constraints ignoriert.

Die Unterschiede können mit Liquibase auch zwischen verschiedenen Datenbanksystemen ermittelt werde, beispielsweise einer MySQL und einer SQLite Datenbank.

Auch wenn die Einarbeitung in Liquibase einige Zeit erfordert und vor allem eine Umstellung in der Arbeitsweise, so möchte ich dieses geniale Tool im täglichen Arbeiten nicht mehr missen, da uns als Team damit viele Sorgen und Mehraufwände abgenommen werden.

07.12. One-click Deployment

Today’s topic is deployment. It’s called one-click deployment for a reason: Developers are lazy.
It’s hard to do less than clicking on one button, so that’s our goal.

With the growing need for lower time-to-market and faster response to user feedback it is inevitable to not be limited by technical factors (there are enough other obstacles already). The focus lies on reproducible results.

Weiterlesen

03.12. Setting up an own QA Environment for Javascript

Nearly every PHP project comes up with a great set of tools to assure the quality of source code; unit tests are a no longer a „nice to have“ feature, they are common components in new projects. While unit tests help you to provide solid interfaces and proof the functionality of a certain method, there is a long list of tools that check the quality of the source code itself with many different metrics. Each of these mentioned tools reports its results into a XML file, which can easily be interpreted by a continuous integration server like Jenkins. The benefit is enormous: After every commit to your version control system your continuous integration server triggers the execution of the tests and the source code quality analysis and shows the result in meaningful diagrams. As a developer you get a direct feedback and you can make a prediction on the status of the entire project, because if even the smallest units work fine, there is a good chance that the whole system runs stable.
Weiterlesen

Buildscripts mit PHING – Teil 3

Im zweiten Teil wurde die Hauptaufgabe, das Zusammenführen aller SQL-Files, durch einen eigenen Task gelöst.
Nun fehlen noch die letzten Schritte, das Bereinigen und Zusammenpacken der Projektdateien und das anschließende Bilden einer Prüfsumme.
Anschließend müssen alle Ausgaben nur noch zusammengefasst ausgeführt werden, um einen Deployfähigen Zustand zu erhalten.
Damit am Schluss alle Aufgaben nur noch zusammengefasst ausgeführt werden müssen, um ein Deployfähigen Zustand zu erhalten.

Weiterlesen

Buildscripts mit PHING – Teil 2

Im letzten Teil wurde erklärt wie ein SVN Repository automatisch exportiert werden kann.
Diese Fortsetzung erklärt das Schreiben eigener Tasks.
Dafür werden wir alle SQL-Files im data Ordner zu einem zusammenfügen.
Der Einfachheit halber nehmen wir an, dass während der Entwicklung die einzelnen SQL-Files mit einem aufsteigend numerischen Präfix gleicher Länge versehen wurden.
Also haben wir zum Beispiel folgende Files:
001_Setup_db.sql
002_data.sql
003_TEST_data.sql

Da wir die Testdaten (003_TEST_data.sql) jedoch nicht mit ausliefern wollen schreit diese Aufgabe geradezu nach einem eigenen Task.
Hier spielt nun PHING erstmals seine Stärke gegenüber ANT aus.
Eigene Tasks werden für PHING in PHP geschrieben, wir müssen als Developer also nicht extra eine neue Sprache lernen.

Weiterlesen

Buildscripts mit PHING – Teil 1

Als Dienstleister veröffentlicht man selten Software direkt auf dem Zielserver.
Meist übergibt man dem Auftraggeber ein Paket, welches sämtlichen Projektcode enthält und eine entsprechende Installationsanleitung.
Nun ist das Vorbereiten eines solchen Paketes eine mühsame Angelegenheit.
Es müssen alle Testdateien entfernt werden, da diese auf einem Produktivsystem nichts zu suchen haben.
Verschiedene SQL-Dateien müssen zu einer zusammengefügt werden, der Kunde möchte schließlich beim Deploy so einfache Anweisungen wie möglich haben.
Diese und viele weitere Aufgaben fallen an, bevor eine Software an den Kunden ausgeliefert werden kann.
Nun entwickeln wir Software, und es kommt auch bei noch so gründlicher Entwicklung und Tests immer wieder zu Bugs.
Nach dem Fixen des Bugs muss also nochmals der Deploymentprozess Schritt für Schritt durchgegangen werden.
All das kostet Zeit, da bei jeder Übergabe an den Kunden die immer gleichen Schritte durchgeführt werden müssen.

Warum also nicht automatisieren?
Weiterlesen