AOP vs funkce

Poměrně orientované programování (AOP) je docela populární. Motivace je dobře vysvětlena v příslušném článku na Wikipedii.

AOP je skvělý nástroj pro skutečně globální koncepty, jako je protokolování, které přímo neovlivňují logiku kódu. Problémy s AOP se však objevují, když se používají pro záležitosti související s obchodem, jako je autorizace. Tyto aspekty aplikace musí být jasně viditelné v příslušném kódu, aby vývojář mohl okamžitě zjistit, zda jsou při čtení odpovídajícího zdrojového kódu správně implementovány. Rámce založené na AOP se obvykle řeší pomocí anotací metod:

@RequireRole (Role.Admin) // jasně viditelný aspekt
fun updateUserPermissions (…) {
    // logika zde
}

Z hlediska čitelnosti se však od funkčního přístupu ke stejnému problému příliš neliší, když místo anotace @RequireRole používá funkci požadavkuRole:

fun updateUserPermissions (…) {
    requestRole (Role.Admin) // vyvolá SecurityException
    // logika zde
}

Funkční přístup má navíc tu výhodu, že rozšiřuje i složitější kontroly oprávnění, jako je analýza parametrů metody před rozhodnutím, která role uživatele je vyžadována.

Totéž platí pro další aspekty, jako jsou transakce. Bohužel je těžkopádné a nevhodné funkčně reprezentovat složitější koncepty v Javě, což vytváří umělou popularitu pro rámce AOP v ekosystému Java.

To však není případ Kotlina. V Kotlinu namísto přístupu typu Java k transakcím s AOP a anotacím jako je tento:

@ Transactional
fun updateUserPermissions (…) {
    // logika zde
}

Je to stejně dobře čitelné a čisté, když je přepisujete funkčním způsobem:

fun updateUserPermissions (…) = transakční {
    // logika zde
}

Výhodou tohoto funkčního přístupu je to, že ve vašem IDE můžete vždy kliknout na deklaraci transakční funkce a okamžitě zjistit, co přesně to dělá, což obvykle není možné u žádného z běžně používaných rámců AOP. I když je navigace ke zdrojovému kódu aspektu zajištěna zásuvným modulem IDE, vyžaduje dešifrování jeho logiky znalost samostatného bohatého API a / nebo konvencí.

Tato funkční náhrada za AOP na bázi anotací v Kotlinu se bohužel neprodleně nepřizpůsobí případu, kdy se na stejnou funkci, jako jsou složené závorky a zářezy, začnou hromadit více aspektů:

fun updateUserPermissions (…) = přihlášeno {
    transakční {
        // logika zde
    }
}

Cílem práce je vytvoření kombinované funkce vyššího řádu, aby bylo místo použití více aspektů čisté:

fun updateUserPermissions (…) = logTransactional {
    // logika zde
}

Další nevýhodou funkčního přístupu je to, že aspekty jako protokolování vyžadují přístup k parametrům metody. Obvykle jsou přímo k dispozici v tradičních rámcích AOP pomocí speciálních API, ale funkce Kotlin k nim nemohou snadno získat přístup. Abychom tedy mohli čistě funkčním způsobem zaznamenat skutečný logovací aspekt, musíme ještě napsat značné množství kódu kotlové desky:

fun updateUserPermissions (params: Params) =
    přihlášený ("updateUserPermissions ($ params)") {
        // logika zde
    }

Tato úvaha stále dělá AOP nástrojem volby pro protokolování, když ho opravdu potřebujete mít globálně a důsledně ve své aplikaci, ale věřím, že použití AOP pro aspekty, jako je autorizace a transakce, je zneužitím vzhledem k bohatým funkčním abstrakcím, které jsou k dispozici v Kotlině. . Funkce tyto aspekty zvládají lépe a čistěji.

Na závěr bych řekl, že další vylepšení funkčních abstrakcí za účelem ještě lepší náhrady AOP by mohla být pro Kotlinův jazyk slibným vektorem budoucího vývoje. Java AOP frameworks jsou obvykle specifické pro JVM a jsou vnímány jako nějaká neprůhledná magie, zatímco Kotlinovy ​​funkční abstrakce jsou skutečně multiplatformní a pro uživatele transparentní.