Daily archives "December 23, 2011"

2 Articles

Databases in developers environment – Versioning and migrations

One of the most annoying things I get in touch with software development beside the question How can I format this date is How can I put my database under version control?

If you have not already read K. Scott Allens Database series, do it now.
At first follow his three rules:

  1. Never use a shared database server for development work.
  2. Always Have a Single, Authoritative Source For Your Schema
  3. Always Version Your Database

Requirements

Ask your customer which database and which environment is used. Most of these questions should be answered by a well worked out requirement questionnaire.
Ask for

  • Which operating system is used
  • How is the operating system localized
  • Which database management system is installed
  • Which version and service packs of the DBMS are used
  • Which language version of DBMS is used

It might sound irrelavant but database management systems differs from version to version. Setup your development database server with exactly the same settings your customer uses.

Database environment

The ideal situation is that every developer owns at least two database instances on this server. One for unittests, one for integration tests.
Your continuous integration server should also own his two databases.
So you could have these databases:

  • $PROJECT_$DEVELOPER_unittest
  • $PROJECT_$DEVELOPER_integration
  • $PROJECT_CI_unittest
  • $PROJECT_CI_integration (used for Selenium)
  • $PROJECT_customer_integration

The last database should be used for database dumps which came back from your customer for debugging purposes.

Okay, most of this should be clear. Never use a shared database for development work.

Versioning

Why should you now versionize your database? Because of the same reason you versionize your code: Going back in time and retrace occuring bugs of your customer who uses an old but stable version of your program.

In my opinion there are two approaches to halfway achieve this goal:

  • Store every database object (table, view, stored procedure, function) in its own .sql file
  • Do database migrations like Ruby on Rails does

1 on 1

Storing every database object means that you have a directory structure like

/tables/tbl1.sql
/tables/tbl2.sql
/views/view1.sql
/views/view2.sql
/sps/stored_procedure1.sql
/functions/function1.sql

You get it. Every SQL script contains the CREATE statement for your database object.
This very charmant, because you can track the stuctural changes via your commit log.

The problem begins when you want to migrate your developer integration databases and the database of your customer. Stored procedures or functions can be easily replaced because you can use CREATE OR REPLACE syntax. Views can be replaced by DROP VIEW view1; CREATE VIEW view1 AS…
But – and that’s a big but – you have to compare the current database of your customer with your current table definition and write the ALTER TABLE statements by hand. Not so funny.
Additionally you must delete unused views, stored procedures or functions by hand. Otherwise you’ll get a grave with dead database objects which are no longer used.

I know none database tool which can automatically generate a 100% working update script without any pitfalls. And writing a DBMS independent tool on your own is a lot of work.

1 on n (migrations)

The second approach is to create database migration scripts for every completed database change.
At first the negative aspect: You wil get a lot of files and you can not easily make a git/svn diff of the structural change of your database object because the changes are distributed over many files.

The good news is: You don’t have to write additional ALTER statements on deploy time because they are already there. That means, that you just give your customer your migration SQL scripts, he executes the SQL scripts in a given order and will get the latest database version.

To weaken the problem of diffing different database versions, you can migrate one database to version n and another database to n+1. After that you make an SQL export and use diff (n).sql (n+1).sql.

A few days ago I came to the conclusion that there is no other effective way to achieve the goal, so I decided to further speculate about the second approach.

Implementing migrations

There were some requirements I thought about

  • The database development process and file naming have to be standardized
  • The current installed version of your database must be stored inside the database itself
  • The migration process must be ran easily
  • The migration process must support pre/post scripts
  • The migration process must support different scenarios (deploying on customer, no need for migrations on developer site – just install latest version, different databases)

Standardization was easy. Every project contains a folder named db which contains four sub folders

Directory structure of database migrations

Directory structure of database migrations

  • /coredata contains the core data which every database must contain.
  • /fixtures/[integrationtest|unittest] contains the fixtures which will be used in test cases
  • /handlers can be executed before or after migrations
  • /migrations itself contains the migration scripts

