Blog

Wie man beim Schreiben von schlechtem Code scheitert

Age Mooij

Aktualisiert Oktober 22, 2025
4 Minuten

Der Versuch, schlechten Code zu produzieren, ist ziemlich schwierig, wenn Sie Test Driven Development (TDD) verwenden, selbst wenn Sie es absichtlich falsch machen. Kürzlich bereiteten Iwein und ich einige Übungen für eine Entwicklerschulung vor und der Plan war, als Ausgangspunkt einen wirklich schlechten Java-Code zu erstellen. Die Studenten sollten ihn dann bereinigen und neue Funktionen hinzufügen, natürlich in der Absicht, die Auswirkungen schlechter Codequalität auf Ihre Fähigkeit, schnell neue Funktionen hinzuzufügen, zu zeigen. Das sollte ein Kinderspiel werden! Nach einigem Brainstorming für interessante eigenständige Programmieraufgaben kamen wir auf die Idee, einen JSON-zu-XML-Konverter zu schreiben. Er sollte in der Lage sein, jeden gültigen JSON-String in eine einfache XML-Darstellung zu konvertieren. Aus Gewohnheit und ohne wirklich die Möglichkeit in Betracht zu ziehen, diesen Schritt zu überspringen, begannen wir mit einem einfachen fehlgeschlagenen Test. Hier ist er: [java] @Test public void shouldConvertTopLevelEmptyArray() { assertThat(converter.convert("[]"), is("<array></array>")); } [/java] Einfach, oder? Um unseren Konverter zu implementieren, entschieden wir uns für das bekannte Anti-Muster "Rot, Grün, so wenig Refactoring wie möglich". Wir erwarteten, dass dies zu vielen Copy-Paste-Duplikaten, sehr langen Methoden und den anderen typischen Codegerüchen führen würde, die wir alle kennen und verabscheuen. Unser erster Implementierungsansatz bestand darin, einige der beliebtesten Kandidaten für die Produktion von schlechtem Code zu verwenden: Stringmanipulation und reguläre Ausdrücke. Wie Jamie Zawinski bekanntlich sagte: "Wenn manche Leute ein Problem haben, denken sie: 'Ich weiß, ich werde reguläre Ausdrücke verwenden'. Dann haben sie zwei Probleme." Wir hatten ein sicheres Rezept für eine Katastrophe geschaffen. Von nun an sollte es nur noch bergab gehen, zumindest dachten wir das.

Dies funktionierte eine Zeit lang gut und führte zu grünen Tests und einer langsam wachsenden, einzigen langen Konvertierungsmethode, die wirklich etwas Aufräumarbeit gebrauchen könnte. Leider mussten wir bald feststellen, dass wir uns in eine Ecke programmiert hatten, als wir die ersten Tests für das Parsen verschachtelter Objekte und Arrays schrieben. Es schien, als bräuchten wir eine Form der Rekursion und das passte einfach nicht zu der Richtung, in die wir uns entwickelt hatten.Ich würde nicht sagen, dass es unmöglich ist, dieses Problem nur mit regulären Ausdrücken und ohne Rekursion zu lösen, aber es ist definitiv ziemlich schwierig. Das ist kein Problem, wenn man es nur unter dem Gesichtspunkt betrachtet, schlechten Code zu schreiben, aber wir haben uns selbst unterschätzt, was die Fähigkeit angeht, schlechten Code zu schreiben , der tatsächlich funktioniert. Dies erwies sich als das grundlegende Problem unseres Vorhabens. Wir dachten, es wäre einfacher, die Eingabe zeichenweise zu analysieren, und dass dies immer noch genügend Spielraum für die Schaffung von Schrecken jenseits aller Vorstellungskraft lassen würde. Mit dem ersten Teil hatten wir Recht. Das rekursive Parsen eines einfachen Formats ist so mühsam wie jede Parser-Schreibübung, aber es ist nicht schwer. Dann begann etwas Interessantes zu passieren. Jedes Mal, wenn wir ein kleines funktionales Problem behoben hatten, indem wir den schlechten Code, den wir gerade produziert hatten, debuggten, wurde er immer weniger schlecht. Als es am Ende funktionierte, stellte sich heraus, dass wir das primäre Ziel nicht sehr gut erreicht hatten. Wir saßen ein wenig erstaunt da. "Das ist nicht annähernd so schlimm, wie ich erwartet hatte..." "Ich habe schon viel Schlimmeres gesehen" "Ich würde das in die Produktion gehen lassen, ohne viel Schlaf zu verlieren". Einerseits ist es beruhigend zu wissen, dass Sie nicht in der Lage sind, den Mist zu produzieren, den Sie bei Ihren Rezensionen ständig sehen, oder sogar die Art von Mist, die wir selbst noch vor ein paar Jahren geschrieben haben. Auf der anderen Seite ist es enttäuschend. Aber woran liegt es, dass wir versagt haben? Es gibt zwei unbewusste Verhaltensweisen, die hier im Weg waren:

  • haben wir versucht, "altbekannte" Fallen zu vermeiden, d.h. die Fehler, die wir so oft gemacht haben, dass wir sie automatisch vermeiden.
  • wir haben kleine Schritte unternommen, um uns nicht zu verirren Diese Verhaltensweisen werden im Allgemeinen von TDD unterstützt und erzwungen. Wären wir uns dessen bewusster gewesen, hätten wir schon beim ersten Test gewusst, dass er nicht zu übermäßig komplexem Code führen würde: Wenn Sie mit einem möglichst einfachen fehlgeschlagenen Test beginnen und die Komplexität (d.h. neue fehlgeschlagene Tests) in kleinen Schritten hinzufügen, machen Sie es sich nur besonders schwer, den gewünschten Haufen Mist zu produzieren! Wenn wir während der Fehlersuche einen Test hinzugefügt haben, der auf unerwartete Weise fehlgeschlagen ist, haben wir kleine Refactorings vorgenommen, um Probleme leichter zu debuggen oder einfacher zu lösen, was fast automatisch zu einem modulareren und einfacheren Code geführt hat. Wenn man es sich also leicht macht, erhält man einfachen und lesbaren Code. Wer hätte das gedacht (Puh!). Schauen Sie sich selbst die Tests an, mit denen wir gearbeitet haben, und den daraus resultierenden Code. Er ist definitiv nicht so sauber, wie er sein könnte, oder die eleganteste Lösung, aber ist das wirklich schlechter Code? Was meinen Sie dazu?

Verfasst von

Age Mooij

Contact

Let’s discuss how we can support your journey.