Hvordan man bliver sindssygt god til at debugge

  • Programmering

OBS
På baggrund af mine noter og stokastiske kommentarer - nogenlunde sobert formidlet - jeg står inde for hvert et ord og betragtninger - AI har opsummeret mine tanker og sætninger.


Man bliver god til fejlfinding ved at have set nok systemer fejle.

Mange systemer. Mange platforme. Mange generationer af teknologi. Mange dårlige antagelser. Mange fejl, der først ser tilfældige ud, indtil man finder den ene mekaniske forklaring.

Min baggrund starter længe før moderne webudvikling. ZX81, Commodore 64, Amiga, DOS, PC, Windows, Mac og Linux. Maskiner hvor man var tættere på hardwaren, tættere på begrænsningerne og tættere på konsekvensen af sine egne fejl. Som 14-årig sad jeg og disassemblede kode for at finde ud af, hvordan ting var lavet. Det var ikke teori. Det var ren nysgerrighed, stædighed og behovet for at forstå, hvad der faktisk foregik.

Den vane forsvinder ikke.

Når man først har lært at kigge under overfladen, accepterer man ikke længere pæne forklaringer uden bevis. Man lærer at skelne mellem det, nogen tror systemet gør, og det systemet faktisk gør. Den forskel er dér, de fleste fejl bor.

Jeg skrev HTML i Netscape, før ASP og PHP fandtes. CGI var nok. Senere kom serversprog, databaser, sessions, cookies, JavaScript, browserforskelle, DOM, CSS, frameworks, APIer, hosting, DNS, SSL, e-mail, Linux-drift, integrationer og legacy-systemer. Hver generation lagde et nyt lag oven på de gamle. Hvert lag skjulte noget. Hvert lag introducerede nye måder at tage fejl på.

Fejlfinding er ikke magi. Det er disciplin.

Man starter med symptomet. Man tror ikke på symptomet som årsag. Man følger strømmen ned gennem lagene. Brugerens oplevelse. Browseren. Netværket. Serveren. Applikationen. Konfigurationen. Databasen. Filsystemet. Rettighederne. Processen. Loggen. Den manglende log. Den gamle kode. Den implicitte antagelse. Den del af systemet, ingen længere tænker på.

En god debugger gætter ikke for at virke hurtig. En god debugger reducerer usikkerhed.

Det kræver en vis kulde. Man skal kunne lade være med at forelske sig i den første forklaring. Man skal kunne ignorere støj. Man skal kunne høre en kunde forklare problemet upræcist og alligevel finde det tekniske mønster bag. Man skal kunne læse kode, man ikke bryder sig om. Man skal kunne acceptere, at dokumentationen kan være forkert, at miljøet kan afvige, at caching kan skjule virkeligheden, at encoding kan ødelægge data, at DNS kan lyve langsomt, og at en næsten korrekt konfiguration stadig er forkert.

JavaScript har været en særlig god træningsbane. Scope, closures, hoisting, prototypekæder, event loop, async flow, browser-APIer, ECMAScript-versioner og alle de historiske særheder. JavaScript straffer uklare mentale modeller. Hvis man ikke forstår eksekveringsmodellen, ender man med forklaringer, der kun virker tilfældigvis. Den slags holder ikke i fejlfinding.

Det samme gælder systemer generelt.

Fejlfinderen skal have en præcis mental model. Når modellen ikke passer til virkeligheden, er modellen forkert. Ikke virkeligheden. Det er en brutal regel. Den sparer tid.

Man bliver stærk af gamle systemer, fordi gamle systemer sjældent giver én rene fejl. De giver sammensatte fejl. En udløbet certifikatkæde, en gammel PHP-version, en DNS-record med for lang TTL, en mailserver med forkert SPF, en database med beskidte data, en integration med skjult afhængighed, en browser der opfører sig anderledes end forventet, og en kunde der kun kan beskrive det som “det virker ikke”.

Der er ingen elegance i det. Kun arbejde.

Læs fejlen. Find grænsen. Isolér problemet. Reproducer det. Skift én ting. Mål igen. Slå logging til. Fjern antagelser. Følg data. Følg kontrolflow. Følg konfiguration. Følg netværk. Stop først, når forklaringen passer til observationerne.

Efter mange år bliver det en form for teknisk instinkt. Det er stadig ikke gætteri. Det er erfaring, der genkender mønstre hurtigere. Man har set nok dårlige deploys, skjulte afhængigheder, mærkelige browserfejl, ødelagte encoding-kæder, tavse PHP-fejl, DNS-forsinkelser, mailproblemer og integrationsbrud til at vide, hvor man skal begynde at grave.

Den vigtigste egenskab er ikke at kende alle værktøjer.

Den vigtigste egenskab er at nægte at blive imponeret af kompleksitet.

Et system fejler af en grund. Årsagen kan være dum, gammel, skjult, pinlig eller dyr. Den findes stadig. Debugging handler om at blive ved, indtil systemets faktiske opførsel er forklaret bedre end alle de bekvemme historier omkring det.