Marcel Cremer
24. Oktober 2022

Die 7 Arten der Verschwendung in der Softwareentwicklung

Gepostet am 24. Oktober 2022  •  8 Minuten  • 1602 Wörter  • Andere Sprachen:  English

Wie vermutlich jeder weiß, bin ich ein großer Fan von Lean Development. Die Konzepte von Lean Development gehen auf die Lean Manufactoring Methodik zurück, die die Produktion von Toyota in der Mitte des 20ten Jahrunderts sehr erfolgreich und in Teilen sogar zum Marktführer gemacht haben. So wie Toyota die eigene Produktion optimiert hat, kann auch die Softwareentwicklung sehr viel effizienter sein, wenn wir die Lean Prinzipien in unserer täglichen Arbeit beachten. Da ein kompletter Überblick über die Lean Development Prinzipien in einem Artikel nicht möglich ist, konzentrieren wir uns heute auf die sieben Arten der Verschwendung in der Softwareentwicklung.

Was bedeutet “Verschwendung”

Wie in der Einleitung beschrieben, hat Lean Development seinen Ursprung in den Konzepten von Lean Manufacturing. Wenn man sich eine beliebige Produktionslinie anschaut, bemerkt man sehr schnell, dass während der Produktion Ressourcen “verschwendet” werden, beziehungsweise das “Abfall” entsteht. So ist es zum Beispiel unumgänglich, dass

All diese Arten der Verschwendung sind in physikalischen Produktionsprozessen ziemlich offensichtlich, aber existieren sie auch in der Softwareentwicklung?

Die Antwort ist natürlich ja - es gibt Arten von Verschwendung in der Softwareentwicklung, die aber auf den ersten Blick nicht ersichtlich sind. Also schauen wir uns diese doch einmal näher an.

Teilweise erledigte Arbeiten

Weil diese Art der Verschwendung in der Softwareentwicklung meiner Meinung nach die größte Rolle spielt, möchte ich sie gleich zu Anfang nennen. Ist dir schon einmal aufgefallen, dass Software, obwohl sie bereits programmiert wurde, häufig erst sehr spät ausgeliefert wird? Das kann unterschiedliche Gründe haben - teilweise sind sie sogar prozessual gewollt. Als Beispiel dafür kann man “time boxed” Releaszyklen nenn - egal, ob sie aufgrund von halbjährlichen Releases oder wöchentlichen Sprints geplant werden. Zum Teil wird entwickelte Software sogar gar nicht mehr ausgeliefert, weil die Hauptapplikation sich zwischen Entwicklung und Auslieferung soweit verändert hat, dass die Änderungen nicht mehr kompatibel sind. Leider ist dies kein Einzelphänomen und passiert täglich, weshalb “teilweise erledigte Arbeiten” so teuer sind.

Um das metaphorisch zu verdeutlichen:
Stell dir einmal vor, du betreibst eine Autofabrik und stellst 24 / 7 einen Auspuff nach dem anderen her. Das Problem: Du kannst nur einen Motor pro Monat beziehen und damit nur ein Auto pro Monat ausliefern. Was würde passieren? Natürlich: Dein Lager wäre bis unters Dach mit Auspuffen gefüllt. Diese würden vielleicht sogar Arbeiten an anderen Arbeitsstationen blockieren, weil sie so viel Platz einnehmen. Genauso ist es in der Softwareentwicklung.

Wenn wir immer weiter verschiedene Bugs fixen und Features implementieren ohne diese auszuliefern, haben wir einen Haufen verschiedener Puzzleteile in unserem “Software-Lagerhaus”, die die Prozesse verstopfen und keinen echten Nutzen bringen. Nur wenn wir es schaffen, diese möglichst schnell in das Produkt zu integrieren, fangen sie an, für die Nutzer sowie den Softwarehersteller wertvoll zu werden. Aus diesem Grund sollten wir den Prozess soweit wie möglich dahingehend optimieren, dass wir kleine Teile der Software entwickeln und diese so schnell wie möglich releasen. Das “verrotten” lassen von entwickelten Features oder Bugfixes, weil die Hauptsoftware sich während der “Lagerung” ändert, sollten wir unter allen Umständen vermeiden.

Überproduktion