It is important that all files in /coredata, /fixtures and /migrations have an ongoing number. These must not be identical to your SVN revision. It is only important that they can be executed successively.
You can see that that I use the format YYYYMMDD_$DAYVERSION as ongoging identifier.

The database must store their migration version. This is needed for doing migrations. Every migration file greater than $DATABASE_VERSION must be executed.
In my structure above the schema migration table is executed first (20111219_001_schema_migration.sql) and contains only one statement

CREATE TABLE schema_migration (id int not null auto_increment, migration_on DATETIME, version char(20)  NOT NULL, filename LONGTEXT, PRIMARY KEY(id));

After these point I started to write a small prototype migration definition file which supported different scenarios (supporting different databases and servers, migration process, recreate process).

For this definition (see my first draft) I had to write my own parser or use Xtext, so I transformed it into an XML (see my template) sample. It seemed to be ideal for xsd.exe and C#/Visual Studio.
But after I had struggled with serialization problems I took a closer look to the XML file. It looked like… Ant. The processes were more or less the same.
I did a research and came to the conclusion that almost every requirement could be solved with Ant. I implemented a halfway working solution.
The build.xml currently does not insert the migration version after a file is applied. I will fix it ASAP.
Please note, that you need to have js.jar, bsf.jar (both for JavaScript), commons-logging.jar and ant-contrib.jar (for task) in your Ant classpath for using the build.xml.
The build.xml itself is designed for MySQL. You need to customize the build.xml for every DBMS you use. But this should be easy to implement.

Update: Jens Schauder published a post about Tips for Testing Database Code.

Jahresrückblick 2011

Das Jahr 2011 geht dem Ende entgegen. Für mich ist das gut und andererseits auch nicht so gut.

Gut ist, dass der Prüfungsstress des Studiums in genau drei Wochen vorbei ist. Dann schreibe ich die beiden letzten schwierigen Klausuren. Es folgen noch eine Banane-Klausur, eine Projektarbeit und die Bachelorarbeit.
Nicht so gut ist, dass ich ab nächstem Jahr wieder regelmäßiger zur Arbeit gehen kann/darf/muss.

2011 begann für mich mit einer kompletten Umstellung: Mein Plan war bereits Mitte/Ende 2010, dass ich in 2011 mich komplett auf das Studium und ein paar private Projekte konzentrieren wollte. Somit wurde mein Arbeitsvertrag geändert und ich sollte 2011 nur noch ca. 10h/Woche im Büro arbeiten. Theoretisch.
Ebenfalls Ende 2010 suchten meine Freundin und ich eine gemeinsame Wohnung. Nach erfolgloser Suche und der Feststellung, dass es in der Stadt keine passable Wohnung für uns zwei gibt, mieteten wir einfach zu Januar eine zweite Wohnung in dem Haus, in dem ich bereits wohnte. Geniale 110qm Wohnfläche waren nun unser eigen. Ich hatte einen eigenen, riesengroßen Arbeitsraum – meine Freundin ein eigenes Ankleidezimmer.

Während wir also im Januar zusammenzogen, musste ich mich voll in Mathematik 2 reinknien. Stressig, da ich keine Ahnung von der Materie hatte und mir auch die Lust fehlte. Nebenbei musste ich mit meinen Azubis die Abschlussprojekte ihrer Ausbildung durchsprechen und Testklausuren korrigieren.

Mitte Februar hatte ich langsam den Verdacht, bei Mathe durchzusteigen. Was nicht zuletzt an der Art und Weise meines Lernprozesses lag: Jeden Tag die selben Aufgaben rechnen, so dass sich die Vorgehensweisen ins Hirn einbrannten. Hallo Gauss!
Beim Ausbildersprechtag meiner Azubis redeten wir über eine Art Forum für Auszubildende, die sich einmal pro Monat/Blockunterricht verschiedene externe Dozenten anhören können. Die Idee ist immer noch in meinem Kopf – leider konnte ich das in den darauffolgenden Monaten nicht weiter angehen.
Auf der Arbeit beschäftigte ich mit Netzwerkthemen, fixte ein par Bugs in ZABOS und lernte Mathe.

