DevOps – geänderte Anforderungen führen zu neuen Bugs?!

In dem vorherigem Artikel ging es um ein immer wieder kehrendes Problem aus der Praxis – die Anforderung des Kunden hat sich geändert. Die Vorgehensweise zur Qualitätssicherung ist in diesem Artikel näher beschrieben.

Hier geht es um das Thema Automatisierung von alltäglichen, meist bekannten Prozessen:

  • geänderte Anforderung – neue Fehler?
  • Integration neuer Funktionen (Continous Integration)
  • automatische Builds mit anschließenden Tests

Fehler treten immer wieder auf, können aber durch folgende Schritte bereits frühzeitig festgestellt und behoben werden:

  1. Änderung am Code durchführen
    => geänderte Anforderung wird umgesetzt
  2. Alle Tests laufen lassen, um sicherzustellen, dass die bestehende Funktionalität weiterhin in Ordnung ist
    => Alles Tests sind weiterhin grün
  3. Sicherstellen, dass sich der geänderte Code auch weiterhin integrieren lässt und auch keine abhängigen Projekte betroffen sind
    => Es müssen alle Projekte, die die gemeinsame Codebasis verwenden, geprüft werden

Was ist bei der Integration neuer Funktionalität zu beachten? Auch hier gibt es immer wieder kehrende Schritte:

  1. Abholen der letzten stabilen Version der Software aus der Versionskontrolle
  2. Lokales kompilieren der neuen Codebasis
  3. Alle Tests lokal ausführen
  4. Alle auftretenden Fehler müssen behoben werden
  5. Sind alle Tests grün?
    => Die neue Codebasis kann eingecheckt werden

Durch den Check-In Vorgang lassen sich weitere Prozesse anstoßen, die weitestgehend automatisiert auf einem oder mehreren Build-Servern ablaufen können. Die meisten Build-Tools führen diese Workflow-Schritte bereits ohne größere Konfiguration aus.
Im folgenden ein Ausschnitt eines möglichen Build-Prozesses:

  1. Hole die letzte Version mit allen Projekten
  2. Kompiliere alle betroffenen Projekte
  3. Generiere eine eindeutige Build-Nummer
  4. Stelle das Kompilat auf einem (Test-) Server bereit
  5. Starte alle vorhandenen Tests
  6. Im Fehlerfall: Informiere den notwendigen Personenkreis, dass Fehler aufgetreten sind.
    => Prozess wird hier beendet
  7. Kein Fehler: Stelle das Ergebnis auf einer Staging-Umgebung bereit
  8. Konfiguriere alle weiteren Komponenten wie Datenbanken o.ä.
  9. Stelle die Software bereit, z.B. SQL-, Deploy-Skripte, etc.

Meine Empfehlung:

Aus eigener Erfahrung kann ich nur jedem Team – egal ob Entwicklung oder Betrieb – ans Herz legen, automatisierte Builds mit anschließenden Tests einzuführen. Jedes Teammitglieder sollte in der Lage sein, innerhalb weniger Stunden eine neue, stabile Softwareversion zu erzeugen. Dazu gehört aber nicht nur die Erstellung eines Setups oder der Skripte zur Bereitstellung der Software sondern auch die automatische Integration in die bestehende Software (Continous Integration). Bereits bei einer kleinen Änderung muss automatisch sichergestellt sein, dass der Rest der Software davon nicht beeinträchtigt wird. Eine ständige Integration von neuen Funktionen in eine Versionskontrolle gehört ebenso zu den Grundvoraussetzungen wie ein gesundes Maß an Automatisierung.

DevOps – ständig neue Anforderungen?!

In vielen Projekten kommt seit Jahren das Wasserfall-Modell zum Einsatz. Hier stehen mit Lasten- und Pflichtenheft alle Anforderungen zu einem Zeitpunkt X fest und es kann mit der Entwicklung begonnen werden. Der Ablauf ist in jeweils für sich abgegrenzte Phasen getrennt. Eine Phase muss abgeschlossen sein, bevor die nächste begonnen werden darf.

  1. Analyse
  2. Design / Konzeption
  3. Implementierung
  4. Testen (mit und ohne Kunde)

