Fonctions AOP vs

La programmation orientée aspect (AOP) est très populaire. La motivation pour cela est bien expliquée dans l'article de Wikipedia correspondant.

L'AOP est un excellent outil pour des concepts vraiment globaux tels que la journalisation, qui n'affectent pas directement la logique du code. Cependant, des problèmes avec AOP apparaissent quand il est utilisé pour plus de choses liées aux affaires telles que l'autorisation. Ces aspects de l'application doivent être clairement visibles dans le code correspondant, de sorte qu'un développeur puisse immédiatement voir s'ils sont correctement implémentés lors de la lecture du code source correspondant. Les frameworks basés sur AOP le résolvent généralement en utilisant des annotations de méthode:

@RequireRole (Role.Admin) // aspect clairement visible
fun updateUserPermissions (…) {
    // la logique ici
}

Cependant, du point de vue de la lisibilité, il n’est pas très différent d’une approche fonctionnelle du même problème qui utilise la fonction requireRole au lieu de l’annotation @RequireRole:

fun updateUserPermissions (…) {
    requireRole (Role.Admin) // lève SecurityException
    // la logique ici
}

De plus, l’approche fonctionnelle présente l’avantage de pouvoir évoluer vers des vérifications d’autorisations plus complexes, telles que l’analyse des paramètres de méthode avant de décider du rôle d’utilisateur requis.

La même chose est vraie pour d'autres aspects comme les transactions. Malheureusement, il est fastidieux et peu pratique de représenter fonctionnellement des concepts plus complexes en Java, ce qui crée une popularité artificielle pour les frameworks AOP dans l'écosystème Java.

Ce n'est pas le cas avec Kotlin, cependant. Dans Kotlin, au lieu d'une approche de type Java pour les transactions avec AOP et les annotations comme celle-ci:

@Transactional
fun updateUserPermissions (…) {
    // la logique ici
}

Il est tout aussi lisible et épuré lorsqu'il est réécrit de manière fonctionnelle:

fun updateUserPermissions (…) = transactionnel {
    // la logique ici
}

L'avantage de cette approche fonctionnelle est que vous pouvez toujours Ctrl / Cmd + Click sur la déclaration de fonction transactionnelle dans votre IDE et voir immédiatement ce que cela fait, ce qui n'est généralement pas possible avec les frameworks AOP couramment utilisés. Même lorsque la navigation vers le code source de l'aspect est fournie par un plug-in IDE, déchiffrer sa logique nécessite la connaissance d'une API riche séparée et / ou de conventions.

Malheureusement, cette solution de remplacement fonctionnelle pour les AOP basées sur des annotations de Kotlin ne s'adapte pas immédiatement au cas où plusieurs aspects sont appliqués à la même fonction, car les accolades et l'indentation commencent à s'empiler:

fun updateUserPermissions (…) = connecté {
    transactionnel {
        // la logique ici
    }
}

La solution consiste à créer une fonction combinée d'ordre supérieur pour que le site d'utilisation de plusieurs aspects reste clair:

fun updateUserPermissions (…) = logsTransactional {
    // la logique ici
}

Un autre inconvénient de l'approche fonctionnelle est que des aspects tels que la journalisation nécessitent un accès aux paramètres de la méthode. Ils sont généralement directement disponibles dans les frameworks AOP traditionnels via des API spéciales, mais les fonctions Kotlin de base ne peuvent pas y accéder facilement. Ainsi, pour représenter réellement l'aspect de la journalisation dans la vie réelle de manière purement fonctionnelle, il reste encore à écrire une quantité considérable de code de plaque signalétique:

fun updateUserPermissions (params: Params) =
    connecté ("updateUserPermissions ($ params)") {
        // la logique ici
    }

Cette considération fait toujours de l'AOP un outil de choix pour la journalisation lorsque vous avez vraiment besoin de l'avoir globalement et systématiquement dans votre application, mais je pense qu'utiliser AOP pour des aspects tels que l'autorisation et les transactions est un abus, étant donné les riches abstractions fonctionnelles disponibles dans Kotlin. . Les fonctions gèrent ces aspects mieux et plus proprement.

Pour conclure, je dirais que de nouvelles améliorations dans les abstractions fonctionnelles pour fournir un remplacement encore meilleur de l'AOP pourraient être un vecteur prometteur de l'évolution future du langage Kotlin. Les frameworks AOP basés sur Java sont généralement spécifiques à la JVM et sont perçus comme une magie opaque, tandis que les abstractions fonctionnelles de Kotlin sont vraiment multi-plateformes et transparentes pour l'utilisateur.