Clean Code Architektur

Warum "Quick & Dirty" meistens teuer wird

Stephan Pfeiffer

"Mach es einfach schnell lauffähig, wir refactorn das später!" – Ein Satz, den wohl jeder Softwareentwickler schon einmal gehört hat. In der Realität kommt dieses "Später" allerdings fast nie. In diesem Artikel betrachte ich aus der Praxis, warum sich der Mehraufwand für saubere Architektur fast immer auszahlt.

Die Illusion der Geschwindigkeit

Zu Beginn eines Projekts mag das "Hacken" ohne Rücksicht auf Design-Patterns schneller erscheinen. Features fliegen nur so in die Codebase. Das Problem beginnt, wenn das Projekt wächst. Ohne Konzepte wie DRY (Don't Repeat Yourself) oder das Single Responsibility Principle (SRP) fängt der Code an zu "verrotten" (Code Rot).

Die Folge: Um ein neues Feature einzubauen, muss Entwickler A erst an drei völlig unverwandten Stellen Anpassungen vornehmen, was Entwickler B's Code ungewollt zerschießt. Die Entwicklung kommt zum Stillstand.

SOLID ist kein Buzzword

Die SOLID-Prinzipien (von Robert C. Martin) sind nicht einfach nur akademische Theorie, sondern das Fundament wartbarer Software in objektorientierten Sprachen wie C#.

  • S - Single Responsibility: Eine Klasse sollte genau eine Aufgabe haben. Ein CustomerService, der E-Mails verschickt, PDF-Rechnungen generiert und in die Datenbank schreibt, ist ein Albtraum beim Testen.
  • O - Open/Closed: Der Code sollte offen für Erweiterungen, aber geschlossen für Modifikationen sein. Anstatt bei jeder neuen Zahlungsmethode eine riesige switch-Anweisung zu erweitern, nutzen wir Interfaces (IPaymentProcessor) und Dependency Injection.
  • D - Dependency Inversion: Wir hängen von Abstraktionen ab, nicht von konkreten Implementierungen. Genau deshalb nutzen wir in ASP.NET Core exzessiv die IServiceCollection.

Interfaces und Dependency Injection in C#

Nehmen wir ein praktisches Beispiel. Anstatt einen Logger hart zu instanziieren, fordern wir ihn im Konstruktor an:

Constructor Injection
public class OrderService
{
    private readonly ILogger<OrderService> _logger;
    private readonly IOrderRepository _repository;

    public OrderService(ILogger<OrderService> logger, IOrderRepository repository)
    {
        _logger = logger;
        _repository = repository;
    }

    public async Task ProcessOrder(Order order)
    {
        _logger.LogInformation($"Processing order {order.Id}");
        await _repository.SaveAsync(order);
    }
}

Dieser Code ist nun zu 100% testbar. Im Unit-Test (z.B. mit xUnit und Moq) können wir das IOrderRepository einfach mocken, ohne dass wirklich etwas in eine echte Datenbank geschrieben wird.

Fazit: Wann lohnt sich "Quick & Dirty"?

Für Einweg-Skripte, kleine Proof of Concepts oder Wegwerf-Prototypen ist "Quick & Dirty" absolut legitim. Aber für produktiven Code, der über Monate oder Jahre gewartet, im Team bearbeitet und skaliert werden muss, ist fehlende Architektur die größte Kostenfalle der modernen Softwareentwicklung. Wir lesen Code zehnmal häufiger, als wir ihn schreiben. Er sollte sich wie ein gut geschriebenes Buch lesen.