Beitragsreihe: Clean Code Developer

Code ist schnell mal geschrieben, Lösungen lassen sich zügig herbeiführen und mit etwas Glück halten diese dann auch dem Test der Zeit stand. Um jedoch professionelle Softwarelösungen bieten zu können, gilt es, das Know-How über ein Team hinweg möglichst hoch zu halten. Aus diesem Grunde haben wir uns bereits vor langer Zeit entschlossen, uns fachlich als Team kontinuierlich weiterzuentwickeln.

Als solide Grundlage für ein gemeinsames Qualitätsbewusstsein in der Softwareentwicklung dient uns die "Clean Code Dev" Initiative - abgeleitet aus dem Buch "Clean Code" von Uncle Bob, Robert C. Martin. Unsere erlangten Kenntnisse wollen wir gerne mit Dir teilen und veröffentlichen nachfolgend in unregelmäßigen Abständen kurze Auszüge verschiedener Paradigmen und Ansätze des "CCD".

Was dich bewegt

Häufig gestellte Fragen

Müssen schon mal gar nix... dürfen und können aber sehr wohl. Und zwar darfst Du Dir den jeweiligen Auszug gerne durchlesen, ggf. weiterführende Lektüre dazu suchen und Dich bei Fragen jederzeit melden.
Grundsätzlich einmal für jeden, den es interessiert. Egal ob Frontend oder Backend, egal ob Entwickler, Designer, und Co. Denn Paradigmen der Softwarentwicklung haben keinen unmittelbaren Bezug zur konkreten Programmiersprache sondern sind interdisziplinär zu betrachten und mit ein wenig Transferarbeit im täglichen Arbeitsgeschehen problemlos einsetzbar. Egal ob Du eine CSS Klasse benennst, event-getriebene JavaScript Anwendungen codest oder PHP-Klassen, Entwurfsmuster oder ganze Systeme implementierst. Es beginnt im Kleinen und genau aus diesem Grund ist es auch jeder Einzelne, der das Große Ganze positiv beeinflussen kann.
Zweifellos, denn Softwarequalität ist wie Meditation... nur wer Paradigmen wie ein Mantra regelmäßig wiederholt wird diese verinnerlichen. Wer denkt, er könne schon alles und braucht nicht mehr an sich zu arbeiten, der bleibt über kurz oder lang auf der Stelle stehen. Der Rest winkt dem-, der- oder denjenigen aber dann gerne von weiter vorne aus zu 😉
Lediglich wenige Minuten. Es gibt keine Hausaufgaben, außerdem ist es keine Pflichtveranstaltung oder dergleichen. Wenn Du die paar Minuten allerdings investierst, aufmerksam liest und versuchst Dir das Thema zu Herzen zu nehmen oder Dir gegebenenfalls selbst die Frage stellst inwieweit gerade Du was wo anwenden kannst, dann wird Dir das im Daily Business nachhaltig weiterhelfen.

Nun, damit solltest du jetzt einen groben Eindruck gewonnen haben worum es hier geht. Nachfolgendes Inhaltsverzeichnis gibt dir einen Überblick über die verschiedenen Teilbereiche dieses Beitrags. Wie bereits erwähnt, werden wir diese nach und nach inhaltlich ergänzen. Wir wünschen dir viel Spaß beim Lesen und freuen uns über dein Interesse.

Teil 1Die Pfadfinder-Regel: Hinterlasse einen Ort immer in einem besseren Zustand als du ihn vorgefunden hast

Und los geht's - Wir beginnen gaaaanz einfach, technisch losgelöst und einleuchtend...

Auf die Softwareentwicklung angewandt bedeutet die Pfadfinder-Regel: Clean Code Developer hinterlassen Code immer in einem “besseren Zustand” als sie ihn vorgefunden haben. Nach getaner Arbeit stimmt der Code also mit dem Clean Code Development Wertesystem mehr überein als vorher. Was dafür zu tun ist, hängt stark von der Situation bzw. dem Code ab. Im Sinne des "Baby Step Refactorings" genügt es beispielsweise bereits den Code zu formatieren oder einen veralteten Kommentar zu aktualisieren. Es kommt nicht auf den Impact an sondern auf die Motivation dahinter und den guten Willen.

