Funcions AOP vs AOP

La programació orientada a aspectes (AOP) és força popular. La seva motivació s’explica bé a l’article de Wikipedia corresponent.

AOP és una gran eina per a conceptes realment globals com el registre que no afecten directament la lògica del codi. No obstant això, els problemes amb AOP es mostren quan s'utilitza per a coses més relacionades amb l'empresa com l'autorització. Aquests aspectes de l'aplicació han de ser clarament visibles en el codi pertinent, de manera que un desenvolupador pot veure immediatament si s'implementen correctament quan llegeix el codi font corresponent. Els marcs basats en AOP solen solucionar-se mitjançant anotacions de mètodes:

@RequireRole (Role.Admin) // aspecte clarament visible
fun update ... UsuarisPermisos (...) {
    // lògica aquí
}

Tanmateix, des del punt de vista de la llegibilitat, no és gaire diferent un enfocament funcional del mateix problema amb la funció requireRole en lloc de l’anotació @RequireRole:

fun update ... UsuarisPermisos (...) {
    requireRole (Role.Admin) // llança SecurityException
    // lògica aquí
}

A més, l’enfocament funcional té l’avantatge que també s’escala fins a comprovacions de permisos més complexes, com analitzar els paràmetres del mètode abans de decidir quina funció de l’usuari cal.

El mateix succeeix en altres aspectes com les transaccions. Malauradament, és molest i molest representar funcionalment conceptes més complexos a Java, la qual cosa crea una popularitat artificial per als marcs AOP de l'ecosistema Java.

No és el cas de Kotlin. A Kotlin, en lloc de l'aproximació similar a Java per a transaccions amb AOP i anotacions com aquesta:

@Transaccional
fun update ... UsuarisPermisos (...) {
    // lògica aquí
}

És igual de llegible i d’aspecte net quan es reescriu de manera funcional:

funeraria updateUserPermissions (...) = transaccional {
    // lògica aquí
}

L’avantatge d’aquest enfocament funcional és que sempre podeu fer Ctrl / Cmd + clic a la declaració de funció transaccional del vostre IDE i veure immediatament el que fa exactament, cosa que normalment no és possible amb cap dels frameworks AOP d’ús habitual. Fins i tot quan un complement IDE proporciona la navegació al codi font d’aspecte, desxifrar la seva lògica requereix el coneixement d’una API i / o convencions riques separades.

Malauradament, aquest reemplaçament funcional per AOP basat en les anotacions a Kotlin no s’implanta de forma immediata al cas quan s’apliquen diversos aspectes a la mateixa funció que comencen a apilar-se les clavades arrissades i la sagnat:

funeraria updateUserPermissions (...) = registrat {
    transaccional {
        // lògica aquí
    }
}

L'objectiu és crear una funció combinada d'ordre superior per mantenir net el lloc d'ús de diversos aspectes:

fun updateUserPermissions (...) = loggedTransactional {
    // lògica aquí
}

Un altre desavantatge de l'enfocament funcional és que aspectes com el registre necessiten accés als paràmetres del mètode. Generalment estan directament disponibles en els marcs tradicionals AOP mitjançant API especials, però les funcions de Kotlin no poden accedir-hi fàcilment. Per tant, per representar realment un aspecte de registre de la vida real d’una manera purament funcional, encara s’ha d’escriure una quantitat considerable de codi de placa de caldera:

funció actualitzacióUserPermissions (params: Params) =
    logged ("updateUserPermissions ($ params)") {
        // lògica aquí
    }

Aquesta consideració encara fa que AOP sigui una eina d’elecció per registrar quan realment necessiteu tenir-lo de manera global i coherent a la vostra sol·licitud, però crec que utilitzar AOP per a aspectes com l’autorització i les transaccions és un abús, atès que es fan abstraccions funcionals riques disponibles a Kotlin. . Les funcions gestionen aquests aspectes millor i més nets.

En conclusió, diria que les millores en les abstencions funcionals per proporcionar un reemplaçament encara millor de l'AOP podrien ser un vector prometedor de l'evolució futura del llenguatge Kotlin. Els marcs AOP basats en Java solen ser específics del JVM i es perceben com una màgia opaca, mentre que les abstraccions funcionals de Kotlin són realment multiplataforma i transparents per a l'usuari.