Continous Integration in der Softwareentwicklung.

Veröffentlicht am 14. Oktober 2014 von Markus Saradjuk

Continous Integration kurz (CI) ist ein Best Practise, der das kontinuierliche Integrieren neuer Funktionen in bestehende Software beschreibt. Das erste mal wurde CI von dem Vorgehensmodell XP[1] rudimentär beschrieben [2]. Hier wird darauf eingegangen das Entwickler ihren Code an ein zentrales Repository commiten sollen und zwar nicht irgendwann sondern mehrmals täglich. Jeder soll über Tests sicherstellen, dass der Code auch funktioniert. Dieser Ablauf verhindert das Auftreten von größeren Integrationsproblemen gegen Ende eines Projekts.

CI hat sich im Laufe der Zeit weiter entwickelt und wird mittlerweile in vielen Projekten eingesetzt. Außerdem gibt es viele unterstützende Tools, die aufwändige Arbeit abnehmen wie z.B. Jenkins[3], Capistrano[4] oder Git[5].

Im Folgenden soll beispielhaft der Ablauf des Continous Integration und die dafür benutzten Tools für CheroKey gezeigt werden:



Um den Code zu verwalten und Änderungen nachzuverfolgen wird als zentrales Repository Git verwendet. Ist ein nutzbares Teilstück einer neuen Funktion fertig wird es committed, und in das zentrale Repository gepusht.

          
            git add model.rb
            git commit –m „add new model“
            git pull origin master
            git push –u origin master

Auch wenn sie noch nicht den vollen Funktionsumfang enthält. Das pushen auf das zentrale Repository setzt auch voraus, das der aktuelle Codestand des Repositoy lokal vorhanden ist und das alle Tests fehlerfrei durchlaufen. Somit wird auch überprüft, ob sich die Funktion mit dem Gesamtsystem verträgt.

          
            RAILS_ENV=test bundle exec rake spec

Manche Funktionen lassen sich allerdings nicht in mehrere Commits aufteilen ohne das Testfälle fehlschlagen. Hier werden so genannte Feature Toggles[6] eingesetzt. Vereinfacht gesagt trennen sie den alten Code vom neuen durch eine Bedingung. Dadurch können Änderungen auf das Repository gepushet werden, ohne das bestehende Testfälle fehlschlagen. Nachdem die Aufgabe abgeschlossen ist kann die Bedingung abgeändert werden und das neue Feature ist freigeschaltet.

          
            If rolled_out? :new_time_sheet
              # new code
            else
              # old code
            end

Dieses Vorgehen stellt sicher, das auf dem Repository immer valider Code läuft, der zum Deployen genutzt werden kann.

Um zu gewährleisten dass im Repository alle wichtigen Dateien vorhanden sind und keine Einstellungen vergessen wurden, wird Jenkins als CI Server genutzt. Die vorhandenen Jobs sind so eingestellt, dass sie eine Veränderung im Repository erkennen und automatisch eine Testsuite anstoßen. Hier wird nochmals die Integrität des Codes auf einem unabhängigen System getestet. Läuft die Testsuite ohne Fehler durch, wird ein Build angestoßen, der die neuen Funktionen auf ein Referenzsystem deployed. Sollten Tests fehlschlagen oder ein Build nicht funktionieren werden die Entwickler per Email informiert und können sich das Problem sofort ansehen.

          
            #!/bin/bash -e
            source "/usr/local/rvm/scripts/rvm"
            rvm use `cat .ruby-version`
            bundle install
            rm -f log/*
            bundle exec cap cherokey deploy 

Das eigentliche Deployment der Applikation wird von Capistrano übernommen. Hier ist hinterleget wie und was wohin geschoben werden muss, damit die Applikation funktioniert. Am Ende wird die Applikation noch gestartet.

Mit dem Referenzsystem wird sichergestellt, dass das spätere Ausrollen auf eine Produktivinstanzen ohne Fehler durchläuft. Das Referenzsystem dient auch dazu neue Funktionen vorzuführen oder auszuprobieren.

Sind die neuen Funktionen auf dem Referenzsystem abgenommen werden die Änderungen auf allen Produktivinstanzen von Hand deployed. Hierfür wird ein Job in Jenkins erstellt der alle anderen Jobs anstößt, die die neue Version ausrollen. Dadurch ist es möglich mit einem Klick alle Produktivinstanzen zu deployen.

Zusammenfassend hier noch einmal die Vor- und Nachteile von CI.

Vorteile:

  • „It runs on my machine“ wird ausgemerzt, da es ein Referenzsystem gibt.
  • Integrationsprobleme werden durch das häufige Pushen auf das Repository gering gehalten.
  • Komfortables Ausrollen einer Instanzen mit einem einzigen Klick.
  • Fehler können schneller behoben werden.
  • Alles läuft vollautomatisch ab und es gibt Benachrichtigungen falls etwas schief läuft.

Nachteile:

  • Initial hoher Aufwand, um die Systeme und Tools aufzusetzen bzw. zu benutzen.
  • Zusätzliche Tests die sicherstellen, dass der Ablauf reibungslos funktioniert.
  • Eventuelles umdenken im Workflow der Entwicklung.

1 http://c2.com/cgi/wiki?ExtremeProgramming
2 http://www.extremeprogramming.org/rules/integrateoften.html
3 http://jenkins-ci.org/
4 http://capistranorb.com/
5 http://git-scm.com/
6 http://martinfowler.com/bliki/FeatureToggle.html