Diskussion: "Clean Code" von Uncle Bob. Sinnvoll?

#basTi

Commodore Pro
Registriert
Aug. 2005
Beiträge
4.759
Nachdem in einem Thread (https://www.computerbase.de/forum/t...-veroeffentlicht.1940315/page-9#post-24028945 )eine ziemliche OT Debatte am laufen ist, würde ich das doch gerne in einen eigenen Thread verlagern.

Als erstes Thema, weil die Diskussion damit losgetreten wurde würde ich das Thema "Kommentare" wählen.
"Clean Code" sagt im Prinzip, dass Kommentare so weit wie möglich vermieden werden sollen, da man sonst mehr zu pflegen hat (code+comment). Zudem sollte der Code so geschrieben werden, dass er von sich aus lesbar ist, auch ohne Kommentar.
Dies geht natürlich nicht immer aber als Guideline ist das mMn schonmal erstebenswert.
Siehe u.a. auch https://blog.usejournal.com/stop-writing-code-comments-28fef5272752 .


@new Account() war in dem anderen Thema aber anderer Meinung. In dem Thread hatte er zwei Codezeilen gepostet um seinen Standpunkt zu erklären. Aus so wenig Code war es leider schwer sein Argument zu verstehen.
Also wenn du ( @new Account() ) hier ein minimalbeispiel posten würdest, dann können wir gern drüber diskutieren.
Ich bin immer gern bereit neues dazu zu lernen. Also falls du ein valides Argument hast oder anwendungsfälle in denen minimalste Kommentare wirklich nicht sinnvoll sinn interessiert mich das.

Let's discuss :)
 
#basTi schrieb:
Dies geht natürlich nicht immer aber als Guideline ist das mMn schonmal erstebenswert.
Siehe u.a. auch https://blog.usejournal.com/stop-writing-code-comments-28fef5272752 .


@new Account() war in dem anderen Thema aber anderer Meinung
Nein, ich bin ziemlich der Meinung des Artikels.
Mit so Emotionalisierungen wie "evil" kann ich mich dann aber trotzdem nicht anfreunden - wers nötig hat...

@Slerpee dagegen war der Ansicht, dass Code, der Kommentare enthält, zwangsläufig schlechter Code ist.

PS: Ich muss auch zugeben, dass die Beispiele diesbzeüglich nicht wirklich hilfreich waren.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: KingLM97 und Hayda Ministral
Nein, ich habe dir sogar eine Ausnahme genannt, bei der ich es akzeptieren würde.

Und sorry, aber deine Beispiele waren Paradebeispiele dafür, wie man Kommentare durch sinnvolle Methoden und Typen vermeiden kann.

Mir ging es auch um die pauschale Aussage von Cooler Master, große Projekte ohne Kommentare wären Selbstmord, was so einfach Unsinn ist und ich nicht stehen lassen wollte...
 
Man soll Kommentare nicht vermeiden, sondern seinen Code so schreiben, dass Kommentare überflüssig werden, weil sie einfach nur Wort für Wort den Code wiederholen würden.

Kommentare sind da angebracht, wo es nicht möglich ist, einfachen und lesbaren Code zu schreiben. Ganz einfaches Beispiel: Irgendwelcher Assembler Code im Kernel, der in Assembler geschrieben werden muss, weil er sonst zu ineffizient wäre. Das ist Code, den (fast) niemand fließend runterlesen kann und gleichzeitig versteht was dort passiert.

Ansonsten einfach immer dem Grundsatz folgen, dass eine Methode einen aussagekräftigen Namen erhält und am Besten nur 5-7 Zeilen lang ist (manche sagen auch 10-12 Zeilen. Spielt keine Rolle. Wichtig ist, dass man nicht groß nachdenken muss, um den kompletten Inhalt der Methode zu verstehen):
Code:
function jahreseinkommenBerechnen(jahr) {
  einkommen = 0;
  for ( monat in jahr ) {
    einkommen += monatseinkommenBerechnen(monat);
  }
  einkommen += jahresboniBerechnen(jahr);
  return einkommen;
}
(EDIT: Je nach Fall kann man natürlich auch die gesamte for-Schleife in eine eigene Funktion auslagern. Das hängt u.a. davon ab, ob dieser Teil (inkl. Schleife) eine eigenständige Funktion erfüllt, wiederverwendet werden soll, aber natürlich ist es auch eine Frage der persönlichen Präferenzen und des Stils.)

Der Name der Funktion sagt schon ganz genau was hier passiert. Und der Code in der Funktion ist so kurz, dass man ihn nach wenigen Sekunden verstanden hat.

Der "Nachteil" dieses Verfahrens ist augenscheinlich, dass der Code am Ende aus seeeehr vielen kleinen Funktionen besteht. Das könnte unübersichtlich werden, wenn man die Funktionen nicht sauber benennt und in Dateien und Ordner strukturiert. Und um die gesamte Berechnung zu verstehen muss man mehrere Funktionsblöcke im Blick behalten - was aber im Endeffekt auch nicht anders ist als einen sehr langen Block mit Kommentaren zu verinnerlichen.

Das Gegenbeispiel wäre dann eher sowas:
Code:
function jahreseinkommenBerechnen(jahr) {
  einkommen = 0;
  for ( monat in jahr ) {
    for ( tag in monat ) {
      // Arbeitsstunden für den Tag
      // Stundenlohn
      // Multiplizieren
      // Bonus für neuen Kunden
      // etc.
    }

    // Boni für Mitarbeiter des Monats
    einkommen++;
  }

  // Boni für's ganze Jahr
  einkommen++;
  return einkommen;
}
Funktioniert natürlich auch. Aber hier hast du am Ende eine Funktion mit 50+ Zeilen, über die man sich erst mal einen Überblick verschaffen muss. Die Kommentare innerhalb dieser langen Funktion sind quasi die Funktionsnamen, die man zum Auslagern der Code Blöcke verwenden würde, wie z.B. "arbeitsstundenFürTagBerechnen" oder "boniFürTagBerechnen".

Klarer Nachteile dieses Verfahrens: Man kann Teil-Funktionen nicht einfach testen. Wenn du hingegen 10 kurze Funktionen hast, kannst du jeden Teil davon mit einem kurzen und knackigen Unit-Test versehen.

Und nicht zu vergessen: Wiederverwendbarkeit! Kleine Code Blöcke kann man einfach in einem anderem Kontext wiederverwenden. Bei großen Code Blöcken läuft es meist auf Copy&Paste hinaus, also deutlich schlechter wart- und änderbar.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: Slurpee
Das Problem ist aber, daß eine Funktion mitnichten einfach oder trivial selbsterklärend codiert ist. Bei so Pipibeispielen mag es ja trivial sein. Sobald Du aber wirklich die Monsterfunktionen hast oder komplexe Zusammenhänge, ist das nicht mehr so einfach, oder wenn zig Schleifen hintereinander verwendet werden usw. Da ist dann auch nicht mehr klar, was welcher Zähler oder Bedingung bzw. Begrenzung so soll.

Generell ja, Code schlank halten, selbsterklärend. Beispielsweise mache ich aktuell viele Bash-Scripte, die ich doch wieder erwarten ausführlicher dokumentiere. Ganz einfach: Viele Kollegen sehen den Code, und sind nicht so fit darin. Da sie irgendwann mal den Code selbst pflegen müssen (weil ich externer Mitarbeiter bin), dokumentiere ich hier lieber mehr als weniger. Ebenso schreibe ich gerade bei sehr kurzen Funktionen, wo jetzt für eine Nichtkundigen so schnell einsichtig ist, wie das so funktioniert, doch immer genauer hin, was da passiert.
 
Zuletzt bearbeitet:
PHuV schrieb:
Bei so Pipibeispielen mag es ja trivial sein.
Deswegen ist es mMn auch eine Kunst für sich Clean Code zu schreiben. Weil es eben bei komplexen Dingen Hirnschmalz erfordert. Die 5 geschachtelten Schleifen sind die "ich programmiere es einfach runter" Lösung und meist nicht die Beste Lösung geschweige denn die Verständlichste.

Und ich sage keineswegs dass ich es perfekt beherrsche. Aber ich strebe dannach. Ihr scheint euch mit einem "schlechten" Ergebnis zufrieden zu geben, mit der Erklärung, dass euer Problem so Komplex ist, dass es gar nicht anders geht.
 
  • Gefällt mir
Reaktionen: mistalan, Tumbleweed und Slurpee
new Account() schrieb:

Und nochmal: Ich habe dir sogar ein Beispiel gegeben, bei dem ich es ok finde. Da kannst du jetzt so viel aus dem Zusammenhang zitieren, wie du willst...

#basTi schrieb:
Und ich sage keineswegs dass ich es perfekt beherrsche. Aber ich strebe dannach. Ihr scheint euch mit einem "schlechten" Ergebnis zufrieden zu geben, mit der Erklärung, dass euer Problem so Komplex ist, dass es gar nicht anders geht.

Jap, ist der Klassiker. "Aber mein System ist viel komplexer", "Aber unsere Requirements sind ganz anders" "Ich schreibe code für x, das muss performant sein, CC ist nicht performant", etc. pp.

Bin da voll auf deiner Seite, ich strebe auch danach, weiß, dass ich es nicht perfekt kann, was aber eben auch daran liegt, dass das ganze nicht halb so trivial ist, wie viele sich dass nach nem 20 Minuten CC-Crash-Kurs vorstellen. Clean Code ist eines dieser Bücher, die man mehrfach sehr genau lesen muss, um irgendwann wirklich durch zu steigen.
 
  • Gefällt mir
Reaktionen: ###Zaunpfahl###, mistalan und #basTi
PHuV schrieb:
Sobald Du aber wirklich die Monsterfunktionen hast oder komplexe Zusammenhänge, ist das nicht mehr so einfach, oder wenn zig Schleifen hintereinander verwendet werden usw. Da ist dann auch nicht mehr klar, was welcher Zähler oder Bedingung bzw. Begrenzung so soll.
Sobald man so etwas hatt greift ein weiterer Punkt von Clean Code: das Zerlegen von Funktionen so dass sie nur genau einen Zweck verfolgen und klar und übersichtlich sind.
 
  • Gefällt mir
Reaktionen: Darrel und #basTi
Das Thema ist echt schwierig, weil es bei den Kritikern am Ende immer darauf hinausläuft, dass es in Fall X, an dem sie gerade arbeiten, angeblich nicht geht und die Antwort der Clean Coder ist immer, doch, du kannst es nur nicht, was natürlich keiner hören will...
 
Es hängt auch vom Umfeld ab in dem man arbeitet. Je größer ein Team ist, desto geringer die Wahrscheinlichkeit, dass alle die gleichen Fähigkeiten haben. Alle träumen vom homogenen Team, aber das gibt es nur mit einer Person. Selbsterklärender Code kann häufig sehr gut dokumentieren, was dort passiert, aber gleichzeitig auszudrücken, warum etwas gemacht werden muss ist kaum möglich.
Offensichtlich wird das z.B. bei sehr technischen Code, wo z.B. bei einem Framework eine Initialisierung mit 50 bestimmten Einstellungen gemacht werden muss, um z.B. die Performance Requirements zu erreichen oder den Speicherverbrauch zu begrenzen. Natürlich kapselt man das, aber dort wo die Initialisierung gemacht wird, dokumentiert den Sinn und Zweck jedes nicht offensichtlichen Aufrufs.
 
  • Gefällt mir
Reaktionen: ###Zaunpfahl###, Spezi und new Account()
Nolag schrieb:
aber dort wo die Initialisierung gemacht wird, dokumentiert den Sinn und Zweck jedes nicht offensichtlichen Aufrufs.
Ja, das ist so ne Ausnahme wo ich das auch mach. Nur zu Dokumentationszwecken einen einzelnen Funktionsaufruf nochmals zu kapseln um den Funktionsnamen als Kommentar zu benutzen halt ich auch für übertrieben. Wobei das nicht nur bei seh technischen Sachen sein kann sondern auch bei besonderen fachlichen Anforderungen die nicht direkt ersichtlich sind.
 
  • Gefällt mir
Reaktionen: new Account()
Find das Thema auch interessant.
Stimme prinzipiell zu, daß wenn Code selbsterklärend ist, man sich comments sparen kann.

Auf der anderen Seite hat Code kurz und knapp zu sein (concise). Wer 100 Zeilen braucht, um das zu tun, wofür man fünf gebraucht hätte, und das mit Lesbarkeit rechtfertigt, der gehört getreten.

Man muß schon ein vernünftiges Maß finden.
 
  • Gefällt mir
Reaktionen: new Account()
RalphS schrieb:
Auf der anderen Seite hat Code kurz und knapp zu sein (concise). Wer 100 Zeilen braucht, um das zu tun, wofür man fünf gebraucht hätte, und das mit Lesbarkeit rechtfertigt, der gehört getreten.

Würde keiner tun. Wie schon gesagt, entsteht Lesbarkeit ja unter anderem dadurch, dass du kurze, knappe Methoden schreibst, die eine Sache tun und sinnvoll benannt werden können.

Du wirst also nie vor diese Wahl gestellt oder zumindest hatte ich noch nie so einen Fall. Ganz im Gegenteil, mein Wunsch nach mehr Lesbarkeit führt immer ganz automatisch zu kürzeren Methoden und kleineren Klassen.

Die einzige Abwägung, die man treffen muss ist Lesbarkeit vs. Performance. Nur nehmen das manche Leute leider so ernst, dass sie jedes Fitzelchen Code wie einen Linux Kernel patch behandeln.

Auch hier hilft wieder clean code: Keine voreiligen Optimierungen. Erst coden, auf Lesbarkeit und Veränderbarkeit achten, verifizieren, dass es inhaltlich passt, dann profilen und gezielt optimieren, da wo es wirklich nötig ist und nicht da wo man vom Bauchgefühl her denkt, dass es nötig wäre.
 
  • Gefällt mir
Reaktionen: mistalan
Im Endeffekt geht es ja nur um "Managing Complexity".

Dafür gibt es Tools.
Damit man die Tools sinnvoll verwenden kann, muss man sie verstehen und wissen, wann sie funktionieren und wann nicht.
Ebenso muss man wissen, wer an der Software arbeitet, denn unterschiedliche Teams haben unterschiedliche Mitarbeiter und auch unterschiedliche Fertigkeiten.

Ein Kommentar kann die Komplexität senken, wenn damit ein Warum aufgelöst wird, das ohne Kommentar nicht ersichtlich ist.
Ein Kommentar kann die Komplexität erhöhen, wenn er redundant ist.

Das gilt aber auch für andere Tools. Alle haben ihren Nutzen, können aber überstrapaziert werden, bspw. DRY und YAGNI.
 
  • Gefällt mir
Reaktionen: PHuV und new Account()
Man merkt ziemlich schnell, wer hier mit Programmieren schon länger Geld verdient und wer nicht ;)
 