Teil 2Source Code Konventionen

Wer hätte es gedacht, Code wird häufiger gelesen als geschrieben. Aus diesem Grund ist es wichtig, sich an Konventionen zu halten welche ein schnelles Lesen und Verstehen überhaupt erst möglich machen. Denn: ein guter Programmierer ist jener, der Code so einfach und verständlich schreiben kann dass jeder andere Entwickler - egal welchen Erfahrungsgrads - diesen durch reines Lesen verstehen kann. Ob nun grün oder blau, das ist eine Frage des Ökosystems in dem man sich als Programmierer sowie Team bewegt. Wichtig ist dabei vielmehr das Bewusstseit, dass Konventionen notwendig sind. Dadurch fällt der Fokus auf das Wesentliche und erhöht die Austauschbarkeit von menschlichen Ressourcen. Es gilt daher die einfache Formel: Konvention >= Geschmackssache

Teil 3Principle of Least Astonishment

Wenn sich eine Komponente überraschenderweise anders verhält als erwartet, wird ihre Anwendung unnötig kompliziert und fehleranfällig. Wir alle wissen, Softwareentwicklung ist vielmals auch ein kreativer und vor allem iterativer Prozess. Konzentration auf das Wesentliche ist der Schlüssel zum Ziel. Jetzt stelle man sich nur mal vor, man sitzt am Rechner eines Kollegen, verschränkt seine Finger um einen üblichen Shortcut anzuwenden und plötzlich passiert etwas völlig anderes als man erwartet hätte.

Ein bildhaftes Beispiel... das allerdings Parallelen passend zum Thema aufzeigt. Denn: Software sollte stets überraschungsarm implementiert sein!

Einfaches Beispiel: Wenn die Methode getFirstname() also beispielsweise nicht wie erwartet den Vornamen eines Users zurückgibt sondern zusätzlich noch den Nachnamen des Users ändern würde, kann es nicht nur zu unerwarteten Sideeffects kommen. Der Entwickler, der mit dieser Methode arbeiten muss, wird sie womöglich anpassen (dies verursacht neue Risiken), nur im äußersten Notfall verwenden oder gar gänzlich meiden. Doch wie lassen sich Überraschungen im Code vermeiden? Ein erster, einfacher Schritt ist es Methoden, Variablen oder selbst einfache CSS-Klassen so zu benennen, dass deren reine Aussagekraft möglichst alle Ungewissheit im Vorfeld aus dem Weg räumt. So lassen sich Missverständnisse in der Verwendung von Code weitestgehend beseitigen, noch bevor sie entstehen.

Weiterführende Herangehensweisen und Methoden hierzu, wie etwa das "Integration Operation Segregation Principle", "Separation of Concerns", etc. sind Themen für die Zukunft.

Teil 4You Ain't Gonna Need It (YAGNI)

"Verschwende keine Zeit für Dinge, die nicht benötigt werden." Es ist eines der einfachsten Prinzipien der Softwareentwicklung und dennoch jenes, welches am häufigsten vernachlässigt bzw. missachtet wird. Mangelnde Anforderungsgenauigkeit und die Immaterialität von "Software", die somit von einer nahezu unendlichen Flexibilität geprägt ist (viele Wege führen nach Rom), sind in Kombination der Keim des Misserfolgs vieler Projekte. Ungenaue Anforderungen werden durch hochflexible Implementierungen kompensiert, um gleich im Vorfeld eventuell künftig auftretende Anforderungen mit abzudecken. Durch sich ständig wechselnde Anforderungen (etwa durch die Agilität eines Projekts, unklare Definitionen, iterative Prozesse, etc.) werden insbesondere in Relation zu Zeit und Kosten meist schnelle Lösungen nachgezogen, was der bereits angesprochenen Immaterialität der Software zuzuschreiben ist. Das alles ist jedoch zweifellos kontraproduktiv: "vermeintlich, vorausschauend, eventuell irgendwann auftretende" Probleme oder Aufgaben ohne real existierende Notwendigkeit zu lösen führt zu Overengineering, einer Verbreiterung der Architektur sowie aufgrund der Flexibilität zu einer unnötigen Steigerung der Komplexität. "Schnelles Umbauen" erzeugt zudem den Umstand der sogenannten Qualitätserosion von Code: je mehr man auf die Schnelle umbaut, desto schneller verkommt die Codequalität der Software. Unnötige Aufwände, inkonsequente Architekturen, spröder Code, meist ungetestet. Am Ende entsteht das, das man eigentlich vermeiden wollte: budgetsprengende Projekte, die nach wenigen Jahren unwartbar geworden sind.

