La Programación Orientada a Aspectos (AOP) es un paradigma de programación bastante popular. El
artículo de Wikipedia explica bien la motivación de este enfoque.
AOP es una herramienta excelente para conceptos globales, como: el registro, que, directamente, no afecta la lógica del código.
Sin embargo, los problemas con AOP se descubren cuando se usa para requisitos comerciales como la autorización. Dichos aspectos deben ser claramente visibles en el código apropiado para que el desarrollador pueda ver inmediatamente al leer el código fuente si están implementados correctamente. Los marcos de AOP generalmente resuelven este problema con anotaciones:
@RequireRole(Role.Admin)
Sin embargo, en términos de legibilidad, no es muy diferente del enfoque funcional, ya que utiliza el método
requireRole en lugar de la anotación.
Nota del traductor : en el artículo original, se utiliza la expresión cuando se reescribe de manera funcional o con un enfoque funcional, que se puede interpretar como un enfoque funcional o una llamada de función directa / específica. El artículo tiene ejemplos que se pueden interpretar de diferentes maneras.
También:
1. En el futuro, volveremos al concepto de funciones de orden superior.
2. El artículo encuentra el aspecto de la palabra, que es el inglés y el concepto en el aspecto AOP
fun updateUserPermissions(…) { requireRole(Role.Admin)
Además, el enfoque funcional tiene la ventaja de escalar a verificaciones de control de acceso más complejas, como el análisis de los parámetros del método, antes de decidir qué rol de usuario se requiere.
Lo mismo es cierto para otros tipos de aspectos, como las transacciones. Desafortunadamente, presentar funcionalmente conceptos más complejos en Java es engorroso e inconveniente, lo que crea la popularidad artificial de los marcos de AOP en el ecosistema de Java.
En Kotlin, en lugar de un enfoque de transacción similar a Java usando AOP y anotaciones como esta:
@Transactional fun updateUserPermissions(…) {
También es legible y se ve limpio cuando se reescribe sin anotaciones, con un enfoque funcional.
fun updateUserPermissions(…) = transactional {
La ventaja de este enfoque es que siempre puede presionar Ctrl / Cmd + clic en la declaración de la función
transaccional en su IDE e inmediatamente ver qué hace exactamente. Lo cual generalmente no es posible con ninguno de los marcos de AOP comúnmente utilizados. Incluso cuando se proporciona navegación al código de aspecto utilizando el complemento IDE, el descifrado de su lógica requiere el conocimiento de una API y / o convenciones multifuncionales separadas.
Desafortunadamente, hay problemas al escalar la forma de reemplazar las anotaciones de AOP en Kotlin. Para el caso cuando se aplican varios aspectos a la misma función, con la acumulación de llaves y sangrías:
fun updateUserPermissions(…) = logged { transactional {
Una solución alternativa es crear una
función de orden superior para preservar el código aceptable al aplicar varios aspectos:
fun updateUserPermissions(…) = loggedTransactional {
Otro inconveniente del enfoque funcional es que aspectos como el registro requieren acceso a los parámetros del método. Por lo general, están disponibles en marcos de AOP a través de API especiales, pero al usar las funciones estándar del lenguaje Kotlin no puede acceder fácilmente a ellas. Por lo tanto, para presentar realmente un ejemplo real del aspecto del registro, en una forma puramente funcional, aún necesita escribir una cantidad significativa de
código de placa de
caldera :
fun updateUserPermissions(params: Params) = logged("updateUserPermissions($params)") {
Esta consideración aún convierte a AOP en la herramienta de registro preferida cuando realmente necesita tenerla global y consistentemente en su aplicación. Al mismo tiempo, usar AOP para funcionalidades como autorización y transacciones es un abuso, dadas las ricas abstracciones funcionales que están disponibles en Kotlin. Las funciones hacen frente a estos requisitos mejor y más limpio.
En conclusión, diría que una mejora adicional de las abstracciones funcionales para proporcionar un reemplazo aún mejor para AOP podría ser un vector prometedor para el desarrollo futuro del lenguaje Kotlin. Los marcos de AOP basados en Java son típicamente específicos de JVM y se perciben como mágicos, mientras que las abstracciones funcionales de Kotlin son verdaderamente multiplataforma y transparentes para el usuario.
Nota del traductor :
1. Artículo sobre medio (ing) .
2. El autor del artículo original es Roman Elizarov (Team Lead JetBrains, que trabaja en Kotlin coroutines and libs, programación deportiva / ICPC, concurrencia y algoritmos, matemática / finanzas cuantitativas; anteriormente Devexperts). Sobre Habr elizarov