Samstag, 21. November 2009

Rewrite or Refactor?

Das Team arbeitet seid einigen Jahren an dem Produkt. Es ist erfolgreich und verdient gutes Geld. Die Kunden sind glücklich (auch wenn sie sich beschweren, im großen und ganzen sind sie glücklich). Aber hinter den Kulissen brodelt es. Die Entwickler haben keinen Spaß mehr an der Arbeit. Jedes neue Feature braucht länger als das vorhergehende. Das Management muss immer wieder katastrophal hohe Zeitschätzungen entgegennehmen die sich mit keinem Marketingplan vertragen. Die Entwickler werden gedrängt zu sparen und "schneller zu entwickeln, wir haben keine Wahl!". Und irgendwann ist es so weit: die Entwickler nehmen all ihren Mut zusammen und sprechen mit dem Chef.

Entwickler: "Wir können so nicht mehr arbeiten. Das alte System ist verrottet. Natürlich können wir weiter Features einbauen, aber wegen dem schlechten Code wird das immer langsamer werden. Und langsamer. Und langsamer. Das wird richtig teuer und immer teurer! Wir haben nur eine Möglichkeit ... wir müssen das System neu schreiben!".

Chef: "Aber wird das neu schreiben nicht auch teuer? Wird es nicht sehr lange dauern?"

Entwickler: "Natürlich wird es einige Zeit beanspruchen. Aber wir sind auch in einer sehr starken Position. Wir haben all das schon mal gemacht. Wir wissen jetzt genau was das System können muss und können von Anfang an die Anforderungen haargenau definieren. Wir werden viel schneller sein als beim ersten mal denn wir können die Architektur diesmal genau an die Anforderungen anpassen. Wir setzen uns hin, analysieren den alten Code und schreiben die Anforderungsliste haarklein nieder. Dann entwickeln wir die passende Architektur. Und zum Schluss brauchen wir bloß noch alles runter zuschreiben."

Chef: "Na gut, wie lange schätzt ihr denn dass ihr brauchen werdet?"

Entwickler: "Eine exakte Schätzung ist zwar sehr schwierig, aber wir haben uns natürlich schon Gedanken gemacht. Wir denken, dass wir das in drei bis sechs Monaten geschafft haben. Das mag zwar viel klingen, aber die Zeit haben wir schnell wieder raus. Schließlich arbeiten wir dann auf einer sauberen Architektur und können neue Features viel schneller entwickeln."


Nach einigem hin und her sind sich alle einig. Die beste Lösung ist es tatsächlich das System neu zu schreiben und dann auf dem neuen, sauberen, komplett getestetem Code effizient neue Features zu implementieren.

Wird das Erfolg haben?




Konsequenzen

Die Welt steht nicht still. Die Annahme, dass man alle Anforderungen durch eine Analyse der vorhandenen Anwendung gewinnen kann ist naiv. Die Software wird von Kunden verwendet, in einer sich schnell ändernden Welt. Das Management kommt nicht ohne Grund häufig zu den Entwicklern und verlangt "dieses Feature so schnell wie möglich". Den letzten beißen die Hunde und die Konkurrenz schläft nicht. Ein Feature das heute das Geld in die Taschen spült ist in drei Monaten keinen Pfifferling mehr wert. Wenn ein halbes Jahr eingeplant wird um Funktionalität neu zu implementieren die schon vorhanden ist (wenn auch häßlich, schlecht wartbar, nicht erweiterbar ...) dann kommen zwangsläufig während dieser Zeit neue Anforderungen. Und diese können nicht einfach ignoriert werden. Die Kunden erwarten Fortschritt, die Software muss verkauft werden weil jede nicht verkaufte Lizenz bares Geld kostet.

Weil sich die Anforderungen also auch während der Neuentwicklung ändern gibt es zu Anfang der Neuentwicklung keine Chance eine vollständige Anforderungsliste zu erstellen. Genauso wie immer werden sich die Anforderungen während der Entwicklung ändern. Und die Architektur wird unvollkommen sein. Während der Neuentwicklung werden unvorhergesehene Anpassungen vornehmen müssen, was den Gesamtaufwand vergrößert. Die Entwicklung wird länger dauern als geplant war, es werden noch mehr neue Anforderungen kommen und der Druck wird steigen.

Der Druck wird so weit steigen, dass das Management die Entwickler bittet das neue Feature "so schnell wie irgend möglich" einzubauen. Wieder werden Kompromisse gemacht werden. Das Ende vom Lied ist, dass die Anwendung trotz allem guten Willens nach einigen Jahren genauso verrottet ist wie die Alte. Und der Wunsch alles neu zu machen, alles "auf saubere Füße zu stellen", kommt auf. Es ist nichts gewonnen, nur eine Menge Zeit verloren.

Aber was ist die Alternative?


Ursachen

Um die Alternative zu finden muss zuerst das eigentliche Problem erkannt werden. Der alte, verrottete, nicht erweiterbare Code ist nicht schuld. Code kann keine Schuld tragen, es ist nur ein Text. Und dieser ist nur ein Ding, nichts dem man eine Schuld für irgend etwas geben könnte.

Das Management ist auch nicht Schuld. Die Prioritäten des Managements müssen "so viele Features so schnell wie möglich" sein, denn das ist es was die Kunden wollen. Und man kann nicht erwarten das jede Person in der Hierarchie die Probleme der Entwickler versteht, das verstanden wird was es bedeutet wenn der Code verrottet und welche Entscheidungen dazu führen, dass dies geschieht.

