Warum viele Entwickler zu früh aufhören und wie du bessere Software baust
Ich höre es immer wieder:
“Es funktioniert doch.”
Und jedes Mal zucke ich innerlich ein bisschen zusammen.
Versteh mich nicht falsch: Funktionierender Code ist großartig. Aber “funktioniert” ist nicht das Ziel, es ist der Anfang. Wärst du mit einem Heizungsbauer zufrieden, der dein Haus anzündet, damit es warm wird?
Ich möchte heute darüber sprechen, warum Funktionieren in der Softwareentwicklung einfach nicht reicht und warum du niemals ein echter Senior Entwickler sein kannst, wenn du dich auf Funktionieren ausruhst.
Wenn “funktioniert” das Ende ist.
Ich sehe es regelmäßig: Ein Feature ist fertig, die Tests laufen durch, der Pull Request ist offen und als Begründung steht da:
“Es funktioniert.”
Doch was heißt das eigentlich? Funktioniert in welchem Kontext? Heute? Auf deiner Maschine? Oder auch noch in sechs Monaten, wenn jemand anderes den Code anfassen muss? Hier fängt die eigentliche Arbeit erst an. Denn Code, der nur funktioniert, löst heute ein Problem, aber schafft oft das nächste für morgen.
Die unsichtbaren Anforderungen
Funktionieren ist einfach messbar. Wartbarkeit, Lesbarkeit, Wiederverwendbarkeit sind es nicht und genau deshalb werden sie zu oft ignoriert.
Aber frag dich einmal ehrlich:
- Wirst du in einem halben Jahr noch verstehen, was du da gebaut hast?
- Kann jemand anderes diesen Code erweitern, ohne Angst zu haben, dass alles auseinanderfällt?
- Wird es Spaß machen, deinen Code zu verwenden?
Ein paar Beispiele, wo “funktionieren” nicht reicht:
Wartbarkeit
Nur weil etwas läuft, heißt das nicht, dass es jemand versteht. Wenn du deinen eigenen Code nach sechs Monaten liest, weißt du dann noch, was du dir dabei gedacht hast? In nahezu allen Projekten wirst du später Anpassungen machen müssen. Seien es geänderte Anforderungen oder später entdeckte Fehler. Du musst dich also von Beginn an darauf einstellen, dass du deinen Code nochmals anfassen musst, und dafür musst du in der Lage sein, ihn zu verstehen.
Wiederverwendbarkeit
Schreibst du Code nur für den einen Anwendungsfall oder so, dass er auch morgen noch nützlich ist? Manchmal reicht ein kleiner Perspektivwechsel, um aus einem “Quick Fix” ein wiederverwendbares Bauteil zu machen. Ein einfaches Beispiel könnte ein Logger sein. Wenn du beispielsweise in NodeJS etwas loggen willst, wirst du geneigt sein, einfach ein console.log in deinen Code zu schreiben. Alternativ könntest du dir eine Klasse Logger schreiben, die dann auch verschiedene LogLevel oder Ausgabekanäle unterstützen könnte. Durch die durchgängige Verwendung deiner Klasse im Projekt kannst du das Logging einfach anpassen, ohne viel Code zu ändern. Und wenn du es in einem anderen Projekt auch brauchst, kopierst du einfach die Klasse oder erstellst daraus eine Bibliothek.
Ich werde häufig gefragt, wie ich Probleme so schnell lösen kann. Die Antwort ist einfach: Ich habe einen Werkzeugkasten an fertigen Lösungen. Diese Lösungen sind über Jahre entstanden und ich kann immer wieder darauf zurückgreifen. Das heißt nicht zwangsläufig, dass der Code fertig in der Schublade liegt, aber da ich das Problem in meinem Kopf bereits gelöst habe, kann ich immer wieder darauf zurückgreifen.
Dieser Werkzeugkasten ist ein elementarer Baustein auf deiner Reise zum Senior Entwickler.
Komplexität der Nutzung
Komplexität verschwindet nicht, sie verlagert sich. Du kannst sie in deinen Code stecken oder deinen Nutzern aufbürden. Wenn du willst, dass dein System erweiterbar bleibt, dann “versteck” die Komplexität da, wo sie hingehört, nicht in den Stellen, die oft angefasst werden.
Ein einfaches Beispiel dazu: Stell dir vor, du entwickelst einen Service für die Erstellung eines Produkt-Feeds. Dazu sollen die Informationen von einer Shop-API abgerufen und als CSV bereitgestellt werden. Anhand dieses Beispiels solltest du dir die folgende Frage stellen:
“Welcher Teil wird sich vermutlich ändern?”
Ich sehe an diesen Stellen Potenzial:
- Du musst eine zusätzliche Datenquelle hinzufügen (der Feed soll um Lagerbestände aus der Warenwirtschaft ergänzt werden).
- Aus den bestehenden Datenquellen sollen zusätzliche Felder in den Feed übernommen werden.
Genau diese zwei Punkte sind für mich Beispiele, bei denen die Komplexität so gering wie möglich sein sollte. Die zusätzliche Datenquelle könnten wir über einen abstrakten DataProvider deklarieren, der eine getBySku-Methode oder einen Iterator erfordert. Für die Definition der Felder verwendest du Config-Dateien oder Mapper-Klassen. Das sind die Bereiche, die so einfach und intuitiv wie möglich sein müssen. So können wir die Komplexität für das Bauen des Feeds in CSV, das Verarbeiten der Mapper und Sonstiges im Inneren des Codes “verstecken”, und die Erweiterung wird für dich und deinen Nachfolger so einfach und günstig wie möglich gestaltet.
Namen und Verständlichkeit
Du wirst immer wieder damit konfrontiert sein, Dinge zu benennen. Neben einheitlichen Schreibweisen solltest du dir aber auch über die tatsächliche Benennung von zum Beispiel Funktionen, Variablen und Klassen Gedanken machen. Im ersten Moment mag es absurd erscheinen, deine kostbare Zeit in den Namen einer einzelnen Funktion zu stecken, aber langfristig wird es dir unglaublich helfen.
Warum hören wir auf, wenn es funktioniert?
Ich habe mir oft die Frage gestellt, warum so viele Entwickler aufhören, wenn es “läuft”. Vielleicht erkennst du dich ja in einem dieser Punkte wieder:
- Du kannst es (noch) nicht besser.
- Du hast keine Lust mehr.
- Du stehst unter Druck, endlich fertig zu werden.
- Du willst zeigen, dass du schnell liefern kannst.
Egal, welcher Grund es ist: Sie sind alle menschlich. Aber als Entwickler und besonders, wenn du Senior werden möchtest, musst du lernen, trotzdem weiterzugehen. Auch wenn dein Vorgesetzter dich unter Druck setzt, ist es deine Aufgabe als Senior, für die Qualität deiner Arbeit und damit auch die notwendige Zeit einzustehen.
Der Unterschied zwischen “funktioniert” und “gut gemacht”:
Ein Senior-Entwickler hört nicht auf, wenn etwas funktioniert. Er (oder sie) fragt sich:
- Kann das jemand anderes verstehen?
- Kann ich es morgen anpassen, ohne alles neu zu schreiben?
- Habe ich die Komplexität an der richtigen Stelle?
- Ist der Code so geschrieben, dass er sich erklärt, auch ohne Kommentar?
Denn Software ist nie fertig. Aber sie kann gut sein. Und guter Code ist nicht der, der einfach nur läuft, sondern der, der lebt, wächst und gepflegt werden kann.
Fazit
Funktionieren ist das Minimum. Wartbar, erweiterbar, verständlich, das ist unser Anspruch.
Also, wenn du das nächste Mal einen PR öffnest und schreiben willst: “Es funktioniert”, dann frag dich: “Und was passiert morgen?”
Mach es besser. Nicht weil du musst, sondern weil du kannst. Denn genau das macht dich zum Senior.