Ob nun "clean code" oder nicht "clean code" was auf keinem Fall geht sind die "camelCase" Beispielen

Code:
getAgeByUserId($id) {

}

ist einfach total dumm zu lesen. Ich bin wirklich kein Fan davon und verwende dann lieber:

Code:
get_age_by_user_id($id) {

}

Gerade bei Clean Code sollte man auf Camel Case verzichten, weil dadurch der Code lesbarer wird.
 
nerdalicious schrieb:
Man merkt ziemlich schnell, wer hier mit Programmieren schon länger Geld verdient und wer nicht ;)
Und was hat das damit zu tun? Schlechten Code kann man auch nach 25 Jahren Berufserfahrung produzieren, insbesondere dann, wenn nach 24 Jahren wieder mal die Torpfosten verschoben wurden und "gut" plötzlich ganz anders definiert wird.

"Lesbarkeit" gut und schön, aber das ist kein Kriterium für guten Code, bestenfalls ein sekundäres. Ansonsten gehen die Leute einfach her und programmieren Batch-style in allen Programmiersprachen, stupide einen Schritt nach dem anderen, weil "lesbar".

Ist eine fünfzeilige Methode schlechter Code, wenn sich der Schreiberling ein paar Gedanken dazu gemacht hatte und diese Methode nun zwar hochperformant, aber leider nicht mehr auf einen Blick nachvollziehbar ist? Das gilt einen Schritt weiter auch für SQL-Abfragen. Die erfordern immer ein bißchen Gehirnschmalz, wenn sie sich nicht grad auf SELECT dummy FROM dual beschränken. Nachvollziehbar auf den nächsten Blick sind sie in > 50% der Fälle nicht => ergo schlecht?

