AOP - Aspect Oriented Programming by Adventy

Qu’est-ce que l’AOP ?

AOP, Définition

L’AOP est l’acronyme de « Aspect Oriented Programming » (Programmation Orientée Aspect ou POA). Cela consiste à développer de façon modulaire en rendant les fonctionnalités transversales et indépendantes les unes des autres, car gérant des traitements différents. Cette pratique n’est pas différente de la création de fonctions ou de méthodes, puisqu’elle divise le code par fonctionnalité métier, applicative et technique, soit la séparation des préoccupations, pour éviter la duplication de code, mais surtout pour favoriser la réutilisabilité et d’en avoir une meilleure maîtrise.

Une fonctionnalité transversale ne doit exécuter qu’une seule et unique tâche, ce qui la dédie donc à résoudre une problématique bien spécifique. Cette préoccupation de la tâche unique et transversale fait ressortir 3 types de traitement :

  1. le premier désigne les tâches fonctionnelles, donc liées uniquement au métier ;
  2. ensuite viennent les tâches applicatives (ex : authentification, gestion des droits) ;
  3. et enfin les tâches techniques telles que la journalisation, la persistance des données, etc.

A ce stade, ce n’est pas encore de l’AOP, car il ne suffit pas de rendre une fonctionnalité transversale et indépendante. Malgré la mise en oeuvre de toutes les bonnes pratiques (DRY, KISS, YAGNI, SyC, SoC, SOLID, etc.), cela reste ni plus ni moins de la programmation orientée objet ou procédurale.
Alors que manque-t-il pour le passage à l’AOP ?

La Programmation Orientée Aspect fait apparaître la notion de tisseur d’aspect. C’est à travers cette couche qu’une fonctionnalité (ou traitement) est appelée, et dans laquelle il est possible d’y ajouter des traitements, avant, à la place de, ou après cette fonctionnalité.
Comme dans tout concept, l’AOP apporte aussi son lot de jargons :

Pourquoi l’AOP ?

AOP, Aspect Oriented Programming

Lorsqu’une fonctionnalité devient compliquée, et dont la tâche principale est polluée par des traitements applicatifs (ex : authentification, gestion des droits) et/ou techniques (ex : journalisation, notification), cela fait apparaître plusieurs problématiques :

  1. le code est peu lisible (code spaghetti), rendant la maintenance difficile ;
  2. le code principal ne peut être testé unitairement, car dépendant du code applicatif/technique ;
  3. la réutilisation du code principal est limitée à cause du code applicatif/technique qui y est lié.

Cette façon de programmer est consommatrice en temps pour la maintenance et l’évolution, mais aussi impacte lourdement la fiabilité de l’application. Pour résoudre ce problème, les actions consistent à :

  1. démêler le code en le regroupant par sous-tâche. C’est la technique du SyC (Sort your Code - Triez votre code). Cela fait ressortir le code de la tâche principale, ainsi que le code des traitements applicatifs et/ou techniques ;
  2. convertir ces sous-tâches en méthode, et si possible en méthode statique afin de supprimer les dépendances et de faciliter sa réutilisabilité. C’est la technique du SoC (Separation of Concerns - Séparation des préoccupations). Les tests unitaires peuvent ainsi être appliqués sur les méthodes obtenues.

A ce niveau de transformation du code, le développeur peut être fière de son travail, car les méthodes qui en résultent sont réutilisables. Cependant, il existe encore un point sensible concernant le traitement parent, appelant ces nouvelles méthodes :

  1. le traitement parent n’est toujours pas testable unitairement, car il est dépendant des appels de méthodes ;
  2. même si ces méthodes passent les tests unitaires avec succès, rien ne prouve que le traitement parent fonctionne correctement, surtout s’il utilise des instructions conditionnelles et itératives.

Ici, la programmation traditionnelle a atteint ses limites, et c’est là que la Programmation Orientée Aspect (POA ou AOP pour Aspect Oriented Programming) fait son apparition avec son tisseur d’aspect. En reprenant le jargon de l’AOP, chacune des méthodes obtenues est appelée aspect, car gérant des préoccupations différentes. Ensuite, le traitement parent est remplacé par le tisseur d’aspect, qui n’est autre qu’un fichier déclaratif d’une liste d’aspects à traiter séquentiellement. Cette technique est une pratique adoptée par le framework Adventy. Ce dernier à remplacé le Controller du MVC (Model - View - Controller) par le tisseur d’aspect, d’où son architecture basé sur le MVA (Model - View - Aspect).
Grâce à cette pratique de l’AOP, il n’y a plus de test unitaire à faire sur le traitement parent, puisque ce dernier n’existe plus. Le travail du développeur est donc réduit à :

  1. développer les aspects en respectant le principe du SoC ;
  2. effectuer les tests unitaires sur les aspects ;
  3. créer le tisseur d’aspect, et y déclarer les aspects à exécuter.

