Clean Code bedeutet leicht lesbaren, wartbaren und veränderbaren Code. Es geht nicht um Perfektion, sondern um Klarheit der Absicht: Jede Klasse, Methode und Variable soll kommunizieren, was sie tut – ohne Kommentar, ohne Nachdenken.
Es führt dazu, dass man den Code einfacher testen kann, und mit guter Testabdeckung können wir den Code mit höherer Sicherheit erweitern.
Hier Bespiele von schlechte und bessere Praxis:
// Schlecht – Name verrät nichts über die Absichtpublic void p() {}// Besser – sofort verständlichpublic void processOrder() {}
Lesbarkeit:
processOrder() kommuniziert den Zweck sofort. Kein mentaler Aufwand, kein Kommentar nötig.
Wartbarkeit:
Bei Bugfixes und Reviews ist der Kontext direkt klar. Die Suche nach „was macht p?“ entfällt.
Erweiterbarkeit:
Neue Entwickler können gezielt erweitern, ohne den gesamten Call-Graph zu verstehen.
Effective Naming:
// Schlechtint d = 3650;// Besser – Einheit im Namenint ageInDays = 3650;// Am bestenstatic final int TEN_YEARS_IN_DAYS = 3650;
Lesbarkeit
Einheit und Konzept sind direkt aus dem Namen ableitbar – kein Kommentar, kein Kontext nötig.
Wartbarkeit
Magic Numbers sind gefährlich. Ein benannter Wert zeigt, wo Änderungen wirken.
Erweiterbarkeit
Konstanten können zentral geändert werden. Umbenennung per IDE ist sicher und vollständig.
Abstraktion:
Richtige Abstraktionsebene vereinfacht das Verständnis
Eine Methode soll auf einer einzigen Abstraktionsebene operieren. placeOrder() delegiert – sie beschreibt was passiert, nicht wie.
public void placeOrder() { validateOrder(); // hohe Abstraktion persistOrder(); // hohe Abstraktion notifyCustomer(); // hohe Abstraktion}// Schlechtes Gegenstück: Details mischen sichpublic void placeOrder() { if (order.items.isEmpty()) throw new IllegalStateException(); db.save(order); smtp.send(customer.getEmail(), "Bestätigung...");}
Lesbarkeit:
Drei Zeilen erzählen eine Geschichte. Der Leser versteht den Flow ohne Details zu kennen.
Wartbarkeit:
Jede Sub-Methode kann unabhängig geändert, getestet und ersetzt werden.
Erweiterbarkeit:
Ein neuer Schritt (z. B. reserveInventory()) wird einfach eingefügt, ohne die Logik anderer Schritte zu berühren.
Cognitive Load:
Refactoring reduziert mentale Belastung
Jede Bedingung, Verschachtelung und Variable erhöht die mentale Last. Prägnante Guards und sprechende Methoden entlasten das Arbeitsgedächtnis.
// Hoch – zwei Konzepte gleichzeitig prüfenif (user != null && user.isActive()) { ... }// Reduziert – Intention benannt, null-sicherif (isActiveUser(user)) { ... }private boolean isActiveUser(User user) { return user != null && user.isActive();}
Lesbarkeit:
Die if-Bedingung liest sich wie ein Satz. Kein Null-Check im Kopf halten nötig.
Wartbarkeit:
Null-Checks oder weitere Regeln werden an einer Stelle gepflegt. Keine vergessenen Duplikate.
Erweiterbarkeit:
Erweiterte Prüfungen (z. B. user.isVerified()) werden in isActiveUser() ergänzt.
Lean Code:
Nur das bauen, was aktuell benötigt wird
Code der nicht existiert, kann keine Bugs enthalten. InvoiceService soll genau die heute benötigten Features umsetzen – keine spekulativen Methoden, keine „vielleicht später“-Strukturen.
// Spekulativ – ungenutzte Infrastrukturpublic class InvoiceService { void generatePdf() {} void exportToXml() {} // "könnte gebraucht werden" void syncWithSAP() {} // niemand braucht es}// Lean – nur was gebraucht wirdpublic class InvoiceService { void createInvoice(Order order) {}}
Lesbarkeit:
Kleine Klassen sind vollständig im Kopf haltbar. Kein Rauschen durch ungenutzten Code.
Wartbarkeit:
Weniger Code = weniger Testaufwand, weniger Bugs, kürzere Reviews. Dead Code schleicht sich ein.
Erweiterbarkeit:
Neue Features werden dann hinzugefügt, wenn sie gebraucht werden – mit aktuellem Wissen über die Anforderungen.
Spezifischer vs. abstrakter Code:
Zu viel Abstraktion erhöht Komplexität
Interfaces sind mächtig – aber nur wenn sie echte Varianten abstrahieren. Ein PaymentProcessor-Interface ist sinnvoll, wenn mehrere Implementierungen (Stripe, PayPal, SEPA) existieren oder geplant sind.
// Nur eine Impl. existiert → Interface ist Overengineeringinterface PaymentProcessor {}class StripePaymentProcessor implements PaymentProcessor {}// Passend – echte Varianten rechtfertigen das Interfaceinterface PaymentProcessor { PaymentResult process(Payment payment);}class StripeProcessor implements PaymentProcessor { ... }class PayPalProcessor implements PaymentProcessor { ... }
Lesbarkeit:
Konkrete Klassen sind direkter zu verstehen. Jede Indirektionsebene kostet mentale Energie.
Wartbarkeit:
Premature Abstraction erzeugt Boilerplate ohne Nutzen. Refactoring zu einem Interface ist später einfach.
Erweiterbarkeit:
Das Interface entfaltet seinen Wert, wenn Erweiterungen tatsächlich kommen – nicht vorher.

Hinterlasse einen Kommentar