Corporate Bullshit Generator for Java

Lőn vala, egykoron a Corporate Bullshit Generator, és miután láttam vala, hogy ez jó és még Dilbert főnöke is ezt használja, így legyen meg ez Java nyelven is.

Már régóta kacérkotam a gondolattal, hogy kéne vetni erre egy pillantást. Az IR minden bizonnyal jóváhagyta volna a projekt megszületését. :) A Markov láncok érdekes téma amúgy is, illetve, ha valaki dolgozott már multinál, akkor pontosan tudja, miről is beszél az, aki a “corporate bullshit” fogalmára gondol.

A ChatGPT elveszi a munkánkat ***, ez különösen igaz az ehhez hasonló generátorokra, mivel az AI-nak akár megadhatjuk a stílust is, hogy mihez hasonló eredményt szeretnénk. Egyéb, machine learning megoldásokkal is jobb eredményt lehet elérni, tehát nem érdemes túl sok erőforrást beletenni a tutira megírt optimalizációba. Így aztán én is inkább kerestem egy létező implementációt, és azt fordítottam át, majd alakítottam át.

Dilbert's pointy-haired boss

*** Ez a cikk még nem ChatGPT hozzáadásával készült.

CBSG github-on

Az egész lényegében egy ujjgyakorlat, nem is vettem túl szigorúan az alap szoftverfejlesztési szabályokat. Néhány elvárást azért rögzítettem magamnak:

  • zero dependency - ne legyen semmilyen függősége
  • old standard - java8 legyen, hogy bárki bármilyen projectbe behúzhassa
  • külön fájlokba szervezett szótár
  • legyen cserélhető a szótár
  • egyszerűen legyen használható, akár konzolból is, akár behúzható lib függőségként is

Képzeljük el az esetet, amikor a megrendelő odaállít egy Excel fájllal, hogy ezt kéne megírni, mikorra lesz kész. Ilyenkor lehet érdemes hasonló módszerrel dolgozni, de esetünkben ez csak hobbi célokat szolgál.

Fejlesztési napló

1. Transpile

Azért választottam pont ezt az implementációt, mert Pythonhoz azért valamennyit lehet érteni, és elég egyszerű a kódja. Mindenféle transpiler létezik, de a legtöbb fizetős. Részben azért találtam működőt, de az indexelést többnyire elrontotta, illetve egyes esetekben a “replace all” gyorsabban eredményre vezetett.

Ennek az eredménye lett egy szép hosszú, végig statikus metódusokkal operáló, de sok kalapálás után már működő generátor.

2. Szótárak kiszervezése

A fentebb már hivatkozott Markov-láncok szócikkben részletesen ki van fejtve, hogy mi miért is úgy van. De az átfordított kódban rengeteg tömb és Map szerepelt, épp ahol szükség volt rá, bevésve a kódbázis közepébe. Ezt kicsit átláthatóbbá kéne tenni, de még úgy, hogy az értelmesen elnevezett metódusok megmaradjanak.

Egy ilyen generátor legnagyobb értéke a szótára. Sok esetben csak véletlenszerű szavakat választunk. Nem mindegy, hogy “manager”, “evangelist”, “leader” vagy “mastermind” szerepel a mondatban? Dehogynem!

Moldova óta tudjuk, hogy egy átlagos TSZ elnök szókincse maximum háromezer szó, ez fokozottan érvényes a “corporate mátrixban”.

Így aztán CbsgResourceUtil osztályba ki lett szervezve a classpath-ról fájl betöltő segédlet. Máris sokkal rövidebb, átláthatóbb lett az egész. Konvenciónak “word_” kezdetű fájlnevek hivatkoznak a sima szótár formára, a kulcsokat pedig konstansként definiáltam.

A következő lépés a súlyozott kifejezések kiszervezése lett. Szeretnénk meghatározni, hogy egyes kifejezések milyen gyakorisággal forduljanak elő. Itt a konvenció a “senw_” kezdetű fájlnevek által tárolt Map jellegű információ. Nem igazi CSV formátum, hanem egy pozitív egész szám, ami a súlyt képviseli, azután vessző, majd az összes többi lesz a lényegi kifejezés.

Amennyiben a vessző után semmi sincs, az jelképezi az alapértelmezett ágat. Sokszor ez speciális továbbhívás is jelenthetett.

A kód így már kezdett egész kezelhető méretű lenni.

3. Template rendszer

Míg eddig a triviálisan megoldható, sima kiszervezések történtek, így megtehettem, hogy ne foglalkozzak a nehezebb esetekkel. De itt beleütköztem több kereszthivatkozásba, ami ugyan kényelmetlenül megoldható, de elég nagy kuszaságot okoz.

Emellett szerettem volna megőrizni az eredeti forrás aránylag átlátható metódusait, ami aránylag könnyen követhető. Például a person() bizonyos súllyal a boss() metódus eredményét adja vissza.

Patrick Bateman a megmondhatója, hogy mennyire fontos a titulus a komoly vállalati hierarchiában. Ennek megfelelően talán túlzottan is cizellált a “főnök” generátor.

Itt jönnének a képbe a különféle template engine megoldások, például a Jamal vagy Apache FreeMarker. De az elején leszögeztük, hogy nem akarunk függőséget. Így aztán egy nagyon primitív szövegfeldolgozó készült. Itt lényegében templateFunction() metódusban definiált változókat helyettesítjük be a meghívásnak megfelelően, amit sima regexp segítségével azonosítunk.

Így már lehet ehhez hasonló mondatfoszlányokat definiálni:

1,there can be no $growthAtom until we can achieve $addIndefiniteArticleGrowth

Dinamikus nyelvekkel ez amúgy sokkal elegánsabban megoldható, de ez Java, annak minden előnyével és hátrányával.

A másik továbbra is létező probléma, ami nincs is feloldva, hogy a template-en belül hivatkozhat olyan kulcsra, ami szintén saját magára hivatkozik. Ez persze körkörös hivatkozás, azaz egy végtelen ciklus, ami szép StackOverflowError-ral honorálja a hibás definíciót. Mondjuk ez más template engine esetén is fennáll.

4. Használhatóság rendezések

Az eredeti egy statikus osztályból álló implementáció megváltozott. A fájlok kezelését végző rész kikerült a CbsgResourceUtil osztályba. Az eddigi konstans elérés helyett dinamikusan, egy Properties -ben tárolt szótár definíciókat használunk, melyhez a kulcsokat a CbsgDictionaryKey definiálja.

A CbsgGenerator osztályba kerültek a bemenő argumentumokat kezelő, és a dinamikus szótárbetöltést hivó logika. Itt is igaz, hogy vannak kidolgozott argumentum kezelő függvények, de nem akarunk függőségeket. Alapértelmezetten a ‘dict/en/dictionary.properties’

A CbsgCore osztály tartalmazza a lényegi implementációt, amit fentebb bővebben kifejtettem.

Út közben többször is jól jött volna var, Map.of() és még számos újabb eszköz, de ugye nem ez volt a cél.

Eredmények

A kitűzött célt sikerült elérni, kicsi, egyszerű alkalmazás készült, nulla függőséggel és Java8 kompatibilitást megőrizve. A szótárakat lehetne bővíteni, vagy akár teljesen más kontextust hozzáadni. Mindenki használja egészséggel!