Právě se nacházím zhruba tak v půlce stáže a myslím, že to je ta správná chvíle na napsání článku :). Co jsem tady ten měsíc a půl dělal? Možná se budu trošku opakovat, ale pokusím se navázat na článek první zážitky ze stáže.
Seznámení se s projektem
První zhruba tak týden, dva, jsem se seznamoval s projektem. Nejprve jsem musel projekt dostat do kompilovatelného stavu, což se ukázalo jako úkol na dlouhou dobu. Musím říct, že hned po prvním dni jsem si říkal ZLATÝ MAVEN! Ano, kdyby používali na takto rozsáhlý projekt Maven a správně nastavené závislosti mezi projekty, nemusel bych strávit několik dní nad hledáním a nastavováním závislostí, ale byl bych schopen projekt zkompilovat během 5 minut.
Poté, co se mi podařilo projekt úspěšně zkompilovat, na mě čekal další nelehký úkol – brodit se stovkami souborů a tisíci řádky kódu a pochopit, jak že to vlastně funguje. Nebylo to snadné, styl, jakým je kód psaný, mi to vůbec neusnadňoval. Soubory jsou plné komentářů a poznámek, které jsou mnohdy i několik let staré a na 99% neaktuální a zcela jistě naprosto zbytečné. Ovšem jsou tam… Nevím proč, ale jsou. A dokonce si ten zvyk psát ke každé úpravě kódu komentář se jménem, kdo a kdy to upravil, udržují dodnes. Přestože používají SVN a tyto změny by si mohly vyhledat tam.
Hlavní úkol stáže
Na konci prvního týdne jsme si dali meeting s vedoucím projektu a ten mi vysvětlil, co že vlastně budu dělat. Popsal mi pro mě důležité části projektů, co dělají apod. Projekt má 3 hlavní části, na kterých budu pracovat – POM – nástroj na počítání metrik kódu, SAD – nástroj na detekci tzv. code smells a Ptidej – nástroj na detekci návrhových vzorů. Pak jsme se dostali k tomu, jak spolu ony nástroje souvisí atd. Dozvěděl jsem se, že mým hlavním úkolem bude pracovat na nástroji Ptidej – ten je ze všech nejpomalejší a nejvíc potřebuje paralelizaci. Následně jsme se velice povrchně dostali k tomu, jak Ptidej funguje.
A hned jsme zabrousili do dalších souvisejících projektů. Aby bylo možné hledat návrhové vzory, je nutné nejprve vytvořit graf tříd. Takovýto graf obohacený o různé informace tvoří model tříd. Projekt, který se zabývá popisem modelu tříd, a vlastně nejdůležitější ze všech projektů, je PADL. Tento projekt tvoří meta-model pro model tříd.
Samotné vyhledávání návrhových vzorů je založené na principu isomorfismu podgrafu. Musím říct, že mě to poměrně zaskočilo. Celkově jsem byl velice překvapený, jaké psí kusy se zdrojovými kódy dělají, aby udělali nějaké ty analýzy. Původně jsem se mylně domníval, že půjde o něco jako lexikální analýzu. Celkově jsem očekával mnohem více práce se zdrojovými kódy, než s modelem tříd apod.
Když vyprchal můj prvotní šok, dali jsme do vymýšlení způsobu, jak to vyřešit. Vedoucí mi navrhoval, že by nejraději rozdělil model tříd na několik částí, a prováděl analýzu na těchto dílčích částech. Ovšem bylo potřeba vymyslet, jak model dělit, a jak jeho rozdělené části zase spojit zpět. Zpočátku to vůbec nevypadalo jasně, ale domluvili jsme se, že budeme model dělit na úroveň balíčků či namespaců. První úkol zněl jasně – analyzovat kód balíček po balíčku.
Metriky kódu
Nástroj, na kterém budu prvně pracovat je POM. POM dělá několik analýz kódu. V první fázi vypočítává metriky, jako je například CBO (coupling between objects), DIT (depth of inheritance tree) apod. Těchto metrik je celkem 72. Většina metrik je unárních, tedy počítají se vzhledem k 1 třídě, ale také je tam několik binárních metrik, které vyjadřují vztah mezi 2 třídami. Většina metrik je závislých na celkovém modelu, takže na ně není možné použít navrhovaný způsob rozdělení modelu do několika menších částí. Ovšem některé závislé nejsou, a tak jsem se dal do identifikace těch nezávislých. Postupně jsem prošel všechny metriky, prozkoumal jejich zdrojové kódy, zjistil, zda vyžadují celkový model či ne, a ty, které ne, jsem otagoval příslušným interfacem. Na závěr jsem si napsal unit test, který zkouší spočítat metriky na úrovni balíčků a porovnává hodnoty s metrikami z celkového modelu.
Nástroj na slučování dílčích modelů – PADL Merger
Dalším krokem bylo vyřešit ony metriky závislé na celkovém modelu. A tady přišlo na řadu spojování dílčích částí modelu. Nejprve jsem musel dopodrobna prozkoumat, jak vypadá zdrojový kód tříd modelu, jak se model sestavuje apod. Zjistil jsem, že každá entita z analyzovaného zdrojového kódu (balíček, třída, interface, metoda, parametr…) má svou reprezentaci ve zdrojových kódech onoho nástroje na analýzu a tvoří tak meta-model. Třídy, ke kterým není k dispozici zdrojový kód (například vnitřní implementace standardních tříd Javy), jsou reprezentovány pomocí interface IGhost.
Rozhodl jsem se tedy vytvořit nástroj, který nalezne všechny ghosty v modelu a shromáždí jejich reference na jednom místě – v hash mapě. Už to samo o sobě mi dalo docela zabrat, ale docela mě to bavilo. Naučil jsem se přitom používat návrhový vzor Visitor 🙂 Dalším logickým krokem bylo nahrazení těchto ghostů entitami, které reprezentují plně analyzovanou implementaci daného ghosta. Těmto entitám interně říkám implementing entities nebo zkráceně implementors. Nahrazení ghostů funguje tak, že se pracuje se 2 modely. V prvním modelu, nazvěme ho třeba cílový, se postupně projdou všichni ghostové a zkusí se vyhledat podle ID v druhém modelu, zdrojovém modelu. Pokud zdrojový model obsahuje entitu s daným ID, máme vyhráno. Stačí ji vyjmout ze zdrojového modelu a vložit do cílového 🙂 Ovšem tahle sranda není vůbec jednoduchá a dala mi docela zabrat. Zdrojové kód třídy, která toto dělá, má skoro 1000 řádek.
Unit testing
Když jsem dokončil slučovací nástroj, dal jsem se do psaní testů. Vůbec jsem nevěděl, jak ověřit, jestli jsou modely sloučené správně. A tak mě napadlo zkusit porovnat počet entit ve sloučeném modelu a v modelu, který byl vytvořen bez slučování. Pak mě napadlo porovnat také metriky, pokud jsou modely stejné, měly by být i metriky stejné…
Bugy
Ovšem tady jsem narazil. Metriky stejné nebyly 🙁 A tak jsem se dal do hledání bugů. Po opravení několika svých bugů jsem narazil na neočekávané chování několika tříd z projektu PADL. Nahlásil jsem toto chování profesorovi, který je hlavním vedoucím projektu. Ten mi potvrdil, že je to neočekávané, a že se s největší pravděpodobností jedná o bug. A tím začalo moje hledání bugů v projektu PADL 🙂 Doposud jsem jich našel a opravil nemalé množství, ale mnohé stále zůstávají neobjeveny. Když už jsem se hrabal ve zdrojových kódech PADLu, napadlo mě, že spustím unit testy z projektu zvaného All Tests. To jsem asi neměl dělat.. Testů tam bylo obrovské množství (asi 500), běžely poměrně dlouho (odhaduji to na 20 minut), a výsledkem bylo, že jich více než polovina neprošla. Zajímavé.. Bohužel toto je výsledkem poměrně nekoordinovaného způsobu práce, který tu provozují. Na projektu dělá několik lidí, vždycky někdo někde něco upraví, commitne a dál se o to moc nestará. Nějaké konvence, návrhové vzory apod. se tu moc neřeší. Je to trošku paradox, projekt na analýzu kódů, vyhledávání návrhových vzorů a code smells je, bohužel, plný code smells 😀
Paralelizace? Ještě ne…
V první části stáže jsem se tedy (bohužel) vůbec nedostal k žádné paralelizaci. Zatím jsem pouze řešil nástroj na spojování modelů a opravoval bugy. Také jsem radil kolegovi z Mexika, který měl tu smůlu, že musel tento projekt používat na analýzu kódu. Sice jsem byl trochu zklamaný z toho, že jsem s tím moc nepohnul, ale měl jsem radost z toho, že tomu rozumím natolik, že jsem schopný radit ostatním 🙂 Také jsem byl rád, že jsem nalezl a opravil několik bugů. Celkově mi první část projektu dala trošku jiný pohled na rozsáhlé a zejména teoretické projekty.