Natürlich sind Kommentare nicht inhärent schlecht. Sie müssen ebenso wie der Code kurz und knapp sein - detailliertere Erklärungen, die dafür sorgen, daß man 100 Zeilen Text mit 95 Zeilen Kommentar hat, sind natürlich ein Problem -- sie müssen sinnvoll sein - sowas wie
Java:
// addiere 1
a++;
ist ebenfalls Mumpitz.

Nicht akzeptabel für "guten Code" ist aber eine Beschränkung auf n Zeilen oder das pauschale Eliminieren von Verständnispunkten/Kommentaren, wenn das Auswirkungen auf das hat, wofür der Code da ist: nämlich etwas zu tun.
A minimal, wenn 4 Schritte das tun, was 5 Schritte auch schaffen, dann vier.
B atomic, jede Methode implementiert exakt eine (unabhängige) Sache.
C Laufzeit, wenn eine obere Schranke niedriger gewählt werden kann als für eine andere.

Jedes Argument "Lesbarkeit" was gegen eins davon verstößt ist fehl am Platz und macht aus dem vormals "besseren" Code schlechteren.
Und wenn das Team aus Stümpern besteht und mit qualitativem Code nix anfangen kann, dann gehört es geschult und das heißt an der Stelle, zusätzlich zu Inline-Kommentaren noch "Developer-Doku" wo detallierter drinsteht, was user.ID ?? group.Add(user.ID) nun genau macht.
 
