Bogárirtás IT módra – avagy mindent a debuggingról
2. rész
Az előző részben megnéztük, hogy miért bogár a bug, mik lehetnek a leggyakoribb problémák, most pedig ezekre keresünk megoldási módszereket.
Felező módszer
A felező módszer egy általános, de mégiscsak leginkább műszaki környezetben használt módszer. De mi is ez? Van egy hosszú, egymás után következő eseményláncolat, és ahhoz, hogy a megfelelő eredményt kapjuk, mindegyiknek jól kell működnie. Lehet ez egy házimozi-rendszer, amiben ahhoz, hogy halljuk a hangot, kell áram, a videófelvételnek kell legyen hangja, kell, hogy a számítógép videólejátszója le is tudja játszani, össze kell legyen kapcsolva a számítógép az erősítővel, az erősítőnek jól kell működnie, be kell legyen kapcsolva, az szintén össze legyen kapcsolva a hangfalakkal, amelyek megintcsak jók és bekapcsolt állapotban kell lenniük. Bármely ponton probléma van, a rendszerben nem hallunk hangot.
Az egyik lehetőség az, hogy komponensről komponensre végigmegyünk egyesével, de ha nagyon sok darabból áll, akkor ez nagyon időigényes (talán néhányaknak vannak még élénk emlékei a nem működő – soros kapcsolású – karácsonyfaizzósort “debugoló” apukáról).
A gyorsabb megoldás, hogy megpróbáljuk “valahol középen” megnézni, hogy ott rendben vannak-e még a dolgok (van-e még hang), és az eredménytől függően folytatjuk tovább a vizsgálódást.
- Ha ez 100 komponensű rendszer 50. komponensénél probléma van, akkor azt már biztosan tudjuk, hogy az első 50 komponens valamelyike elromlott, így tekinthetjük ezt az első 50 komponenst egy olyan rendszernek, amiben van egy hiba – hasonlóan járunk el, mint a korábbi 100 komponensűvel, csak ezúttal feleakkora a rendszer, tehát megnézzük, hogy a 25. elemnél mi a helyzet, és így tovább…
- Ha pedig az 50. komponensnél minden oké, akkor tudjuk, hogy az első 50 komponenst kipipálhatjuk, tehát a problémát a második 50 komponensben kell keresni: ezúttal is 50 komponensünk van, amik együtt hibát okoznak, de nem tudjuk melyik és hol: ugyanezt a technikát követjük, csak megint egy feleakkora méretű rendszerre.
A fenti technikát folytatva folyamatosan feleződik a vizsgált rendszer mérete, így nagyjából féltucatnyi vizsgálat után megtaláljuk a rendszerben a hibát – feltéve, ha egyet kellett megtalálni.
A gyakorlat persze más, legtöbbször nem osztható pontosan félbe a rendszer, és lehet, hogy a vizsgálat elvégzése sem egyszerű (lásd még soros kapcsolású karácsonyfaizzók), de az elv elég sokat segít a legtöbb esetben.
A felező módszerhez tartozik pl. a frontendet és backendet tartalmazó webes rendszerek esetében a két komponens közötti kommunikáció megvizsgálása: ha látjuk azt, hogy a frontend mit küld el a backendnek, és hogy erre a backend mit válaszol, el tudjuk dönteni, hogy a hibakeresést hol kezdjük el: a frontend kérte rosszul vagy dogozta fel rosszul, netán a backend válasza lett hibás.
Naplóírás
A manapság használt legtöbb környezet biztosít lehetőséget arra, hogy a program naplózza, amit éppen csinál. Ennek azért van jelentősége, mert a hiba sokszor már az átadott, üzemelő rendszerben kerül elő, a programozónak pedig utólag kell, nyomozó módjára, összerakni a történéseket. A krimis analógiánkkal élve: bár az olvasó szemáben a krimi élvezeti értékét csökkentené, de az ügy megoldását nagyban felgyorsítaná, ha az áldozat gondosan lejegyzetelné, hogy “Bejött John, előhúzott egy pisztolyt, rámfogta, elmondta, hogy mindezt azért csinálta, mert velem csalta meg a felesége, és hogy ezt a fegyvert egy Tim nevű fegyverkereskedőtől lopta a Harmadik utcában, a sorozatszáma xxxxx, majd meghúzta a ravaszt kétszer, és én meghaltam.”
Egy ilyen hiteles napló a programozásban nagyon hasznos, és jellemzően készül is.
Ilyesmit még akkor is nagyon könnyen elő tudunk állítani, ha éppen most kezdtünk el programozni tanulni – a legelső parancs, amit az ember megtanul, az a szöveges képernyőre való kiírás (lásd még Hello World). Ha ennél még nem is tudunk sokkal többet, naplót szöveges képernyőre kiírás segítségével mi is készíthetünk magunknak. Ez persze sokkal fapadosabb, mint a naplózásra kifejlesztett célrendszerek, de bizonyos esetekben a célnak ez is megfelel.
De ha már célrendszereknél tartunk, az egyes programozási nyelvekhez jellemzően van legalább egy ilyen rendszer, Javában pl. több is: Log4j2, Logback, esetleg Apache Commons Logging vagy a Java beépített standard logolója, amit a belső elnevezése (“csomagneve”: java.util.logging) alapján JUL-nak is szoktak hívni. A legfrissebb és mindegyik kollégájával együttműködni képes Simple Logging Facade for Java, azaz SLF4J. Mára ez vált a logolók között de facto szabvánnyá.
Lépésenkénti futtatás
Az IDE-k (fejlesztőkörnyezetek) jellemzően tartalmaznak olyan funkciót, amellyel a programunkat sorról sorra tudják futtatni, és a részeredményeket ki tudják jelezni. Ezt hívják lépésenkénti futtatásnak, esetleg nyomkövetésnek vagy tracingnek. A nyomkövetés onnan jön, hogy ahogyan az erdőben a vadat vagy a gyilkost, úgy követjük lépésről lépésre azt, hogy mi történt a programban, mi hogy változott meg, hol merre haladt tovább a program.
Akkor hasznos, ha éppen a saját gépünkön próbáljuk a hibánkat feltárni, és akkor is viszonylag pepecselős módszer (a karácsonyfaizzós megoldásra hasonlít), ezért gyakran inkább kombináljuk a felező módszerrel, és inkább a 100 komponensből csak néhányat vizsgálunk meg ennyire tüzetesen. Viszont a vizsgálat tényleg tüzetes, tehát ha nézzük a programot, annak részeredményeit, akkor az eltérés a fejünkben lévő szándék és a valóság között nagyon gyorsan feltűnik.