Die letztliche Verantwortung über die Qualität der Software kann nur bei den Entwicklern liegen. Nur hier sind alle Informationen und alles Wissen (hoffentlich) verfügbar um die täglichen Entscheidungen zu treffen. Um zu entscheiden: Wird dieses Feature jetzt ganz dreckig rein gehackt, oder müssen wir uns ein klein wenig Zeit nehmen? Ist ist nicht praktikabel jedes mal den Chef zu befragen ob das jetzt so oder so implementiert werden soll. So schwer das ist, diese Verantwortung kann nicht in der Hierarchie weiter nach oben gereicht werden. Die Entwickler müssen an dieser Stelle die Verantwortung akzeptieren und verantwortungsvoll handeln.

Was aber heißt verantwortungsvoll? Es ist verlockend den Leuten "über einem" die Verantwortung zu geben. Auf ein "Wir brauchen dieses Feature so schnell wie möglich" mit einem "Na gut, dann scheiß ich das hier in den Code rein. Ich sag euch das wird nicht lecker, aber ihr habt es so gewollt!" zu reagieren. Der Chef wird ein Lob aussprechen, weil der Entwickler so gute Arbeit macht, die Kollegen werden ihn bewundern, weil dieses harte Feature so schnell erledigt wurde, der Entwickler wird gut dastehen.

Aber er hat nicht verantwortungsvoll gehandelt. Denn die Kosten sind nicht gesunken. Sie sind gestiegen! Code wird einmal geschrieben, aber oft gelesen. Die Kosten um neue Features zu implementieren sind durch die Entscheidung ein klein wenig angestiegen, denn es ist schwieriger neue Features auf Dreck aufzubauen als auf Code der einen Unterstützt. Wenn der Code an einer oder zwei Stellen dreckig ist, weil ein Feature tatsächlich lebensnotwendig für die Firma war, dann kann man damit Leben. Wenn das Dreckige aber zur Gewohnheit wird, dann wird die Entwicklung immer langsamer und langsamer, bis es unmöglich erscheint in dem alten Kram weiter zu arbeiten.

Man kann sich hier der Metapher des Schulden machens bedienen ... ein schnell gehacktes Feature ist wie ein Kauf auf Pump. Man kann damit glänzen, man erhält schnell ein neues Feature, und wenn man es nicht übertreibt ist es auch ok. Aber die Zinslast ist in Form gesunkener Produktivität in der Zukunft zu zahlen, und wenn die Schulden zu hoch werden muss Insolvenz angemeldet werden ... ein Rewrite steht bevor.

Was also kann getan werden?


Alternative

Jeder Entwickler muss für sich seinen Teil der Verantwortung übernehmen. Natürlich kann man immer sagen "Ich habe keine Schuld, der Entwickler vor mir hat nur Müll zurück gelassen!". Aber man muss sich, wenn man längere Zeit an einer vorhandenen Codebasis gearbeitet hat, auch fragen lassen ob es denn besser geworden ist seid man dabei ist. Hat man einfach weiter gemacht wie bisher, oder hat die eigene Arbeit zu Verbesserungen geführt? Ist die Schuldenlast gesunken?

Der komplette Rewrite einer Software ist im Prinzip nichts anderes, als alle Schulden die man im Laufe der Jahre angehäuft hat mit einem Schlag zurück zu zahlen. Oder besser noch: abzuarbeiten. Aber das ist in der Regel ein zu großer Batzen, denn so lange man nur Schulden abarbeitet hat man kein Geld für den Lebensunterhalt. Daher muss eine Strategie der kleinen Schritte gefunden werden. Die Schuld muss Stück für Stück getilgt werden, damit man nebenher noch für seinen Lebensunterhalt arbeiten kann.

Der erste Schritt auf diesem Weg besteht darin keine weiteren Schulden mehr aufzunehmen. Wenn die Entwickler weitermachen wie bisher, also der neue Code nicht besser ist als der Alte, dann wird sich nichts ändern. Neuer Code muss "high quality" sein! Das ist zunächst einmal ungewohnt, weil man zuerst einmal langsamer wird, aber es ist unumgänglich wenn man aus der Falle ausbrechen will.

Der zweite Schritt ist es die Schulden Stück für Stück zurück zu zahlen. Der ganzen Batzen ist zu groß. Aber als Entwickler kann ich mich jedes mal, wenn ich an einer vorhandenen Codestelle arbeiten muss, fragen "Ist das guter Code? Kann ich ihn verbessern? Einfacher machen? Ist es duplizierter Code? Kann ich abstrahieren?". Und ähnliche Fragen. Dabei muss nach meiner Arbeit nicht alles Gold sein. Es muss nur ein wenig besser sein als vorher. Wenn alle Entwickler jedes mal wenn sie arbeiten dafür sorgen, dass der Code ein wenig besser wird, ein wenig der Schuld zurück gezahlt wird, ein klein wenig refactoring betreiben, dann wird die Entwicklung langfristig wieder schneller werden. Das wird nicht innerhalb einiger Wochen geschehen, dafür ist der Code vermutlich schon zu verrottet, aber die kontinuierliche Pflege wird den Patienten wieder auf die Beine bringen.

Das also ist der Weg:
  1. Verantwortung übernehmen
  2. Neuer Code muss guter Code sein
  3. Den alten Code jeden Tag ein wenig verbessern

Martin C. Fowler über "The big redesign in the sky"
Chad Fowler über "The big rewrite"

0 Kommentare:

Kommentar veröffentlichen