Begriff
Debugging
Warum wichtig?
Dieser Begriff ist ein Knoten im SengakujiWorks-Wissensnetz. Nutze Level 0 für die erste Einordnung, Level 1 für Praxis, Level 2 für technische Struktur und Level 3 für Grenzen, Fallstricke und Expertenkontext.
Debugging ist die Jagd nach Fehlern (Bugs) im Computerprogramm. Der Begriff kommt von einem echten "Bug" (Motte), die 1947 in einem alten Computer einen Kurzschluss verursachte. Wenn ein Programm abstürzt oder komische Dinge tut, muss der Programmierer den Detektiv spielen:
Was ist passiert?
Musterantwort: Beginne mit dem konkreten Fall, prüfe die Fakten und erkläre den Begriff daran. Für diesen Abschnitt gilt: Wie debuggt man? 1. Print-Statements: Der Anfänger-Weg. Man schreibt überall print("Ich bin hier") in den Code, um zu sehen, wie weit das Programm kommt. 2. Fehlermeldungen lesen: Der Computer sagt oft genau, was falsch ist ("Error in Line 55: Division by Zero"). Viele lesen das leider nicht. 3. Debugger nutzen: Profi-Tools (in der IDE), mit denen man das Programm Schritt für Schritt (Zeile für Zeile) ablaufen lassen kann. Man kann die Zeit anhalten und in die Variablen hineinschauen ("Aha, X ist hier 0, deshalb knallt es!").Wo im Code steht der Fehler?
Musterantwort: Beginne mit dem konkreten Fall, prüfe die Fakten und erkläre den Begriff daran. Für diesen Abschnitt gilt: Wie debuggt man? 1. Print-Statements: Der Anfänger-Weg. Man schreibt überall print("Ich bin hier") in den Code, um zu sehen, wie weit das Programm kommt. 2. Fehlermeldungen lesen: Der Computer sagt oft genau, was falsch ist ("Error in Line 55: Division by Zero"). Viele lesen das leider nicht. 3. Debugger nutzen: Profi-Tools (in der IDE), mit denen man das Programm Schritt für Schritt (Zeile für Zeile) ablaufen lassen kann. Man kann die Zeit anhalten und in die Variablen hineinschauen ("Aha, X ist hier 0, deshalb knallt es!").Wie repariere ich ihn?
Musterantwort: Beginne mit dem konkreten Fall, prüfe die Fakten und erkläre den Begriff daran. Für diesen Abschnitt gilt: Wie debuggt man? 1. Print-Statements: Der Anfänger-Weg. Man schreibt überall print("Ich bin hier") in den Code, um zu sehen, wie weit das Programm kommt. 2. Fehlermeldungen lesen: Der Computer sagt oft genau, was falsch ist ("Error in Line 55: Division by Zero"). Viele lesen das leider nicht. 3. Debugger nutzen: Profi-Tools (in der IDE), mit denen man das Programm Schritt für Schritt (Zeile für Zeile) ablaufen lassen kann. Man kann die Zeit anhalten und in die Variablen hineinschauen ("Aha, X ist hier 0, deshalb knallt es!").
Es ist oft der frustrierendste, aber wichtigste Teil der Programmierung.
Merksatz: Der systematische Prozess, Softwarefehler zu finden und zu beheben.
Wie debuggt man?
- Print-Statements: Der Anfänger-Weg. Man schreibt überall
print("Ich bin hier")in den Code, um zu sehen, wie weit das Programm kommt. - Fehlermeldungen lesen: Der Computer sagt oft genau, was falsch ist ("Error in Line 55: Division by Zero"). Viele lesen das leider nicht.
- Debugger nutzen: Profi-Tools (in der IDE), mit denen man das Programm Schritt für Schritt (Zeile für Zeile) ablaufen lassen kann. Man kann die Zeit anhalten und in die Variablen hineinschauen ("Aha, X ist hier 0, deshalb knallt es!").
1. Breakpoints & Watch
Im Debugger setzt du einen Breakpoint (roter Punkt am Zeilenrand).
Das Programm läuft vollgas bis zu diesem Punkt und friert dann ein (Suspend).
Jetzt kannst du Watches definieren: "Zeig mir immer den Wert von Variable user_id an."
Wenn du dann "Step Over" klickst, siehst du live, wie sich die Werte ändern.
2. Rubber Duck Debugging
Eine berühmte Methode: Erzähle dein Problem einer Quietscheente (die auf dem Schreibtisch steht). Erkläre ihr Zeile für Zeile, was der Code tun soll. Oft fällt dir beim Erklären ("...und dann prüft er, ob X größer 5 ist... oh verdammt, X ist ja ein Text!") der Fehler selbst auf. Das laute Aussprechen aktiviert andere Gehirnregionen.
3. Heisenbugs
Besonders fiese Fehler: Sie verschwinden, wenn man versucht, sie zu beobachten (wie in der Quantenmechanik). Beispiel: Ein Fehler passiert nur, wenn das Programm schnell läuft. Wenn du es im Debugger langsam Schritt für Schritt machst, funktioniert alles. (Oft Timing-Probleme / Race Conditions).
1. Bisecting (Git Bisect)
Wenn eine riesige Codebase ("1000 Commits am Tag") plötzlich einen Fehler wirft, und niemand weiß, wer ihn wann eingebaut hat, sucht man nicht manuell.
Man nutzt Binary Search via Git (git bisect).
Du sagst Git: "Die heutige Version ist kaputt (Bad). Die Version von vor 30 Tagen war definitiv heile (Good)."
Git halbiert die Zeitlinie und testet den Tag 15 aus (Checkout). Du schaust, ob der Fehler da ist. Wenn ja, weiß Git: "Der Fehler liegt zwischen Tag 1 und 15". Es halbiert auf Tag 7.
Es ist der mathematisch schnellste Weg (aus O(N) wird O(log N)), um in Minuten den exakten Diff (Commit) von vor zwei Wochen zu finden, der das System zerbrochen hat.
2. Core Dumps & Post-Mortem Debugging
Das Programm stürzt beim Kunden ab. Der Kunde hat keinen Debugger offen. Wie kommst du Wochen später an den Fehler?
Betriebssysteme generieren im Falle eines Segmentation Faults (Speicherzugriffsverletzung) einen Core Dump.
Das OS macht im Bruchteil der Crash-Sekunde ein fotografisches 1-zu-1 Abbild des gesamten CPU-Registrierungszustandes und des RAM-Arbeitsspeichers dieses Prozesses, und brennt es in eine Datei auf die SSD (core.1345).
Du lädst diese Dump-Datei später auf deinen Entwickler-Laptop und lädst sie in den C-Debugger gdb ("Post-Mortem"). Der Debugger baut das tote Programm aus dem Fossil genau so wieder auf, wie es im Moment des Todes aussah.
3. Tracing vs. Logging (eBPF & Strace)
Logging (print, log.info) ist proaktiv. Du musst vorher wissen, wo du es platzierst.
Ein Bug in den Tiefen des Betriebssystems oder in Fremdbibliotheken verrät sich oft nicht über deine Logs.
Hier betritt man die Welt der Syscall-Tracer (strace, DTrace oder modern eBPF).
Damit klinkst du dich dynamisch in den laufenden Linux-Kernel ein und belauschst den Traffic. "Welche Dateien versucht die App nginx gerade vergeblich zu öffnen?" (Du siehst z.B. hunderte -1 ENOENT Errors auf /etc/config.json). Tracing benötigt keine Anpassung am Quellcode!
Quick-Check
Warum heißt es "Bug"?
Weil Grace Hopper 1947 eine echte Motte in einem Relais des Mark II Computers fand. Sie klebte sie ins Logbuch mit der Notiz "First actual case of bug being found".Was ist besser: Print-Statements oder ein echter Debugger?
Debugger sind viel mächtiger, weil man den Zustand prüfen kann, ohne den Code zu ändern. Aber für schnelle Checks sind Prints oft einfacher.Was hilft, wenn man den Fehler absolut nicht findet?
Pause machen. Schlafen. Oder der Gummiente das Problem erklären. Tunnelblick ist der Feind des Debuggings.