Robert Važan

Cezjazyčná integrácia v Jave

Java je jedným z najpopulárnejších programovacích jazykov, ale je zatienená JavaScriptom a Pythonom. To má za následok, že mnohé užitočné opensource knižnice nie sú v Jave k dispozícii hoci podobné knižnice sú dobre podporované v JavaScripte alebo Pythone. Javovskí vývojári tak majú nezávideniahodnú úlohu integrovať do javovských aplikácií nejavovské knižnice.

Existuje niekoľko spôsobov, ako rozchodiť nejavovské knižnice v Jave:

  1. Portovanie: Reimplementácia knižnice v Jave má najlepšie výsledky, ale aj napriek tomu, že portovanie je lacnejšie ako pôvodný vývoj, a napriek asistencii od LLM, portovanie každej užitočnej knižnice do Javy nie je reálne.
  2. GraalVM: GraalVM je polyglot runtime. Je to najlepšia nádej pre cezjazyčnú integráciu v Jave. Je taký perspektívny, že pravdepodobne vysáva život z jednojazyčných runtimov: Rhino a Nashorn sú zastarané, zatiaľ čo Jython je zaseknutý na Pythone 2. Status, kompatibilita a budúcnosť GraalVM sa stále kryštalizujú, takže prechod naň je netriviálny a riskantný. V súčasnosti sa zdá byť nevhodný pre použitie v knižniciach.
  3. Lua: Lua je špeciálne navrhnutá pre embednutie do iných jazykov a preto je tu nádej, že by sa s ňou mohlo pracovať ľahšie než s Pythonom alebo JavaScriptom. Žiaľ, v praxi Lua nie je tak dobre podporovaná. Je na vás, aby ste si vybrali taký fork Luaj, ktorý vám bude fungovať. Samozrejme, na embednutie Luy potrebujete najprv knižnicu implementovanú v Lue a pre autorov knižníc je žiaľ Lua len zriedka prvou voľbou cieľového jazyka.
  4. WebAsembler: WebAsembler pravdepodobne jedného dňa nahradí Luu s oveľa širšou podporou knižníc a oveľa lepším výkonom, ale ešte tam nie sme. Aspoň teraz, v roku 2023, ani Python ani JavaScript nebežia vo WebAsembleri.
  5. JNI/JNA: Prístup k natívnym knižniciam je užitočný pre integráciu C, C++ a nedávno aj Rust knižníc, ale nemožno ho priamo použiť na volania do Pythonových alebo JavaScriptových knižníc, ktoré sú najrozšírenejšie. Môžete ho použiť na integráciu s Python/C API a V8 (možno prostredníctvom Javet), ale pravdepodobne je lepšie použiť GraalVM.
  6. CLI: Shell out do Pythonu alebo Node.js používa primárny runtime jazyka, ktorý je vždy aktuálny. Je to univerzálne riešenie, ktoré funguje takmer s každým jazykom. Navyše poskytuje prístup k existujúcim CLI nástrojom. Háčik je v dependency managemente a v časovej náročnosti spustenia samostatného procesu pri každom použití knižnice.
  7. Mikroservisy: Tento prístup je podobný CLI v tom, že funguje takmer pre všetko. Náklady na spustenie samostatného procesu sú nahradené oveľa nižšími nákladmi na RPC volanie. Nevýhodou je, že teraz musí byť proces neustále v RAM-ke a pribúdajú starosti s bezpečnosťou. Aj keď je možné vyvinúť špecializované RPC API pre každú knižnicu, pravdepodobne bude jednoduchšie proste spraviť všeobecné REPL API alebo len spustiť REPL na localhoste cez IPC kanál.
  8. Dáta: Ak je knižnica len tenkým wrapperom okolo modelu strojového učenia alebo iných dát, je často pomerne jednoduché prepísať wrapper v Jave. Dáta potom môžete bez zmeny skopírovať.

Neexistuje žiadne bezstarostné riešenie. Vo všeobecnosti si môžete vybrať jednu z dvoch ciest:

  1. Čistá Java: Vaše možnosti sú obmedzené na portovanie, Luu, WebAsembler a owrapovanie dát. Váš kód zostáva platformovo nezávislý a ľahko kompilovateľný, ale platíte za to množstvom času potrebného na vývoj.
  2. Kontajnerizácia: Namiesto toho, aby ste dodávali Java aplikáciu, dodávate kontajner. Toto samozrejme funguje len pre aplikácie, nie pre knižnice. Kontajner vytvára kontrolované prostredie, do ktorého môžete nainštalovať nejavovské závislosti.

Myslím, že koreňovou príčinou týchto problémov je to, že Maven nemá štandardnú sadu rozšírení na správu nejavovských závislostí. Pokusy o embednutie nejavovských závislostí do JAR súborov bývajú poloúspešné a spôsobujú problémy v downstreame. Java má len prostriedky na spustenie nejavovských závislostí. Nevie ich deklarovať ani inštalovať. To v praxi núti Java knižnice, aby boli čisto javovské, zatiaľ čo aplikácie musia používať dodatočnú kontajnerovú vrstvu, ktorá ich viaže na konkrétnu kontajnerizačnú platformu.