Viele denken, ein Test müsse „echt“ sein, also mit echter Datenbank und echten APIs, sonst sei er wertlos. Das klingt plausibel, weil Software am Ende ja wirklich laufen muss.
Tatsächlich prüft ein Unit-Test nur eine Einheit isoliert – meist eine einzelne Funktion oder Methode einer Klasse. Abhängigkeiten wie Datenbanken oder APIs werden dafür durch Test-Doubles ersetzt, also Nachahmungen, die festgelegte Werte liefern. Solche Tests laufen in Millisekunden und ganz ohne Netz. Das Zusammenspiel mit echten Nachbarn prüfen stattdessen Integrationstests, etwa gegen eine echte PostgreSQL-Instanz.
Der Irrtum entsteht, weil „Test“ sich erst einmal gleich anhört, egal welche Schicht er prüft. Die Testpyramide rät deshalb ausdrücklich: viele schnelle Unit-Tests, weniger Integrationstests und wenige End-to-End-Tests, also Tests über die gesamte Anwendung hinweg.
Ein Beispiel: Eine Funktion berechnet den Bruttopreis aus Nettopreis und Steuersatz. Ihr Unit-Test ruft sie mit konkreten Werten auf und vergleicht das Ergebnis mit dem erwarteten Wert, ganz ohne Datenbank. In Node.js reicht dafür seit Version 20 der eingebaute Test-Runner node:test.
„Woran man es erkennt:“ Läuft der Test offline in Millisekunden, prüft er eine Einheit. Berührt er Datenbank oder Netzwerk, ist er ein Integrationstest – und gegen eine gemockte Datenbank findet er keine SQL-Fehler, denn dafür gehört mindestens ein Test gegen die echte Datenbank-Engine dazu.
Unit heißt nicht „kleiner Test von irgendetwas“, sondern isolierte Prüfung einer Einheit mit Test-Doubles für alle Abhängigkeiten.
📌 Einheit isoliert · Test-Doubles · Testpyramide
📚 Webentwicklung von Grund auf · Tag 6 von 30
#testing #NodeJS #typescript #webdev
Mehrere SQL-Befehle können zu einer unteilbaren Einheit gebündelt werden. Das passiert überall dort, wo mehrere Schritte zusammengehören, etwa bei jeder Überweisung.
Zuerst beginnt die Transaktion mit BEGIN (dem Startbefehl der Einheit). Eine Überweisung von Konto A auf Konto B besteht aus zwei Befehlen. Der erste UPDATE-Befehl verringert den Kontostand von A.
Dann erhöht ein zweites UPDATE den Kontostand von B. SQL ist die Abfragesprache relationaler Datenbanken wie PostgreSQL; UPDATE ändert darin bestehende Zeilen. Beide Befehle gehören zwingend in dieselbe Transaktion.
Danach entscheidet der Abschluss. Läuft alles fehlerfrei, macht COMMIT alle Änderungen dauerhaft sichtbar. Schlägt ein Schritt fehl, etwa weil Konto B nicht existiert, verwirft ROLLBACK alles. Die Datenbank steht dann so da, als wäre nichts geschehen.
Zuletzt ein Blick auf den Einsteigerirrtum: Viele setzen jeden SQL-Befehl einzeln ab und vertrauen darauf, dass die Datenbank die Zusammengehörigkeit von selbst erkennt. Das Gegenteil ist der Fall. Ohne BEGIN führt die Datenbank jeden Befehl sofort eigenständig aus; dieses Verhalten heißt Autocommit. Das Geld wäre dann schon von A abgebucht, ohne dass B je etwas erhielt.
Diese Alles-oder-nichts-Eigenschaft heißt Atomicität. Sie ist eine der vier Grundeigenschaften, die zuverlässige Datenbanksysteme garantieren.
Transaktion heißt nicht „mehrbefehliges Skript“, sondern unteilbare Einheit: erst COMMIT macht dauerhaft, ROLLBACK nimmt alles zurück.
📌 BEGIN · COMMIT · ROLLBACK
📚 Webentwicklung von Grund auf · Tag 5 von 30
#PostgreSQL #backend #webdev
Das Register listet Begriffe alphabetisch, jeweils mit einer Seitenzahl daneben. Wer „Mutation“ sucht, blättert nicht, sondern springt direkt zur angegebenen Seite. Neu aufgenommene Begriffe müssen sich an der richtigen Stelle einreihen. Deshalb bleibt das Register sortiert, egal wie oft das Buch sich füllt.
Fachlich ist der Index eine sortierte Zusatzstruktur neben der Tabelle. Er speichert die Werte einer Spalte in sortierter Form, jeweils mit einem Verweis auf die zugehörige Zeile. Der Standard-Indextyp ist der B-Tree, der Gleichheit und Bereichsvergleiche sowie Sortierung unterstützt. Die Datenbank steigt darin wie im Lexikon von Verweis zu Verweis ab, statt alle Zeilen zu lesen.
Ohne Index führt die Datenbank bei einer Abfrage mit WHERE einen Sequential Scan aus: Sie prüft jede Zeile einzeln. In einer Bestelltabelle mit Millionen Zeilen gehört daher ein Index auf die Kundennummer, den Fremdschlüssel, der auf den Primärschlüssel verweist, der jede Zeile der Kundentabelle eindeutig identifiziert. Mit EXPLAIN zeigt PostgreSQL den Ausführungsplan der Abfrage, mit EXPLAIN ANALYZE wird sie zusätzlich ausgeführt und zeigt dann tatsächliche Zeiten und Zeilenzahlen.
Das Bild hat eine Grenze: Ein Buchregister wird einmal gesetzt, ein Index muss bei jedem Schreiben gepflegt werden. Jeder zusätzliche Index verlangsamt INSERT, UPDATE und DELETE und belegt Speicherplatz.
Ein Index heißt nicht „automatisch schneller“, sondern „schneller finden bei gezielten Fragen“. Er gehört auf Spalten, nach denen häufig gefiltert, sortiert oder verbunden wird, nicht auf jede Spalte.
📌 Sortierte Zusatzstruktur · B-Tree · Schreibkosten
📚 Webentwicklung von Grund auf · Tag 5 von 30
#PostgreSQL #backend #webdev
In der Tabelle bestellungen stehen Name und Adresse des Kunden in jeder Zeile kopiert. Nach einer Änderung stimmen manche Zeilen, andere nicht, und niemand weiß, welche Kopie die richtige ist.
In einer relationalen Datenbank wie PostgreSQL liegen Daten in Tabellen aus Zeilen und Spalten. Jede Zeile braucht einen Primärschlüssel, also eine Spalte, deren Wert genau einmal vorkommt, oft eine fortlaufende ID, die die Datenbank beim Einfügen vergibt. Ohne eindeutige Kennung wüsste die Datenbank bei zwei inhaltsgleichen Zeilen nicht, welche gemeint ist; ein UPDATE oder DELETE könnte die falsche Zeile treffen. Der Fremdschlüssel löst das Kopierproblem: Er speichert nicht die Daten selbst, sondern nur den Verweis auf den Primärschlüssel der anderen Tabelle.
In der Tabelle kunden bekommt jeder Kunde eine eigene ID. Die Tabelle bestellungen enthält statt Name und Adresse nur die Spalte kunden_id mit dem Wert 7. Ändert sich der Kundenname, wird er genau einmal in kunden geändert, und alle Bestellungen sehen automatisch den neuen Wert. Die Datenbank prüft dabei die Gültigkeit: Eine Bestellung mit einer kunden_id, die es gar nicht gibt, wird mit einem Fehler abgewiesen.
So prüft man es: Nachschauen, ob jede Tabelle einen Primärschlüssel hat und ob zusammengehörige Daten über Fremdschlüssel verbunden sind. Kopierte Kundendaten in jeder Bestellzeile sind ein Alarmzeichen.
Der Fehler heißt nicht schlampige Pflege, sondern fehlende Schlüssel. Wer eindeutig kennzeichnet und nur verweist, speichert jede Information genau einmal.
📌 Primärschlüssel · Fremdschlüssel · Verweis statt Kopie
📚 Webentwicklung von Grund auf · Tag 5 von 30
#PostgreSQL #backend #webdev
Nur mit festen Spalten kann die Datenbank Daten prüfen, vergleichen und verbinden. Ohne dieses Gerüst wären Verweise zwischen Datensätzen blind.
🌐 Eine relationale Datenbank wie PostgreSQL legt Daten in Tabellen aus Zeilen und Spalten ab. Jede Zeile ist genau ein Datensatz, etwa ein Kunde mit Name und E-Mail-Adresse. Jede Spalte ist ein Feld dieses Datensatzes, mit einem festen Namen und Datentyp wie Text oder Zahl.
🧩 Ein Primärschlüssel identifiziert jede Zeile eindeutig, etwa über eine Spalte id. Ein Fremdschlüssel verweist auf den Primärschlüssel einer anderen Tabelle und verbindet zusammengehörige Daten. So hängt eine Tabelle bestellungen mit der Spalte kunde_id an kunden.id: Jede Bestellung gehört zu genau einem Kunden.
🔒 Die Spalten gelten für alle Zeilen und werden vorab festgelegt. Eine neue Zeile fügt Daten hinzu, nie eine neue Spalte – das Gerüst ist starr und dadurch verlässlich. Weil jedes Feld Namen und Typ hat, kann die Datenbank Eingaben prüfen, Werte vergleichen und Verbindungen sicher auflösen.
Das Ganze nennt man Datenbankschema: die Beschreibung aller Tabellen und Spalten, die vor den Daten entsteht. Tabellen sind dabei keine Tabellenkalkulation: Es gibt keine bedeutsame Zeilenreihenfolge, Verweise laufen immer über Schlüssel. Das Grundgerüst heißt nicht flexibel, sondern vorhersehbar – und genau das macht Ordnung erst möglich.
📌 Tabelle · Zeile und Spalte · Schlüssel
📚 Webentwicklung von Grund auf · Tag 5 von 30
#PostgreSQL #backend #webdev
Was wir unterschätzt haben: Persistent Volumes und StatefulSets sind deutlich trickreicher als Stateless-Deployments. Unsere PostgreSQL-Migration auf K8s hat 3 Anläufe gebraucht. Lesson learned: Datenbanken gehören (noch) nicht in Kubernetes, es sei denn man hat dediziertes DB-Ops-Know-how.
Was sich gelohnt hat: GitOps-Workflow mit ArgoCD, automatische Rollbacks bei fehlgeschlagenen Health-Checks, und Resource-Quotas die verhindern dass ein Team den gesamten Cluster lahmlegt. #kubernetes #devops #cloudnative