{{historisch}}[[Kategorie:Themenabend]][[Kategorie:2015]]
{{Themenabend | TITEL= Clean Code | UNTERTITEL= | TERMIN= 23.07.2015 | ORT= HQ | THEMA= | REFERENTEN= Nico Krebs | C3D2WEB= http://www.c3d2.de/news/ta-clean-code.html | TOPIC= | SLIDES= [[Themenabend/Clean Code]] }}
__TOC__
How to code
_______        _______ _______ __   _      _______  _____  ______  _______
|       |      |______ |_____| | \  |      |       |     | |     \ |______
|_____  |_____ |______ |     | |  \_|      |_____  |_____| |_____/ |______
; name: Nico Krebs ; blog: [http://www.mensch-und-maschine.de www.mensch-und-maschine.de] ; work:[http://www.projektmotor.de www.projektmotor.de] ; mail: nkoding@gmail.com Alles, was im Folgenden beschrieben wird, ist eine Utopie, ein nie erreichbares Ideal und keine dogmatische Handungsanweisung. Doch ich versuche mich, so nah wie möglich da heran zu bringen - immer pragmatisch auf den Anwendungsfall bezogen. Jeder der folgenden Vorschläge kann für sich allein angewendet werden, man muss nicht das ''Komplettpaket'' einbauen, sondern man sollte sich heraussuchen, was praktikabel ist. == Warum sind wir hier? == Wir alle haben das schon erlebt und wollen es in Zukunft vermeiden: * Projekte werden mit der Zeit immer träger. * Neue Features implementieren dauert länger, je mehr Features es gibt. * Bugs fixt man nicht mehr in Minuten sondern in Wochen oder Monaten (z.b. wenn Architekturfehler erst spät sichtbar werden). * Evtl. wird ein paralleles Projekt gestartet, das alles besser machen soll - aber dann dieselben Methoden verwendet. * Beide Arbeitsgruppen konkurrieren, keine kommt wirklich voran. * User sind unzufrieden. * Das Projekt stirbt an seiner Größe und die Firma ggf. gleich mit. * Es gibt sehr viele Sicherheitslücken im Projekt. * Bekannteres Bsp.: flash. Vermutlich ist das Code mit ähnlichen Eigenschaften. Entsprechend anfällig ist das Ganze für Sicherheitslücken. == Wie kommt man aus diesem Teufelskreis? == === Analyse: Was ist schlechter Code und warum? === * große Funktionen und Klassen/Scriptfiles * eine Funktion erledigt viele Aufgaben * Abhängigkeiten sind hard coded * Verschachtelte Schleifen und Konstrukte wie Branches ("switch" und "if/then/else") werden häufig genutzt. * Logik befindet sich innerhalb von if-Blöcken. * Klassen-/Funktions-/Variablennamen sind nicht aussagekräftig. * Funktionen mit vielen Parametern * Um den Code nachzuvollziehen, muss ständig zwischen Dateien gewechselt und darin über mehrere hundert/tausend Zeilen gescrollt werden. * Funktionen sind schlecht oder gar nicht testbar, weil ein Testcase so komplex werden würden, dass sie selbst Tests bräuchten. * im worst case GOTO-Anweisungen * hohe Wahrscheinlichkeit von Sicherheitslücken
=> Spaghetti code === Im Umfeld schlechten Codes findet man häufig auch: === * keine automatischen Tests, weil untestbar (z.b. jUnit) * keine Versionskontrolle (z.B. git) * kein Ticketsystem (z.B. Redmine) * kein CI-System (z.b. Jenkins/Hudson) * keine Nutzung von IDEs (z.B. NetBeans) * keine Dokumentation * keine leistungsfähigen Kommunikationskanäle (twitter/foren/chat/...), sondern höchstens per E-Mail-/Telefonsupport === Was ist sauberer Code? === * verständlich im Hinblick auf Leistungsfähigkeit des Gehirns (drei bis sieben Elemente im Kurzzeitgedächtnis) * lesbar wie ein Buch * Eine Funktion hat genau eine Funktion. * wenige Kontrollkonstrukte * strikte Trennung von Logik und Fehlerprüfung * testbare Funktionen und Klassen * Nutzung von Test Driven Development, Ticketsystem, Buildsystem etc., um sich selbst zu organisieren und Überblick zu behalten === Wie schreibt man sauberen Code? === ==== Leistungsfähigkeit des Gehirns als Grundlage ==== * möglichst drei bis sieben Packages pro Modul/Plugin * möglichst drei bis sieben Klassen pro Package * möglichst nicht mehr als sieben Funktionen pro Klasse -> besser drei * möglichst drei bis sieben Zeilen Logik pro Funktion * Klassen müssen so geplant oder refaktoriert werden, dass sie möglichst wenige hard coded Abhängigkeiten haben. * Kommentare möglichst vermeiden, da sie meist sowieso nicht gepflegt werden. Besser sind selbsterklärende Funktions- und Variablennamen. * Ein doc-Block für API-Methoden muss jedoch sein (für die User der API). ==== Lesbar wie ein Buch ==== * Buch = Modul * Packagenames = Kapitelüberschriften * Kapitel = Sammlung von Klassen * Buchseite = Klasse * aufgerufene Funktionen immer im Code unter der aufrufenden schreiben * sinnvolle Funktionsnamen verwenden ==== Eine Funktion hat genau eine Funktion. ==== * Parameter sparen, möglichst viel über Klassenproperties abdecken * geschlossene Systeme mit Klassen schaffen * keine Branches ("if/then/else" Verzweigungen) in der Logik ==== Kontrollkonstrukte eliminieren! ==== * Durch Branches (if-Konstrukte) in der Logik hat eine Funktion meist nicht mehr nur eine Funktion. * Branches und Switches (switch/if-Konstrukte) aufteilen ** interface mit canRun()/run()-Methoden ** in einer Schleife alle Implementierungen des Interfaces durchlaufen, die erste die canRun() mit true beantwortet, deren run()-Methode wird aufrufen ==== Strikte Trennung von Logik und Fehlerprüfung ==== * Trennung von Fehlerbehandlung und Logik ** error checking standardisieren *** immer am Anfang einer Methode *** Logik ohne störende Kontrollkonstrukte am Ende *** idealerweise in eine eigene Funktion abkapseln === Teile und herrsche === * monolithische Systeme immer weiter aufteilen * Je kleiner die Teile eines Systems sind, desto beherrschbarar sind sie für Menschen. * siehe Quicksort, Design Patterns, rekursive Funktionen allgemein === Emergenz === * Zusammenschluss vieler einfacher Komponenten * Bsp.: Schwärme, neuronale Netze, Würfelhaufen/Flummis, Conway's Game of Life, genetische/evolutionäre Algorithmen * Was passiert da? ** Kontrolle an die Einzelteile abgeben ** Jedes Element kennt selbst den besten Weg, eine Situation zu behandeln. ** Komponenten können miteinander kommunizieren. ** Durch die Verbindungen entstehen neue Eigenschaften des Gesamtsystems (leider nur schwer vorhersagbar, welche. siehe Bewusstsein und freier Wille). ** Einige Eigenschaften sind jedoch vorhersagbar - und das kann man nutzen! ** Es gibt keinen "master", der die Einzelteile kontrolliert (Anmerkung: also auch kein Script, das Kommandos verbindet. Als emergent könnte man es bezeichnen, wenn zwei oder mehr Scripte autonom agieren und Daten miteinander austauschen.) ** Insofern können auch autonome Module, Klassen und Funktionen emergentes Verhalten produzieren. -> siehe Multithreading == Aktuelle Forschungsschwerpunkte == * Erhöhung der Systemsicherheit * fehlertolerante Systeme * fehlerbehebende Systeme * cyber physical systems * Standardisierung von Komponenten & model driven development (nutzbare Variante, nicht CASE) ** Vorbild: Automobilindustrie *** Zuverlässigkeit *** Vorhersagbarkeit der Kosten & Entwicklungszeit *** standardisierte Tests *** hochgradig wiederverwendbare Komponenten *** standardisierte Schnittstellen => das Ziel: Software Design => Software *Engineering*