• Aucun résultat trouvé

2.4 Séparation des préoccupations

2.4.2 La Programmation Orientée Aspects (AOP)

La programmation par aspects (AOP) a été proposée par Kiczales et al en 1997 [15, 17]. Il s’agit d’un paradigme qui permet de définir des abstractions logicielles qui viendront se superposer à une application de base. A ses origines, la programmation par aspects est partie du constat suivant : malgré tous les efforts faits en ce sens, il existe toujours un fort entrelacement entre le code métier d’une application et celui des préoccupations transverses (sécurité, monitoring . . .). L’idée de la programmation par aspects est donc de représenter de manière séparée, dans des aspects, ces préoccupations transverses. Il s’agit alors d’injecter le code des préoccupations transverses dans le code de base. Cette injection se fait par l’intermédiaire d’un tisseur d’aspects.

Un aspect se découpe en points de coupe et greffons. Les premiers identifient « où » le code doit être tissé tandis que les seconds décrivent le code à injecter, le « quoi » (Fig. 2.10). L’ensemble des attaches sur lesquelles peuvent être tissées des aspects s’appellent des points de jonctions. Selon les paradigmes sur lesquels repose la programmation par aspects, cet ensemble change de nature (objets, composants, code . . .) mais l’AOP offre toujours une bonne séparation des préoccupations, une bonne modularité transverse [7]. Les points de coupes permettent donc de choisir un sous-ensemble de points de jonction sur lesquels seront ajoutés un comportement. L’abstraction fournie par les points de coupes permet à un aspect d’être tissé en plusieurs endroits de l’application ; la programmation par aspects permet donc de minimiser la dispersion du code, en le regroupant dans des entités réutilisables. Classiquement, les langages de greffon offrent des mécanismes pour ajouter du comportement aux points de coupe à l’aide des opérateurs after, before et around. Ainsi le greffon before sera exécuté avant l’exécution du point de jonction vérifiant le point de coupe qui lui est associé et inversement avec un greffon after. Un greffon around permet soit de remplacer le point de coupe soit d’exécuter du code avant et après le point de coupe.

1 public aspect Nom_Aspect { pointcut Nom_Method() : // code

4 //// Greffon

before():Nom_Method() { // code

7 } }

FIGURE2.10 – Modèle d’un aspect en AspectJ

Avec le temps, les aspects ont étés couplés à différents paradigmes parmi lesquels les services [6, 7] ou encore les composants [21] qui, comme nous l’avons vu précédemment, sont d’excellents candidats pour la création d’applications en informatique ambiante. Ce couplage peut être envisagé

avec deux visions différentes. Cela peut consister à modifier un composant avec une approche invasive qui entraîne la perte des propriétés de boite noire des composants. Sinon, cela peut consister en des modifications de la structure d’un assemblage comme le propose par exemple FAC (Fractal Aspect Component) [101] qui intègre la notion d’aspects dans Fractal [61]. Il propose alors la définition de Aspect Component (AC), c’est-à-dire de composants encapsulant une préoccupation transverse. Le code du composant représente alors le greffon de l’aspect et les points de coupe sont définis au niveau du connecteur. Les points de jonction sont les composants, les interfaces et les méthodes sur lesquels un AC peut être appliqué. L’application d’un AC peut se faire à l’exécution. Navase et al [19] mettent alors en avant les avantages suivants pour le couplage entre une approche orientée composant avec des aspects non invasif : faciliter la conception de l’architecture de l’application, réduire le coût de développement, augmenter la réutilisation de section d’architecture et réduire le coût de la maintenance.

Le tisseur est le mécanisme qui prend en entrée ces aspects ainsi qu’une application et produit une application augmentée. Les premiers mécanismes de tissage comme dans AspectJ [14] étaient statiques et intervenaient à la compilation. Avec AspectJ, le code décrit dans les greffons est tissé dans le code de l’application pour générer un nouveau fichier, par exemple .java ou bytecode. Ainsi, la séparation des préoccupations introduite par les aspects n’a plus lieu à l’exécution. Par la suite, des approches permettant un tissage dynamique sont introduites. Dans la plupart des approches, les aspects sont alors tissés séquentiellement même si quelques approches proposent de gérer la concurrence entre aspects comme par exemple Douence et al [8]. Dans ces approches l’application d’un aspect ne bloque pas nécessairement complètement l’exécution de l’aspect de base jusqu’à ce que le greffon soit totalement tissé. L’approche proposée consiste donc à étendre leurs premiers travaux sur EAOP, pour lesquels les aspects étaient tissés en séquence, avec un tissage concurrent (CEAOP). Pour cela des opérateurs de synchronisation sont intégrés. Si les aspects s’appliquant sur un même point de jonction peuvent toujours être appliqués en séquence, des opérateurs (ParOr, ParAnd) permettent désormais leur application en parallèle.

Les aspects ne sont pas toujours indépendants les uns des autres ; des problèmes d’interactions peuvent apparaître entre eux. Une interaction entre deux aspects se défini comme une relation inter- venant entre deux aspects, impliquant la perte de leur indépendance [23]. Sanen et al [22, 23] ou encore Greenwood et al [13] identifient différents types d’interactions parmi lesquelles nous pouvons retrouver, par exemple, la notion de renforcement lorsque la présence d’un aspect accentue le bon comportement sémantique d’un autre aspect. Une interaction est qualifiée de conflit lorsqu’un aspect requiert l’absence d’un autre aspect pour avoir un comportement sémantiquement correct. Lorsque cette relation entre deux aspects est conflictuelle, c’est-à-dire qu’au moins un des deux aspects ne fonctionne plus comme prévu, on parle d’interférence. Sanen et al dans [22] définit un interférence comme suit :

Définition 5 : Interférence

« We define aspect interference as a conflicting situation where one aspect that works correctly in isolation dœs not work correctly anymore when it is com- posed with other aspects.[22] » .

Classiquement la gestion des interférences entre aspects se fait en établissant un relation d’ordre entre eux. On parle de précédence [16]. En effet, l’opération de tissage d’aspects n’est généralement pas symétrique f ⊗ g 6= g ⊗ f [16]. Quelques travaux proposent de s’attaquer à la gestion des

interactions principalement en fournissant des mécanismes de détection d’interférence [2] et en fournissant des outils pour aider à leur résolution [24, 5]. Celle-ci reste généralement à la charge du développeur comme l’approche step-wise proposée dans [24]. Il en va de même dans EAOP [9], pour lequel la gestion des interactions peut se faire de deux manières : (1) en contrôlant la visibilité d’aspects par leur encapsulation dans d’autres aspects et (2) en composant explicitement des greffons intervenant sur un même points de jonction (a. séquence, b. sélection d’un unique aspect, c. séquence arbitraire décidée par l’analyseur). Une autre approche présentée dans [2], consiste à simuler et à représenter les différents états au runtime d’un programme sous la forme d’un graphe puis à identifier les interférences comportementales entre les aspects et en particulier en fonction de leur ordre d’exécution.

Grâce à l’abstraction offerte par les points de coupe, un même aspect peut être instancié en plu- sieurs endroits d’une même application. Les aspects sont donc plus particulièrement adaptés pour exprimer les préoccupations transverses homogènes. Les préoccupations transverses hétérogènes sont quant à elles plus naturellement exprimées à l’aide la programmation orientée feature qui permet d’intégrer dans une application différentes variantes d’une même fonctionnalités.

Documents relatifs