Abschnitt 20 · Lektion 1
Namen und kleine Funktionen
Ab hier kommt kein neues Sprachmittel mehr. Du kennst alles, was du brauchst. Was jetzt noch fehlt, ist der Unterschied zwischen Code, der läuft, und Code, mit dem man arbeiten kann.
Der Unterschied ist keine Geschmacksfrage. Er entscheidet, wie lange du an einer Änderung sitzt.
Erst einmal ansehen, worum es geht
<p>Sieh in die Console.</p> body {
font-family: system-ui, sans-serif;
max-width: 40rem;
margin: 0;
padding: 1rem;
line-height: 1.6;
color: #1c1917;
}
p {
margin: 0 0 0.75rem;
} const d = [
{ t: "HTML-Kurs", p: 4900, m: 1 },
{ t: "CSS-Kurs", p: 6900, m: 1 },
{ t: "Aufkleber", p: 240, m: 2 },
];
function calc(a) {
let s = 0;
for (const x of a) {
s = s + x.p * x.m;
}
// 5000 = Grenze, 495 = Pauschale
if (s < 5000) {
s = s + 495;
}
return (s / 100).toFixed(2).replace(".", ",") + " €";
}
console.log(calc(d)); Diese Funktion ist richtig. Sie rechnet einen Warenkorb zusammen, schlägt bei kleinen Bestellungen den Versand drauf und gibt einen deutschen Betrag zurück. Sie hat elf Zeilen.
Und trotzdem musst du sie lesen wie eine Geheimschrift. Was ist s? Was ist x.m? Warum steht da 5000 und woanders 495?
Stell dir vor, dein Chef fragt: „Können wir die Versandgrenze auf 3000 senken?” Du müsstest die Funktion erst verstehen, bevor du die Zahl überhaupt findest. Und wenn dieselbe 5000 an drei Stellen im Projekt steht, findest du sie zweimal und übersiehst die dritte.
Noch etwas fehlt, und es fällt erst auf, wenn man danach sucht: Du kannst diese Funktion nichts fragen. Öffne das erste Beispiel und tipp in der Eingabezeile der Console calc(d). Du bekommst 122,80 €, das ganze Ergebnis. Frag jetzt nach dem Versand allein: typeof versandkostenInCent antwortet undefined. Es gibt keinen Versand in diesem Code, es gibt nur die elf Zeilen als Ganzes.
Derselbe Code, nur mit Namen
<p>Sieh in die Console.</p> body {
font-family: system-ui, sans-serif;
max-width: 40rem;
margin: 0;
padding: 1rem;
line-height: 1.6;
color: #1c1917;
}
p {
margin: 0 0 0.75rem;
} const VERSANDFREI_AB_CENT = 5000;
const VERSANDKOSTEN_CENT = 495;
const warenkorb = [
{ titel: "HTML-Kurs", preisInCent: 4900, menge: 1 },
{ titel: "CSS-Kurs", preisInCent: 6900, menge: 1 },
{ titel: "Aufkleber", preisInCent: 240, menge: 2 },
];
function zwischensummeInCent(posten) {
let summe = 0;
for (const eintrag of posten) {
summe = summe + eintrag.preisInCent * eintrag.menge;
}
return summe;
}
function versandkostenInCent(zwischensumme) {
if (zwischensumme >= VERSANDFREI_AB_CENT) {
return 0;
}
return VERSANDKOSTEN_CENT;
}
function gesamtpreisInCent(posten) {
const zwischensumme = zwischensummeInCent(posten);
return zwischensumme + versandkostenInCent(zwischensumme);
}
function euroText(cent) {
return (cent / 100).toFixed(2).replace(".", ",") + " €";
}
console.log("Zwischensumme:", euroText(zwischensummeInCent(warenkorb)));
console.log("Versand:", euroText(versandkostenInCent(zwischensummeInCent(warenkorb))));
console.log("Gesamt:", euroText(gesamtpreisInCent(warenkorb))); Zwei Dinge sind hier passiert, und beide sind einfacher, als sie klingen.
Die Zahlen haben einen Namen bekommen. VERSANDFREI_AB_CENT steht genau einmal da. Wenn die Grenze sich ändert, änderst du eine Zeile, und zwar die, die so heißt wie das, was du ändern willst. Für Werte, die sich im Programmablauf nie ändern, ist Großschreibung mit Unterstrich üblich. Das ist reine Übereinkunft, aber eine hilfreiche: du siehst sofort, dass hier niemand etwas zuweist.
Die Funktion ist in vier Funktionen zerfallen. Jede tut eine Sache, und der Name sagt welche. Du kannst versandkostenInCent lesen, verstehen und ändern, ohne zu wissen, was euroText macht.
Und jetzt kannst du fragen. Öffne das zweite Beispiel und stell in der Eingabezeile der Console die Frage von oben, ohne eine Zeile zu lesen: versandkostenInCent(4999) antwortet 495, versandkostenInCent(5000) antwortet 0. Damit weißt du, dass die Grenze einschließlich gilt, und du weißt es aus dem laufenden Code und nicht aus einem Kommentar. VERSANDFREI_AB_CENT antwortet 5000, zwischensummeInCent(warenkorb) antwortet 12280.
Das ist nicht bloß bequem. Eine Funktion, die man einzeln aufrufen kann, kann man einzeln prüfen, und genau davon lebt die nächste Lektion.
Die Regel dahinter ist alt und hält sich hartnäckig: Ein Name sagt, was etwas ist oder was es tut, nie wie es gemacht wird. kursliste statt arr. berechneGesamtpreis statt calc. Substantive für Werte, Verben für Funktionen.
Eine Funktion tut eine Sache
Woran merkst du, dass eine Funktion zwei Dinge tut? An ihrem Namen.
Wenn du ihn nur mit einem „und” bilden kannst, sind es zwei. speichereUndZeichneNeu ist zwei Funktionen, die noch nicht getrennt wurden. ladeDatenUndZeigeFehler auch.
Das ist kein Selbstzweck. Eine Funktion, die nur rechnet, kannst du mit Testfällen abnehmen, und genau das tut dieser Kurs seit Abschnitt 5 mit jeder Aufgabe. Eine Funktion, die rechnet und dabei ins DOM schreibt, kannst du nur noch ansehen. Warum das so wichtig ist, ist das Thema der nächsten Lektion.
Eine Zahl für die Länge gibt es nicht. Wenn du beim Lesen scrollen musst, um den Anfang wiederzufinden, ist es zu lang. Das ist ungenau und trotzdem der beste Maßstab, den es gibt.
Wahrheitswerte, und der Kommentar, der bleibt
<p>Sieh in die Console.</p> body {
font-family: system-ui, sans-serif;
max-width: 40rem;
margin: 0;
padding: 1rem;
line-height: 1.6;
color: #1c1917;
}
p {
margin: 0 0 0.75rem;
} const VERSANDFREI_AB_CENT = 5000;
// Der Name sagt nicht, was der Wert bedeutet.
// Ist das der Versand, kostet er etwas, ist er frei?
const versand = 4200 < VERSANDFREI_AB_CENT;
console.log("versand:", versand);
// Mit ist am Anfang liest sich der Aufruf wie ein Satz.
function istVersandkostenfrei(zwischensumme) {
return zwischensumme >= VERSANDFREI_AB_CENT;
}
console.log("4200 frei?", istVersandkostenfrei(4200));
console.log("6000 frei?", istVersandkostenfrei(6000));
if (istVersandkostenfrei(6000)) {
console.log("Der Versand ist frei.");
}
// Dieser Kommentar bleibt, denn kein Name kann ihn ersetzen.
// Der Zahlungsdienst rundet zu unseren Gunsten, unsere
// Buchhaltung will aber abrunden. Deshalb floor, nicht round.
function provisionInCent(betragInCent) {
return Math.floor(betragInCent * 0.029);
}
console.log("Provision auf 14280:", provisionInCent(14280)); Ein Name für einen Wahrheitswert beginnt mit ist, hat oder kann. istVersandkostenfrei, hatFehler, kannBearbeiten. Dann liest sich jedes if wie ein deutscher Satz, und du musst nie überlegen, ob true jetzt „ja” oder „nein” bedeutet.
Damit zum Kommentar. Die zwei Kommentare im ersten Beispiel waren Notlösungen: Sie erklärten Zahlen, die einen Namen gebraucht hätten. Solche Kommentare verschwinden, sobald der Name da ist. Und das ist gut so, denn Kommentare veralten. Der Code ändert sich, der Kommentar bleibt stehen, und irgendwann steht dort etwas Falsches.
Der Kommentar am Ende des Beispiels ist von anderer Art. Er hält fest, warum dort Math.floor steht und nicht Math.round. Das sieht man dem Code nicht an, das steht in keiner Zeile, und der nächste Mensch würde es „aufräumen”.
Als Faustregel: Der Code sagt, was passiert. Ein Kommentar sagt, warum es so passiert. Wenn dein Kommentar den Code nacherzählt, lösch ihn und such einen besseren Namen.
Die Reihenfolge in einer Datei
Es gibt keine Vorschrift, aber eine Ordnung, die fast überall funktioniert und die du in den Beispielen dieser Lektion siehst.
Ganz oben die Konstanten, damit man die Stellschrauben sofort sieht. Darunter die Hilfsfunktionen. Ganz unten das, was das Programm tatsächlich startet.
Der Grund ist praktisch: Wer die Datei zum ersten Mal öffnet, sieht oben, womit gerechnet wird, und unten, was passiert. Die Details in der Mitte liest er nur, wenn er sie braucht.
Der Punkt, an dem alle stolpern
Der Reflex bei langen Namen ist: das tippt sich schlecht.
Das stimmt, und es spielt keine Rolle. Du tippst einen Namen einmal, dein Editor ergänzt ihn danach von selbst, und gelesen wird er hundertmal. Ein Name, der beim Lesen eine Rückfrage spart, hat sich in derselben Minute bezahlt gemacht.
Der zweite Reflex geht in die andere Richtung: alles zerlegen, bis jede Funktion drei Zeilen hat. Auch das ist falsch, nur andersherum. Wer für jeden Einzelschritt eine Funktion baut, muss beim Lesen zwischen zwanzig Stellen hin und her springen. Die richtige Größe ist die, bei der eine Funktion einen Gedanken beschreibt. Dafür gibt es kein Maß, nur Übung.
Zum Mitnehmen
Code wird einmal geschrieben und danach oft gelesen. Meistens von dir selbst, drei Monate später, ohne jede Erinnerung daran, was du dir gedacht hast.
Jetzt du
Basis Konto, kostenlosZu 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.
Was in dieser Lektion steckt
-
Artikel mit 3 Beispielen zum Ausprobieren
Steht hier, ohne Konto lesbar.
-
Aufgabe im Editor, direkt im Browser geprüft
Öffnet sich mit dem Basis Konto.