Der März kam und mir ging der Hintern ordentlich auf Grundeis. Die erste Matheprüfung des Jahres war für das Ende des Monats angesetzt. Ich lernte jeden Tag mindestens 6h. Die Prüfung selbst lief dann äußerst gut. Meine Vorbereitungen waren super und zahlten sich aus. Zwischen März und April arbeitete ich nebenbei noch an Nostradamus und stellte fest, dass die Kombination JPA (EclipseLink)/AspectJ/Spring/Maven außerordentlich suckte. Die Entwicklung machte aufgrund der langen Ladezeiten und anderweitiger Fehler keinen Spaß. Ich legte das Projekt erstmal ad acta.

Das erste Vorstellungsgespräch für einen neuen Azubi hatten wir dann im April. Lief gut. Den wollten wir haben und wir bekamen ihn schließlich auch. Nebenbei lernte ich für Mathematik 3. Auf meinem privaten Balkon, da das Wetter bereits Anfang April enorm gut gewesen ist.
Ende April hatte ich bereits eine knusprige Hautfarbe.
Direkt nach Ostern hörte ich mit dem Rauchen auf. Von heute auf morgen und freiwillig. Erste Veränderungen konnte ich bereits 4 Wochen später beim Schwimmtraining deutlich bemerken.

Im Mai schrieb ich dann Mathmatik 3. Lief ebenfalls gut. Ich rauchte dann zwar zur Netzwerkparty Anfang Juni noch eine Kippe, schmiss sie dann aber nach der Hälfte weg.

Dann kam das wohl einschneidenste Ereignis des Jahres: Jürgen – Geschäftsführer und Freund – verstarb plötzlich. Ich war unheimlich geschockt und hatte Probleme, meine Vorbereitungen zu Mathematik 4 (Statistik) und IT-Recht zu erledigen.
Direkt nach dem Prüfungstermin am 1. Juli fuhr ich wieder zurück nach Wolfsburg, nur um dann am nächsten Tag mit meiner Liebsten zur Hochzeitsfeier ihrer Mutter nach Frankfurt zu fahren. War eine sehr lustige Party, bei der ich kuriose Geschichten hörte.

Ein paar Tage später hatten wir dann Vorstellungsgesprächsmarathon. Einer der Bewerber auf eine feste Stelle fiel dabei besonders negativ durch seine unkonventionellen Antworten auf. Wenn er denn mal antwortete.
Zwei der Bewerber auf eine Ausbildungsstelle kamen bei uns hingegen besonders gut an. Nach einigen Gesprächen einigten wir uns darauf, dass wir in diesem Jahr gleich 3 Auszubildende (1 Anwendungsentwickler, 2 Systemintegratoren) einstellen wollten. Eine Entscheidung, die ich nicht bereue.

Der Juli war vom Wetter her nicht so gut, wie die zwei Monate zuvor. Ich bereitete mich auf meine weitere Klausuren Ende September vor, machte ein paar Tage Urlaub auf dem Balkon, spielte viel Gitarre, las einige Bücher. Mit der Freundin ging es für drei Tage zur Saltherme Lüneburg. Inklusive Sauna und Massagen. Die Salzmassage war grandios.

Es folgte der August. Eigentlich hatte ich geplant, dass ich die ersten paar Tagen mit unseren neuen Azubis verbrachte und nebenbei ein bißchen studierte. Stattdessen musste ich mehr oder weniger von heute auf morgen die Entwicklung in einem unserer Projekte übernehmen. Der Zeitdruck war ziemlich mörderisch. Meine angepeilten 10h/Woche im Büro konnte ich vergessen. Ebenso die letzten halbwegs sonnigen Tage.
Meine Planung war mehr oder weniger: 4h/Tag für Projekt, 2h/Tag Azubis, 4h/Tag Studium. Freizeit ade.