Das YAGNI-Prinzip hilft einem dabei, die Spreu vom Weizen zu trennen. Man zerlegt die Aufgabenstellung in kleine Teile, zieht das wirklich notwendige auf die Haben-Seite und trennt somit jene Dinge, die nicht unmittelbar nutzbringend oder gar zweifelhaft sind, vom relevanten Teil ab. Wichtig ist, zu erwähnen, dass YAGNI zu jedem Zeitpunkt eines Projekts, beginnend im Anforderungs- und bis hinter zum Qualitätsmanagement, eingesetzt werden kann und sollte. Wann immer sich Fragen über die Notwendigkeit von etwas stellen. Egal, ob laut ausgesprochen oder für sich selbst gedacht. Die Antwort darauf ist stets die gleiche: "Wenn Zweifel bestehen, entscheide dich gegen den Aufwand!"

Teil 5Baby Step Refactoring

Um Teil 1 unserer Beitragsreihe gerecht zu werden und ein vorbildlicher Pfadfinder zu sein, sollte man Code stets besser hinterlassen als man ihn vorgefunden hat. Dazu sind Eingriffe an bestehendem Code nun einmal nötig. Dem gegenüber steht jedoch der in der IT-Welt allseits bekannte Leitsatz: "Never touch a running system!" Wie also vorgehen?

Das Zauberwort lautet: "Baby Step Refactoring"! Je kleiner und überschaubarer die Maßnahmen, die man ergreift um Code zu verbessern, desto sicherer fühlt man sich. Diese Sicherheit lässt einen zusätzlich den Fokus behalten und reduziert das Risiko, ungewollte Bugs einzubauen, Sideeffects zu erzeugen oder womöglich versehentlich ganze Programmpfade zu eliminieren. Zu den üblichen Tätigkeiten, die unter "Baby Step Refactoring" fallen, gehört beispielsweise das Umbenennen von Methoden, Parametern, Variablen, etc. wo nötig. Die Betonung liegt dabei aber explizit auf "wo nötig"! Variablen- oder Funktionsbezeichnungen umzubenennen, weil sie einem so besser gefallen, entzieht sich nicht nur der fachlichen Grundlage. Es steigt damit das Risiko, dass die eingeführte Bezeichnung - auch wenn sich diese tatsächlich "schöner" lesen möge - aus dem Kontext der Anwendung rutscht. Es gilt also: Umbenennen nur wo nötig!

Wann oder wo also ist es "nötig"? Etwa dann, wenn sich hinter einer Bezeichnung etwas verbirgt, das der beim Lesen entstandenen Erwartung widersprechen würde. Beispiel:

    
        // method seems to return the firstname
        public function getFirstname(): string
        {
            return "John Doe"; // but returns the fullname
        }
    

Wie im Beispiel zu erkennen, gibt die Methode getFirstname() anstatt des Vornamens - so wie man es beim Lesen der Methodenbezeichnung erwarten würde - den gesamten Name des Herrn zurück. Sogenannte "visual debts", also visuelle Zweifel, entstehen und damit auch die Gefahr der kontextuell falschen Anwendung dieser Methode. Um also zu vermeiden, dass ein Entwickler die Methode besten Wissens und Gewissens konsumiert, jedoch auf die falsche Namensgebung "hereinfällt", gilt hier: Umbenennen dringend empfohlen.

Teil 6Don't repeat yourself! (DRY)

