i18n/de/skills/fail-early-pattern/SKILL.md
Wendet das Fail-Early-(Fail-Fast-)Muster an, um Fehler so frueh wie moeglich zu erkennen und zu melden. Behandelt Eingabevalidierung mit Guard-Klauseln, aussagekraeftige Fehlermeldungen, Assertion-Funktionen und Anti-Muster, die Fehler still verschlucken. Primaere Beispiele in R mit allgemeiner/polyglotter Anleitung. Verwenden beim Schreiben von Funktionen, die externe Eingaben akzeptieren, beim Hinzufuegen von Eingabevalidierung vor der CRAN-Einreichung, beim Refaktorieren von Code der still falsche Ergebnisse erzeugt, beim Ueberpruefen von PRs auf Fehlerbehandlungsqualitaet oder beim Absichern interner APIs gegen ungueltiger Argumente.
npx skillsauth add pjt222/agent-almanac fail-early-patternInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Wenn etwas scheitern wird, sollte es so frueh wie moeglich, so laut wie moeglich und mit so viel Kontext wie moeglich scheitern. Dieser Skill kodifiziert das Fail-Early-Muster: Eingaben an Systemgrenzen validieren, Guard-Klauseln verwenden, um schlechten Zustand abzulehnen bevor er sich ausbreitet, und Fehlermeldungen schreiben, die beantworten was scheiterte, wo, warum und wie man es behebt.
Kartieren, wo externe Daten ins System eintreten. Diese Punkte benoetigen Validierung:
Interne Hilfsfunktionen, die nur durch eigenen validierten Code aufgerufen werden, benoetigen generell keine redundante Validierung.
Erwartet: Eine Liste von Einstiegspunkten, an denen nicht vertrauenswuerdige Daten in den Code eintreten.
Bei Fehler: Falls Grenzen unklar sind, rueckwaerts von Fehlern in Logs oder Bug-Reports verfolgen, um herauszufinden, wo schlechte Daten zuerst eingetreten sind.
Eingaben am Anfang jeder oeffentlichen Funktion validieren, bevor irgendeine Arbeit beginnt.
R (base):
calculate_summary <- function(data, method = c("mean", "median", "trim"), trim_pct = 0.1) {
# Guard: Typenpruefung
if (!is.data.frame(data)) {
stop("'data' must be a data frame, not ", class(data)[[1]], call. = FALSE)
}
# Guard: Nicht leer
if (nrow(data) == 0L) {
stop("'data' must have at least one row", call. = FALSE)
}
# Guard: Argument-Abgleich
method <- match.arg(method)
# Guard: Bereichspruefung
if (!is.numeric(trim_pct) || trim_pct < 0 || trim_pct > 0.5) {
stop("'trim_pct' must be a number between 0 and 0.5, got: ", trim_pct, call. = FALSE)
}
# --- Alle Guards bestanden, echte Arbeit beginnen ---
# ...
}
R (rlang/cli — bevorzugt fuer Pakete):
calculate_summary <- function(data, method = c("mean", "median", "trim"), trim_pct = 0.1) {
rlang::check_required(data)
if (!is.data.frame(data)) {
cli::cli_abort("{.arg data} must be a data frame, not {.cls {class(data)}}.")
}
if (nrow(data) == 0L) {
cli::cli_abort("{.arg data} must have at least one row.")
}
method <- rlang::arg_match(method)
if (!is.numeric(trim_pct) || trim_pct < 0 || trim_pct > 0.5) {
cli::cli_abort("{.arg trim_pct} must be between 0 and 0.5, not {.val {trim_pct}}.")
}
# ...
}
Allgemein (TypeScript):
function calculateSummary(data: DataFrame, method: Method, trimPct: number): Summary {
if (data.rows.length === 0) {
throw new Error(`data must have at least one row`);
}
if (trimPct < 0 || trimPct > 0.5) {
throw new RangeError(`trimPct must be between 0 and 0.5, got: ${trimPct}`);
}
// ...
}
Erwartet: Jede oeffentliche Funktion beginnt mit Guard-Klauseln, die ungueltige Eingaben ablehnen, bevor Nebeneffekte oder Berechnungen beginnen.
Bei Fehler: Falls Validierungslogik lang wird (>15 Zeilen Guards), einen validate_*-Helfer extrahieren oder stopifnot() fuer einfache Typ-Assertions verwenden.
Jede Fehlermeldung sollte vier Fragen beantworten:
cli::cli_abort)Gute Meldungen:
# Was + Warum (erwartet vs. tatsaechlich)
stop("'n' must be a positive integer, got: ", n, call. = FALSE)
# Was + Warum + Wie zu beheben
cli::cli_abort(c(
"{.arg config_path} does not exist: {.file {config_path}}",
"i" = "Create it with {.run create_config({.file {config_path}})}."
))
# Was + Kontext
cli::cli_abort(c(
"Column {.val {col_name}} not found in {.arg data}.",
"i" = "Available columns: {.val {names(data)}}"
))
Schlechte Meldungen:
stop("Error") # Was ist gescheitert? Keine Ahnung
stop("Invalid input") # Welche Eingabe? Was ist damit falsch?
stop(paste("Error in step", i)) # Keine handlungsrelevante Information
Erwartet: Fehlermeldungen sind selbstdokumentierend — ein Entwickler, der den Fehler zum ersten Mal sieht, kann ihn ohne Lesen des Quellcodes diagnostizieren und beheben.
Bei Fehler: Die drei juengsten Bug-Reports ueberpruefen. Falls einer das Lesen des Quellcodes erforderte, um ihn zu verstehen, muessen seine Fehlermeldungen verbessert werden.
stop() (oder cli::cli_abort()) verwenden, wenn die Funktion kein korrektes Ergebnis erzeugen kann. warning() nur verwenden, wenn die Funktion noch ein sinnvolles Ergebnis liefern kann, aber der Aufrufer von einem Problem wissen sollte.
Faustregel: Falls ein Benutzer still eine falsche Antwort erhalten koennte, ist das ein stop(), kein warning().
# RICHTIG: stop wenn Ergebnis falsch waere
read_config <- function(path) {
if (!file.exists(path)) {
stop("Config file not found: ", path, call. = FALSE)
}
yaml::read_yaml(path)
}
# RICHTIG: warnen wenn Ergebnis noch verwendbar ist
summarize_data <- function(data) {
if (any(is.na(data$value))) {
warning(sum(is.na(data$value)), " NA values dropped from 'value' column", call. = FALSE)
data <- data[!is.na(data$value), ]
}
# Mit gueltigen Daten fortfahren
}
Erwartet: stop() wird fuer Bedingungen verwendet, die falsche Ergebnisse erzeugen wuerden; warning() ist fuer degradierte-aber-gueltige Ergebnisse reserviert.
Bei Fehler: Bestehende warning()-Aufrufe pruefen. Falls die Funktion nach der Warnung Unsinn zurueckgibt, auf stop() aendern.
Fuer Bedingungen, die "niemals passieren sollten" in korrektem Code, Assertions verwenden. Diese fangen Programmiererfehler waehrend der Entwicklung auf:
# R: stopifnot fuer interne Invarianten
process_chunk <- function(chunk, total_size) {
stopifnot(
is.list(chunk),
length(chunk) > 0,
total_size > 0
)
# ...
}
# R: explizite Assertion mit Kontext
merge_results <- function(left, right) {
if (ncol(left) != ncol(right)) {
stop("Internal error: column count mismatch (", ncol(left), " vs ", ncol(right),
"). This is a bug -- please report it.", call. = FALSE)
}
# ...
}
Erwartet: Interne Invarianten werden assertiert, damit Bugs sofort an der Verletzungsstelle auftreten, nicht drei Funktionsaufrufe spaeter mit einem kryptischen Fehler.
Bei Fehler: Falls stopifnot()-Meldungen zu kryptisch sind, auf explizites if/stop mit Kontext umstellen.
Diese gaengigen Anti-Muster identifizieren und beheben:
Anti-Muster 1: Leeres tryCatch (Fehler verschlucken)
# VORHER: Fehler verschwindet still
result <- tryCatch(
parse_data(input),
error = function(e) NULL
)
# NACHHER: Protokollieren, neu werfen oder typisierter Fehler
result <- tryCatch(
parse_data(input),
error = function(e) {
cli::cli_abort("Failed to parse input: {e$message}", parent = e)
}
)
Anti-Muster 2: Standardwerte, die schlechte Eingaben verdecken
# VORHER: Aufrufer weiss nie, dass seine Eingabe ignoriert wurde
process <- function(x = 10) {
if (!is.numeric(x)) x <- 10 # ersetzt schlechte Eingabe still
x * 2
}
# NACHHER: Aufrufer ueber das Problem informieren
process <- function(x = 10) {
if (!is.numeric(x)) {
stop("'x' must be numeric, got ", class(x)[[1]], call. = FALSE)
}
x * 2
}
Anti-Muster 3: suppressWarnings als Loesung
# VORHER: Symptom verstecken statt Ursache beheben
result <- suppressWarnings(as.numeric(user_input))
# NACHHER: Explizit validieren, erwarteten Fall behandeln
if (!grepl("^-?\\d+\\.?\\d*$", user_input)) {
stop("Expected a number, got: '", user_input, "'", call. = FALSE)
}
result <- as.numeric(user_input)
Anti-Muster 4: Catch-All-Ausnahmebehandler
# VORHER: Jeder Fehler wird gleich behandelt
tryCatch(
complex_operation(),
error = function(e) message("Something went wrong")
)
# NACHHER: Spezifische Bedingungen behandeln, unerwartete propagieren lassen
tryCatch(
complex_operation(),
custom_validation_error = function(e) {
cli::cli_warn("Validation issue: {e$message}")
fallback_value
}
# Unerwartete Fehler propagieren natuerlich
)
Erwartet: Anti-Muster werden durch explizite Validierung oder spezifische Fehlerbehandlung ersetzt.
Bei Fehler: Falls das Entfernen eines tryCatch kaskadierte Fehler verursacht, hat der Upstream-Code eine Validierungsluecke. Die Quelle beheben, nicht das Symptom.
Die Testsuite ausfuehren, um zu bestaetigen, dass Fehlerpfade korrekt funktionieren:
# Fehlermeldungen pruefen ob sie ausgeloest werden
testthat::expect_error(calculate_summary("not_a_df"), "must be a data frame")
testthat::expect_error(calculate_summary(data.frame()), "at least one row")
testthat::expect_error(calculate_summary(mtcars, trim_pct = 2), "between 0 and 0.5")
# Pruefen ob gueltige Eingaben noch funktionieren
testthat::expect_no_error(calculate_summary(mtcars, method = "mean"))
# Vollstaendige Testsuite ausfuehren
Rscript -e "devtools::test()"
Erwartet: Alle Tests bestehen. Fehlerpfad-Tests bestaetigen, dass schlechte Eingaben die erwartete Fehlermeldung ausloesen.
Bei Fehler: Falls bestehende Tests auf stillen Fehlern beruhten (z.B. NULL bei schlechter Eingabe zurueckgeben), sie aktualisieren, um den neuen Fehler zu erwarten.
stop() wird fuer Bedingungen verwendet, die falsche Ergebnisse erzeugenwarning() wird nur fuer degradierte-aber-gueltige Ergebnisse verwendettryCatch-Bloecke, die Fehler still verschluckensuppressWarnings() als Ersatz fuer ordentliche Validierungstopifnot() oder explizite Assertions"Invalid input" zwingt den Aufrufer zu raten. Immer den Parameternamen, den erwarteten Typ/Bereich und den tatsaechlich erhaltenen Wert einbeziehen.stop() verwenden und den Aufrufer entscheiden lassen, wie damit umzugehen ist.tryCatch(..., error = function(e) NULL) versteckt Bugs. Falls gefangen werden muss, mit hinzugefuegtem Kontext protokollieren oder neu werfen.stop("msg") standardmaessig den Aufruf ein, was fuer Endbenutzer laestig ist. In benutzerseitigen Funktionen call. = FALSE verwenden. cli::cli_abort() macht dies automatisch.write-testthat-tests - Tests schreiben, die Fehlerpfade verifizierenreview-pull-request - Code auf fehlende Validierung und stille Fehler pruefenreview-software-architecture - Fehlerbehandlungsstrategie auf Systemebene beurteilencreate-skill - neue Skills nach dem agentskills.io-Standard erstellensecurity-audit-codebase - sicherheitsfokussierter Review, der sich mit Eingabevalidierung ueberschneidettesting
Launch all available agents in parallel waves for open-ended hypothesis generation on problems where the correct domain is unknown. Use when facing a cross-domain problem with no clear starting point, when single-agent approaches have stalled, or when diverse perspectives are more valuable than deep expertise. Produces a ranked hypothesis set with convergence analysis and adversarial refinement.
tools
Write integration tests for a Node.js CLI application using the built-in node:test module. Covers the exec helper pattern, output assertions, filesystem state verification, cleanup hooks, JSON output parsing, error case testing, and state restoration after destructive tests. Use when adding tests to an existing CLI, testing a new command, verifying adapter behavior across frameworks, or setting up CI for a CLI tool.
development
Screen a proposed trademark for conflicts and distinctiveness before filing. Covers trademark database searches (TMview, WIPO Global Brand Database, USPTO TESS), distinctiveness analysis using the Abercrombie spectrum, likelihood of confusion assessment using DuPont factors and EUIPO relative grounds, common law rights evaluation, and goods/services overlap analysis. Produces a conflict report with a risk matrix. Use before adopting a new brand name, logo, or slogan — distinct from patent prior art search, which uses different databases, legal frameworks, and analysis methods.
tools
Scaffold a new CLI command using Commander.js with options, action handler, three output modes (human-readable, quiet, JSON), and optional ceremony variant. Covers command naming, option design, shared context patterns, error handling, and integration testing. Use when adding a command to an existing Commander.js CLI, designing a new CLI tool from scratch, or standardizing command structure across a multi-command CLI.