Themenabend/Clean Code: Unterschied zwischen den Versionen

Aus C3D2
Zur Navigation springen Zur Suche springen
KKeine Bearbeitungszusammenfassung
 
(4 dazwischenliegende Versionen von 2 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
{{historisch}}[[Kategorie:Themenabend]][[Kategorie:2015]]
<div style="float:right">
{{Themenabend|
{{Themenabend
TITEL= Clean Code |
| TITEL= Clean Code
UNTERTITEL= |
| UNTERTITEL=
TERMIN= 23.07.2015 |
| TERMIN= 23.07.2015
ORT= HQ |
| ORT= HQ
THEMA= |
| THEMA=
 
| REFERENTEN= Nico Krebs
REFERENTEN= Nico Krebs |
| C3D2WEB= http://www.c3d2.de/news/ta-clean-code.html
C3D2WEB= http://www.c3d2.de/news/ta-clean-code.html |
| TOPIC=
TOPIC= |
| SLIDES= [[Themenabend/Clean Code]]
SLIDES= [[ Themenabend/Clean_Code#Inhalt | Abschnitt Inhalt ]]|
}}
}}
</div>


= Inhalt =
__TOC__


<pre>How to code
<pre>
How to code
_______        _______ _______ __  _      _______  _____  ______  _______
_______        _______ _______ __  _      _______  _____  ______  _______
|      |      |______ |_____| | \  |      |      |    | |    \ |______
|      |      |______ |_____| | \  |      |      |    | |    \ |______
|_____  |_____ |______ |    | |  \_|      |_____  |_____| |_____/ |______</pre>
|_____  |_____ |______ |    | |  \_|      |_____  |_____| |_____/ |______
</pre>


;name
; name: Nico Krebs
:Nico Krebs
; blog: [http://www.mensch-und-maschine.de www.mensch-und-maschine.de]
;blog
; work:[http://www.projektmotor.de www.projektmotor.de]
:www.mensch-und-maschine.de
; mail: nkoding@gmail.com
;work
:www.projektmotor.de
;mail
:nkoding@gmail.com


Alles, was im Folgenden beschrieben wird, ist eine Utopie, ein
Alles, was im Folgenden beschrieben wird, ist eine Utopie, ein
Zeile 40: Zeile 38:


Wir alle haben das schon erlebt und wollen es in Zukunft vermeiden:
Wir alle haben das schon erlebt und wollen es in Zukunft vermeiden:
* Projekte werden mit der Zeit immer träger
* Projekte werden mit der Zeit immer träger.
* Neue Features implementieren dauert länger, je mehr Features es gibt
* 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)
* 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
* Evtl. wird ein paralleles Projekt gestartet, das alles besser machen soll - aber dann dieselben Methoden verwendet.
* Beide Arbeitsgruppen konkurrieren, keine kommt wirklich voran
* Beide Arbeitsgruppen konkurrieren, keine kommt wirklich voran.
* User sind unzufrieden
* User sind unzufrieden.
* Das Projekt stirbt an seiner Größe und die Firma ggf. gleich mit
* Das Projekt stirbt an seiner Größe und die Firma ggf. gleich mit.
* Es gibt sehr viele Sicherheitslücken im Projekt
* 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
* 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? ==
== Wie kommt man aus diesem Teufelskreis? ==
Zeile 57: Zeile 55:
* eine Funktion erledigt viele Aufgaben
* eine Funktion erledigt viele Aufgaben
* Abhängigkeiten sind hard coded
* Abhängigkeiten sind hard coded
* Verschachtelte Schleifen und Konstrukte wie Branches ("switch" und "if/then/else") werden häufig genutzt
* Verschachtelte Schleifen und Konstrukte wie Branches ("switch" und "if/then/else") werden häufig genutzt.
* Logik befindet sich innerhalb von if-blöcken
* Logik befindet sich innerhalb von if-Blöcken.
* Klassen-/Funktions-/Variablennamen sind nicht aussagekräftig
* Klassen-/Funktions-/Variablennamen sind nicht aussagekräftig.
* Funktionen mit vielen Parametern
* Funktionen mit vielen Parametern
* um den Code nachzuvollziehen muss ständig zwischen Dateien gewechselt und darin über mehrere hundert/tausend Zeilen gescrollt werden
* 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, daß sie selbst Tests bräuchten
* 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
* im worst case GOTO-Anweisungen
* hohe Wahrscheinlichkeit von Sicherheitslücken<br>=> Spaghetti code
* hohe Wahrscheinlichkeit von Sicherheitslücken<br>=> Spaghetti code
Zeile 69: Zeile 67:


* keine automatischen Tests, weil untestbar (z.b. jUnit)
* keine automatischen Tests, weil untestbar (z.b. jUnit)
* keine Versionskontrolle (z.b. git)
* keine Versionskontrolle (z.B. git)
* kein Ticketsystem (z.b. redmine)
* kein Ticketsystem (z.B. Redmine)
* kein CI-System (z.b. jenkins/hudson)
* kein CI-System (z.b. Jenkins/Hudson)
* keine Nutzung von IDEs (z.b. NetBeans)
* keine Nutzung von IDEs (z.B. NetBeans)
* keine Dokumentation
* keine Dokumentation
* keine leistungsfähigen Kommunikationskanäle (twitter/foren/chat/...), sondern höchstens per e-mail-/Telefonsupport
* keine leistungsfähigen Kommunikationskanäle (twitter/foren/chat/...), sondern höchstens per E-Mail-/Telefonsupport


=== Was ist sauberer Code? ===
=== Was ist sauberer Code? ===


* Verständlich im Hinblick auf Leistungsfähigkeit des Gehirns (drei bis sieben Elemente im Kurzzeitgedächtnis)
* verständlich im Hinblick auf Leistungsfähigkeit des Gehirns (drei bis sieben Elemente im Kurzzeitgedächtnis)
* lesbar wie ein Buch
* lesbar wie ein Buch
* eine Funktion hat genau eine Funktion
* Eine Funktion hat genau eine Funktion.
* wenige Kontrollkonstrukte
* wenige Kontrollkonstrukte
* strikte Trennung von Logik und Fehlerprüfung
* strikte Trennung von Logik und Fehlerprüfung
Zeile 88: Zeile 86:
=== Wie schreibt man sauberen Code? ===
=== Wie schreibt man sauberen Code? ===


==== Die Leistungsfähigkeit des Gehirns als Grundlage ====
==== Leistungsfähigkeit des Gehirns als Grundlage ====


* möglichst drei bis sieben Packages pro Modul/Plugin
* möglichst drei bis sieben Packages pro Modul/Plugin
Zeile 94: Zeile 92:
* möglichst nicht mehr als sieben Funktionen pro Klasse -> besser drei
* möglichst nicht mehr als sieben Funktionen pro Klasse -> besser drei
* möglichst drei bis sieben Zeilen Logik pro Funktion
* möglichst drei bis sieben Zeilen Logik pro Funktion
* Klassen müssen so geplant oder refactoriert werden, daß sie möglichst wenige hard coded Abhängigkeiten haben
* 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 Variablennnamen
* 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)
* Ein doc-Block für API-Methoden muss jedoch sein (für die User der API).


==== Lesbar wie ein Buch ====
==== Lesbar wie ein Buch ====
Zeile 107: Zeile 105:
* sinnvolle Funktionsnamen verwenden
* sinnvolle Funktionsnamen verwenden


 
==== Eine Funktion hat genau eine Funktion. ====
==== Eine Funktion hat genau eine Funktion ====


* Parameter sparen, möglichst viel über Klassenproperties abdecken
* Parameter sparen, möglichst viel über Klassenproperties abdecken
Zeile 114: Zeile 111:
* keine Branches ("if/then/else" Verzweigungen) in der Logik
* keine Branches ("if/then/else" Verzweigungen) in der Logik


==== Kontrollkonstrukte eliminieren! ====


==== Kontrollkonstrukte eliminieren ====
* Durch Branches (if-Konstrukte) in der Logik hat eine Funktion meist nicht mehr nur eine Funktion.
 
* durch Branches (if-Konstrukte) in der Logik hat eine Funktion meist nicht mehr nur eine Funktion
* Branches und Switches (switch/if-Konstrukte) aufteilen
* Branches und Switches (switch/if-Konstrukte) aufteilen
** interface mit canRun()/run()-methoden
** 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
** 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 ====
==== Strikte Trennung von Logik und Fehlerprüfung ====
Zeile 130: Zeile 125:
*** Logik ohne störende Kontrollkonstrukte am Ende
*** Logik ohne störende Kontrollkonstrukte am Ende
*** idealerweise in eine eigene Funktion abkapseln
*** idealerweise in eine eigene Funktion abkapseln


=== Teile und herrsche ===
=== Teile und herrsche ===


* monolithische Systeme immer weiter aufteilen
* monolithische Systeme immer weiter aufteilen
* je kleiner die Teile eines Systems sind, desto beherrschbarar sind sie für Menschen
* Je kleiner die Teile eines Systems sind, desto beherrschbarar sind sie für Menschen.
* siehe Quicksort, Design Patterns, rekursive Funktionen allgemein
* siehe Quicksort, Design Patterns, rekursive Funktionen allgemein


Zeile 141: Zeile 135:


* Zusammenschluss vieler einfacher Komponenten
* Zusammenschluss vieler einfacher Komponenten
* bsp: Schwärme, neuronale Netze, Würfelhaufen/Flummis, Conway's Game of Life, genetische/evolutionäre Algorithmen
* Bsp.: Schwärme, neuronale Netze, Würfelhaufen/Flummis, Conway's Game of Life, genetische/evolutionäre Algorithmen


* Was passiert da?
* Was passiert da?
** Kontrolle an die Einzelteile abgeben
** Kontrolle an die Einzelteile abgeben
** jedes Element kennt selbst den besten weg, eine Situation zu behandeln
** Jedes Element kennt selbst den besten Weg, eine Situation zu behandeln.
** Komponenten können miteinander kommunizieren
** Komponenten können miteinander kommunizieren.
** durch die Verbindungen entstehen neue Eigenschaften des Gesamtsystems (leider nur schwer vorhersagbar, welche. siehe Bewusstsein und freier Wille)
** 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!
** Einige Eigenschaften sind jedoch vorhersagbar - und das kann man nutzen!
** es gibt keinen "master", der die Einzelteile kontrolliert (anm: also auch kein Script, das Kommandos verbindet. Als emergent könte man es bezeichnen, wenn zwei oder mehr Scripte autonom agieren und Daten miteinander austauschen)
** 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
** Insofern können auch autonome Module, Klassen und Funktionen emergentes Verhalten produzieren. -> siehe Multithreading
 


== Aktuelle Forschungsschwerpunkte ==
== Aktuelle Forschungsschwerpunkte ==
Zeile 168: Zeile 161:


=> das Ziel: Software Design => Software *Engineering*
=> das Ziel: Software Design => Software *Engineering*
[[Kategorie:Themenabend]]
[[Kategorie:2015]]

Aktuelle Version vom 22. Dezember 2016, 12:26 Uhr

Veranstaltung
Titel Clean Code
Untertitel
Termin 23.07.2015
Ort HQ
Thema
Vortragende(r)
Referent(inn)en: Nico Krebs
Links
C3D2 Webseite http://www.c3d2.de/news/ta-clean-code.html
Thema
Folien Themenabend/Clean Code
How to code
_______        _______ _______ __   _      _______  _____  ______  _______
|       |      |______ |_____| | \  |      |       |     | |     \ |______
|_____  |_____ |______ |     | |  \_|      |_____  |_____| |_____/ |______
name
Nico Krebs
blog
www.mensch-und-maschine.de
work
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*