Der Kunde stellt fest, dass die Software soweit passt, aber das eine kleine Feature muss noch dringend umgesetzt werden.
„Ich will meine aktuellen Änderungen speichern können. Und die aktuellen Einstellungen sollen natürlich auch – Personen abhängig – geladen werden. Das hatten wir doch im Workshop XYZ so besprochen…“, wer kennt das nicht?

Das Team fällt aus allen Wolken!
Persistenz, personenspezifische Einstellungen – und das über alle Schichten hinweg. Der Abgabetermin ist nicht zu halten!
Ein möglicher Grund: Das Team war beim entscheidenden Workshop aus akutem Zeitmangel natürlich nicht dabei – zu viele offenen Punkte.

Ein weiteres Szenario:
Missverständnisse bei der Kommunikation der Anforderungen zwischen Kunde und dem Team bestehend aus Business-Analysten, Designern bzw. Entwicklern und dem Betriebsteam. Der Geschäftsprozess wurde völlig falsch verstanden…

Fakt ist, dass kurzfristige Änderungen der Anforderungen am bestehenden Prozess treten immer wieder auf.

Doch wie lässt sich sicherstellen, dass Änderungen keine Seiteneffekte und Fehler in anderen Bereichen verursachen?
Wie kann die bestehende Qualität mindestens auf demselben Niveau gehalten oder gar verbessert werden?

Mehr zu den Vorgehensweisen rund um die Qualitätssicherung und Testen habe ich in diesem Artikel beschrieben.

DevOps – Testen, aber richtig! Klassisch vs. Unit Tests, TDD

Bei der Qualitätssicherung – und die besteht nun einmal hauptsächlich aus Testen – unterscheide ich zwischen dem SOLL und IST Zustand der klassischen Vorgehensweise und Unit Tests durch den Test-First Ansatz (Test-Driven-Development, TDD).

Die Vorgehensweise der Qualitätssicherung im klassischen Sinn (SOLL):

  1. Entwickler schreibt eine Methode, Klasse oder eine Applikation
  2. Wenn genug Zeit vorhanden, meistens nur optional
    • Manuelle Tests starten
    • Unit Tests erstellen
    • Integration Tests erstellen
  3. Wenn genug Zeit vorhanden, meistens nur optional
    • Es werden alle manuellen Tests von Anfang an neu gestartet
    • Es werden alle Unit Tests neu gestartet
    • Es werden alle Integrationstests neu gestartet
  4. Es werden gemeldete Fehler behoben

Die Vorgehensweise der Qualitätssicherung im klassischen Sinn (IST):

  1. Entwicklungsteam schreibt eine Methode, Klasse oder eine Applikation
  2. Es werden Fehler behoben (und ggf. ungewollt weitere erzeugt)
  3. Fehleranalyse dauert sehr lange, Kosten steigen pro Fehlerfall

Die Vorgehensweise der Qualitätssicherung bei Test Driven Development (Test-First Ansatz, ausgeführt zur Entwicklungszeit)

  1. Schreibe einen Test
  2. Starte alle Tests
  3. Stelle sicher, dass der/die Tests grün werden
    => der produktive Code muss geschrieben werden
  4. Starte alle Tests
    1. Der neue Test schlägt fehl (Red)?
      => Fehler beheben und weiter mit 4.
    2. Der neue Test ist okay (Green)
      => Produktiven Code aufräumen (Blue)
    3. Alle Tests sind okay und kein Bedarf den Code aufzuräumen
      =>  Schreibe einen neuen Test (weiter mit 1.)

Dadurch entsteht ein Zyklus, der mit einem fehlschlagenden Test beginnt (RED) und behoben wird (GREEN). Ggf. kann der Code vereinfacht und aufgeräumt werden (BLUE).
Es entwickelt sich dadurch nach und nach der produktive, aufgeräumte Quellcode – in kleinsten Schritten, überschaubar, lesbar und voll automatisiert.

Mein Fazit:
Der Idee hinter TDD steht für mehr Qualität, Stabilität, Wartbarkeit – und das zu jederzeit automatisiert per Knopfdruck

Weitere Empfehlungen zum Thema Unit Tests und Test Driven Development