Un autre avantage qu’apporte le tisseur d’aspect, est qu’il est possible d’y ajouter d’autres aspects (ou d’en supprimer), sans devoir à toucher une seule ligne de code, et donc aucun risque de changer le comportement de la fonctionnalité principale.

Ce paradigme de programmation n’est lié à aucun langage orienté objet ou procédural. L’AOP propose un style de programmation plus élégant, clair, et centré sur les préoccupations. Cette technique favorise la réutilisabilité, facilite les tests unitaires, et donc améliore la fiabilité de l’application.

L’AOP par l’exemple

Pour bien comprendre le principe de l’AOP, l’exemple proposé consiste à enregistrer dans une base de données, les données envoyées depuis un formulaire d’inscription à une activité sportive. Les champs de ce formulaire sont les suivants :

  1. la civilité : Madame ou Monsieur ;
  2. le prénom, entre 1 et 32 caractère ;
  3. le nom, entre 1 et 32 caractères ;
  4. la date de naissance, au format jj/mm/aaaa ;
  5. l’e-mail, entre 6 et 32 caractères ;
  6. l’activité sportive : tennis, badminton ou tennis de table.

Pour simplifier l’exemple, la gestion des exception, des erreurs techniques et de la transaction seront ignorées volontairement. Un framework gère tout cela déjà nativement, et si ce n’est pas le cas, il le devrait.

En programmation traditionnelle, les actions détaillées à développer sont :

  1. contrôler la validité des données : optionnalité, format, longueur minimale et maximale ;
  2. vérifier les règles métiers : inscription à partir de 5 ans ;
  3. enregistrer les données en base de données.

En programmation orientée aspect, chacune des actions ci-dessus sont mises en méthodes (ou en fonction), soit en aspect. Cette séparation des préoccupations (SoC) permet de définir le type d’aspect :

  1. le contrôle de la validité des données est un aspect technique, soit transversal, et donc réutilisable ;
  2. le contrôle des règles métiers est un aspect métier ;
  3. l’enregistrement de données en base de données est un aspect métier, puisque c’est l’action principale.

Le tisseur d’aspect contient donc la déclaration de ces méthodes (noms de méthode donnés à titre d’exemple) dans l’ordre d’exécution suivant :

  1. checkParameters : contrôle la validité des données ;
  2. checkRegistrationData : contrôle les règles métiers ;
  3. saveRegistrationData : enregistre les données en base de données.

Comme il est possible d’ajouter de nouveaux traitements dans le tisseur d’aspect, sans changer le comportement du traitement principal, voilà ce que cela pourrait donner :

  1. startDuration : démarre la mesure du temps d’exécution du traitement ;
  2. checkParameters : contrôle la validité des données ;
  3. checkRegistrationData : contrôle les règles métiers ;
  4. logData : logue les données à enregistrer (en cas de plantage de la base de données) ;
  5. saveRegistrationData : enregistre les données en base de données ;
  6. endDuration : termine la mesure du temps d’exécution du traitement ;
  7. logDuration : logue la durée du traitement en vue de traitements statistiques ;
  8. trackUser : logue les informations (IP, navigateur, OS) du client en vue de traitements statistiques ;
  9. notify : envoie une notification par e-mail d’une nouvelle demande d’inscription.

Avec l’AOP, le développeur n’a seulement besoin d’implémenter que 2 méthodes, car les autres étant transversales provenant soit du framework, soit de bibliothèques externes :

  1. le contrôle des règles métiers si elles existes (checkRegistrationData ) ;
  2. le traitement principal, ici l’enregistrement des données en base de données (saveRegistrationData ).

L’agilité et l’AOP

Dans un projet agile, le PO (Product Owner) découpe la fonctionnalité en sous-tâches, qui sont les aspects. Il crée autant de ticket qu’il y a d’aspect, puis un autre pour le tisseur d’aspect qui va utiliser ces aspects. Ce dernier ticket est le ticket principal. Dépendant des tickets d’aspect, le ticket principal ne pourra être traité que si les tous tickets d’aspect auront été préalablement terminés.

