Diese Erfahrungen haben mittlerweile viele Unternehmen gemacht: je länger ein IT-Projekt andauert, desto öfter verwandelt es sich Stück für Stück in eine langweilige und kostspielige Routine. Änderungen und Anpassungen dauern immer länger, werden immer teuerer und führen immer häufiger zu den Fehlern an ganz unerwarteten Stellen. Software erodiert. Manchmal wird es sogar zu teuer und zu unsicher, die Software an die geänderten Geschäftsanforderungen anzupassen, so dass die Geschäftsleitung gezwungen ist, wichtige Prozessänderungen zurückzustellen oder auf sie gar zu verzichten. Das führt unweigerlich zu der Unzufriedenheit auf allen Ebenen. Auch die Entwickler sind frustriert, da sie immer mehr in den Kleinigkeiten und in der Behebung von Fehlern versaufen, statt sich neuen interessanten Herausforderungen zu stellen. Lässt man diesen Teufelskreis immer weiter laufen, wird es schnell kritisch, kann unter Umständen sogar dazu führen, dass das Geschäft komplett eingestellt werden muss.
Es muss aber nicht immer weiter so laufen. Es gibt Wege und Möglichkeiten, diese Routine zu unterbrechen. Dies kann auch in kleinen Schritten erfolgen, jeder von denen zu den schnellen spürbaren Verbesserungen führt. Diese Schritte können und müssen auf unterschiedlichen Ebenen erfolgen – einige davon betreffen die Projektsteuerung, andere zielen darauf ab, die technische Seite der Software zu verbessern, und die dritte Gruppe der Maßnahmen hat ihren Zweck in der Erhöhung der Qualifikation einzelner Entwickler und in der Unterstützung ihrer Motivation. Projektsteuerung Die Begriffe ‚agile Methoden‘, Scrum usw. sind heute jedem bekannt, der sich mit der Steuerung von Softwareprojekten befasst. Genau diese Gruppe von Maßnahmen wird häufig als das Heilige Gral betrachtet, das die Projekte schneller und sicherer laufen lässt, die Transparenz und Planbarkeit herstellt, die Qualität der Software nachhaltig verbessert und die Motivation auf allen Ebenen aufrechterhält. Die Methoden dieser Gruppe sind gut bekannt, formalisiert, lassen sich relativ einfach einführen und können auch gemessen werden, was dazu führt, dass die Akzeptanz seitens Entscheidungsträgern für diese Maßnahmen wesentlich höher ist als bei den anderen. Oft wird es sogar missverstanden, dass allein das Einführen der Daily Stand-Ups, Sprints, Scrum Boards usw. alle aktuellen Probleme löst und die Dinge damit automatisch an die richtigen Stellen rücken werden. Leider ist es selten der Fall. Keine Frage, diese Methoden sind in den meisten Fällen sinnvoll, tragen aber eher dazu bei, die Transparenz in die aktuelle Projektsituation einzubringen und die Schwachstellen zu erkennen. Es ist gut nach jedem Stand-Up zu wissen, dass Entwickler bei der Lösung ihrer aktuellen Aufgaben immer wieder mit unerwarteten (oder auch erwarteten) Problemen zu tun haben, dass diese Probleme nicht zügig gelöst werden können und dass dadurch die Fertigstellung immer wieder gefährdet wird. Aber was macht man dann mit diesen Erkenntnissen? Mehr sogar – führt die Einführung von den agilen Methoden in der Projektsteuerung nicht zu schnellen spürbaren Verbesserungen, werden sie als eher lästig und unangenehm empfunden. An dieser Stelle müssen andere Maßnahmen greifen, die sehr stark von der konkreten Projektsituation abhängen und individuell gestaltet werden müssen. Grob kann man diese Maßnahmen in zwei Gruppen unterteilen: technische Verbesserungen und Erhöhung der Teamproduktivität.
Heute streitet keiner ab, dass die Unit-Tests zu der Software dazu gehören müssen. Startet ein neues Projekt, wird in der Regel stark darauf geachtet, dass die automatisierten Tests nicht zu kurz kommen. Leider zeigt die Praxis, dass die erste Phase des ‚euphorischen Testens‘ in der Regel relativ schnell abflaut.
Dazu gibt es mehrere Gründe:
Das Wichtigste ist aber aus meiner Sicht, die erzwungene Komplexität der Tests ist ein Zeichen dafür, dass es mit der Kernfunktionalität etwas nicht stimmt. So ist z. B. die Notwendigkeit, komplexe Objektnetze vorzubereiten, um einzelne Funktion zu testen, häufig ein Zeichen dafür, dass die zu testende Funktion zu viele Abhängigkeiten aufweist. Wird es problematisch, die Testergebnisse zu prüfen, weist das auf ein undeutlich definiertes Interface hin. Und das ist in meinen Augen das Wertvollste am kontinuierlichen Vorantreiben der automatisierten Tests – der Entwickler setzt sich unweigerlich mit der Grundarchitektur auseinander.
Eine der wichtigsten Voraussetzungen der agilen Entwicklung ist schnelles Feedback. Bringt ein Entwickler seine Änderungen in ein gemeinsames Code-Repository, muss er spätestens in ein Paar Minuten wissen, ob diese Änderungen etwas an den bestehenden Funktionen beeiflusst haben. Ist die Umsetzung einer Funktion fertig, muss das Team so schnell wie möglich wissen, ob die Anforderungen richtig und in vollem Maße umgesetzt wurden. Um das permanente Ausführen der automatisierten Tests und schnelles und unkompliziertes Ausliefern der fertigen Software zu gewährleisten, kommen Continuous Integration und Continuous Delivery Tools wie z. B. Jenkins zum Einsatz.
Refactoring ist eine Verbesserung der Code-Qualität, ohne die Funktionalität zu beeinflussen. Es existieren bereits hunderte von Refactoring-Methoden, vom einfachen Extrahieren einer Variable bis hin zu der Umstrukturierung einer ganzen Klassenhierarchie. Es reicht aber bei Weitem nicht, diese Techniken zu kennen – man braucht eine gewisse Erfahrung, um die Refactorings schnell und sicher durchzuführen.
Es hat 1994 mit GoF angefangen – und gehört heute aus meiner Sicht in den Werkzeugkasten jedes Entwicklers. Design Patterns sind Lösungsschablonen, die sich mit wiederkehrenden Entwicklungsproblemen befassen. Die Palette ist mittlerweile mehr als umfangreich – von einfachen Commands bis hin zu den Patterns, die ein komplettes System beschreiben (MVC, DI, Rule-Based Interpreter etc.).
Das Ganze ist mehr als die Summe seiner Teile.
–Aristoteles
Softwerentwicklung ist eine anspruchsvolle geistige Tätigkeit, und es ist ganz wichtig, dass diese Arbeit in einem optimalen Umfeld verrichtet wird. Je mehr ein Entwickler bei seiner täglichen Arbeit berücksichtigen muss, desto weniger eigener Kapazitäten wird er der unmittelbaren Lösung der Aufgaben widmen können. Auf der anderen Seite ist es essenziel, ein möglichst hohes Kommunikationsnivaue innerhalb des Teams zu erreichen, damit jeder die Gelegenheit hat, von anderen zu lernen und seine eigenen Ideen zu äußern.
Bricht man die Lösung einer Entwicklungsaufgabe auf die einzelnen Schritte herunter, sehen diese relativ einfach aus: Aufgabe verstehen – sich mit dem existierenden Code vertraut machen – Lösungsansatz erarbeiten – Funktion und entsprechenden automatisierten Tests implementieren – Code einchecken – Sicherstellen, dass keine bestehenden Funktionen gebrochen wurden. Der Teufel steckt aber wie immer in Details. Ist die Aufgabe zu groß, muss sie erst in Unteraufgaben zerlegt werden. Tauchen bei der Analyse fachliche Fragen auf, müssen Rückfragen gestellt werden. Ist die Umsetzung komplexer als ein Paar Zeilen Code, müssen die allgemeinen Architekturrichtlinien eingehalten werden, usw.
Wenn die Spielregeln in jeder Situation bekannt und von allen akzeptiert und befolgt werden, werden die Formalitäten quasi ‘blind’ abgearbeitet. Habe ich als Entwickler eine Aufgaben in einem Ticketsystem zugewiesen bekommen, gehe ich davon aus, dass hier alle relevantent Details beschrieben sind. Ist es nicht der Fall und fehlt mir die Information – stelle ich meine Fragen und weise das Ticket dem Autor zurück. Erscheint mir die Aufgabe zu groß – zerteile ich sie für mich in Untertickets, jedes von denen einzeln abgearbeitet werden kann. Habe ich meinen Code eingecheckt und keinen automatisierten Test zum Fallen gebracht – gehe ich davon aus, dass ich nichts kaputt gemacht habe.
Die beiden Methoden werden oft ausschließlich als Maßnahmen zum Erhöhen der Qualität vom erzeugten Code verstanden. Es ist zwar richtig, aber aus meiner Sicht bei Weitem nicht der einzige – und manchmal sogar nicht der wichtigste – Nutzen. Vor allem schaffen diese Methoden die Möglichkeit, das Wissen zu teilen. Entweder direkt – beim Pair Programming – oder indirekt und formalisiert durch Code Review und Analysieren des Feedbacks.