• Aucun résultat trouvé

Comment assembler des entités logicielles (services, composants) ?

1.4 Bilan

2.1.2 Comment assembler des entités logicielles (services, composants) ?

2.1.2.1 Assemblage de composants

Nous distinguons deux types d’assemblage de composants [35] : – l’assemblage horizontal (connexion des entrées sorties) – l’assemblage vertical (encapsulation des fonctionnalités).

Assemblage horizontal Nous appelons assemblage horizontal, un assemblage qui met en relation

les entrées-sorties des composants logiciels.

Connecteur. “Je sais avec qui je communique.” Un connecteur est une liaison explicite, une entité

qui représente les interactions entre composants logiciels [36]. Un composant appelle directement un autre composant à travers un connecteur qui permet de spécifier le type d’interaction qu’il peut y avoir entre les composants (exemple : appel distant, local, ...). Un connecteur est basé sur l’utilisation de langages décrivant des relations entre des concepts propres à la composition. Bien que ces langages soient proches des langages de description d’architecture ADL [37], ils se différencient de ces derniers par le fait que le résultat de la composition est toujours exécutable. Des exemples de langages déclaratifs sont décrits dans les travaux de Birngruber et Wuyts [38, 39].

Appel de service : “Je ne sais pas avec qui je communique.” Un appel de service est une liaison

implicite. Une application construite à partir de services implique que les fournisseurs de ces services ne sont pas câblés dans l’application : un service n’appelle jamais directement un autre service et les fournisseurs peuvent changer à travers les différentes exécutions de celle-ci. De nouveaux services peuvent être découverts à l’exécution. Les langages de script, tels que CorbaScript [40] ont tendance à être non-typés et interprétés [41].

Assemblage vertical Nous appelons assemblage vertical, un assemblage qui encapsule les

com-posants logiciels pour en créer un nouveau. L’assemblage hiérarchique utilise l’encapsulation pour construire des composants en imbriquant des composants à l’intérieur d’autres composants dits composites. L’intérêt d’assembler les composants de manière hiérarchique réside dans la diminu-tion de la complexité de l’architecture grâce au groupement des composants réalisant des tâches communes. L’assemblage hiérarchique nécessite de réaliser la connexion d’éléments présents dans les vues externes et internes de la description [42].

2.1.2.2 Composition de services

Les services peuvent être composés pour former un nouveau service. Des exemples de composition sont par exemple l’orchestration ou les gestionnaires de workflow.

Une orchestration est un ensemble de mécanismes conçus pour construire un nouveau service à partir de services disponibles. Une orchestration comprend des variables qui permettent de partager des informations entre les invocations de services. Les notations, comme celles répertoriées par List [43] associées aux orchestrations, visent à favoriser le maintien d’un faible couplage et un contrôle plus précis de la composition. Ainsi, sans orchestration, la composition de services est réduite à la résolution par la plate-forme des références vers les autres services (donc de manière cachée).

Un gestionnaire de workflow sert à décrire et à contrôler des applications à grande échelle demandant le calcul d’ensemble d’informations qui peuvent être manipulées indépendamment à partir d’une seule analyse. Il existe un large potentiel de parallélisme à exploiter pour rendre ces applications performantes [44].

La recherche de service Lorsque l’on ne connaît pas l’entité avec laquelle on communique,

notamment dans le cas de l’appel de service, on a recours à un système de recherche de service appelé annuaire. Un annuaire référence l’ensemble des entités disponibles dans une architecture. Il participe ainsi activement à la mise en œuvre d’une cartographie dynamique des entités logicielles. Il est un intermédiaire entre les fournisseurs et les consommateurs de services. L’annuaire contient

un ensemble de descripteurs de service ainsi que des références vers les fournisseurs de ces services. Il fournit également des mécanismes permettant de l’interroger pour obtenir des références vers les fournisseurs de services. L’ensemble des descripteurs de service (se trouvant dans l’annuaire) peut changer de manière constante.

