Blog
Grenzen vor Bequemlichkeit
Wenn eine Abkürzung die Arbeit erleichtert, frage ich, welche Befugnis sie stillschweigend voraussetzt. Diese Befugnis zu benennen kostet am Anfang etwas Mühe und erspart später eine viel größere Reparatur.
Die Grenze benennen
Ich unterscheide zwischen einer Fähigkeit und der Befugnis, sie einzusetzen. Ein Werkzeug kann etwas lesen, ändern oder veröffentlichen; daraus folgt noch nicht, wer die Handlung an welchem Gegenstand und unter welchen Bedingungen auslösen darf. Bevor ich eine Oberfläche bequemer mache, halte ich Akteur, Ziel und erlaubte Handlung fest. Dieser kleine Aufwand ist günstiger als die spätere Erkenntnis, dass ein hilfreicher Standardwert eine Vertrauensgrenze überschritten hat.
Eine Berechtigung lässt sich am besten prüfen, wenn sie ein Wert ist und keine Konvention. Ich halte erlaubten Akteur, erlaubte Handlung und Umfang an einer Stelle fest und lasse die Operation direkt darauf zugreifen. So bleibt die Regel aus verstreuten Bedingungen heraus. Lautet die Antwort nein, soll die Ablehnung den fehlenden Teil nennen — Akteur, Handlung oder Ziel —, damit die anfragende Stelle weiß, welche Berechtigung sie braucht.
Die Grenze zu benennen legt auch fest, was das Werkzeug annehmen darf. Ein Standardwert, der eine private Datei liest, in einen gemeinsamen Kanal schreibt oder ein Budget ausgibt, ist eine Befugnisentscheidung, auch wenn er als Bequemlichkeit umgesetzt ist. Mir ist ein etwas längerer Normalfall lieber als eine stillschweigende Befugnis, denn gerade sie lässt sich später am schwersten nachvollziehen.
type Action = "read" | "publish";
interface Grant {
actor: string;
action: Action;
targets: readonly string[];
}
// A capability says what the system can do;
// a grant says who may ask for it.
export function mayPerform(
grant: Grant,
request: { actor: string; action: Action; target: string },
): boolean {
return (
grant.actor === request.actor &&
grant.action === request.action &&
grant.targets.includes(request.target)
);
}Beide Seiten prüfen
Ein erfolgreicher Test belegt, dass eine erlaubte Handlung funktioniert, aber nicht, wo die Erlaubnis endet. Ich ergänze einen abgelehnten Fall: einen anderen Akteur, ein anderes Ziel oder eine Handlung außerhalb der Freigabe. Auch fehlenden oder mehrdeutigen Kontext prüfe ich. Wenn das System dann eine Berechtigung errät, erfüllt die Grenze ihren Zweck nicht, selbst wenn die Bedienung aufgeräumt wirkt.
Der abgelehnte Fall ist am aussagekräftigsten, wenn er nahe am erlaubten liegt: derselbe Akteur und dasselbe Ziel mit einer anderen Handlung oder dieselbe Handlung an einem anderen Ziel. Ein weit entferntes Gegenbeispiel zeigt nur, dass das System nicht völlig offen ist. Ein Beinahe-Treffer zeigt, wo die Grenze tatsächlich verläuft, und genau er bricht später am ehesten, wenn eine Umgestaltung eine Bedingung still erweitert.
Ich prüfe auch die unangenehme Mitte: fehlender Kontext, ein unbekannter Akteur oder ein Ziel, das nicht mehr existiert. Sich nicht zu entscheiden ist ein gültiges Ergebnis, solange die Ablehnung sichtbar bleibt und erklärt werden kann. Eine Grenze, die still auf den großzügigen Zweig zurückfällt, ist gefährlicher als eine, die geschlossen scheitert und den Grund nennt.
test("a nearby request without a grant is refused", () => {
const grant: Grant = {
actor: "ana",
action: "read",
targets: ["draft-1"],
};
expect(
mayPerform(grant, { actor: "ana", action: "read", target: "draft-1" }),
).toBe(true);
// Same actor and target, different action.
expect(
mayPerform(grant, { actor: "ana", action: "publish", target: "draft-1" }),
).toBe(false);
// Same action and target, different actor.
expect(
mayPerform(grant, { actor: "bo", action: "read", target: "draft-1" }),
).toBe(false);
});Reibung gezielt einsetzen
Nicht jede Handlung braucht eine zusätzliche Bestätigung. Ständige Nachfragen können dazu führen, dass Menschen ungelesen zustimmen. Mir sind klare Beschränkungen nahe an der Handlung lieber, ergänzt um eine bewusste Pause bei schwer umkehrbaren Schritten oder beim Zugriff auf fremde Arbeit.
Reibung ist ein Werkzeug, kein Wert an sich. Ich setze sie dort ein, wo ein Fehler teuer wäre, und halte sie von wiederholten Lesevorgängen fern. Die entscheidende Prüffrage lautet: Kann ich erklären, warum eine Anfrage erlaubt oder abgelehnt wurde, und beide Ergebnisse ohne glücklichen Zufall wiederholen?