Ako nájsť chybu v apke pomocou polenia intervalu

Ak programujete, tak sa s polením intervalu (bisekciou) pravdepodobne stretávate často a ani si to moc neuvedomujete. Väčšinou to bude pri hľadaní chýb.

Po aktualizácii jednej knižnice v našej UI apke sme sa dostali do vcelku nepríjemnej situácie. Prestala fungovať jedna z jej častí. Spravili sme revert a začali hľadať chybu.

Sú v podstate dva spôsoby ako takúto chybu odhaliť. Buď pomocou Gitu alebo manuálne. Oba sú však postavené na rovnakom základe.

Nájdenie zlej revízie pomocou Gitu

Pri práci s Gitom je možné použiť príkaz git bisect. Ten slúži na identifikovanie zmeny, ktorá spôsobila, že vaša apka sa prestala chovať podľa očakávania.

Spočíva to v tom, že označíte revíziu ktorá je pokazená a následne revíziu, ktorá ešte fungovala. Následne Git pre vás vyberie revíziu medzi nimi a tú opäť označíte za pokazenú alebo funkčnú. A takto sa viac a viac zmenšuje interval medzi funčknou a nefunkčnou revíziou, až nakoniec nájdete revíziu, ktorá apku rozbila.

V praxi to môže potom vypadať takto:

$ git bisect start       
$ git bisect bad HEAD    
$ git bisect good 153d377
Bisecting: 3 revisions left to test after this (roughly 2 steps)
[3366a36571a115ee579fa8fac9818352d34fd4cf] Merge pull request #43 from ujovlado/prev-next-tuning
$ git bisect bad
Bisecting: 1 revision left to test after this (roughly 1 step)
[ea42b2839c2178cc3d771342b8b33afff21cbfca] Merge pull request #42 from ujovlado/prev-next-init
$ git bisect good
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[ef5fa78913880e69850f93778494ba4a95ed0703] Keep previous/next size even if displayed alone
$ git bisect bad 
ef5fa78913880e69850f93778494ba4a95ed0703 is the first bad commit
commit ef5fa78913880e69850f93778494ba4a95ed0703
Author: Vladimír Kriška <ujovlado@users.noreply.github.com>
Date:   Sat Jan 9 22:52:40 2021 +0100

    Keep previous/next size even if displayed alone

 components/PreviousAndNextPost.js | 44 +++++++++++++++++++++++++++++----------
 1 file changed, 33 insertions(+), 11 deletions(-)
$ git bisect reset

Tento spôsob sme ale v našom prípade použiť nemohli, pretože sa jednalo o zmenu v rámci jednej revízie. Že je zlá vieme hneď, bez hľadania.

Manuálne nájdenie chyby

Pri manuálnom hľadaní chyby väčšinou potrebujete zistiť, ktorá časť súboru je pokazená, prípadne ktorú časť súboru alebo vstupu vaša apka nevie spracovať.

TypeError: Super expression must either be null or a function.

Na základe správy vyššie sme po chvíli zistili, že chyba je v tom ako sa pripravuje balíček apky (tzv. build).

Aktualizácia devDependencies (Webpack a pod.) nepomohla, veľa závislostí má totiž zafixovanú verziu v yarn.lock súbore. Tak sme ho pokusne zmazali. Pomohlo.

Oprava je teda možná aktualizáciou všetkých závislostí. Čo nie je úplne najšťastnejšie, a to napriek tomu, že jednotlivé knižnice sú nastavené tak, že aktualizácia by bola v rámci major verzie (napr. ^16.8.0).

Potrebovali sme identifikovať, ktorú knižnicu treba aktualizovať, aby sa problém vyriešil. A tak sme využili polenie intervalu. Je to taký "manuálny bisect". 🙂

Začal som mazať časti yarn.lock súboru. Zmazal som jeho prvú polovicu a spustil príkaz yarn. Apka nenabehla, takže som vedel, že chyba je spôsobená nejakou starou knižnicou v druhej polovici súboru.

Presunul som sa na druhú polovicu yarn.lock súboru. Zmazal som z nej prvú polovicu a spustil príkaz yarn. Apka nenabehla, takže som vedel, že ...

A pokračoval som rovnakým spôsobom ďalej, kým sa okruh podozrivých knižníc zúžil na minimum.

Podľa jednotlivých knižníc som identifikoval, že problém bude spôsobený pravdepodobne knižnicou Terser. A tak to aj bolo. Táto knižnica je zodpovedná za minifikáciu kódu, používa ju Webpack.

Následne som zmazal terser a terser-webpack-plugin z yarn.lock súboru, spustil príkaz yarn, ktorý tieto dve knižnice aktualizoval a bolo po probléme.

Nakoniec to nebolo až také zložité, ako sa na začiatku zdalo, pretože veľkosť súboru sa zmenší vždy o polovicu, a tak stačí pár krokov a chyba je odhalená.