Au niveau utilisation, le consommateur de services interroge le registre pour découvrir des fournisseurs d’un service particulier à partir d’un ensemble de critères relatifs au descripteur. Si des fournisseurs répondant aux critères ont été publiés au préalable dans l’annuaire, ce dernier renvoie des références du fournisseur au demandeur. Le demandeur doit ensuite choisir des fournisseurs appropriés et effectuer ses appels au service. Nous avons répertorié quatre manières d’utiliser la fonction de recherche d’un annuaire :

– Recherche à priori : recherche effectuée lors de la conception dans un assemblage statique ; – Recherche dynamique : celui qui réalise le service (celui qui l’implémente et le fournit) est

connu au moment de l’exécution ;

– Recherche par type d’interface : “Je recherche un capteur qui a l’interface Présence et qui se trouve dans la cuisine.” ;

– Recherche par besoin : “Je veux ouvrir les volets électriques du salon !”

2.1.2.3 Modularités transverses

Les composants et les services proposent les techniques d’assemblage de composants et de compo-sition de services pour créer l’architecture de l’application. La programmation orientée aspect peut être vue comme une approche orthogonale à l’assemblage. La programmation orientée aspect a été proposée par Kiczales et al. en 1997 [21]. Les paradigmes de programmation habituels re-posent sur le fait que les différentes préoccupations de l’application puissent se décomposer en une collection d’abstractions (procédures, fonctions, objets, composants, classes, etc.). Cependant cer-taines préoccupations transverses, ne peuvent pas respecter cette décomposition et se retrouvent éparpillées entre plusieurs abstractions. Un exemple simple de préoccupation transverse est la mise au point des programmes : de nombreux ajouts sont nécessaires pour tester des assertions ou tracer une valeur. Ils se retrouvent entrelacés dans tout le code. De manière non exhaustive, la gestion de la sécurité, la mise en œuvre de transactions et la gestion de la distribution (synchronisation des accès concurrents) sont des préoccupations transverses.

La programmation par aspects se base sur l’idée qu’une application est mieux décrite en sé-parant toutes les préoccupations et propose de représenter de manière séparée ces préoccupations transverses dans les abstractions appelées aspects. De façon plus générale, l’expressivité du pro-grammeur est parfois contrainte par le paradigme de programmation utilisé. Celui-ci choisit une manière de décomposer l’application. Inévitablement certaines préoccupations ne respectent mal-heureusement pas cette décomposition au sein du paradigme. Ce problème de la “tyrannie de la décomposition dominante” se produit avec tous les paradigmes de programmation. Même si la ma-jorité des travaux sur l’AOP est appliquée à la programmation orientée objet, différentes recherches ont montré que ce paradigme pouvait aussi être appliqué à la programmation impérative [45], fonctionnelle [46] et réactive [47].

La programmation par aspects repose sur un langage d’aspects conçu pour décrire les pré-occupations transverses et un tisseur qui intègre automatiquement les aspects au programme de base. De plus, les aspects permettent également de modifier le comportement de l’application de base et sont décrits dans des langages d’aspects qui décrivent où et comment modifier le programme et son exécution. Comme les langages d’aspects sont généralement basés sur des transformations syntaxiques, une des difficultés de la programmation par aspects réside au niveau du raisonnement sur l’application sans visualiser le code tissé (le code obtenu après tissage). De plus, l’application tissée peut avoir des comportements non souhaités à cause de potentielles interactions néfastes entre certains aspects. Un des défis majeurs de la programmation par aspects est donc de permettre un raisonnement modulaire, c’est-à-dire raisonner sur l’application de base et les aspects sans étudier le code tissé.

Figure 2.1 – Éviter l’éparpillement du code

Dès les années 80, la programmation structurée et la programmation orientée-objet ont introduit de nouvelles approches pour concevoir un programme et un ensemble de règles et de conventions pour aider les programmeurs à produire du code plus lisible et plus facilement réutilisable à l’aide par exemple de l’éradication des gotos au profit des boucles [48], l’introduction des types et des structurations à partir de composants logiciels [49]. Dans cette même direction, et 30 années plus tard, l’aspect résout des problèmes qui peuvent, bien sûr, être traités dans des approches classiques, mais d’une manière très élégante.