“Wenn wir das jetzt anfassen, dann sollten wir es diesmal aber richtig machen.”
Genau diesen Satz habe ich letztens von einem Team in einem schnell wachsenden Unternehmen gehört, ausgesprochen mit einer gehörigen Portion Frustration.
Das Team hatte ambitionierte Ziele, die es auch auf jeden Fall erreichen wollte. Die Diskussion drehte sich um die Frage, wie das Ziel erreicht werden kann. Das Team musste entscheiden, ob sie eine umfangreiche Änderung an der Architektur inkl. Umbau auf ein neues Framework durchführen, um langfristig schneller zu sein, oder ob sie bei der aktuellen Struktur bleiben sollen. Die Diskussion war nicht einfach. Alle sahen das große Risiko mit dem Umbau die Deadline zu reißen und evtl. am Ende gar nichts vorweisen zu können.
Das Team steckte in einem Dilemma: Wie kann man gleichzeitig auf Qualität achten und schnell Lösungen für dringende Anforderungen liefern? Auf der einen Seite ist es wichtig, die Dinge richtig und sauber umzusetzen, um Nutzerprobleme langfristig zu lösen und eine gute Basis für die zukünftige Entwicklung zu schaffen. Auf der anderen Seite müssen schnell Lösungen für ggf. sehr akute Anforderungen / Nutzerprobleme adressiert werden, um Nutzer zufrieden zu stellen und schnell Mehrwert zu bieten.
Beides ist notwendig, um langfristig ein erfolgreiches Produkt zu betreiben. Das Team muss sowohl die Dinge richtig und sauber erledigen als auch schnell sein.
Wie lässt sich dieses Dilemma auflösen? Dahinter stecken ein paar Annahmen, die es sich lohnt genauer anzuschauen.
Annahmen
Alle technischen Schulden sind gleich Dem ist nicht so: Wenn ein Stück Code fast nie angefasst (oder verstanden) werden muss, ist es auch okay es einfach so zu lassen, egal wie unschön es ist. Stattdessen kann man die Zeit besser in Stellen investieren, die in Zukunft oft geändert, gelesen und verstanden werden müssen.
Code kein Selbstzweck, er löst (idealerweise) immer ein Nutzerproblem.
Der Code / die Architektur behindert uns in Zukunft.
Wenn klar ist, was genau ‘in Zukunft’ gemacht werden soll, lohnt es sich evtl. hier Zeit zu investieren. Wenn das ‘in Zukunft’ eher ein unbestimmtes Gefühl ist, lohnt es sich höchstwahrscheinlich nicht. Es kann sich einfach noch zu viel ändern (Lean Prinzip: “Decide as late as possible”).
Unsere Nutzer brauchen sofort eine Lösung.
Nutzerprobleme kommen oft mit einer gewissen Dringlichkeit in der Entwicklung an. Trotzdem kann man die Frage stellen, wie und wie schnell reagiert werden muss. Vielleicht ist es möglich, das Problem in mehreren Schritten anzugehen.
Ansonsten haben wir nicht die Ressourcen, um die Anforderung umzusetzen.
Sollte die Anforderung dann überhaupt umgesetzt werden? Offensichtlich gibt es hier Anforderungen, die in der Priorität höher stehen und mehr Anspruch auf die Ressourcen des Unternehmens haben. Dann ist es - aus meiner Sicht - nicht sinnvoll, die verfügbare Kapazität an der Stelle durch zusätzliche Arbeitslast zu verwässern.
Der Entwickler weiß, wie die richtige / saubere Lösung aussieht
Das ist leider sehr oft nicht der Fall. Wenn ein größerer technischer Umbau von einer Einzelperson (oder kleinen Gruppe) getrieben wird, ist die Wahrscheinlichkeit hoch, dass das Ergebnis mittelmäßig ist oder die Situation sogar verschlechtern kann.
Prinzipien
Aus den Annahmen lassen sich Prinzipien ableiten, die helfen können Technical Debt zu reduzieren und gleichzeitig die Entwicklung voranzutreiben:
-
Allen Entwicklerinnen muss klar sein, wie eine gute Lösung aussieht. Hier helfen Blue Prints (eigene Design Patterns des Teams / des Unternehmens) und eine klares Zielbild / eine klare Zielarchitektur. So können alle verstehen wo Abweichungen liegen und wie das Ideal aussieht.
-
Technical Debt nur dort abbauen, wo es tatsächlich weh tut. Refactorings und Umbauten lohnen sich am meisten an Stellen, die oft angefasst und verstanden werden müssen. Hier kommt die Scout Rule ins Spiel. Immer dann, wenn ein Stück Code verstanden oder bearbeitet werden muss, wird es aufgeräumt (und auch nur dieses Stück Code), so dass es näher an das Zielbild herankommt und die Anforderung leicht umgesetzt werden kann. Dabei ist darauf zu achten, dass der Umbau im Verhältnis zur Anforderung steht.
-
Schlechten Code und unschöne Stellen akzeptieren. Code der nie gelesen oder bearbeitet werden muss, muss nicht aufgeräumt werden, solange er tut was er soll.
-
Fokus auf die wichtigsten Anforderungen. Wenn nicht genug Kapazität (Zeit und Geld) vorhanden ist um eine Anforderung so umzusetzen, dass das System dabei in einem besseren Zustand hinterlassen wird, sollte die Anforderung gar nicht umgesetzt werden. Sie hat im Verhältnis zu anderen Anforderungen zurzeit nicht die notwendige Priorität. Es lohnt sich mehr die Zeit und Energie in die höher priorisierten Anforderungen zu stecken.
-
Unnötige Komplexität vermeiden. Ist das wirklich die einfachste Umsetzung für die Anforderung? Ist die Anforderung wirklich die einfachste Lösung für das Nutzerproblem? Oft sind Nutzerprobleme mit sehr einfachen Mitteln lösbar, wenn man sie einmal richtig verstanden hat.
Das klingt jetzt erstmal alles einfach und teilweise offensichtlich. Wichtig ist, dass der Abbau von Technical Debt und die Weiterentwicklung des Systems für den Nutzer nicht im Widerspruch stehen müssen. Wenn wir die Annahmen hinter diesem Widerspruch hinterfragen und die richtigen Prinzipien ableiten, gibt es die Möglichkeit beides zu bekommen.
Fazit
Um Features sowohl schnell als auch in hoher Qualität zu liefern ist es notwendig ein paar der zentralen Annahmen hinter diesem Konflikt zu benennen und zu hinterfragen. Dieser Artikel ist der erste Schritt dazu.
Qualität und Entwicklungsgeschwindigkeit sind kein Widerspruch: Die Forschung von Forsgren, Humble und Kim 1 hat auf breiter Basis gezeigt, dass die Unternehmen, die ihre Qualität im Griff haben, eine höhere Entwicklungsgeschwindigkeit erreichen.