Gute Abstraktionen erkennt man daran, was sie weglassen.

Nicht jede Wiederholung braucht ein Framework. Wie kleine, klare Schnittstellen uns helfen, bessere Entscheidungen zu treffen.

Beispielartikel aus der CodeKapitel-Konzeptvorschau.

Lesemodus

Weniger Entscheidungen am falschen Ort

Stell dir eine Anwendung vor, die Bestellbestätigungen verschickt. An drei Stellen werden Empfänger, Betreff und Nachricht zusammengesetzt. Der erste Impuls liegt nahe: Alles in eine universelle Versandfunktion ziehen. Doch die Zahl ähnlicher Zeilen sagt wenig darüber aus, ob diese Stellen dieselbe Aufgabe haben. Eine Bestätigung, eine Zahlungserinnerung und eine interne Warnung können heute ähnlich aussehen und morgen ganz unterschiedliche Regeln brauchen.

Eine hilfreiche Abstraktion gibt ihrer aufrufenden Stelle eine passende Sprache. Wer eine Bestellung bestätigt, sollte keine Vorlagenkennung auswählen oder Transportdetails kennen müssen. Die Schnittstelle beschreibt die fachliche Absicht und hält technische Entscheidungen dort, wo sie sinnvoll geändert werden können. Sie spart also nicht nur Zeichen. Sie verringert die Zahl der Fragen, die man beantworten muss, um den nächsten Schritt im Programm zu verstehen.

Das ist ein praktischer Maßstab beim Lesen: Kann ich den Aufruf verstehen, ohne sofort in seine Implementierung zu springen? Wenn nicht, hat die neue Schicht womöglich nur Code verschoben. Eine kürzere Datei ist noch kein besser verständliches System.

Eine kleine Grenze ist oft genug

Beginnen wir mit einer bewusst schmalen Schnittstelle. In unserem Beispiel kennt die Bestelllogik eine Funktion zum Senden einer Bestätigung. Wie eine Nachricht tatsächlich zugestellt wird, bleibt außerhalb dieser Funktion. Ein übergebener Versandbaustein reicht dafür aus; eine Vererbungshierarchie ist für diesen Fall nicht nötig.

Der folgende Ausschnitt zeigt nur die Grenze. In einer echten Anwendung würden Inhalt, Zustellung und mögliche Fehler zur fachlichen Anforderung passen. Für den Entwurf ist entscheidend: Die Bestelllogik übergibt eine Bestellung und muss keine Sammlung optionaler Einstellungen verwalten. Ein Test kann einen einfachen Ersatz für den Versand verwenden und die erzeugte Nachricht untersuchen.

type Order = { id: string; email: string };
type Message = { to: string; subject: string; text: string };
type Send = (message: Message) => Promise<void>;

async function confirmOrder(order: Order, send: Send) {
  await send({
    to: order.email,
    subject: "Deine Bestellung ist angekommen",
    text: "Wir haben Bestellung " + order.id + " erhalten.",
  });
}

Die nächste Änderung ist der eigentliche Test

Eine Abstraktion bewährt sich nicht durch die Anzahl ihrer Nutzer, sondern durch die Änderungen, die sie verständlich macht. Nehmen wir an, Bestätigungen brauchen künftig eine andere Formulierung. Das gehört in die Bestätigung. Wechselt dagegen der technische Versandweg, sollte sich die fachliche Bestelllogik möglichst wenig bewegen. Zwei Änderungsgründe haben damit zwei nachvollziehbare Orte.

Problematisch wird es, wenn jede neue Anforderung einen weiteren Schalter erzeugt: intern, dringend, mit Anhang, ohne Begrüßung. Solche Schalter sind nicht grundsätzlich falsch. Ihre Kombinationen können aber anzeigen, dass mehrere Aufgaben unter einem zu allgemeinen Namen zusammengefasst wurden. Dann lohnt es sich, die ursprünglichen Anwendungsfälle nebeneinanderzulegen und ihre Unterschiede ausdrücklich zu benennen.

Die Lösung kann eine Aufteilung sein. Sie kann auch darin bestehen, vorerst etwas ähnlichen Code zu behalten. Entscheidend ist, ob Änderungen unabhängig bleiben können. Gemeinsam aussehende Zeilen sind dafür ein Hinweis, aber kein Beweis.

Erst beobachten, dann verallgemeinern

Bei einem neuen Anwendungsfall fehlt oft das Wissen, welche Teile dauerhaft zusammengehören. Statt mögliche Zukunftsszenarien in eine Konfiguration zu gießen, lohnt sich eine direkte, gut benannte Lösung. Beim nächsten echten Fall lassen sich Gemeinsamkeiten anhand konkreter Anforderungen besprechen. So entsteht die Schnittstelle aus Erfahrung statt aus Vermutungen.

Drei Fragen helfen im Review: Welche Entscheidung nimmt die Schnittstelle ihrem Aufrufer ab? Welche Änderung soll an genau einer Stelle stattfinden? Und welcher konkrete Fall würde die Grenze sprengen? Werden die Antworten unklar, ist das kein persönliches Scheitern des Entwurfs. Es ist ein Anlass, die Grenze kleiner zu machen. Gute Abstraktionen lassen genug weg, damit das Wesentliche sichtbar bleibt.

Gedanke mitnehmen. Weiterdenken.

Ein gutes Kapitel ist erst der Anfang.

Entdecke weitere Perspektiven auf Software, Architektur und die Arbeit am Code.

Weitere Artikel entdecken