Alors que les applications voient augmenter leur taille, leurs adaptabilité et flexibilité, ainsi que leur durée de vie, d’utilisation et leur aspect distribué, elles nécessitent de plus en plus une architecture manipulable, modulaire et adaptable. Pour satisfaire à ces nouveaux besoins, les paradigmes composants et services ont été développés, ouvrant la voie à la construction par assemblage des applications. De nombreux frameworks ont ainsi été conçus pour supporter l’exécution d’architectures orientés services ou composants, tels SCA, J2EE, OSGI ou encore Fractal. Ces frameworks mettent en oeuvre divers services techniques comme la gestion du cycle de vie des applications ou celle des ressources disponibles. Néanmoins, ils offrent peu de moyens pour garantir la fiabilité, ou gérer les défaillances, des applications en raisonnant de manière générique sur leur configuration architecturale et les spécifications de leurs parties.
Dans ce contexte, le bon fonctionnement d’applications, constituées d’assemblages d’éléments logiciels, repose sur la bonne collaboration de ces derniers. Pourtant bien qu’une cause essentielle d’erreur d’assemblage réside dans des propriétés restées implicites, il n’a pas été développé d’outil contractuel permettant de valider une architecture en intégrant simultanément différents formalismes (et leurs outils de vérification) développés séparément. Ceci, alors que les architectes ou administrateurs d’architectures concrètes ne s’intéressent pas à une unique propriété ou un unique formalisme, mais à la validité globale de leur système.
Il convient, pour concevoir un tel outil, de considérer non seulement l’approche contractuelle de la validation des assemblages, mais aussi comment les différents intervenants du système observé sont impliqués dans celle-ci. Ainsi pour l’architecte de l’application, la mise en oeuvre de l’outil d’évaluation de la validité de l’assemblage doit être transparente. L’architecture de l’application ne doit pas être modifiée pour permettre l’application de cet outil, et l’architecte ne doit pas avoir à acquérir une expertise supplémentaire à sa spécialité. L’auteur des spécifications (assertions, automates…) doit pouvoir les rédiger et les mettre en oeuvre, sans se préoccuper de l’intégration de leur formalisme à l’architecture qu’elles contraignent. L’administrateur de l’application est responsable du maintien de son bon fonctionnement. Il a ainsi autant besoin d’un indicateur de ce dernier, que du diagnostic précis d’une défaillance pour mettre en oeuvre son rétablissement, ce que lui fournit l’évaluation de l’assemblage. Enfin, un des objectifs de cet outil est de permettre l’application conjointe de différents formalismes à des architectures diverses. A cette fin, architectures et formalismes doivent lui être interfacés. Pour ce faire, un intégrateur de formalisme doit produire l’extension correspondante à l’outil d’évaluation, ce qui permet d’appliquer ce formalisme uniformément aux architectures qui sont intégrées à l’outil. Un intégrateur d’architecture doit produire l’extension convenable à l’outil d’évaluation, ce qui permet d’appliquer uniformément à l’architecture, les formalismes intégrés à l’outil.
Architectures logicielles
Le contrat que nous envisageons, a pour principe de garantir une architecture par la validation de la collaboration qu’elle supporte. En effet, cette collaboration est constituée d’un ensemble d’échanges qui sont définis par les relations qui relient ses participants. Nous choisissons de nommer « motif d’interaction » l’ensemble des relations qui définissent les échanges de la collaboration. Ces relations identifient une partie d’architecture à laquelle un contrat peut s’appliquer. Nous étudions dans cette partie trois types d’architectures qui reposent sur trois types d’éléments différents : les objets, les composants et les services. Pour ce faire, nous passerons en revue chacun d’entre eux du point de vue de ses entités, motifs d’interaction, de ses interactions, des propriétés de ses relations et de leur cycle de vie.
Systèmes à objets
A. Entités
Il existe de nombreuses définitions des objets, l’une d’entre elles est donnée par Booch [14] : « Un objet a un état, un comportement et une identité ; la structure et le comportement d’objets similaires sont définis par leur classe commune ; les termes instances (de la classe) et objet sont interchangeables. » L’état de l’objet est contenu dans ses « attributs » ou « champs », des variables, tandis que son comportement est implémenté par ses « méthodes », le code qui modifie ces variables. En théorie, un objet ne peut envoyer de données à un autre qu’en invoquant une de ses méthodes mais les langages objets permettent souvent de contourner cette règle (en donnant un accès direct aux attributs). Les classes peuvent avoir des sous classes, qui héritent de leurs attributs et méthodes, mais peuvent aussi y ajouter ou y substituer les leurs.
B. Motif d’interaction
Dans les systèmes objets à base de classes, les entités impliquées sont de deux types, les classes et leurs instances. On distingue alors deux catégories de motifs d’interaction, le graphe d’héritage et le graphe des objets (instances de classes). Le graphe d’héritage existe de manière statique indépendamment de l’exécution du programme, il est composé des relations d’héritage. Le graphe d’objets repose sur les relations d’association et aggrégation, et n’apparaît qu’à l’exécution. La description des graphes d’héritage et d’objets fait partie du code source, sous forme de lien d’héritage ou de références. Par défaut, les relations ainsi définies entre objets ne comportent qu’assez peu d’information, essentiellement le type acceptable. Des motifs d’interaction remarquables sont proposés via les design patterns [39] qui identifient classes et objets en leur donnant un rôle dans un assemblage donné. Ils définissent ainsi des collaborations génériques.
C. Interactions
Dans les systèmes à objets les interactions basiques consistent en appels de méthode, ou des accès aux attributs. Vis à vis de ces interactions, on peut remarquer que ces deux graphes sont complémentaires, le graphe d’héritage définit les interactions entre classes parentes et enfantes alors que le graphe d’objet décrit quelles instances peuvent communiquer.
D. Propriétés du motif d’interaction
La relation d’héritage comporte des propriétés contraignant à la fois la construction du graphe d’objets et la réalisation des interactions. En effet tel que le rappelle B. Meyer [71], une utilisation efficace de l’héritage fait intervenir :
• le polymorphisme et la consistance de type qui fixent des règles de production du graphe d’objets : une référence peut être mise à jour à l’exécution et pointer vers tout objet dont le type est un sous-type du sien,
• la redéfinition et la liaison dynamique qui jouent sur la réalisation de l’interaction : la méthode appelée dépend du type de l’entité dynamiquement référencée.
Les interactions sont en général synchrones, mais peuvent être asynchrones et suivant les modèles d’objets des signaux peuvent être définis. La résolution de la méthode à exécuter peut aussi varier sur la base de son nom, de sa signature, du modèle d’héritage.
E. Cycles de vie
Pour ce qui est des cycles de vie des relations, celle d’héritage est définie au moment de la conception des classes. C’est une relation qui ne peut être modifiée une fois le système instancié, et sa durée de vie est identique à celle d’une classe. Les relations d’association et d’aggrégation, définies en conception, peuvent apparaître et/ou disparaître ainsi qu’être modifiées au cours de l’exécution de l’application.
Systèmes à composants
Par rapport aux objets les composants se veulent d’une granularité moins fine et font apparaître explicitement leurs dépendances. Les applications à base de composants sont assemblées et non plus développées.
A. Entités
Il existe de nombreuses définitions des composants. Une d’entre elles, communément admise, est celle de C. Szyperski [101] : Une unité de composition avec des interfaces spécifiées contractuellement et seulement des dépendances explicites vis à vis de son contexte. Un composant logiciel doit pouvoir être déployé indépendamment et est l’objet de la composition par des tiers. Plus programmatiquement, les composants sont en général des structures de données et de code se présentant sous forme de boites noires. Ils n’interagissent avec leur environnement que via les interfaces qu’ils exposent, qu’ils requièrent ou fournissent.
B. Motif d’interaction
Dans les systèmes à composants, les entités impliquées sont essentiellement les composants et leurs connecteurs, organisés dans une architecture généralement explicite. Les relations architecturales mises en oeuvre sont le plus souvent de deux types, la connexion entre interfaces requises et fournies (éventuellement via un connecteur) et l’inclusion de composants dans un autre. Le motif d’interaction de composant mêle les deux types de relations. La connexion peut avoir lieu directement entre composants comme dans l’ADL Darwin [47], ou entre composant et connecteur comme dans le système SOFA [34]. L’inclusion peut être réalisée par un composant en contenant d’autres, ainsi que par des connecteurs potentiellement composites comme dans le modèle SOFA [30]. Le modèle de composants Fractal [17] présente la possibilité de composition partagée, en effet dans celui-ci un composant peut appartenir à plusieurs composites qui ne sont pas imbriqués mais se chevauchent (pour modéliser par exemple des ressources partagées). L’architecture d’un système de composants peut être décrite soit dans le code métier des composants, soit dans un fichier de description utilisé pour produire le système (ADL). Dans ce cadre les relations sont plus riches en information qu’entre objets. En particulier la connexion est au minimum déterminée par les deux interfaces qu’elle relie. Suivant les systèmes de composants, des contraintes diverses peuvent porter sur ce couple d’interface vis-à-vis de leur connexion [70]. L’utilisation d’un connecteur peut enrichir le schéma de ses caractéristiques, il permet en particulier de désigner par des rôles les entités qu’il met en relation [38].
Les caractéristiques essentielles des styles architecturaux sont définies par [93] :
• Description de la structure du système à l’aide de termes issus d’une ontologie de haut niveau d’abstraction vis-à-vis des éléments mis en oeuvre et de leurs interactions. Par exemple, utilisation des termes « clients » et « serveurs » pour désigner des types de composants donnés,
• Richesse des interactions décrites dans les styles architecturaux, elles sont plus que de simples appels de méthode, par exemple : « pipe » avec des conventions de circulation, « event broadcast », accès aux bases de données, transaction etc,
• Expression de propriétés globales : la conception de l’architecture s’occupe généralement de propriétés à l’échelle du système, par exemple la résistance d’une partie d’un système à la panne d’une autre etc…
|
Table des matières
1 Introduction
2 Etat de l’art
2.1 Introduction
2.2 Architectures logicielles
2.2.1 Systèmes à objets
2.2.2 Systèmes à composants
2.2.3 Architecture de services
2.3 Fondation de l’approche contractuelle
2.3.1 Définition du contrat logiciel
2.3.2 Etude de la « conception par contrat »
2.4 Formalismes de spécification
2.4.1 Spécifications fonctionnelles appliquées aux objets
2.4.2 La conception par contrat appliquée aux composants
2.4.3 Spécifications non-fonctionnelles appliquées aux objets et interfaces
2.4.4 Spécifications non-fonctionnelles appliquées aux composants
2.4.5 Spécifications non-fonctionnelles appliquées aux services
2.5 Le raisonnement par hypothèse garantie
2.5.1 Paradigme Assume-guarantee et logique de Hoare
2.5.2 Portées architecturales des différents types de spécifications
2.5.3 Positionnement par rapport à la notion de compatibilité
2.5.4 Conclusion
2.6 Les modèles et métamodèles de contrat
2.6.1 Méta-modèles de contrat
2.6.2 Objets
2.6.3 Composants
2.6.4 Service
2.6.5 Agents
2.6.6 Bilan
2.7 Conclusion
3 Modèle de contrat
3.1 Introduction
3.2 Système exemple
3.2.1 Description
3.2.2 Spécifications du système
3.3 Analyse et choix de conception
3.3.1 Propriétés du système réifiées par le contrat
3.3.2 Architectures acceptées par le modèle de contrat
3.3.3 Formalismes acceptés par le modèle de contrat
3.3.4 Synthèse
3.4 Conception du modèle générique de contrat
3.4.1 Les constituants du contrat
3.4.2 Vue d’ensemble
3.4.3 Le motif architectural (ArchitecturalPatternInstance)
3.4.4 Le type de contrat (ContractType)
3.4.5 Cycle de vie du contrat
3.4.6 Evaluation du contrat
3.5 Modèle hiérarchique
3.5.1 Exploitation des dépendances entre contrats
3.6 Conclusion
4 Mise en oeuvre
4.1 Introduction
4.2 Architectures
4.2.1 Modélisation de l’architecture
4.2.2 Modélisation des observations
4.3 Formalismes
4.3.1 Modélisation des contraintes sur un système
4.3.2 Modélisation de contraintes sous une forme évaluable
4.3.3 Interprétation des spécifications en hypothèses et garanties
4.3.4 Mise en oeuvre dans un contrat
4.4 Conclusion
5 Validation
5.1 Introduction
5.2 Cas d’étude
5.2.1 Contexte de l’exemple
5.2.2 Motivation de l’utilisation des contrats
5.2.3 Le système Amui
5.2.4 La mise en oeuvre des contrats
5.2.5 Conclusion
5.3 Implémentation
5.3.1 Gestion des contrats
5.3.2 Système de contrat
5.3.3 Plugins et spécialisation du système de contrat
5.4 Discussion
5.4.1 Par rapport à l’état de l’art
5.4.2 Intérêts de l’approche
5.4.3 Limites de la solution
5.5 Conclusion
6 Conclusion
Télécharger le rapport complet