Zuletzt bearbeitet von einem Moderator:
#basTi schrieb:
Und ich sage keineswegs dass ich es perfekt beherrsche. Aber ich strebe dannach. Ihr scheint euch mit einem "schlechten" Ergebnis zufrieden zu geben, mit der Erklärung, dass euer Problem so Komplex ist, dass es gar nicht anders geht.
Woher willst Du das wissen oder wie kannst Du das so beurteilen? Zudem, was wünschenswert ist und was man dann tatsächlich umsetzen kann und darf sind zwei paar Stiefel. Nur die wenigsten Entwickler hier können neuen Code schreiben. Die meisten müssen an Fremdcode ran, der einem vor vollendete Tatsachen stellt, wo man “schnell“ ein paar Änderungen vornehmen soll. Da ist oftmals ein Zeit- und Budgetlimit drin, das sowas wie Refactoring trotz Notwendigkeit ein reines Wunschkonzert bleibt.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: RalphS
RalphS schrieb:
Ist eine fünfzeilige Methode schlechter Code, wenn sich der Schreiberling ein paar Gedanken dazu gemacht hatte und diese Methode nun zwar hochperformant, aber leider nicht mehr auf einen Blick nachvollziehbar ist?
In 99% der Fälle sollte der Compiler und/oder die VM dafür sorgen, dass es keine Performanceeinbußen gibt. Klar gibt's Ausnahmen und extrem performancekritische Anwendungen - aber das ist die Ausnahme, weil sich heutzutage fast jedes Performanceproblem mit Geld, ergo mehr Hardware, erschlagen lässt. Für die meisten Firmen sind ein paar hundert Euro zusätzliche Servermiete immer noch günstiger als ein Entwickler, der seine Zeit damit verbringt den Code auf Performance zu optimieren, und dann nachträglich womöglich noch mehr Zeit der Entwickler frisst, weil sich die Methode jetzt nicht mehr so leicht an neue Gegebenheiten anpassen lässt.