Ähnlich wie bei dem ersten Beispiel von Verschwendung, können wir unser “Software-Lagerhaus” auch mit Dingen zumüllen, die nie gefragt wurden und die niemals gebraucht werden. Wenn wir versuchen, Features zu implementieren, nur weil wir diese für sinnvoll halten, diese aber am Ende vom User nicht genutzt werden und auch keine Verkäufe erleichtern, haben wir uns selbst eine Arbeitsbeschaffungsmaßnahme geschaffen, die dazu auch noch sehr teuer war. Viel schlimmer noch: Diese Extra-Features müssen über die Zeit gewartet werden und erzeugen dadurch sogar noch mehr Kosten, je länger sie in einem Produkt sind. Aus diesem Grund sollten wir das YAGNI Prinzip (You ain’t gonna need it) unter allen Umständen beherzigen - egal wie “cool” wir unsere eigenen Ideen finden - und nur Dinge implementieren, die auch wirklich gebraucht werden.

Unnütze Prozesschritte

Eine weitere Art von Verschwendung, sind unnütze Prozesschritte. “Unnütz” sind Prozesschritte immer dann, wenn wir etwas in den Prozess implementieren, was keinen weiteren Nutzen stiftet. Ein Beispiel: In unserer Firma ist die Qualitätssicherung dafür verantwortlich, das Deployment von Releases anzustoßen, was eher ungewöhnlich ist. Warum QA? Weil QA die letzte Station ist, die an einer bestimmten Aufgabe arbeitet. Wenn sie alles getestet haben, es freigeben und sagen, es kann deployed werden, was für einen Sinn hat es dann, dass sie den Ball wieder Dev oder Ops oder jemand anderem zuspielen, nur damit der symbolische “Knopf” für das Release gedrückt wird? Ohne irgendeinen Nutzen zu stiften, bauen wir neue Wartezeiten in unseren Prozess ein, die die Kunden davon abhalten, das Feature oder den Bugfix zu erhalten.

Noch einmal zum mitschreiben: Jeder Schritt in einem Prozess, der nur aufgrund von Regeln, übermäßigem Kontrollwahn oder ähnlichem implementiert wird, und der unser Stück Software kein bisschen besser macht, sollte sofort gestrichen werden.

Aufgaben- oder Kontext-Switching

Hast du dich jemals gefragt, warum es häufig so lange dauert, wenn man ein eigenes Motiv auf ein T-Shirt drucken lassen möchte? Um Bilder auf Kleidung zu drucken sind häufig recht schwere Maschinen nötig. Diese Maschinen müssen für einen Motivwechseln in der Regel entweder umprogrammiert werden, oder es müssen Druckplatten, Farben oder “Drucksiebe” gewechselt werden, bevor man mit dem eigentlichen Druck loslegen kann. Aus diesem Grund ist es auch viel einfacher, 1000 T-Shirts mit dem gleichen Motiv zu drucken, als 5 Shirts mit jeweils unterschiedlichen. Die Onboarding-Zeit killt hier jegliche Produktivität.

Das gleiche gilt für die Softwareentwicklung:
Jedes Mal, wenn ein Entwickler die Aufgabe wechselt, muss man mit einer “Onboardingzeit” rechnen. Wenn gerade an einer anderen Aufgabe gearbeitet wurde, muss zum Beispiel die aktuelle Änderung commited und die Branch gewechselt werden, man muss sich in die neue Aufgabe einlesen, diese verstehen und dann implementieren. Und wenn die Implementierung abgeschlossen ist, muss wieder commited und ein PR aufgemacht werden, man muss zurück in die andere Branch wechseln und herausfinden, wo man denn vorher aufgehört hat.

Kontext-Switching ist ziemlich teuer und selbst eine 5-Minuten-Aufgabe kann sehr schnell, sehr viele Ressourcen fressen - vor allem, wenn es öfter vorkommen. Aus diesem Grund sollte Kontext-Switching unter allen Umständen vermieden werden.

Warten auf andere / Verzögerungen