Im September ging es dann mit der Ruderregatta weiter. Wegen Personalmangels und technischer Probleme war für mich sowohl die Vorbereitung als auch die der Ablauf Stress. Nebenbei lernte ich natürlich. Die Prüfungen liefen dabei halbwegs gut. Wenigstens konnte ich auf der Netzwerkparty direkt Anfang Oktober ausspannen. War lustig, da die neuen Azubis ebenfalls dabei waren.

Beim Zahnarzttermin Mitte Oktober wurde mir dann geraten, alle Weisheitszähne herauszunehmen.
Ein Tag später war Brenntag in Flechtorf. Chilliger Abend. Ich war völlig völlig entspannt – irgendwas war aber im Busch. Leider lag ich da mit meiner Vermutung richtig.
Der Termin beim Kieferchirguen in der darauf folgenden Woche machte mir Mut: Einfach mal alle Weisheitszähne bei Vollnarkose im Dezember entfernen lassen.

Die Abnahme des Projekts im November lief gut. Kunde glücklich, Team glücklich. Alles gut.
Ich motivierte mich und begann Nostradamus von Java auf PHP umzustellen. Innerhalb von zwei Wochen mit PHP mehr geschafft, als mit Java in 1 1/2 Jahren. Scary.
Es folgte ein paar Telefonate und Treffen mit unterschiedlichen Xing-Kontakten, die allsamt sehr interessant gewesen sind. Meine Prüfungen Ende November liefen hingegen schlecht. Motivation auf dem Nullpunkt, kalte Jahreszeit, eine Woche bis zur Weisheitszahn-OP und ein paar Tage zuvor erfahren, dass ich am Fuß operiert werden muss.

Die Weisheitszahn-OP zum 2. Dezember war ok. Nicht okay waren die zwei Wochen danach. Die miesesten Schmerzen, die ich bis dato hatte. Und ich bin häufig vom Baum gefallen und musste zum Nähen ins Krankenhaus gebracht werden.
Totaler Nervenzusammenbruch nach 4 Tagen ohne Schlaf, fehlendem Schmerzmittel am letzten der vier Tage und einer tauben rechten unteren Gesichtshälfte. Mimimi. Damn it.
Zwei Wochen später die Fuß-OP. War nicht so schlimm. Leider zwei weitere Wochen außer Gefecht und dementsprechend dazu verdammt, nicht schwimmen zu können.

Und nun haben wir es einen Tag vor Heiligabend. In 5 Tagen kommen die Fäden am Fuß raus, die Schmerzen im Gesicht sind fast weg. Das Studium ist fast fertig. Das Jahr ist fast geschafft.
Dieses Jahr war einfach nur stressig. Meine Planungen, die ich zu Jahresbeginn hatte, waren für die Katz. Nostradamus hätte an den Start gehen sollen. Ging es aber nicht. Keine Zeit. Ich wollte entspannen. Ging nicht. Keine Zeit. Ich wollte mehr Gitarre spielen und lesen. Ging nicht. Keine Zeit.
Was allerdings ging: Lernen – und davon viel.
Privat habe ich meine Ziele für 2011 nicht mal zu 50% erreicht – In Bezug auf Arbeit und Studium hingegen übertroffen. Ich hoffe mal, dass das 2012 anders wird.
Meine Vorsätze bzw. groben Pläne für das kommende Jahr habe ich bereits:

  • Meine Klausuren fertig schreiben
  • Endlich mal bei der JUG Ostfalia auftauchen
  • Nostradamus endlich an den Start bringen
  • Mehr Holzarbeiten. Srsly.
  • Wieder Schwimmtraining – wie mir das fehlt
  • Gödel, Escher, Bach zu Ende lesen
  • Diät wegen Nahrungsmittelunverträglichkeit machen
  • Endlich zum Bouldern gehen
  • Mein privates Mediacenter fit machen
  • Eventuell neuen Fernseher kaufen
  • Ein, zwei große Sachen, die ich zu ggb. Zeit verkünden werde

Wünsche frohe Weihnachten und einen guten Rutsch.