Kontext
Účetní kategorie byla klasifikace, podle které se účtované položky řadily ve finančních reportech. Používala se i při následných kontrolách, takže nebyla jen technickým detailem v databázi. Když kategorie na položkách neseděla, neseděly ani reporty.
Původní implementace kategorii na položce neukládala jako stabilní hodnotu. Kdykoliv ji systém potřeboval přečíst — například při generování reportu — dopočítala se z aktuální konfigurace a dalších souvisejících dat.
Problém
Největší problém byl v tom, že historická data nebyla dost stabilní. Uživatel mohl vygenerovat report za stejné minulé období dvakrát v různém čase a dostat jiné výsledky, protože se mezitím změnila konfigurace, ze které se účetní kategorie dopočítávala.
U účetních dat je to zásadní rozdíl. Aktuální konfigurace má ovlivnit budoucí nebo ještě otevřené položky, ale neměla by zpětně měnit význam položek, které už patří do minulosti nebo jsou součástí uzavřeného účtu.
Zpřehlednění výpočtu
Než šlo změnit, kdy se účetní kategorie ukládá nebo přepočítává, bylo potřeba nejdřív pochopit a zjednodušit samotný výpočet. Ten byl rozložený na více místech: různé typy položek byly do sebe zamotané a logika pro jeden typ položky mohla být rozprostřená přes několik tříd nebo pomocných metod najednou.
Refaktoring směřoval k tomu, aby každý typ položky měl jasně dané místo, kde se jeho účetní kategorie počítá. Díky tomu bylo možné projít algoritmus krok za krokem a při chybě rozlišit, jestli je problém v nastavení, ve vstupních datech nebo v samotném výpočtu.
Součástí práce byla i dokumentace algoritmu podle typů položek. Sloužila hlavně supportu, který do kódu neviděl, ale potřeboval umět ověřit, proč konkrétní položka dostala právě danou kategorii.
Snapshotování a přepočty
Další krok byl začít účetní kategorii ukládat přímo na položku. Tím se report nemusel pokaždé vracet k aktuální konfiguraci a znovu dopočítávat hodnotu, která měla být pro historická data stabilní.
Nebyl to ale jednoduchý model „ulož a už nikdy neměň“. Pokud se změnila data, která měla oprávněně ovlivnit budoucí nebo ještě otevřené položky, bylo potřeba kategorii přepočítat.
Smyslem bylo zachovat obě věci najednou: budoucí položky měly reagovat na relevantní změny nastavení, ale historické reporty se neměly přepisovat jen proto, že se mezitím změnila konfigurace.
Migrace a reporty
Protože se snapshotování zavádělo až poté, co už v systému existovalo velké množství položek, bylo potřeba historická data zpětně vyhodnotit. Připravil jsem migrátor, který uměl běžet ve dvou režimech: dry run pouze generoval report a fix mode aplikoval opravy.
Dry run jsem použil k vygenerování exportů pro více než 5000 hotelů. Výstupem byl CSV/Excel report se seznamem položek, u kterých uložená účetní kategorie neseděla. Obsahoval identifikaci položky, aktuální uloženou hodnotu, nově vypočtenou správnou hodnotu a data, podle kterých se výpočet dal ověřit.
Technicky nejtěžší část byla výkonová a provozní. Pro výpočet kategorie bylo potřeba načítat hodně konfiguračních dat hotelu. Pokud jeden batch obsahoval položky z tisíců různých hotelů, znamenalo to načítat konfiguraci a související záznamy pro každý z nich. Při zpracování po jednom hotelu se naopak stejná konfigurační data dala používat opakovaně pro velkou část položek. Proto jsem nad migrací připravil orchestraci po jednotlivých hotelech: jeden job procházel hotely a pro každý z nich spouštěl samostatné zpracování jeho položek.
Opravný režim jsem potom předal support týmu spolu s návodem. Support mohl použít stejný nástroj pro hotely, které si opravu vyžádaly: nejdřív ověřit dopad v reportu a potom podle potřeby spustit fix mode.
Výsledek
Práce trvala zhruba čtyři měsíce a dotáhli jsme ji do konce. Účetní kategorie se začala ukládat přímo na položky, takže historické reporty už neměly záviset na aktuální konfiguraci v okamžiku generování.
Stejně důležité pro mě bylo zpřehlednění celého výpočtu. Když se objevila otázka, proč má položka určitou kategorii, šlo projít konkrétní algoritmus pro daný typ položky, ověřit nastavení a rozlišit chybu v konfiguraci od chyby v kódu.
Vedle samotné změny vznikl i provozní nástroj: reportovací a opravný job, který support mohl používat pro konkrétní hotely. To z migrace neudělalo jen jednorázový skript, ale bezpečnější proces, kde šlo nejdřív zjistit dopad a teprve potom opravovat data.