Clean Code Prinzipien
Clean Code: Prinzipien für besseren Code
Clean Code ist lesbarer, wartbarer und fehlerfreier Code. Lernen Sie die wichtigsten Prinzipien für professionelle Softwareentwicklung.
Warum Clean Code?
| Aspekt | Dirty Code | Clean Code |
|---|---|---|
| Lesbarkeit | Schwer verständlich | Selbsterklärend |
| Wartung | Riskant, zeitaufwändig | Einfach, sicher |
| Bugs | Versteckt, schwer zu finden | Offensichtlich, leicht zu fixen |
| Onboarding | Langwierig | Schnell |
1. Aussagekräftige Namen
// ❌ Schlecht
$d = 86400;
$arr = getU();
function calc($a, $b) { }
// ✅ Gut
$secondsPerDay = 86400;
$activeUsers = getActiveUsers();
function calculateTotalPrice($items, $taxRate) { }
// ❌ Schlecht - Zu generisch
$data = fetchData();
$info = getInfo();
$result = process($input);
// ✅ Gut - Spezifisch
$userProfile = fetchUserProfile($userId);
$orderDetails = getOrderDetails($orderId);
$validatedEmail = validateEmail($rawEmail);
// Booleans sollten wie Fragen klingen
$isActive = true;
$hasPermission = false;
$canEdit = checkEditPermission($user);
2. Funktionen - Klein und fokussiert
// ❌ Schlecht - Funktion macht zu viel
function processOrder($order) {
// Validierung
if (!$order->items) throw new Exception('No items');
if (!$order->customer) throw new Exception('No customer');
// Preis berechnen
$total = 0;
foreach ($order->items as $item) {
$total += $item->price * $item->quantity;
}
$tax = $total * 0.19;
$total += $tax;
// In Datenbank speichern
$db->insert('orders', [...]);
// Email senden
$mailer->send($order->customer->email, 'Order Confirmation', ...);
// PDF generieren
$pdf = new PDF();
$pdf->generate(...);
return $total;
}
// ✅ Gut - Jede Funktion macht eine Sache
function processOrder($order) {
validateOrder($order);
$total = calculateTotal($order);
saveOrder($order, $total);
sendConfirmationEmail($order);
generateInvoicePDF($order);
return $total;
}
function validateOrder($order) {
if (!$order->items) {
throw new InvalidOrderException('Order has no items');
}
if (!$order->customer) {
throw new InvalidOrderException('Order has no customer');
}
}
function calculateTotal($order) {
$subtotal = calculateSubtotal($order->items);
$tax = calculateTax($subtotal);
return $subtotal + $tax;
}
3. Wenige Parameter
// ❌ Schlecht - Zu viele Parameter
function createUser($name, $email, $age, $street, $city, $zip, $country, $phone) {
// ...
}
// ✅ Gut - Objekt übergeben
function createUser(UserData $userData) {
// ...
}
// Oder mit Named Parameters (PHP 8+)
createUser(
name: 'Max',
email: 'max@example.com',
address: new Address(...)
);
// ❌ Schlecht - Boolean Parameter
function sendEmail($to, $subject, $body, $isHtml, $hasAttachment) {
// Was bedeutet sendEmail(..., true, false)?
}
// ✅ Gut - Separate Methoden oder Objekt
function sendHtmlEmail($to, $subject, $body) { }
function sendPlainEmail($to, $subject, $body) { }
// Oder mit Options-Objekt
function sendEmail($to, $subject, $body, EmailOptions $options) { }
4. Keine Seiteneffekte
// ❌ Schlecht - Versteckter Seiteneffekt
class UserService {
function checkPassword($user, $password) {
if (hash($password) === $user->passwordHash) {
Session::start(); // Überraschung!
$user->lastLogin = now();
$user->save();
return true;
}
return false;
}
}
// ✅ Gut - Funktion tut nur was der Name sagt
class UserService {
function verifyPassword($user, $password): bool {
return hash($password) === $user->passwordHash;
}
function login($user) {
Session::start();
$user->recordLogin();
}
}
// Aufruf ist jetzt klar
if ($userService->verifyPassword($user, $password)) {
$userService->login($user);
}
5. DRY - Don't Repeat Yourself
// ❌ Schlecht - Duplizierter Code
function getActiveUsers() {
$users = $db->query('SELECT * FROM users WHERE status = "active"');
$result = [];
foreach ($users as $user) {
$result[] = [
'id' => $user->id,
'name' => $user->name,
'email' => $user->email
];
}
return $result;
}
function getInactiveUsers() {
$users = $db->query('SELECT * FROM users WHERE status = "inactive"');
$result = [];
foreach ($users as $user) {
$result[] = [
'id' => $user->id,
'name' => $user->name,
'email' => $user->email
];
}
return $result;
}
// ✅ Gut - Abstraktion
function getUsersByStatus($status) {
$users = $db->query('SELECT * FROM users WHERE status = ?', [$status]);
return array_map(fn($user) => formatUser($user), $users);
}
function formatUser($user) {
return [
'id' => $user->id,
'name' => $user->name,
'email' => $user->email
];
}
6. Kommentare richtig nutzen
// ❌ Schlecht - Kommentar erklärt schlechten Code
// Prüfe ob User älter als 18 ist
if ($u->a >= 18) { }
// ✅ Gut - Code erklärt sich selbst
if ($user->isAdult()) { }
// ❌ Schlecht - Offensichtlicher Kommentar
// Counter erhöhen
$counter++;
// ✅ Gut - Kommentar erklärt WARUM
// +1 weil Array 0-indexed, aber IDs bei 1 starten
$displayIndex = $arrayIndex + 1;
// ✅ Gut - Warnung
// ACHTUNG: Diese Methode ist nicht thread-safe!
function updateCache() { }
// ✅ Gut - TODO mit Kontext
// TODO: Refactor nach Migration zu PHP 8 (Stand: 2024-01)
function legacyFunction() { }
// ❌ Schlecht - Auskommentierter Code
// function oldImplementation() {
// ...
// }
// Lösung: Löschen! Git hat die Historie.
7. Error Handling
// ❌ Schlecht - Fehler verschlucken
function getUser($id) {
try {
return $db->find($id);
} catch (Exception $e) {
return null; // Problem versteckt!
}
}
// ✅ Gut - Fehler explizit behandeln
function getUser($id): User {
$user = $db->find($id);
if (!$user) {
throw new UserNotFoundException("User {$id} not found");
}
return $user;
}
// ✅ Gut - Fehler dokumentiert
/**
* @throws UserNotFoundException
* @throws DatabaseException
*/
function getUser($id): User { }
// ❌ Schlecht - Exception als Flow Control
try {
$user = getUser($id);
processUser($user);
} catch (UserNotFoundException $e) {
createUser($id); // Exception als normaler Flow
}
// ✅ Gut - Explizite Prüfung
if ($userService->exists($id)) {
$user = $userService->get($id);
processUser($user);
} else {
$userService->create($id);
}
8. Konsistenz
// ❌ Inkonsistent
function getUsers() { }
function fetch_orders() { }
function RetrieveProducts() { }
// ✅ Konsistent
function getUsers() { }
function getOrders() { }
function getProducts() { }
// Innerhalb einer Codebase:
// - Gleiche Namenskonventionen
// - Gleiche Formatierung
// - Gleiche Patterns für gleiche Probleme
// - Gleiche Ordnerstruktur
9. Early Return
// ❌ Schlecht - Tiefe Verschachtelung
function processPayment($order) {
if ($order) {
if ($order->isPaid === false) {
if ($order->total > 0) {
if ($paymentService->isAvailable()) {
// Endlich die eigentliche Logik...
return $paymentService->process($order);
}
}
}
}
return false;
}
// ✅ Gut - Early Returns
function processPayment($order) {
if (!$order) {
return false;
}
if ($order->isPaid) {
return false;
}
if ($order->total <= 0) {
return false;
}
if (!$paymentService->isAvailable()) {
return false;
}
return $paymentService->process($order);
}
10. Boy Scout Rule
// "Hinterlasse den Code sauberer als du ihn vorgefunden hast." // Wenn du Code änderst: // - Verbessere Variablennamen // - Extrahiere kleine Funktionen // - Entferne toten Code // - Füge fehlende Typen hinzu // - Korrigiere offensichtliche Probleme // ABER: Nicht alles auf einmal! // Kleine, inkrementelle Verbesserungen
💡 Zusammenfassung:
1. Namen sollten Absicht zeigen
2. Funktionen: klein, eine Aufgabe
3. Wenige Parameter, keine Seiteneffekte
4. DRY - Keine Wiederholungen
5. Kommentare nur wenn wirklich nötig
6. Fehler explizit behandeln
7. Konsistent bleiben
8. Early Return statt Verschachtelung
2. Funktionen: klein, eine Aufgabe
3. Wenige Parameter, keine Seiteneffekte
4. DRY - Keine Wiederholungen
5. Kommentare nur wenn wirklich nötig
6. Fehler explizit behandeln
7. Konsistent bleiben
8. Early Return statt Verschachtelung