Clean Code #4: SOLID — Die fünf Prinzipien guter Architektur
Michael Nikolaus
Vorstand & Softwarearchitekt, Minicon eG
SOLID ist das Akronym für fünf Designprinzipien, die zu wartbarem, flexiblem und verständlichem Code führen. Jeder professionelle Entwickler sollte sie kennen — und anwenden können.
S — Single Responsibility Principle
Jede Klasse sollte genau einen Grund haben, sich zu ändern.
Eine UserService-Klasse, die gleichzeitig Benutzer anlegt, E-Mails versendet und Logs schreibt, hat drei Gründe sich zu ändern. Wenn sich das E-Mail-Format ändert, muss die UserService-Klasse angefasst werden — obwohl sich am User-Management nichts geändert hat.
// ❌ Drei Verantwortlichkeiten
class UserService {
void CreateUser(User user) { /* ... */ }
void SendWelcomeEmail(User user) { /* ... */ }
void LogUserCreation(User user) { /* ... */ }
}
// ✅ Getrennte Verantwortlichkeiten
class UserService { void CreateUser(User user) { /* ... */ } }
class WelcomeMailer { void Send(User user) { /* ... */ } }
class AuditLogger { void LogCreation(User user) { /* ... */ } }O — Open/Closed Principle
Software sollte offen für Erweiterung, aber geschlossen für Änderung sein.
Statt bestehenden Code zu ändern, wenn neue Anforderungen kommen, sollte die Architektur es erlauben, neue Funktionalität durch Erweiterung hinzuzufügen.
// ❌ Muss bei jedem neuen Typ geändert werden
decimal CalculateDiscount(string customerType) {
if (customerType == "premium") return 0.2m;
if (customerType == "business") return 0.15m;
if (customerType == "student") return 0.1m; // neu!
return 0;
}
// ✅ Erweiterbar ohne Änderung
interface IDiscountStrategy { decimal Calculate(); }
class PremiumDiscount : IDiscountStrategy { ... }
class BusinessDiscount : IDiscountStrategy { ... }
class StudentDiscount : IDiscountStrategy { ... } // einfach hinzufügenL — Liskov Substitution Principle
Subtypen müssen sich so verhalten, dass sie den Basistyp ersetzen können.
Das klassische Beispiel: Ein Square das von Rectangle erbt. Setzt man die Breite, muss beim Quadrat auch die Höhe geändert werden — das bricht die Erwartung, die man an ein Rechteck hat.
Wenn Ihr Code eine Basisklasse erwartet, muss jede Unterklasse funktionieren, ohne Überraschungen.
I — Interface Segregation Principle
Clients sollten nicht von Methoden abhängen, die sie nicht nutzen.
// ❌ Fettes Interface
interface IWorker {
void Work();
void Eat();
void Sleep();
}
// ✅ Schlanke Interfaces
interface IWorkable { void Work(); }
interface IFeedable { void Eat(); }
// Ein Roboter implementiert nur IWorkableD — Dependency Inversion Principle
High-Level-Module sollten nicht von Low-Level-Modulen abhängen. Beide sollten von Abstraktionen abhängen.
// ❌ Direkte Abhängigkeit
class OrderService {
private SqlDatabase _db = new SqlDatabase(); // fest verdrahtet
}
// ✅ Abstraktion
class OrderService {
private readonly IOrderRepository _repo;
OrderService(IOrderRepository repo) => _repo = repo;
}Das ermöglicht Testbarkeit (Mock-Repository), Flexibilität (anderer Datenspeicher) und klare Architekturschichten.
Fazit
SOLID ist kein Selbstzweck. Diese Prinzipien existieren, weil Software sich ändert. Code, der heute funktioniert, muss morgen erweitert, nächste Woche gefixt und nächstes Jahr vielleicht umgebaut werden. SOLID macht diese Änderungen sicher und beherrschbar.
Nächster Artikel: Clean Code #5: Kommentare — Wann sie helfen und wann sie schaden
Lassen Sie uns über Ihr Projekt sprechen
Das erste Gespräch ist kostenlos. Wir hören Ihnen zu und finden die beste Lösung für Sie.