1. Einführung
"Sauberer Code" ist kein heiliges Mantra, sondern ein echtes Überlebenswerkzeug für Programmierer. In jedem, selbst im schönsten, OOP-Projekt sammeln sich sehr schnell viele Klassen, Felder, Methoden, tricky Verbindungen... Wenn du die Ästhetik und Struktur verletzt, wird dein eigener Code nach einer Woche zu einem unlösbaren Quest. Mehr über den "Kampf ums Überleben" findest du bei Robert Martin, "Clean Code" – genau über solche Schlachten.
Stil im Code ist nicht "jeder wie er will", sondern dafür da, dass alle leichter leben:
- Ein Kollege (oder du selbst) kann schnell verstehen, was abgeht.
- Fehler (vor allem architektonische) sind sofort sichtbar.
- Der Code ist einfacher zu erweitern, mit weniger Fehlern.
Schauen wir uns an, wie man OOP-Code so schreibt, dass ihn Reviewer, Kollegen und sogar Linter lieben.
2. Namen: Deine erste Verteidigungslinie
Klassen benennen
Klassen in C# nennt man üblicherweise im PascalCase (jeder neue Wortteil beginnt mit einem Großbuchstaben, z.B.: MyNewClass) und so, dass der Name klar beantwortet: "Was ist das?". Namen sollten Substantive sein!
public class StudentAccount { /* ... */ }
public class InvoiceGenerator { /* ... */ }
Schlecht:
class doMagic { ... } // Schlecht: Was für Magie? PascalCase verletzt.
Methoden benennen
Methoden – auch im PascalCase, aber hier besser Verb + Objekt:
public void PrintReport() { ... }
public string GetFormattedName() { ... }
Methoden sollten eine Aktion widerspiegeln (Print, Get, Save, Calculate usw.), damit beim Lesen klar ist, was passiert.
Felder und Properties benennen
Felder sind meistens private, werden klein geschrieben im camelCase, oft mit Unterstrich:
private int _count;
private Student _owner;
Properties – PascalCase, weil sie Teil des öffentlichen Interface der Klasse sind:
public int Balance { get; set; }
Variablen
Lokale Variablen – camelCase, so kurz und verständlich wie möglich im Kontext:
string inputName;
int studentCount;
Und bitte Variablen wie a1, result2, something – nur wenn du dir selbst ein Quest für den nächsten Monat bauen willst.
3. Struktur einer Klasse organisieren
Die richtige Anordnung der Klassenmitglieder macht die Navigation einfacher und hilft, schnell zu verstehen, was wo ist.
Meistens ordnet man so:
- Konstruktoren
- Properties
- Methoden
- Verschachtelte Typen (enum, class usw.)
Beispiel:
public class Student
{
// --- Felder ---
private string _name;
// --- Konstruktor ---
public Student(string name)
{
_name = name;
}
// --- Properties ---
public string Name
{
get => _name;
set => _name = value;
}
// --- Methoden ---
public void PrintInfo()
{
Console.WriteLine($"Name: {_name}");
}
}
Diese "Blöcke" kann man gut mit Kommentaren trennen (// --- Methoden ---), besonders in großen Klassen. JetBrains Rider, Visual Studio und andere IDEs erlauben schnelles Ein- und Ausklappen von Sektionen.
4. Kommentare und Dokumentation
Kommentare sind gut. Aber schlecht, wenn man sie übertreibt oder "Erklärungen für unverständlichen Code" schreibt, wenn man einfach den Code ändern könnte!
Ein guter Kommentar erklärt das "Warum", nicht das "Was".
// Wir nutzen Guid als eindeutige ID, weil das System verteilt ist
public Guid Id { get; set; }
Dokumentation von Methoden, Klassen und Properties
Nutze xml-Dokumentation für Klassen und öffentliche Methoden. IDEs zeigen diese Beschreibungen beim Hover an.
/// <summary>
/// Repräsentiert einen Studenten der Uni.
/// </summary>
public class Student
{
/// <summary>
/// Name des Studenten.
/// </summary>
public string Name { get; set; }
}
Was man NICHT kommentieren sollte
- Einfache Sachen (i++ // erhöhen i um 1).
- Schlecht benannte Variablen ("// hier passiert was" – ja, aber was?).
5. Teile und herrsche
Kleine Klassen und Methoden
Goldene Regel: eine Klasse – eine Verantwortung (siehe Single Responsibility Principle). Wenn die Klasse Student Notenverwaltung, E-Mail-Verarbeitung und Stundenplan-Management macht – irgendwas läuft da schief.
- Klassen bis 300-400 Zeilen – okay. Mehr – Grund zum Nachdenken.
- Methoden bis 15-20 Zeilen – lesbar. Ausnahmen gibt's, wenn es ein Handler für einen großen Case ist.
Beispiel für eine "aufgeblasene" Methode:
public void Process()
{
// Benachrichtigung an den Kunden
// Änderungen speichern
// E-Mail senden
// Logs schreiben
// ... (15 Schritte)
}
Besser:
public void Process()
{
NotifyClient();
SaveChanges();
SendEmail();
LogActivity();
}
Jede Aktion ist in eine eigene private Methode ausgelagert, der Code wird kompakter und leichter zu testen.
6. Nützliche Tipps
Visuelle Struktur: Formatierung, Einrückungen, Leerzeilen
IDEs können Code automatisch schön formatieren (Ctrl+K, D in Visual Studio, Ctrl+Alt+L in Rider), aber die Prinzipien sollte man trotzdem kennen.
- EINRÜCKUNGEN – 4 Leerzeichen. Keine Tabs, keine 2 Leerzeichen.
- LEERZEILEN – trenne Methoden voneinander, Felder von Properties, Properties von Methoden.
- KLAMMERN immer in neuer Zeile bei Klassen und Methoden (Allman-Stil):
public class Test
{
public void Print()
{
Console.WriteLine("Hallo");
}
}
"Starke" und "schwache" Klassenmitglieder: Zugriffsmodifikatoren
Mach immer alles so privat wie möglich: Öffne nur das, was wirklich von außen gebraucht wird. Wenn ein Feld oder eine Methode nur innerhalb der Klasse gebraucht wird – private. Nur wenn es für Vererbung gebraucht wird – protected. public – nur für Verträge.
Schlecht:
public string ConnectionString; // Jeder kann das ändern!
Besser:
private string _connectionString;
public string ConnectionString
{
get => _connectionString;
private set => _connectionString = value;
}
Automatische Properties verwenden
Seit es automatische Properties und init-only-Setter gibt, ist es fast schon peinlich, "manuelle" Properties zu schreiben.
Beispiel:
public string Name { get; set; } // Top!
public int Age { get; init; } // Nur zur Initialisierung, sicherer.
Und wenn du berechnete Properties brauchst:
public string FullName => $"{FirstName} {LastName}";
Kapselung und Getter/Setter
Wenn eine Property eine Business-Logik für Änderung oder Kontrolle braucht, nutze ein privates Feld + öffentlichen Getter/Setter mit Logik.
private int _grade;
public int Grade
{
get => _grade;
set
{
if (value < 0) _grade = 0;
else if (value > 100) _grade = 100;
else _grade = value;
}
}
So verhinderst du, dass du oder andere das Objekt versehentlich "kaputtmachen".
7. Noch mehr nützliche Tipps
Hab keine Angst vor Interfaces und Abstraktionen
Interfaces sind für bequeme Verträge, Tests und Erweiterbarkeit da.
Schlecht:
- Interface mit nur einer Methode, die nirgends gebraucht wird;
- Interface, das nur von einer Klasse implementiert wird.
- Interface, das von 2+ Klassen genutzt wird;
- Interface für die Abstraktion externer Systeme (z.B. für Logging, Datenspeicherung).
Schreib Code so, dass er leicht testbar ist
Ein Zeichen für guten OOP-Code ist Testbarkeit.
- Mach keine Methoden, die komplett auf globale Variablen oder statische Felder angewiesen sind.
- Hab keine Angst vor Dependency Injection – über Konstruktor-Parameter (Dependency Injection).
- Trenne Berechnungen (Logik) und User-Interaktion (Input/Output). Das erleichtert nicht nur das Testen, sondern auch die Weiterentwicklung.
Lifehacks und Anti-Patterns für Einsteiger
- Schreib keinen "Gott-Klasse" (God Object), die alles macht.
- Mach keine "magischen Zahlen" ohne Erklärung (if (status == 42) – warum 42?).
- Missbrauch Vererbung nicht nur um der Vererbung willen – manchmal ist Komposition besser (Klasse mit Feldern anderer Klassen statt Vererbung).
- Schreib keine komplexen Methoden mit 100 Zeilen – die kann niemand testen oder verstehen.
- Lass immer Raum für Erweiterung (open/closed principle).
8. Wie schlechter und guter Code aussieht
Schlechtes Beispiel:
class s // Schlecht: Klassenname klein geschrieben.
{
public int a; // sinnlos, schlechter Name
public void m() // Schlecht: Methode mit nur einem Buchstaben.
{
Console.WriteLine(a);
// Schlecht: unklar, was die Methode macht.
}
}
Gutes Beispiel:
// Repräsentiert einen Studenten.
public class Student
{
// Alter des Studenten.
private int _age;
public int Age
{
get => _age;
set => _age = value < 0 ? 0 : value;
}
// Gibt Infos über den Studenten aus.
public void PrintInfo()
{
Console.WriteLine($"Alter des Studenten: {Age}");
}
}
GO TO FULL VERSION