Der "normaler" Anwendungsentwickler sollte sich zu Beginn grundsätzlich keine Gedanken über die Performance machen und stattdessen lieber verständlichen und wartbaren Code schreiben. Ich will damit nicht sagen, dass er sich absichtlich dämlich anstellen soll, sondern einfach mit gesundem Entwicklerverstand an die Sache gehen. Ohne sich Gedanken darum zu machen, ob der Algorithmus schneller läuft, wenn er 2 µOps pro Schleifendurchlauf mehr braucht, aber dafür 4 byte weniger Daten laden muss.

RalphS schrieb:
Nicht akzeptabel für "guten Code" ist aber eine Beschränkung auf n Zeilen oder das pauschale Eliminieren von Verständnispunkten, wenn das Auswirkungen auf das tut, wofür der Code da ist: nämlich etwas zu tun.
Eine sture Beschränkung will ja auch niemand. Das ist in der Praxis auch überhaupt nicht umsetzbar. Es sind einfach nur Hilfestellungen. Ob da jetzt jemand sagt: 7 oder 12 Zeilen. Völlig egal. (Die "7" kommt übrigens daher, dass man sagt, dass der Mensch sich 7 Dinge im Kurzzeitgedächtnis merken kann ohne erneut nachsehen zu müssen.)
Der Punkt dahinter ist doch im Endeffekt nur: Wenn du 50 Zeilen Code am Stück geschrieben hast und/oder selbst drüber grübeln musst, was deine Funktion da eigentlich macht, dann solltest du den Code wohl noch mal überdenken.
Ob du das dann wirklich durch Aufspaltung in kleinere Funktionen machst, oder durch inline Kommentare, aussagekräftigere Variablennamen, oder was auch immer, ist irrelevant. Hauptsache das Endergebnis ist verständlich.