Ein weiterer Typ von Verschwendung ist es, wenn unsere “Entwicklerressourcen” warten müssen. Das kann passieren, wenn Spezifikationen fehlen, man auf andere Entwicklung warten muss oder es andere Blocker gibt, die den Entwicklungsprozess aufhalten und die Weiterarbeit verhindern. Desweiteren können Verzögerungen sehr teuer werden, zum Beispiel wenn für die Devs nur alte Hardware ausgegeben wird und deshalb eine Ewigkeit auf automatisierte Tests oder das Kompilieren der Software gewartet werden muss. Schlecht sind auch zu wenig Ressourcen für die CI / CD Prozesse um “Geld zu sparen”, weil Entwickler zum Teil Stunden auf das Feedback warten, dass sie noch einen kleinen linting Fehler haben. Außerdem führen diese Arten von Wartezeiten häufig zu Kontext-Switching (man will ja “produktiv” sein), weshalb das Warten bzw. Verzögerungen im Prozess gleich doppelte Verschwendung ist.

Übergaben

Jedes Mal, wenn die Person, die eine Aufgabe bearbeitet, sich ändert, verschwendet man in gewisser Art und Weise Ressourcen. Das kommt daher, dass man nie das gleiche Informationslevel bei allen Beteiligten erreichen kann und sich jeder und jede immer wieder neu in die Aufgabe einarbeiten muss. Zum Teil müssen Informationen eingefordert werden oder die gleichen Fehler, die an anderer Stelle schon einmal gemacht wurden, werden erneut gemacht. Das wird besonders dann zu einem Ressourcenfresser, wenn Aufgaben innerhalb des Prozesses vor- und zurückwandern, weil diese dann öfters durch verschiedene Hände gehen.

Diese Art von Verschwendung kann man nicht vermeiden, aber dafür soweit wie möglich reduzieren, indem man Informationen nach Möglichkeit an alle Beteiligten verteilt, diese von Anfang an miteinander arbeiten lässt und Feedbackzyklen verkürzt. Außerdem sollten Learnings, die für andere wichtig sein könnten immer dokumentiert werden und an jeder Arbeitsstation daran gedacht werden, wer noch mit dieser Aufgabe in Berührung kommt. So könnte man zum Beispiel während der Entwicklung eine Notiz für QA hinterlassen, falls die Änderung Seiteneffekte haben könnte, die von außen gesehen nicht logisch, aber vom Code her unter Umständen auftreten können.

Fehler

Ich höre öfter den “Witz”, das Software schnell oder mit hoher Qualität gebaut werden kann und man sich eins davon aussuchen soll. Ich persönlich kann dem nichts abgewinnen, denn wenn die Softwarequalität gering ist, wird die Weiterentwicklung automatisch langsam. Um eine hohe Geschwindigkeit bei der Auslieferung neuer Features zu haben, muss man Fehler so gut wie irgendmöglich vermeiden.

Stellen wir uns mal vor wir haben einen Fehler - egal wie groß oder klein:
Sobald dieser Fehler gefunden wurde, zum Beispiel beim Testing von QA oder von automatisierten Tests während dem Deployment, fängt die Verschwendung von Ressourcen sofort an: Jemand muss sich den Fehler anschauen, versuchen ihn zu reproduzieren und zu debuggen. Danach muss die Grundursache dokumentiert werden und im schlimmsten Fall eine Übergabe an einen anderen Dev erfolgen. Diese/r muss womöglich einen Kontext-Switch (!) machen, um an einer Fehlerlösung zu arbeiten. Danach geht das Feature, was eigentlich schon fertig war, noch einmal durch den kompletten “Produktionsprozess” in der Hoffnung, dass jetzt alles funktioniert.

Fehler sind im Bezug auf die Ressourcenhöhe die schlimmste Art der Verschwendung, weil jedes Mal, wenn ein Fehler auftritt, verschiedene andere Schritte angestoßen werden, die alle erneut Ressourcen verschwenden. Um das zu verhindern, sollte man die Anzahl von Feedback im Prozess erhöhen sowie die Zeit zwischen den verschiedenen Feedbackzyklen verringen. Außerdem sollte man fertiggestellten Code so schnell wie möglich in das Hauptprodukt integrieren und so oft wie möglich ausliefern, weil manche Fehler nur auftreten, wenn echte User die Software verwenden. Eine hohe Entwicklungsgeschwindigkeit ohne hohe Softwarequalität ist aus meiner Sicht einfach nicht möglich.

Follow me

I work on tech-related stuff, manage people and sometimes give some talks