mitmario.dev

Synthese: dein erstes Werkzeug

Node.js Sandbox 3 Min Lesezeit 2 BeispieleLektion 5 von 6

Du hast jetzt alle Teile beisammen. Argumente aus Lektion 4.1, Umgebungsvariablen aus 4.2, die beiden Kanäle und den Exit-Code aus 4.3, dazu das Lesen von Dateien aus Abschnitt 3.

In dieser Lektion geht es darum, wie man sie zusammensetzt, damit am Ende etwas herauskommt, das man einem Kollegen geben kann.

Was ein Werkzeug von einem Skript unterscheidet

Ein Skript tut eine Sache, für die es geschrieben wurde. Es kennt seine Dateinamen, weil sie im Code stehen, und wenn etwas schiefgeht, stürzt es ab. Das ist völlig in Ordnung, solange nur du es benutzt.

Ein Werkzeug ist etwas anderes. Es lässt sich von außen steuern, es hat einen sinnvollen Standardfall, es meldet Probleme auf dem richtigen Kanal, und es endet mit einer Zahl, die etwas aussagt. Der Unterschied ist nicht die Größe, sondern die Frage, ob jemand anders es benutzen kann, ohne dich zu fragen.

Die Reihenfolge, die sich bewährt hat

Ein Werkzeug von oben nach unten
import { readFile } from "node:fs/promises";

const [datei] = process.argv.slice(2);

if (datei === undefined) {
  console.error("Aufruf: node zaehlen.mjs <datei>");
  process.exit(1);
}

console.error(`Lese ${datei} ...`);

const eintraege = JSON.parse(await readFile(datei, "utf8"));

console.log(`${eintraege.length} Einträge`);

Fünf Schritte, immer dieselben:

Erstens: Argumente lesen und prüfen. Fehlt etwas, wird eine Zeile Hilfe ausgegeben und Schluss.

Zweitens: Umgebung lesen. Alles, was von außen kommen darf, wird hier eingesammelt, samt Standardwerten.

Drittens: arbeiten. Erst hier passiert das Eigentliche.

Viertens: Ergebnis ausgeben, auf stdout, und zwar nur das Ergebnis.

Fünftens: Exit-Code setzen, falls etwas nicht geklappt hat.

Im Beispiel siehst du auch die Aufteilung der Kanäle wieder: Das Lese ... steht auf stderr, weil es Ablauf ist, und die Zahl steht auf stdout, weil sie das Ergebnis ist.

Warum die Prüfung ganz nach vorn gehört

Jetzt der Grund für die Reihenfolge, und er ist wichtiger als die Reihenfolge selbst.

Wenn die Prüfung zu spät kommt
import { readFile } from "node:fs/promises";

const eintraege = JSON.parse(await readFile("daten/einkauf.json", "utf8"));
const feld = process.argv[2];

const gruppen = {};

for (const eintrag of eintraege) {
  const wert = eintrag[feld];
  gruppen[wert] = (gruppen[wert] ?? 0) + 1;
}

console.log(gruppen);

Dieses Werkzeug liest erst die Datei und schaut danach nach dem Argument. Es läuft hier ohne Argument, und was dabei herauskommt, steht im Terminal: { undefined: 7 }. Der Weg dorthin ist harmlos und deshalb so gemein: feld ist undefined, eintrag[undefined] ist ebenfalls undefined, und alle sieben Einträge landen in einer Gruppe dieses Namens.

Es stürzt nicht ab. Es meldet keinen Fehler. Es endet mit Exit-Code 0, also mit „alles gut”. Und es gibt Unsinn aus.

Wie es aussehen sollte, siehst du in einem Handgriff: Starte die Sandbox und tipp im Terminal node gruppieren.mjs kategorie. Dann steht dort { Backwaren: 2, Kuehlregal: 3, Obst: 2 }. Zwei Aufrufe derselben Datei, einer davon Unsinn, und keiner von beiden beschwert sich.

Das ist der schlechteste aller Ausgänge. Ein Absturz wäre besser gewesen, denn den hätte jemand bemerkt. So wandert das Ergebnis in die nächste Verarbeitungsstufe, und der Fehler fällt drei Schritte später auf, an einer Stelle, die damit nichts zu tun hat.

Dazu kommt der praktische Punkt: Die Datei wurde umsonst gelesen. Bei einer kleinen JSON-Datei merkst du das nicht. Bei einem Werkzeug, das erst dreißig Sekunden lang etwas herunterlädt und dann sagt, dass ein Argument fehlt, wirst du es merken.

Prüf alles, was du prüfen kannst, bevor du anfängst zu arbeiten.

Was mit einer fehlenden Datei passieren soll

Ein Werkzeug, das eine Datei liest, muss damit rechnen, dass sie nicht da ist. Aus Lektion 3.5 weißt du, wie das aussieht: Der Zugriff wirft, und ohne try bricht dein Programm mit einem Stacktrace ab.

Ein Stacktrace ist die falsche Antwort auf „die Datei gibt es nicht”. Er ist lang, er zeigt auf Node-interne Zeilen, und er sagt einem Benutzer nichts, was ihm hilft.

Fang den Fall ab, schreib einen Satz auf stderr, der das Problem benennt, und beende mit 1. Genau das baust du in der Aufgabe zu dieser Lektion ein.

Der Unterschied in einem Satz: Ein Stacktrace ist für dich beim Entwickeln, eine Fehlermeldung ist für den, der dein Werkzeug benutzt.

Zum Mitnehmen

Prüfen, lesen, arbeiten, ausgeben, Code setzen. In dieser Reihenfolge, und die Prüfung steht ganz vorn.

Jetzt du

Basis Konto, kostenlos

Zu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.

Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.

In diesem Kurs läuft dein Code auf einem Server. Dafür hat das Basis Konto 1 Stunde im Monat, mehr Zeit gibt es mit dem Premium Konto.

Was in dieser Lektion steckt

  • Artikel mit 2 Beispielen zum Ausprobieren

    Steht hier, ohne Konto lesbar.

  • Aufgabe, dein Code läuft auf einem Server

    Öffnet sich mit dem Basis Konto.