RalphS schrieb:
A minimal, wenn 4 Schritte das tun, was 5 Schritte auch schaffen, dann vier.
Davon war bei Clean Code nie die Rede. Es geht um verständlichen Code: Wenn 5 Schritte einfacher zu verstehen sind, dann nimmt man 5. Gar keine Frage. Die Kurzfassung mit 4 Schritten ist eigentlich nur angebracht, wenn es sich um eine der ganz wenigen performancekritischen Stellen handelt und diese Änderung ein real existierendes Performanceproblem löst. Also nichts in Richtung "wir kriegen in Spitzenzeiten zwar nur 5000 requests/sec rein, aber mit dieser Änderung könnte unsere Anwendung 120000 statt 100000 requests/sec schaffen!".

PHuV schrieb:
Die meisten müssen an Fremdcode ran, der einem vor vollendete Tatsachen stellt, wo man “schnell“ ein paar Änderungen vornehmen soll.
Oder es ist der eigene Code, den man vor vielen Jahren im jugendlichen Leichtsinn - gepaart mir der Euphorie durch seinen Uniabschluss - zusammengewurstet hat. Wobei ich das inzwischen auch als "Fremdcode" bezeichnen würde. Bei manchen Zeilen schau ich extra in's Git Log, um herauszufinden ob tatsächlich ich der Übeltäter war :D

PHuV schrieb:
Da ist oftmals ein Zeit- und Budgetlimit drin, das sowas wie Refactoring trotz Notwendigkeit ein reines Wunschkonzert bleibt.
Ja, ein altbekanntes Problem. Ich hab's mir inzwischen angewöhnt in solchen Fällen ein ernstes Wörtchen mit dem Verantwortlichen zu reden, und ihn deutlich darauf hinzuweisen, dass Einsparungen im Jetzt ein zeitintensives und damit teures Nachspiel in der Zukunft haben werden. Ich hab das jetzt schon in mehreren Projekten miterlebt, es ist immer dasselbe. Nach spätestens einem Jahr wird der Code allmählich zum Jenga-Turm.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: ###Zaunpfahl###, mistalan, Slurpee und eine weitere Person
Zurück
Oben