6.1 A debugging mint gondolkodási folyamat – nem varázslat
Áttekintő
Ha azt látod, hogy egy senior fejlesztő 10 perc alatt megtalál egy hibát, amit te két óra alatt sem találtál meg – ne azt gondold, hogy ő több éves tapasztalatból „megérzi" a megoldást. Szinte biztosan nem. Amit csinál: egy jól begyakorolt, szisztematikus folyamatot követ. Ezt a folyamatot te is megtanulhatod – és meg is kell tanulnod, mert ez az egyik legtöbbet hasznosított skill az egész fejlesztői pályán.
A debugging nem misztérium és nem varázslat. Tudományos módszer. Megfigyelés, hipotézis, tesztelés, következtetés – ugyanaz a logika, amit a természettudományos gondolkodás alapjaként tanítanak. Csak éppen nem laboratóriumban, hanem egy szövegszerkesztőben.
Ez az alfejezet arról szól, hogyan gondolkodj hibakeresés közben – mielőtt bármilyen eszközhöz nyúlnál.
Részletes leírás
A legdrágább debugging anti-pattern: a random módosítás
Ismerős a helyzet? Nem működik a kód. Nem tudod pontosan miért. De „megpróbálod" ezt-azt – átírod az egyik sort, mozgatod a feltételt, kommenteled ki a blokkot. Ha megjavul, örülsz. Ha nem, próbálkozol tovább.
Ez a random módosítás anti-pattern, és a következő okok miatt veszélyes:
- Nem tanulsz belőle. Ha véletlenül megjavul, nem tudod, miért. Legközelebb ugyanúgy elveszel.
- Elronthatod, ami működött. Módosítások közben mellékhatásokat vezetsz be, és hamarabb kerülsz mélyebb bajba.
- Időt pazarol. Exponenciálisan. Két óra random próbálgatás sokszor megoldható lett volna 20 perc szisztematikus gondolkodással.
- Csökkenti a magabiztosságodat. Ha nem érted, miért javult meg a hiba, a következő hibánál ugyanolyan tanácstalan leszel.
A senior fejlesztők nem azért gyorsabbak, mert több szintaxist tudnak fejből. Azért, mert nem pazarolnak időt céltalanul – van egy folyamatuk.
A tudományos módszer alkalmazva debuggingra
A klasszikus tudományos módszer négy lépése:
- Megfigyelés – Mi történik pontosan?
- Hipotézis – Mi okozhatja ezt?
- Kísérlet – Hogyan ellenőrzöm a hipotézist?
- Következtetés – Igazolódott vagy megcáfolódott?
Debuggingra lefordítva:
1. Megfigyelés – Mi a pontos hibajelenség?
Mielőtt bármit tennél, pontosan fogalmazd meg, mi a baj. Nem elég, hogy „nem működik". Például:
- Mi az elvárt viselkedés?
- Mi a tényleges viselkedés?
- Mikor jelenik meg a hiba? Mindig? Bizonyos feltételek mellett?
- Mi volt az utolsó változtatás a kódban?
Minél pontosabb a megfigyelés, annál jobban célzott lesz a hipotézis.
2. Hipotézis – Mi okozhatja?
Egy hipotézis egy konkrét, ellenőrizhető feltételezés. Nem „valami elromlott", hanem „valószínűleg az adatbázis-kapcsolat timeout-ol, mert a lekérdezés 30 másodperc után üres eredménnyel tér vissza".
Jó hipotézis jellemzői:
- Specifikus (nem általános)
- Ellenőrizhető (le tudod tesztelni)
- Indokolt (a megfigyelésből következik, nem a levegőből jött)
Ha egyszerre több hipotézised van (és ez normális), rangsorold őket valószínűség szerint – a legvalószínűbbet teszteld először.
3. Kísérlet – Hogyan ellenőrzöm?
A kísérlet célja egy hipotézis igazolása vagy megcáfolása – nem a hiba megjavítása. Ez fontos különbség.
Tesztelési módszerek:
- Logolás hozzáadása – mi az értéke ennek a változónak ezen a ponton?
- A kód egy részének izolálása – ha kiveszem ezt, eltűnik a hiba?
- Reprodukálás különböző feltételekkel – csak nagy adatnál jelenik meg?
- Debugger futtatása – hol változik meg az érték?
Fontos: egy kísérlet, egy hipotézis. Ha egyszerre három dolgot változtatsz, nem fogod tudni, melyik segített.
4. Következtetés – Mit tanultam?
A kísérlet vagy igazolta a hipotézist, vagy megcáfolta. Mindkét eset hasznos:
- Igazolva: Megtaláltad a hibaforrást. Most már javíthatsz.
- Megcáfolva: Kizártál egy lehetséges okot. Ez is haladás – visszalépj és fogalmazz meg új hipotézist.
Türelem és szisztematikusság – az igazi skill
A debugging közben érzett frusztráció teljesen normális. De a türelmetlenség vezet a random próbálgatáshoz. Amikor azt érzed, hogy „csak próbáljuk ki, hátha" – ez a jele, hogy vissza kell lépni.
Néhány praktikus gondolat:
„Biztos vagyok benne, hogy tudom, hol a hiba" Ritkán igaz. A leggyakoribb hibakeresési csapda, hogy egy feltételezéssel elindulsz, és minden mást figyelmen kívül hagysz. Kérdezd meg magadtól: hogyan bizonyítanám be, hogy igazam van?
„Már rég nézem ezt, nem látom a megoldást" Ez nem azt jelenti, hogy hülye vagy. Azt jelenti, hogy a szemed és az agyad megszokta, amit lát – és átugorja a hibát. Legjobb döntés: szünet, vagy más szempontból nézd meg (rubber duck debugging – magyarázd el a kódot egy képzeletbeli kacsának).
„Majd megoldom gyorsan" Ha 15-20 perc után nem közelebb a megoldás, változtass stratégián. Nem érdemes tovább menni ugyanazon az úton.
A debugging gondolkodásmód összefoglalva
Hibajelenség észlelése
↓
Pontos megfigyelés (mi, mikor, milyen körülmények)
↓
Hipotézis megfogalmazása (mi okozhatja?)
↓
Hipotézis tesztelése (egy változtatás, egy teszt)
↓
Következtetés levonása
├── Igazolva → Hiba megtalálva → Javítás
└── Megcáfolva → Új hipotézis megfogalmazása
Életszerű példák
Példa 1: A bejelentkezés nem működik
Hibajelentés: „Nem tudok belépni az oldalra."
Rossz megközelítés (random módosítás): Valaki átírja a session kezelés kódját, mert „gondolja, ott lehet valami". Közben a hiba az volt, hogy a form action URL-je egy régi végpontra mutatott.
Jó megközelítés:
Megfigyelés: A bejelentkezési gomb megnyomásakor mi történik pontosan? A böngésző Network tabján milyen kérés megy el? Milyen válasz érkezik vissza?
Hipotézis: A hálózati tab azt mutatja, hogy 404-es választ kap a kérés. Valószínűleg a request rossz URL-re megy.
Kísérlet: Megnézem a form action attribútumát és összehasonlítom az elérhető route-okkal.
Következtetés: Az action egy régi, már nem létező végpontra mutat. Javítás: a helyes URL-re cserélni.
Példa 2: Az API időnként üres listát ad vissza
Hibajelentés: „Néha nem jön vissza semmi az API-tól."
Rossz megközelítés: Valaki caching réteget von be „mert talán az okozza", majd adatbázis indexet is hozzáad, majd az API timeout értéket növeli – és mindeközben nem tudja, mi a tényleges ok.
Jó megközelítés:
Megfigyelés: Mikor jelenik meg? Minden felhasználónál? Bizonyos szűrési feltételek mellett? Az üres lista 200-as vagy más státuszkóddal érkezik?
Hipotézis: Az üres lista csak akkor jelenik meg, ha a szűrő paraméter üres string. Valószínűleg a lekérdezés nem kezeli az üres string esetét, és nem talál egyező rekordot.
Kísérlet: Küldök egy kérést szándékosan üres szűrőparaméterrel, és nézem a generált SQL lekérdezést a logban.
Következtetés: A lekérdezés WHERE name = '' feltétellel fut üres string esetén – és valóban nulla rekordot talál. Javítás: üres string esetén ne adjuk hozzá a szűrőfeltételt.
Példa 3: Éjjel tört el, reggel nem tudjuk, miért
Helyzet: A staging szerveren reggel nem indul el az alkalmazás. Tegnap este még működött.
Jó megközelítés:
Megfigyelés: Mi a hibaüzenet az indításkor? (Ne kézzel próbálgass – nézd a logot.)
Hipotézis (a hibaüzenet alapján): ModuleNotFoundError: No module named 'requests' – valószínűleg éjjel futott egy automatikus dependency frissítés, ami eltávolított egy csomagot, vagy egy requirements.txt változtatás nem volt visszafelé kompatibilis.
Kísérlet: Megnézem a git historyt: volt-e változtatás a requirements.txt-ben az utóbbi 12 órában? Megnézem a szerver logjait: volt-e automatikus folyamat?
Következtetés: A CI pipeline tegnap este éjfélkor lefutott, és egy dependency verziókonfliktus miatt a requests könyvtár eltávolításra került. Javítás: a verziópinning helyreállítása.
Tesztfeladatok
1. feladat – Sorrendbe állítás
Az alábbi debugging lépések összekeverve szerepelnek. Rendezd sorba őket a helyes sorrendnek megfelelően!
- [ ] Logolást adok hozzá az érintett kódhoz, hogy lássam a változó értékét futásidőben
- [ ] Észreveszem, hogy a felhasználói profil oldal üres adatokat jelenít meg
- [ ] Megnézem, hogy a logból mit kaptam – igazolódott vagy megcáfolódott a hipotézisem?
- [ ] Megfogalmazom: valószínűleg az API hívás nem a helyes user ID-t küldi
Helyes sorrend: %%MANUAL_HELP_NEEDED%% (ellenőrizd, hogy a megjelenítés kérdéses-e)
Megoldás: 2 → 4 → 1 → 3
2. feladat – Anti-pattern azonosítása
Melyik az alábbiak közül a random módosítás anti-pattern?
A) „Nézem a stack trace-t, és keresem a saját kódom sorát." B) „Kommentelem ki az egyik blokkot, majd a másikat, aztán megint az elsőt, hátha segít." C) „Loggolom a változó értékét, mielőtt a hibás sor elé kerül." D) „Megkérdezem a kollégát, aki legutóbb szerkesztette ezt a fájlt."
Helyes válasz: B
3. feladat – Jó hipotézis kiválasztása
Adott a következő hibajelenség: „Az alkalmazás csak bejelentkezés után lassul le."
Melyik hipotézis a legjobb (legspecifikusabb és legellenőrizhetőbb)?
A) „Valami nincs rendben a kóddal." B) „Valószínűleg a bejelentkezési folyamat lassú." C) „Bejelentkezés után a felhasználói adatokat betöltő lekérdezés valószínűleg minden requestnél lefut, és nincs cache-elve – ez okozhatja a lassulást." D) „Lehet, hogy a szerver valami mást csinál közben."
Helyes válasz: C – ez specifikus, ellenőrizhető és a megfigyelésből következik.
4. feladat – Egy kísérlet, egy hipotézis
Anikó azt tapasztalja, hogy az alkalmazás adatfeldolgozó funkciója nagy fájloknál hibát dob. Egyszerre a következő változtatásokat teszi:
- Növeli a PHP memory_limit értékét
- Átvált szinkron feldolgozásról aszinkronra
- Hozzáad egy try-catch blokkot
Ezután a hiba eltűnik. Mi a probléma ezzel a megközelítéssel?
Helyes válasz: Anikó nem tudja megmondani, melyik változtatás oldotta meg a hibát – vagy esetleg mindhárom kellett, esetleg csak egy. Ha a jövőben hasonló hiba jelenik meg, ugyanolyan tanácstalan lesz. Ráadásul két felesleges változtatást is bevitt a kódba, amelyek mellékhatásokat okozhatnak.
5. feladat – Megfigyelés minősége
Olvasd el az alábbi hibaleírásokat, és értékeld, melyik a legjobb kiindulópont a debugging folyamathoz!
A) „Nem működik a kosár." B) „A termék hozzáadása gombra kattintáskor a kosár nem frissül, a böngésző konzolján Uncaught TypeError: Cannot read properties of undefined (reading 'push') hibaüzenet jelenik meg, és csak bejelentkezett felhasználóknál reprodukálható." C) „Valaki elrontotta a kosarat." D) „Néha nem működik."
Helyes válasz: B – pontos hibaüzenet, pontos körülmény (bejelentkezett felhasználók), pontos szimptóma (a hibajelzés helye).
6. feladat – Következtetés levonása
Bence azt feltételezi, hogy egy lassú API endpoint azért lassú, mert az adatbázis-lekérdezés nem indexelt. Fut egy EXPLAIN parancsot az adatbázisban, és az megmutatja, hogy a lekérdezés valóban full table scan-t végez egy 500.000 soros táblán. Mit jelent ez a következtetés szempontjából?
A) A hipotézis megcáfolódott – más okot kell keresni. B) A hipotézis igazolódott – hozzáadhat egy indexet és mérheti a javulást. C) A hipotézis részben igazolódott – más tesztet is kell futtatni mielőtt bármit tesz. D) A EXPLAIN parancs nem ad elég információt.
Helyes válasz: B
7. feladat – Mikor lépj vissza?
Döntsd el, hogy az alábbi szituációkban melyik a helyes lépés!
Szituáció: Már 45 perce keresed a hibát. Az utolsó 20 percben három különböző helyen módosítottál a kódon, de a hiba megmaradt. Egyre frusztráltabb vagy.
Melyik döntés a leghelyesebb?
A) Folytatod – közel lehetsz a megoldáshoz. B) Visszavonod az összes változtatást, pontosan megfogalmazod a hibajelenséget, és felírasz 2-3 konkrét hipotézist mielőtt bármit módosítasz. C) Átírod az egész érintett modult – biztosan lesz benne a hiba. D) Megkérsz valakit, hogy csinálja meg helyetted.
Helyes válasz: B – a random próbálgatás megállítása és visszatérés a szisztematikus módszerhez.
8. feladat – Rubber duck debugging
Mi a rubber duck debugging lényege és miért működik?
A) Egy speciális debugger eszköz, ami automatikusan megtalálja a hibát. B) Amikor valakinek elmagyarázod a kódot vagy a problémát (akár egy tárgynak), kénytelen vagy pontosan fogalmazni – és ez a pontosság gyakran magától megmutatja a hibát. C) Fizikai pihenő a monitor előtt, hogy friss szemmel nézhesd a kódot. D) Egy agilis módszertan, amelyet páros programozáshoz fejlesztettek ki.
Helyes válasz: B
9. feladat – Hipotézis rangsorolása
Az alkalmazás elküld egy e-mailt regisztrációkor, de az e-mail néha nem érkezik meg. Az alábbi hipotézisek közül melyiket tesztelné először egy szisztematikus fejlesztő és miért?
A) Az e-mail szerver szoftverében van egy ismeretlen bug. B) Az e-mail tartalom SPAM szűrőbe kerül. C) A kód nem hívja meg az e-mail küldő függvényt bizonyos esetekben. D) A felhasználók nem nézik meg a SPAM mappájukat.
Helyes válasz: C – ez a legközelebbi és legellenőrizhetőbb hipotézis, amit a saját kódban lehet igazolni vagy megcáfolni. A többi feltételezés külső rendszerektől függ. A logból egyértelműen látható, hogy a függvény meghívódik-e.
10. feladat – Összetett szituáció
Olivér a következő hibát tapasztalja: egy webshopban a "Kedvencekhez adás" gomb kattintásra nem reagál mobilon, de asztali böngészőben működik. Írj egy rövid debugging tervet a tudományos módszer alapján!
Elvárás: 4 lépés (megfigyelés, hipotézis, kísérlet, következtetés iránya).
Mintaválasz:
Megfigyelés: A gomb mobilon (Safari iOS / Chrome Android) nem reagál kattintásra. Asztali Chromeben és Firefoxben működik. A böngésző konzolján nincs hibaüzenet mobilon.
Hipotézis: Mobilon a kattintás esemény nem tüzel – valószínűleg a gomb felett van egy láthatatlan elem, ami elfogja az érintést (z-index / overlay probléma), vagy a touch event nincs megfelelően kezelve.
Kísérlet: Mobilon DevTools-ban (remote debugging) megnézem az elemek z-index értékét és az eseményfigyelőket a gombra. Ellenőrzöm, hogy van-e overlay elem a gomb felett.
Következtetés iránya: Ha overlay van → azt kell eltávolítani vagy z-index sorrendet javítani. Ha nincs overlay → az eseménykezelőt kell megvizsgálni, van-e
touchstartesemény regisztrálva.