Polyglot microservices rendszerekben mindig ugyanaz a pont fáj: az interfész definíciók.
C#-ban megírod az IOrderService-t, aztán átírod Java-ban, aztán Python-ban.
Három fájl, három helyen karbantartva, és előbb-utóbb az egyik elcsúszik a másiktól.
A hiba ott üti fel a fejét, ahol a legkevésbé várja az ember — a rendszerhatáron,
éles környezetben, ahol a két oldal különböző verziót hív.
A forrás egyetlen legyen
A UniContract erre ad választ. Egy .contract fájlban definiálod az interfészt egyszer,
és a tool kigenerálja az összes célplatformra. Nem kézzel szinkronizálsz — a generátor csinálja,
és mindig konzisztens marad.
Egy példa arra, hogyan néz ki egy contract definíció:
namespace DataStoring {
interface IDataStore {
readonly property Connection: IConnection
async method IsCollectionExists(name: string) => boolean
async method GetCollectionByName<T constraint IEntity>(name: string) => ICollection<T>
}
}
Ebből a definícióból C# interfész, Java interface, Python abstract class generálható — mind ugyanazt a kontraktust valósítják meg, és ha a contract megváltozik, mindenki megváltozik.
A fordítóhoz hasonló pipeline
Az architektúra egy komplett fordítóra hasonlít. ANTLR 4 alapú lexer és parser dolgozza fel
a .contract fájlokat, a syntax tree-ből element builder épít szemantikus modellt,
a semantic checker validálja az összefüggéseket, majd a pluggable emitterek generálják
a célnyelvi kódot.
Az emitterek Python modulok — bárki írhat sajátot anélkül, hogy a core engine-hez nyúlna. Ez teszi bővíthetővé: ha egy új platform kell (Rust, Go, TypeScript), egy új emitter modul elég.
Tervezési döntések
A constraint-alapú generikusok (<T constraint IEntity>)
biztosítják, hogy a típusbiztonság megmaradjon minden platformon.
Ez nem magától értetődő — Java, C# és Python generikusokat egészen másképp kezelnek,
de a contract szintjén egységes szemantikát ad.
Az async kulcsszó a contract-ban automatikusan Task-ot generál C#-ban,
Promise-t TypeScript-ben, async def-et Python-ban.
Nem kell minden platformon külön dönteni — a contract megmondja, mi aszinkron.
Az import rendszer lehetővé teszi, hogy a contractok egymásra hivatkozzanak. A PolyPersist például UniContract definíciókat használ az összes store interfészhez — ez garantálja, hogy a C# és a többi platform implementációja konzisztens marad.
Hol használom?
A PolyPersist összes cross-platform interfészét UniContract generálja. A D3I szintén támaszkodik rá az emitter outputok konzisztenciájához. Mindenütt, ahol több platformon kell ugyanazt a kontraktust megvalósítani, a UniContract adja az egységes forrást.