Dem Programmierer/Software-Entwickler/IT'ler wird gerne ein gewisses Maß an Faulheit nachgesagt und damit wundert es nicht, wenn "Copy/Paste", "Find/Replace" und Co. als die am häufigsten verwendeten Shortcuts im Alltag eines Entwicklers betitelt werden. Doch einmal Hand auf's Herz - steckt in der Behauptung nicht ein kleines Fünkchen Wahrheit?

Offen gestanden ist man als Entwickler sehr wohl geneigt, hier und da "mal eben" ein paar Zeilen Code zu vervielfältigen. Besonders wenn es schnell gehen muss, das Budget zwickt oder die Lust zum erneuten Umbau (Refactoring) fehlt. Duplizierter Code allerdings verursacht dezentral gestreute, im Worstcase gar identische, Businesslogik. Daraus resultieren:

  • fehlende "Single Version of Truth"
  • Verbreiterung der Softwarearchitektur
  • potenzielle Bugs werden womöglich nicht an jeder betroffenen Stelle behoben
  • Lines of Code (LoC) nehmen unnötig zu
  • künftige Modifikationen müssen an mehreren Stellen erfolgen
  • sinkende Kohäsion
  • steigende Kopplung zwischen Klassen und Methoden
  • ...

Wenn die Lösung für alle eben genannten Probleme es wäre, ggf. ein paar Zeilen Code in eine extra Methode oder Klasse zu extrahieren... warum dann nicht tun?

Die Vorteile liegen schließlich auf der Hand. Und noch ein Vorteil ergibt sich daraus: Wird Code extrahiert, wandelt sich automatisch die interne Struktur sowie die Art der Verwendung. Ein Umstand der es bei geschickter Vorgehensweise ermöglicht den Code gleich so zu gestalten, dass er testbar ist d.h. dessen Funktionalität durch Unit Tests abgedeckt werden kann.

Don't repeat yourself! Wiederhole dich nicht! Niemals! ;-)

Teil 7Keep it simple, stupid! (KISS)

Als Programmierer stellt man im Laufe seiner Karriere irgendwann fest, dass "KISS" nicht nur eine amerikanische Hard-Rock-Band mit Kultstatus ist. Hinter dem Akronym "KISS" verbirgt sich tatsächlich auch ein Paradigma aus der Softwareentwicklung.

Manchmal entsprechen einfache, bekannte oder gar naheliegende Lösungen nicht dem eigenen Anspruch. Das muss man sich einfach auch mal eingestehen. Dies hat jedoch zur Folge, dass womöglich Lösungen entstehen die komplexer sind als es notwendig gewesen wäre. Im Übrigen gilt das nicht allein für Businesslogik, ebenfalls bei Datenstrukturen und Prozessen besteht ein nicht unwesentliches Risiko von "Overengineering". Dadurch entstandene komplizierte/komplexe Lösungen und Ansätze hängen dem Projekt allerdings nach. Ferner riskieren sie, sich selbst nur schwer ablösbar zu machen. Komplexer Code tendiert außerdem dazu, schlecht testbar zu sein und mutiert zu einem "besser nicht anfassen" Teil der Softwarearchitektur bzw. -landschaft.

Doch was tun um auch in komplexen Anwendungsfällen ein möglichst einfaches Ergebnis zu erhalten? Blindlings darauf zu vertrauen, dass es für jedes Problem ein geeignetes Designpattern gibt und dieses einzusetzen ist jedoch keine adäquate Lösung! Designpattern haben sehr wohl ihre Berechtigung und gewisse Themen erfordern sogar den Einsatz solcher Entwurfsmuster. "Einfacher" gestalten Pattern die Softwarearchitektur allerdings in vielen Fällen nicht oder nur geringfügig.

Stattdessen hilft es, sprechende, verständliche und möglichst kurze Methoden zu schreiben durch die eine minimalistische und nachvollziehbare Lösungs erreicht werden kann. Zumindest für den ersten Wurf, den technischen Durchstich, ist das ein völlig valider Weg und spart nicht nur Zeit sondern eliminiert ganz nebenbei auch noch Mehraufwand für die Einarbeitung in Strukturen, die Bereitstellung neuer Konstrukte in der Softwarelandschaft und auch die Dokumentation, die bei größeren Gebilden ebenfalls benötigt würde.