c3d2-wiki/Themenabend%2FClean_Code.mw

164 lines
7.0 KiB
Plaintext

{{historisch}}[[Kategorie:Themenabend]][[Kategorie:2015]]
<div style="float:right">
{{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]]
}}
</div>
__TOC__
<pre>
How to code
_______ _______ _______ __ _ _______ _____ ______ _______
| | |______ |_____| | \ | | | | | \ |______
|_____ |_____ |______ | | | \_| |_____ |_____| |_____/ |______
</pre>
; 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<br>=> 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*