Il n’y a pas vraiment de priorité dans le traitement des tickets d’aspect, puisque les aspects sont sensés être indépendants les uns des autres. Parmi les aspects, il ne peut y avoir que 3 types d’aspect :

  1. l’aspect métier : traitement dédié à la fonctionnalité ;
  2. l’aspect applicatif : traitement qui, une fois réalisé ou provenant d’une bibliothèque, devient un composant transversal, et donc réutilisable (ex : authentification, gestion des droits utilisateurs) ;
  3. l’aspect technique : traitement déjà existant puisqu’il est souvent inclus dans le framework (ex : journalisation, persistance des données). Par définition, c’est un composant transversal et réutilisable.

Le développeur prend un ticket, et va implémenter la méthode demandée sans se soucier de comment sa méthode va être utiliser. Sa tâche n’est limitée qu’à la problématique décrit du ticket.
Une fois tous les tickets d’aspects traités, le ticket principal peut enfin être réalisé : le tisseur d’aspect.
Avec le framework Adventy, sachant que le tisseur d’aspect n’est autre qu’un fichier déclaratif d’aspects, donc non technique, le PO peut donc lui-même traiter ce dernier ticket, puis tester directement la fonctionnalité.

En principe, le PO connaît son produit, et donc tous les aspects qui compose l’application. De ce fait, il sait construire en toute autonomie, les fonctionnalités pour répondre aux demandes de ses clients.
Quant au développeur, il n’a plus besoin de connaître le produit et son fonctionnel, ce qui un gain de temps. Mais ce n’est pas tout, il y a d’autres avantages :

  1. le PO décrit de façon détaillée l’aspect souhaité. La précision du ticket est un pré-requis, et ne doit laisser place à aucune interprétation possible. Cette description détaillée sert à la fois de spécification, mais aussi de documentation ;
  2. le périmètre du développeur est limité à la préoccupation de l’aspect. Il ne se concentre uniquement que sur une seule et unique tâche ;
  3. un nouveau développeur qui arrive sur le projet est immédiatement opérationnel, quelque soit son niveau. Cela signifie que le turn-over aura un impact très réduit, voire inexistant, sur l’avancement du projet. En effet, le développeur n’a à connaître que la méthode à développer pour commencer à travailler, rien d’autre, même pas le projet lui-même.

Conclusion

L’AOP est une technique de programmation basée sur les bonnes pratiques de SyC (Sort your Code), puis de SoC (Separation of Concerns), rappelant la citation « Diviser pour régner ». Son style de programmation invite naturellement à la création de modules transverses, indépendants, et réutilisables. Il devient alors plus aisé de maintenir le code et de faire des tests unitaires.
Côté traitement parent, appelant les aspects de façon séquentielle, le tisseur d’aspect se présente sous la forme d’un fichier déclaratif. Il n’y a plus de code, et donc plus de risque d’erreur de programmation. Le tisseur d’aspect est simple et est accessible aux personnes non techniques.
Un framework AOP ouvre la voie vers l’automatisation des tâches. Rien que d’avoir un tisseur d’aspect, c’est déjà de l’automatisation, puisque le système ne fait que de dérouler (exécuter) les aspects qui y sont déclarés. Un framework de test unitaire est aussi un bon exemple d’automatisation des tâches.

Le paysage de l’agilité est en train d’évoluer et tend de plus en plus vers une méthodologie d’industrialisation.
Les développeurs traitent leurs tickets, aspect par aspect, donc une préoccupation à la fois, sans même connaître comment le fruit de leur travail va être utilisé ou être inséré dans le tisseur d’aspect.
Quant au PO qui a la connaissance fonctionnelle du produit (ou de l’application), il devient un architecte fonctionnel ou tisseur d’aspect. Sans écrire une seule ligne de code, il aura pour rôle de jongler avec les aspects pour construire les fonctionnalités, donc de tisser les aspects.

Si chaque membre de l’équipe respecte son contrat :

  1. le PO est responsable du découpage des fonctionnalités en aspects, et de l’assemblage des aspects en fonctionnalité ;
  2. le développeur est responsable de la livraison des aspects, avec test unitaire par aspect.

Alors l’objectif d’industrialisation de conception et de développement d’application est atteint. La productivité est donc optimisée.