📅17. September 2026
Um 13:25 Uhr lief zum ersten Mal Code von mir in Produktion. Kein Feuerwerk, nur eine Zeile im Log.
Gebaut haben wir in meinem Praktikum bei KiWebBoost einen Dienst für Fluggastrechte: mehr als drei Stunden Verspätung, Anspruch auf eine Ausgleichszahlung. Vier Dinge haben mir dabei am meisten beigebracht — und keines davon meldet sich von selbst.
Zwei der vier sitzen dort, wo man sie sucht — in den Tests. Die beiden anderen nicht.
Wie viel Geld zusteht, hängt an der Entfernung. Keine reine Leiter:
def amount_for_distance_km(distance_km, intra_eu=False):
if distance_km <= TIER_SHORT_KM: # 1500 km
return AMOUNT_SHORT # 250 EUR
if intra_eu or distance_km <= TIER_MEDIUM_KM:
return AMOUNT_MEDIUM # 400 EUR
return AMOUNT_LONG # 600 EURSechs Zeilen. Auf die vierte kommt es an.
Das oder entscheidet: Innerhalb der EU sind 400 Euro das Maximum, egal wie weit. Wien–Teneriffa, 3.613 Kilometer, trotzdem 400. Wer nur nach Kilometern staffelt, bekommt keinen Absturz und keinen roten Test — sondern eine saubere Zahl, die um 200 Euro zu hoch ist, in einem Schreiben an eine Fluggesellschaft.
Die Suite war grün. Acht E-Mails pro Lauf verließen sie trotzdem, an eine Adresse aus einer Testfixtur, die es nicht gibt. Der Versand war im Test nicht abgefangen — und Mailversand ist bewusst als „best effort“ gebaut, jeder Fehler wird geschluckt. Genau das machte den Fehler unsichtbar.
Der Schutz blockiert nicht nur — er sieht danach nach, ob jemand es versucht hat:
@pytest.fixture(autouse=True)
def kein_echter_mailversand(request, monkeypatch):
versuche = []
# ... requests.post wird blockiert, sobald die URL
# auf den Mailanbieter zeigt, und in "versuche"
# vermerkt ...
yield
# Die zweite Hälfte ist die wichtige: die Sender
# schlucken jeden Fehler, also würde ein blockierter
# Versand sonst spurlos verschwinden.
assert not versucheEin Schutz, der still versagt, ist kein Schutz.
Ein grünes Häkchen sagt: keine Behauptung verletzt. Nicht: nichts passiert.
Tests laufen auf SQLite, weil das schnell ist. Produktion läuft auf Oracle. Beim ersten Lauf gegen eine echte Oracle-Datenbank fielen acht von 348 Tests um: SQLite hält sich nicht an Feldlängen, ein vierstelliger Flughafencode in einem Feld für drei Zeichen ging klaglos durch. Keiner der acht war ein Bug im Produkt — die Tests waren nur auf einer Datenbank richtig, die wir gar nicht benutzen.
Der Rest lag außerhalb des Codes. Der Webserver vor der Anwendung erlaubte Uploads bis ein Megabyte, die Anwendung selbst zehn. Ein Foto einer Buchungsbestätigung liegt dazwischen — es wäre abgewiesen worden, bevor mein Code es zu sehen bekommt. Das findet kein Test, weil es nicht im Programm steckt.
Danach bin ich den Weg einmal als Kunde gegangen. Kein Ticket hat das verlangt; ein Testlauf prüft Zusicherungen, nicht ob der Ablauf als Ganzes stimmt.

Ein Fall setzt sich aus drei Richtungen zusammen. Planzeiten und tatsächliche Ankunft holen wir von zwei unabhängigen Diensten, die nichts voneinander wissen.
Die beiden hervorgehobenen Quellen liefern dieselbe Zahl: die Ankunftszeit, an der der ganze Anspruch hängt. Wir speichern beide Antworten getrennt, statt uns für eine zu entscheiden — weichen sie voneinander ab, wird der Fall zur Prüfung markiert.
Ein großer Teil dieses Projekts ist mit einem KI-Assistenten entstanden, und es wäre unehrlich, das kleinzureden: Er hat den Großteil des Codes geschrieben und den Großteil der Fehler gefunden.
Der Aufwand hat sich damit verlagert: mitlesen. Verstehen, warum etwas so gebaut wurde und nicht anders, und merken, wenn eine Entscheidung zwar funktioniert, an dieser Stelle aber nicht passt. Das ist keine Nebentätigkeit, das ist die Arbeit — er klingt genauso überzeugt, wenn er danebenliegt.

Der Autopilot fliegt die Strecke. Gelesen werden die Instrumente trotzdem.
Keines der vier meldet sich von selbst. Kein Absturz, kein roter Test, keine Fehlermeldung — man findet sie nur, wenn man hinter das grüne Häkchen schaut.
Dass ich an etwas mitbauen durfte, das in den Betrieb gehen kann, und dabei echte Entscheidungen treffen konnte, macht für mich den Unterschied zwischen einem Praktikum und einer Übungsaufgabe. Dafür bedanke ich mich.