- 1 Section
- 10 Lessons
- unbegrenzt
- Debugging & Fehleranalyse10
- 1.1Fehlertypen: Syntaxfehler, Laufzeitfehler, Logikfehler
- 1.2Systematische Fehlersuche: Duck-Debugging, Divide & Conquer
- 1.3Debugger-Grundkonzepte: Breakpoints, Watches, Call Stack
- 1.4Debugging in Java mit IntelliJ / Eclipse
- 1.5Debugging in Python mit VS Code und pdb
- 1.6Debugging in JavaScript: Browser DevTools
- 1.7Logging: Fehler protokollieren und auswerten
- 1.8Fehler in Datenbankabfragen finden
- 1.9Fehler in Netzwerkverbindungen und APIs debuggen
- 1.10Praxisaufgaben: Fehlerhafte Programme korrigieren
Praxisaufgaben: Fehlerhafte Programme korrigieren
Zeit für die Praxis. In den vorherigen neun Lektionen hast du die Theorie gelernt: Fehlertypen, Methodik, Debugger-Konzepte, sprachspezifische Werkzeuge für Java, Python und JavaScript, plus Logging, DB-Debugging und API-Diagnose. Jetzt setzen wir das alles an realen Bug-Szenarien ein.
Diese Lektion enthält 8 Bug-Hunts unterschiedlicher Schwierigkeit. Schau dir jeweils den Code an, überlege was schief ist, dann klick auf „Lösung anzeigen". Versuche es erst ohne Lösung – das Lernen passiert beim selbst-Denken. Die Schwierigkeit reicht von EASY (Syntax-Fehler in 30 Sekunden zu finden) bis HARD (subtile Logikfehler die dich in der Praxis Stunden kosten würden).
1) Dein mentaler Workflow
Bei jedem Bug-Hunt durchläufst du intern dieselbe Sequenz die wir in L2 kennengelernt haben:
- Was tut der Code soll? (Lies den Code, lies den erwarteten Output)
- Was tut er tatsächlich? (Lies den fehlerhaften Output)
- Welcher Fehlertyp? (Syntax, Laufzeit, Logik – aus L1)
- Hypothese: wo könnte die Diskrepanz herkommen?
- Wo würde ich einen Breakpoint setzen / einen
printeinbauen?
Erst dann nach unten klicken. Die ersten Übungen sind einfach – das ist Absicht. Du sollst den Workflow verinnerlichen.
2) Bug-Hunt 1: Off-by-One
Klassischer Fehler bei Schleifen über Zahlenbereiche. Sieht harmlos aus, Ergebnis ist trotzdem falsch:
range(n) in Python liefert die Zahlen 0 bis n-1, also 0,1,2,...,9. Die Summe ist 45, nicht 55.Fix:
range(1, n+1) – liefert 1 bis n inclusive.Such-Strategie: Eine Zeile mit
print(i) in der Schleife → du siehst sofort 0,1,2,...,9 statt 1,...,10. Im Debugger: Breakpoint in Zeile 4, Watch auf i, ein paar Iterationen durchsteppen.
3) Bug-Hunt 2: NullPointer
Eine Java-Methode soll robust mit null umgehen – tut es aber nicht. Crash bei jedem zweiten Aufruf:
user.getName() auf – aber wenn user null ist, crashed das schon hier. Der null-Check kommt zu spät.Fix:
name kann null sein – nicht nur leer.
4) Bug-Hunt 3: String-Vergleich in Java
Login-Check funktioniert in keinem einzigen Fall – obwohl Tests im Unit-Test grün sind:
== bei Objekten die Referenz, nicht den Inhalt. Zwei String-Variablen können denselben Inhalt haben aber unterschiedliche Objekte sein – == ist dann false.Tückisch: wegen String-Interning bei Literalen (
"hello" == "hello" ist oft true) übersehen Anfänger den Bug. Bei Strings aus User-Input, DB oder Netzwerk klappt es plötzlich nicht.Fix:
MessageDigest.isEqual() für Timing-Attack-Sicherheit. Mehr in K11 Secure Coding.
5) Bug-Hunt 4: Mutable Default
Ein Klassiker den jeder Python-Entwickler mindestens einmal erlebt. Sieht völlig harmlos aus:
[] wird einmal beim Funktions-Definieren erzeugt und über alle Aufrufe geteilt. Bei Bob wird "user" angefügt – die geteilte Liste ist jetzt ['user']. Bei Clara wird wieder angefügt – jetzt ['user','user'].Fix:
id(roles) zwischen Aufrufen vergleicht: dieselbe ID! Linter wie pylint warnen mit dangerous-default-value.
6) Bug-Hunt 5: SQL-NULL
Ein subtiler SQL-Bug der fast jeden Entwickler einmal erwischt:
NULL != 'premium' NICHT true, sondern UNKNOWN. UNKNOWN-Treffer fliegen aus dem Filter raus. Drei-wertige Logik!Fix:
COALESCE(role, '') != 'premium'.
7) Bug-Hunt 6: Race Condition
Funktioniert im Test perfekt, in Production stimmen die Zahlen plötzlich nicht. Sehr typisch für Threading-Bugs:
count++ ist KEIN atomarer Befehl – es sind drei Schritte: 1) read count, 2) add 1, 3) write back. Wenn zwei Threads gleichzeitig read'en (beide lesen 5), beide add'en 1 (beide haben 6), beide schreiben zurück (beide schreiben 6) – aber wir hätten 7 erwartet. Ein Increment ist verloren.Fix-Optionen:
8) Bug-Hunt 7: Async/forEach
JavaScript-async-Bug: User-Daten parallel holen sieht einfach aus – ist es nicht:
forEach erwartet keine async-Funktion und wartet nicht auf sie. Die forEach-Schleife läuft sofort durch, alle drei async-Callbacks starten – aber fetchUsers kehrt zurück bevor sie fertig sind. users ist noch leer.Fix mit Promise.all (parallel und schnell):
return users mit leerem Array passiert (Step Over über die forEach hinaus). Lehre: forEach + async = (fast) immer falsch.
9) Bug-Hunt 8: Zeitzone
Letzter Bug, fies subtil. Funktioniert lokal, schlägt erst nach dem Deploy auf einem US-Server fehl:
date.today() liefert das Datum in der Server-Zeitzone. Bei einem US-Server ist UTC um 22:30 Berliner Zeit = 20:30 UTC – also noch derselbe Tag. Aber wenn es 02:00 Berliner Zeit ist (= 00:00 UTC), denkt der Server schon „neuer Tag" während die Berliner noch in der „alten" Nacht sind. Symmetrisch andersrum.Außerdem:
created_at in der DB ist vermutlich auch ohne Zeitzone gespeichert – Datum-Vergleich zwischen unklaren Zeitzonen ist immer ein Bug.Fix:
datetime.now() ohne Argument vermeiden – immer mit tz. DB-Spalten am besten als TIMESTAMPTZ (PostgreSQL) speichern.
10) Was wir gelernt haben
Du hast jetzt acht typische Bug-Klassen durch – das ist ein riesiger Teil dessen was du in der Praxis siehst. Jeder dieser Bugs hat uns auch eine Werkzeug-Lektion gezeigt:
| Bug | Such-Werkzeug |
|---|---|
| Off-by-One | Print/Watch in der Schleife |
| NullPointer | Stacktrace lesen, null-Checks reviewen |
| String == in Java | identityHashCode-Watches |
| Mutable Default | Linter / id()-Vergleich |
| SQL NULL | Subset-Tests in SQL-Konsole |
| Race Condition | Stress-Tests + Logging mit Thread-ID |
| Async forEach | Step durch async-Code im Debugger |
| Zeitzonen | Werte mit Timezone loggen |
11) Skill-Tree: was du beherrschst
Nach diesem Kurs solltest du folgende Skills auf der Hand haben:
12) Was als nächstes?
Mit diesen Skills bist du im Debugging gut aufgestellt. Trotzdem gibt es immer mehr zu lernen. Sinnvolle Vertiefungen:
- Performance-Profiling: über reines Funktional-Debugging hinaus. Tools wie VisualVM, py-spy, Chrome Performance-Tab.
- Memory-Leak-Hunting: Heap-Dumps, Profiler, GC-Logs. Eigenes Themengebiet.
- Distributed-Tracing: bei Microservices, mit Jaeger/Zipkin/OpenTelemetry.
- Test-Driven Development: viele Bugs passieren gar nicht erst wenn man vorher Tests schreibt. Mehr in K54 CI/CD.
- Static Analysis: SonarQube, ESLint, SpotBugs finden viele Bugs ohne dass du sie laufen lassen musst.
- Chaos Engineering: gezielt Fehler einbauen um die Resilience zu testen. Netflix-Klassiker.
Die größte Empfehlung: übe. Jeder echte Bug den du selbst löst ist mehr wert als zehn theoretische Lektionen. Vermeide den Reflex sofort den Kollegen zu fragen – versuche es erst selbst mit der Methodik. Nach ein paar Wochen merkst du wie schnell du wirst.
Zusammenfassung
8 typische Bug-Klassen aus der Praxis durchgegangen, von EASY bis HARD: Off-by-One (range(n) liefert 0..n-1), NullPointer durch falsche Reihenfolge (null-Check muss erste sein), String-Vergleich mit == in Java (equals nutzen, Strings sind Objekte), Mutable Default Argument in Python (geteilte Liste über Aufrufe), SQL-NULL-Falle (Three-Valued Logic), Race Condition in Threading (count++ ist nicht atomar), forEach + async in JavaScript (wartet nicht), Zeitzonen (UTC vs. lokal). Jeder Bug demonstriert eine andere Such-Strategie: Print in Schleifen, Stacktrace lesen, identityHashCode-Watches, Linter, Subset-Tests, Stress-Tests, Step-by-Step Async, Werte mit Timezone loggen. Methodischer Workflow: Soll vs. Ist verstehen, Fehlertyp klassifizieren, Hypothese, gezielte Diagnose, Fix, Regression-Test, 5-Whys. Skill-Tree nach diesem Kurs: Fehler klassifizieren, systematisch suchen, Debugger nutzen, IDE-spezifische Werkzeuge für Java/Python/JS, Logging, SQL, APIs, Stacktraces, Bug-Patterns, Root-Cause-Analyse. Nächste Schritte: Performance-Profiling, Memory-Leaks, Distributed Tracing, TDD, Static Analysis, Chaos Engineering. Üben ist die wichtigste Empfehlung – jeder echte Bug, den du selbst löst, ist mehr wert als zehn Lektionen.
