Když jsem nedávno četl příspěvek Jorise de Gruytera Resolving Compile Errors and Generating CIL is not Optional, hned se mi vybavilo několik problémů, se kterými se pravidelně setkávám ve společnostech vyvíjejících a spravujících řešení založená na Dynamics AX. Mluvit budu jen o “normální” kompilaci do p-code, ne do CIL.
Z pohledu předcházení chybám má kompilace dva důležité důvody:
- Umožňuje odhalit kompilační chyby
- Aktualizuje bytecode, takže správně napsaný kód je i správně spouštěn
1. Včasná identifikace kompilačních chyb
Většina firem (ne všechny!) si uvědomují, že aplikace musí být alespoň zkompilovatelná, když už nic jiného. Navzdory tomu ale kompilují velmi zřídka – buď si neuvědomují důsledky, nebo mají pocit, že je to příliš zdržuje.
Spousta projektů tedy počítá s celkovou kompilací, ale až někdy v průběhu nasazení, často až v produkčním prostředí. Důsledkem je pak pozdní detekce chyb a neúspěšné nasazení aplikace.
Takový (chybový) průběh může vypadat následovně:
- Vyvojář způsobí kompilační chybu mimo svůj projekt. (Například přidá povinný parametr metody, ale neupraví její volání z jiné komponenty. To je mimochodem častý důsledek neaktuálních křížových referencí.)
- Jeho projekt jde zkompilovat, jako .xpo je přenesen na testovací prostředí atd. – Nikdo si není žádné chyby vědom.
- Celá vrstva z testovacího prostředí je nasazena na produkční prostředí, ale kompilace selže.
- Nasazení je třeba zrušit a začít pátrat po problému.
Tu chybu bylo možné najít v průběhu vývoje – takto mnohdy uplyne několik měsíců a vývojáří se musí s kódem znovu seznamovat. Změny v kódu samozřejmě vyžadují opětovné testování, nasazení je třeba provést znovu (včetně plánování servisního okna apod.), zkrátka cena takové chyby je dost vysoká. A tomu celému by se dalo zabránit, kdyby někdo zkompilovat aplikaci dříve.
2. Aktualizace bytecode
Z technického pohledu je smyslem kompilace překlad kódu z lidmi psaného zdrojového textu do podoby, která je lépe srozumitelná pro počítač. Za určitých okolností se ale Dynamics AX dostane do situace, kdy zdrojový kód je sice v pořádku, ale není korektně zkompilován – typickým projevem jsou záhadné chyby za běhu, ale obecně jsou důsledky zkrátka nepředvídatelné.
Naprosto typická je runtime chyba hlásící nesprávné typy v přiřazení proměnné, přestože přiřazení je očividně v pořádku (třeba i přiřazení true do proměnné typu boolean). To je znak toho, že běhové prostředí spouští něco jiného, než co je uvedeno ve zdrojovém kódu.
Nevím přesně, za jakých všech okolností se tato chyba může objevit (to by byla otázka spíš na Microsoft), ale jednu situaci mám spolehlivě vyzkoušenou – k problémům často dochází, když se změní členské proměnné nějaké třídy, ale nejsou překompilovány ostatní třídy v její hierarchii dědičnosti. Pak se právě často stane, že se AX snaží přiřazovat do nesprávných členských proměnných.
Lidé si většinou nejsou vědomi příčiny těchto potíží a i po vysvětlení se snaží vyhnout kompilaci jak jen mohou. Typická reakce je uložit vývojářům, aby kompilovali všechny třídy pomocí Kompilace dopředu (Compile forward). Jedním problémem je dodržování takového nařízení, ale hlavně to stále neřeší konflikt vzniklý mezi modifikovanou třídou a jejími předky. Jistě, bylo by možné vzít změněné třídy, identifikovat vhodného předka každé nich a spustit Compile forward z něj, ale kompilace celé aplikace je jednodušší (a má i další výhody).
Hororový příběh
Ačkoli větší či menší problémy s kompilacemi má skoro každý tým, některé případy značně vyčnívají. Znám dokonce jednoho Gold Partnera, který aplikace nekompiluje vůbec (o jednom jejich zákazníkovi vím, že má v produkčním prostředí čtyřicet kompilačních chyb), problémy s nesprávně zkompilovaným kódem (jaké popisuji v 2. Aktualizace mezikódu) jsou na denním pořádku a každý se řeší jako samostatný support call. Protože tato firma dokáže ze zákazníků dostat nějaké peníze i za tyto případy, možná to považují za ziskovější strategii.
Opravdu doufám, že je to výjimka.
Řešení
Snad se shodneme, že kompilace je důležitá, ale teď jak ji spouštět a jak často?
Pokud máte jen několik málo prostředí, může být i ruční spouštění dostatečné. Na konci dne můžete zkrátka spustit kompilaci celého AOT a ráno se podívat na výsledky. Jednodušší už to být nemůže. Argument, že kompilace trvá dlouho, nehraje roli – má na to celou noc, kdy aplikaci stejně nikdo nepoužívá.
Pokud máte více prostředí nebo třeba chcete spouštět kompilaci až v noci, je daleko lepší ji zautomatizovat. Nemusíte používat PowerShellové skripty z tohoto blogu, můžete jednoduše vytvořit plánovanou úlohu ve Windows a spouštět AX s parametrem -SysStatupCmd=CompileAll. Nicméně pak nezapomeňte se také někdy na výsledky kompilace podívat – jinak jste nevyřešili problém detekce kompilačních chyb.
Ve chvíli, kdy máte automatizovaný process, nestojí vás spouštění žádnou práci a není proto problém kompilovat často. Osobně propaguji kompilaci každou noc a plnou aktualizaci křížových referencí každý víkend.
Nerozumím tomu ani v angličtině ani v češtině, a to jsem překladatelka 🙂 Obdivuju Vaši snahu psát dvojjazyčně, klobouk dolů!
Díky! On každý obor má svůj vlastní jazyk, já zas nerozumím třeba doktorům. 🙂 A “programátorština” je ještě specifická v tom, že spousta termínů existuje jen v angličtině, takže čeština dostává trochu na frak.