• Save

Loading…

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

Like this document? Why not share!

Framework Orienté objet

on

  • 2,938 views

Ce document présente une revue du concept de framework orienté objet, ainsi que de ses applications.

Ce document présente une revue du concept de framework orienté objet, ainsi que de ses applications.

Statistics

Views

Total Views
2,938
Views on SlideShare
2,935
Embed Views
3

Actions

Likes
1
Downloads
0
Comments
0

2 Embeds 3

http://www.linkedin.com 2
http://fr.slideshare.net 1

Accessibility

Categories

Upload Details

Uploaded via as Microsoft Word

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Framework Orienté objet Framework Orienté objet Document Transcript

    • S Y L VA I N D E S B U R E AU X SÉBASTIEN JOBIN JIMMY PERRON PAT R IC K P E L L E T I E R G E ST IO N D E P ROJ ET S O RI EN T E S OB J ET S LES FRAMEWORKS
    • TA BL E D ES MATI ÈR ES Introduction..............................................................................................................5 1 Frameworks orientés-objets et leur développement..............................................6 1.1 Frameworks orientés-objets.....................................................................................7 1.1.1 Qu’est-ce qu’un framework ? .............................................................................................7 1.1.2 Pourquoi utiliser des frameworks ? ..................................................................................11 1.2 le développement des frameworks.........................................................................17 1.2.1 L’organisation du projet.....................................................................................................19 1.2.2 La préparation du développement d’un framework...........................................................23 1.3 La phase d’analyse..................................................................................................26 1.3.1 Les exigences pour le framework......................................................................................27 1.3.2 L’analyse............................................................................................................................29 1.4 La phase de design..................................................................................................32 1.4.1 Le design d’architecture.....................................................................................................35 1.4.2 Le design détaillé...............................................................................................................37 1.5 L’implantation.........................................................................................................38 1.6 Vérification et Validation.......................................................................................42 1.6.1 Test des unités....................................................................................................................45 1.6.2 Test d’Intégration...............................................................................................................46 1.6.3 Test du modèle...................................................................................................................46 1.6.4 Spécificité des frameworks................................................................................................47 1.7 La maintenance.......................................................................................................51 2 Expérience d’application des Frameworks.........................................................53 2.1 Réutilisabilité...........................................................................................................54 2.1.1 Réutilisabilité lors du développement d’un nouveau framework......................................54 2.2 Documentation........................................................................................................60 2.2.2 Les approches CookBook..................................................................................................63 2.2.3 Les approches par Pattern..................................................................................................65 2.2.4 L’approche « Langage de description de frameworks »....................................................67 2.2.5 Conclusion sur la documentation.......................................................................................69 2.3 Exemple...................................................................................................................70 2.4 Conclusion...............................................................................................................80 3 Framework JAFIMA pour les systèmes agent....................................................81 3.1 Le framework d’agent en couche...........................................................................83 3.1.1 La couche senseur..............................................................................................................85 3.1.2 La couche des croyances....................................................................................................87 3.1.3 La couche de raisonnement................................................................................................89 3.1.4 La couche d’action.............................................................................................................90 3.1.5 La couche de collaboration................................................................................................97 3.1.6 La couche de mobilité......................................................................................................105 3.1.7 Le Sous-framework de configuration et d’intégration d’agent........................................107
    • 3.2 Conclusion sur le framework pour les systèmes agent.......................................109 Conclusion............................................................................................................111 2
    • TABLE DES FIGURES Figure 1- 1 : La différence de contrôle entre un framework et une librairie [Landin, Niklasson 95]..............................................................................................9 Figure 1- 2 : Frameworks vs Applications OO traditionnelles : la réutilisation en tête............................................................................................................................12 Figure 1- 3 : Le processus de développement d'un framework.............................18 Figure 1- 4 : Développement de logiciel traditionnel.............................................20 Figure 1- 5 : Plan de développement du Framework.............................................27 Figure 1- 6 : processus de développement des exigences.......................................28 Figure 1- 7 : Les exigences et la phase d'analyse avec leurs produits..................30 Figure 1- 8 : Plan de développement du Framework.............................................33 Figure 1- 9 : la phase design et ses sous-processus................................................34 Figure 1- 10 : le design pattern « stratégie » appliqué dans le framework pour les jeux de dés................................................................................................................35 Figure 1- 11 : Utilisation d’un inline explicite.......................................................41 Figure 1- 12 : La différence entre un case et le polymorphisme...........................48 Figure 2- 13 : Cycle de réutilisation d’un framework............................................56 Figure 2- 14 : Description du problème du premier motif de Hotdraw.................65 Figure 2- 15 : Partie d’un motif du framework HotDraw [Joh, 1992]..................66 Figure 2- 16 : Interface d’un template FDL...........................................................68 Figure 2- 17: Introduction générale du framework...............................................71 Figure 2- 18 : Présentation des concepts du module..............................................72 Figure 2- 19 : Présentation techniques du module................................................74 Figure 2- 20 : Description d’une classe du framework..........................................74 Figure 2- 21 : Présentation des tutoriels.................................................................75 Figure 2- 22 : découpage des diagrammes.............................................................76 Figure 2- 23 : Architecture des classes d’affichage..............................................77 Figure 2- 24 : diagramme d’objets de JTGame......................................................78 Figure 3- 25 : Modèle architectural en couche d’agent.........................................84 Figure 3- 26 : Diagramme de classes de la couche senseur.................................86 3
    • Figure 3- 27 : Diagramme de séquence montrant l’acquisition d’une croyance par un senseur.........................................................................................................87 Figure 3- 28 : Diagramme de classes de la couche des croyances........................88 Figure 3- 29 : Diagramme de séquence pour la mise à jour d’une croyance primitive...................................................................................................................89 Figure 3- 30 : Diagramme de séquence pour la mise à jour d’une croyance composée..................................................................................................................89 Figure 3- 31 : Diagramme de classes de la couche de raisonnement....................90 Figure 3- 32 : Utilisation du pattern « Command » dans la couche d’action.......91 Figure 3- 33 : Le pattern « Abstract Factory » qui instancie les « ConcretePlans » ..................................................................................................................................92 Figure 3- 34 : Utilisation du pattern « Decorator » dans la couche d’action.......93 Figure 3- 35 : Le pattern « Future » et le pattern « Observer » dans la couche d’action....................................................................................................................95 Figure 3- 36 : L’utilisation du pattern « Active Object » dans la couche d’action ..................................................................................................................................96 Figure 3- 37 : Diagramme de séquence pour l’exécution d’un plan.....................97 Figure 3- 38 : Le pattern « Synchronized Singleton »...........................................99 Figure 3- 39 : Le pattern « Decorator » dans la couche de collaboration..........100 Figure 3- 40 : Design de l’interface de collaboration..........................................102 Figure 3- 41 : Design de l’interface de représentation de la collaboration.........103 Figure 3- 42 : Réception de message dans la couche de collaboration...............103 Figure 3- 43 : Diagramme de séquence montrant l’assignation d’un message entrant à un « CollabThread »..............................................................................104 Figure 3- 44 : Diagramme de séquence montrant comment un message sortant est stocké dans un « MesgHolder » et passé à un autre agent.............................105 Figure 3- 45 : Architecture de la couche de mobilité...........................................106 Figure 3- 46 : La création des différentes couche de l’agent par le pattern « Agent Builder »......................................................................................................107 Figure 3- 47 : Design du pattern « Layer Linker »..............................................108 4
    • INTRODUCTION 5
    • 1 FRAMEWORKS ORIENTÉS-OBJETS ET LEUR DÉVELOPPEMENT 6
    • 1.1 FRAMEWORKS ORIENTÉS-OBJETS Toutes les personnes qui s’intéressent de près ou de loin à la programmation Orientée Objets ont déjà entendu parler d’un concept qui lui est souvent associé : la réutilisation. Les frameworks ont vu le jour dans un but de maximisation de la réutilisation. Nous allons donc ici nous intéresser à ce qu’est un framework, puis à la façon de développer des frameworks. 1.1.1 QU’EST-CE QU’UN FRAMEWORK ? Pour mieux comprendre ce que peut être un framework, regardons comment les spécialistes les définissent : ainsi, d’après Johnson, un framework est défini comme suit : “A framework is a set of classes that embodies an abstract design for solutions to a family of related problems.” [Johnson, Foote 91] et “A framework is a set of objects that collaborate to carry out a set of responsibilities for an application subsystem domain.”. [Johnson, Russo 91] Nous pourrions traduire ceci de cette façon : « Un framework est un ensemble de classes qui englobe un design abstrait en guise de solutions à une famille de problèmes similaires. » et « Un framework est un ensemble d’objets qui collaborent pour distribuer un ensemble de responsabilités d'un domaine de sous-système d'application ». On peut donc dire qu’un framework orienté objet est une architecture définie pour permettre au maximum la réutilisation de code dans un domaine donné, ou encore pour un pôle d’applications données. C’est à dire que chaque framework sera construit 7
    • pour un certain domaine de travail ou encore pour une certaine utilisation plus ou moins spécifique. De plus, un framework est composé de classes concrètes et abstraites. Les frameworks sont créés afin de répondre à des besoins spécifiques, et ce en englobant des classes utiles à ces applications. On pourrait donc objecter que les définitions que l’on vient de donner ainsi que les explications adjacentes correspondent exactement à l’idée que l’on se fait des librairies… Il est spécifié dans [Johnson, Foote 91] que les frameworks permettent aussi de réutiliser les implémentations (comme les librairies en fait), mais que ceci est moins important que la réutilisation des interfaces internes d’un système ainsi que la façon dont ses fonctions sont divisées entre ses composants. Et les frameworks permettent tout ceci. Lors d’utilisation de librairies, le développeur fait appel aux classes existantes de ces dernières, alors que pour les frameworks, ce sont les classes internes aux frameworks qui appellent des classes que le développeur doit personnaliser en fonction de son application, ce qui revient à dire que, contrairement aux librairies, le framework va appeler des classes spécialisées : 8
    • Figure 1- 1 : La différence de contrôle entre un framework et une librairie [Landin, Niklasson 95] Pour de plus amples comparaisons entre les frameworks et d’autres concepts tels que les patrons OO (« Object-Oriented Design Patterns »), les patrons de langage (« Language Patterns »), etc., nous vous renvoyons à [Mattsson 96]. Il est aussi précisé que les liaisons dynamiques permettent aux frameworks de traiter un objet sans regarder son implémentation. En fait, pour préciser comment mieux comprendre ce qui a été dit précédemment, nous pourrions dire qu’un développeur dérive une nouvelle classe à partir de la classe abstraite fournie par le framework. En ce faisant, il spécialise le code pour son application tout en suivant le patron fourni par la super classe abstraite contenue dans le framework. On dit parfois qu’un framework fournit une base guidée par l’architecture (aussi appelée boite blanche ou focalisée sur l’héritage) avec une couche supplémentaire guidée par les données (ou boite noire, ou focalisée sur la composition). Cela signifie que le développeur utilise les fonctionnalités fournies avec le framework en créant une instance d’une classe du framework et en appelant ses fonctions membres (on a à faire ici à de la focalisation sur la composition), et qu’il étend et modifie les fonctionnalités en dérivant de nouvelles classes des classes existantes, ou encore en redéfinissant des fonctions membres (ce qui est ici de la focalisation sur l’héritage). 9
    • A noter que lorsque l’on désirera développer des applications à partir de frameworks, il y aura des librairies de sous-classes à choisir, et la personnalisation se fera alors de manière incrémentale par composition (c’est à dire que l’on ajoutera au fur et à mesure des librairies au choix que l’on personnalisera). Par contre, si les applications sont développées uniquement par composition, il n’y aura pas besoin de coder et/ou de tester notre application (on ne fait que récupérer des composants déjà testés et codés), et on gagnera ainsi énormément de temps. M. Taligent a classé les frameworks aussi bien par leur structure interne que par leur domaine d’application [Taligent 94a]. Voici ci-après les différentes catégories qu’il a dégagées : • Les frameworks de support (« support frameworks ») : Ils fournissent des services au niveau système, comme par exemple l’accès aux fichiers, le support de calcul distribué, ou encore les pilotes matériels. Les développeurs d’application utilisent habituellement les frameworks de support directement, ou utilisent des modifications apportées par des constructeurs de matériel. Toutefois, même les frameworks de support peuvent être personnalisés, comme par exemple lorsque l’on développe un nouveau système de fichier, ou un nouveau pilote de matériel. • Les frameworks d’application (« Application frameworks ») : Ils englobent une expertise applicable à une large variété de programmes. Les frameworks commerciaux d’applications de type « interface graphique usagers » (GUI) actuels, qui supportent les fonctions standards requises par toutes les applications GUI, sont un type de framework d’application. • Les frameworks de domaine (« Domain frameworks ») : 10
    • Ils englobent l’expertise dans un domaine particulier, comme par exemple les frameworks multimédia, … Maintenant que nous avons défini les frameworks et passé en revue les différents types de frameworks cités dans la littérature, on peut se demander pourquoi utiliser des frameworks… 1.1.2 POURQUOI UTILISER DES FRAMEWORKS ? Nous avons succinctement abordé précédemment la raison d’être des frameworks, et ceci en rappelant la notion de réutilisation souvent recherchée en programmation, et plus particulièrement depuis l’avènement de la programmation Orientée Objets. Nous allons préciser un peu plus les raisons qui peuvent pousser à utiliser des frameworks. Pour ce faire, nous allons citer les divers avantages que peut avoir de la programmation à base de frameworks, mais nous donnerons aussi les désavantages liés à un tel choix. Tout d’abord, précisons que l’utilisation de frameworks bien conçus, bien documentés, permet la réutilisation à la fois de l’analyse, du design et du code. Un framework rend la réutilisation de l’analyse possible en décrivant les objets importants, les relations entre objets et de quelle façon des problèmes de grande taille peuvent être scindés en des problèmes de taille restreinte. Le design est quant à lui réutilisé dans la mesure où le design du framework lui-même contient des algorithmes abstraits et définit les interfaces, aussi bien que les contraintes qu’une application se doit de satisfaire. Le code est réutilisé puisqu’une classe concrète implantée par l’utilisateur peut hériter d’une super classe. [Johnson, Russo 91] [Mattsson 96] présente, en introduisant le développement des frameworks, la figure ci-dessous qui permet de mettre en relief la réutilisation permise par les frameworks, contrairement aux applications OO traditionnelles. On constate ici qu’en développant 11
    • des frameworks, on n’effectue qu’une seule fois les phases de développement de ceux- ci. En effet, on ne fait qu’une fois l’analyse du domaine et la conception du framework, puis on peut ensuite utiliser celui-ci dans de nombreuses applications. Si l’on avait opté pour une application OO traditionnelle, on devrait refaire les phases d’analyse du domaine et de conception du framework autant de fois qu’il y a d’applications… Autant dire que lors de l’utilisation de framework, on sauve énormément de temps puisque toute l’analyse est déjà faite… Figure 1- 2 : Frameworks vs Applications OO traditionnelles : la réutilisation en tête Nous venons donc ici d’évoquer un des avantages des frameworks, mais ce n’est pas le seul... Nous allons donc voir ci-après les avantages principaux, mais aussi les inconvénients, des frameworks. 1.1.2.1 Avantages Les avantages des frameworks sont nombreux et variés. Nous allons ici passer en revue ceux que [Landin, Niklasson 95] dégagent de leurs recherches. 12
    • • Le temps réduit avant la mise en marché : Lorsque l’on écrit des applications avec des frameworks comme base, seul le code qui diffère des applications précédentes doit être écrit. Il est donc nécessaire d’écrire moins de code, ce qui mène à un temps de développement amoindri et donc un temps réduit avant la mise en marché, comme évoqué en introduction de ce chapitre lors de la présentation de la Figure 1-2. • La maintenance : La maintenance de systèmes est très chère. Entre 60 et 85% du coût total du cycle de vie d’un gros système est passé sur la maintenance, et il y a donc de grosses possibilités d’économies en réduisant le besoin de maintenance [Meyers 88]. Quand on doit tenir à jour des applications se basant sur un même framework, seul le framework lui-même et le code qui diffère de entre chaque application (les spécialisations de méthode des classes du framework par exemple) qui doivent être mis à jour. Cela signifie en outre que les changements ne sont à faire qu’en un seul endroit, ce qui augmente la cohérence de l’application. Comparé à la maintenance de plusieurs systèmes différents, les économies réalisées avec l’utilisation de frameworks est non négligeable. • Les tests : Lorsque l’on réutilise un framework, on réutilise aussi les tests. Le framework que l’on utilise a déjà été testé et il n’y a donc pas besoin de refaire ces tests. Les seuls tests qui doivent être effectués sont les tests des nouveaux modules et les tests des interactions entre ces nouveaux modules et le framework, ainsi que les tests du système. Ainsi, il y a moins 13
    • de tests et de déboggage à effectuer. Bien sûr cela sous-entend que le framework est correct et que les tests du système vérifient que le framework est utilisé correctement. • Le niveau de confiance : Un framework pourrait, comme n’importe quel autre programme, contenir des erreurs et/ou bogues, mais comme le framework est réutilisé, il tend à se stabiliser et les nouvelles erreurs et nouveaux bogues seront alors moins fréquents. On pourrait comparer ce phénomène avec les logiciels « open source » qui voient des failles corrigées par nombre de gens et qui sont sans cesse mis à jour et maintenus. Ils gagnent à être reconnus au bout d’un certain temps lorsque très peu d’erreurs sont trouvées car la participation de tous a permis de stabiliser le produit. Ainsi, le fait de réutiliser des frameworks stables offre une plus grande confiance envers le système développé que d’écrire tout le code depuis rien. • Les standards : Un framework bien conçu d’après les standards de la compagnie permet une meilleure pratique. Quand on développe des applications depuis un framework, le framework impose des contraintes sur le code de l’application développée. Cela conduit à se conformer aux standards de la compagnie aussi bien qu’à acquérir une meilleure pratique de programmation. En fait, on pourrait résumer cela en disant qu’une compagnie peut imposer de bonnes pratiques de programmation pour ses employés (utiliser des noms de fonctions évocateurs, …) mais que ces derniers ne sont pas obligés de les suivre étant donné qu’ils rédigent leur code seul. Cependant, avec la présence d’un framework, le codeur est obligé de respecter la manière dont le framework a été conçu, étant donné 14
    • que ce dernier est la abs du développement et qu’il n’est pas question de le modifier. Ainsi, les bonnes pratiques de programmation se trouvent être suivies de manière involontaire. • Les frameworks englobent de l’expertise : La conception de bons logiciels dans un domaine particulier nécessite une connaissance de ce domaine, qui est acquise généralement seulement par expérience. Puisque les frameworks contiennent cette expertise, les problèmes sont résolus une seule fois et les règles de fonctionnement et de conception sont ensuite utilisables par tous. Cela permet en outre à une société de construire des programmes depuis des bases dont on sait qu’elles ont fonctionné par le passé. Les frameworks permettent aussi aux développeurs de se concentrer sur les solutions spécifiques à leur application et de se reposer sur le framework qui leur apporte des services consistants. Cela libère aussi les développeurs qui ne sont pas nécessairement experts du domaine, en ce sens qu’ils n’auront pas à étudier en profondeur les détails du domaine, qui sont inclus dans le framework et déjà développés. Tout ceci est possible car c’est le framework qui a le contrôle de l’application (cf. Figure 1-1). Ce dernier procure le flot de contrôle pendant que le code du programmeur de l’application attend d’être appelé par le dit framework. Cela revient à dire que le développeur n’a pas à se soucier des détails du framework et qu’il n’aura qu’à se concentrer sur le domaine du problème. [Taligent 94b] • La consistance reconnue et la compatibilité : Les applications développées à partir d’un même framework ont une plus grande capacité à travailler ensemble. Elles sont aussi mieux intégrées du 15
    • point de vue de l’utilisateur, en ce sens qu’elles ont la même interface, ou alors une interface similaire. [Taligent 94b] 1.1.2.2 Les inconvénients En fait d’inconvénients, il est plus à même de parler de difficultés. Les composants et autres architectures ne deviennent pas réutilisables d’eux même. Ils doivent être conçus avec la réutilisation en tête, ou bien avoir été re-conçus dans un but de réutilisation. Ce temps supplémentaire de travail doit être vu comme un investissement sur le long terme. [Johnson, Foote 91] [Taligent 94a] Il est aussi plus difficile de concevoir un framework qu’une bibliothèque de composants, mais le profit potentiel lié à la réutilisation d’un framework est bien plus important que celui lié à la réutilisation d’un composant d’une bibliothèque de composants. La conception d’un framework est plus difficile car l’architecture est à concevoir, mais aussi les communications entre les composants internes du framework [Johnson, Foote 91] [Taligent 94a]. Lorsque l’on conçoit un composant d’une librairie de composants, nous n’avons pas à prendre de telles décisions. Afin de permettre le succès du développement du framework, il doit être soutenu par les processus et organisation de votre équipe. Il faut que tout le monde se rende compte que les bénéfices liés aux frameworks et à la réutilisation se font avec le temps, avec de multiples utilisations du framework. [Johnson, Foote 91] [Taligent 94a] Ainsi, si l’on a vu qu’il y a de nombreux avantages à utiliser les frameworks, nous avons aussi vu qu’il n’est pas forcément si simple de concevoir puis réaliser ces dits frameworks. Intéressons-nous désormais au développement des frameworks. 16
    • 1.2 LE DÉVELOPPEMENT DES FRAMEWORKS Pendant le développement d’un framework, les développeurs doivent essayer de réunir dans le framework le plus grand nombre possible de comportements communs entre les diverses applications. Nous allons présenter ici un processus permettant la construction d’un framework adéquat. Nous avons eu un aperçu des phases de développement d’un framework en Figure 1-2 lors de la comparaison entre la réutilisation d’un framework et celle d’une application OO traditionnelle. En fait, le processus que nous allons expliquer est plus précis que cela : 17
    • Analyse du domaine Exigences et phase d’analyse Design du framework Implémentation du Framework test Analyse de l’application Design de l’application Implémentation de l’application Figure 1- 3 : Le processus de développement d'un framework Ce processus est tiré de [Landin, Niklasson 95] et ne doit pas être considéré comme le seul processus efficace. Il existe d’autre processus, comme le développement basé sur l’expérience, l’utilisation de « Design Patterns », … Pour de plus amples renseignements sur ces autres processus, nous vous renvoyons à [Mattsson 96]. Remarquons cependant que le processus que nous allons étudier ici est considéré par [Mattsson 96] comme le processus général de développement des frameworks, en ce sens qu’il réunit toutes les caractéristiques communes des processus existants, lesquels diffèrent de ce dernier de quelques détails. 18
    • Nous allons expliquer plus en détails chacune des phases de ce processus dans la suite de ce chapitre. 1.2.1 L’ORGANISATION DU PROJET Avant de considérer plus en détail le processus de développement d’un framework, il faut savoir qu’il existe des étapes importantes pour la bonne réalisation d’un projet qui n’apparaissent pas dans le processus en lui-même. L’organisation du projet en fait partie. Nous allons au cours de ce chapitre donner une brève introduction sur les questions organisationnelles liées au développement de frameworks. Nous allons dans un premier temps regarder comment un produit de développement de framework devrait être traité en fonction des contraintes temporelles. Nous poursuivrons avec les difficultés liées à la répartition du travail entre divers groupes de travail fonctionnant en parallèle. Nous verrons ensuite quelques-unes des difficultés liées à l’adaptation des organisations au développement pour et avec la réutilisation. 1.2.1.1 Un investissement stratégique La responsabilité du développement d’un framework ne devrait pas se faire comme une organisation ordinaire de projets. La réutilisation d’un framework dépend de façon très importante d’interfaces bien définies et d’une bonne architecture, étant donné que des changements plus tardifs de ces interfaces et/ou architecture affecteraient toutes les applications dépendantes de ce framework. De ce fait, le développement d’un framework ne devrait pas être une partie critique d’un projet car l’équipe responsable de ce développement ne devrait en aucun cas faire des concessions sur le framework, ce qui conduirait à de mauvaises architectures et des interfaces mal définies. On conçoit bien là qu’il est nécessaire de faire des frameworks complets et bien définis si 19
    • l’on ne veut pas qu’ils aient été conçus pour rien, et que pour ce faire il faut donner à l’équipe responsable de sa réalisation les conditions nécessaires à cette réussite. Le développement d’un framework devrait être vu comme un investissement stratégique plus que comme un investissement opérationnel. Un framework bien développé sera un plus pour la compagnie, car quand il sera réutilisé diminuera les efforts de développement et fera gagner du temps pour les autres projets. La création d’un département ou d’une équipe responsable des développements stratégiques pourrait ainsi être un plus pour la société… 1.2.1.2 L’organisation du travail Figure 1- 4 : Développement de logiciel traditionnel Dans le développement de logiciel traditionnel, le travail est fait, dans la mesure du possible, par de petites équipes de développement travaillant en parallèle, avec des interfaces bien définies (cf. Figure 1-4). Chaque petite équipe travaille sur une partie bien définie du système et chaque interface du sous-système avec les autres parties a été définie au préalable, lors de phases d’étude précédentes. Un architecte Système garde à jour l’image globale du système. Une équipe de développement de framework ne devrait pas être plus grande qu’une équipe de développement de logiciels traditionnels. En effet, quand la taille d’une équipe de développement de logiciel augmente, les communications augmentent et il 20
    • est nécessaire de fournir plus d’efforts pour garder tout le monde informé. Il est aussi plus difficile de garder une image de la progression globale de l’équipe. Une équipe appropriée pour le développement de frameworks ne devrait pas excéder huit personnes. Il peut être judicieux de faire varier le nombre de membres de l’équipe en fonction de la phase de développement dans laquelle on se trouve. Il est par exemple important que l’équipe s’occupant de l’analyse du domaine incluse un ou deux experts du domaine. Dans la suite du processus de développement, la présence d’experts du domaine n’est plus utile mais le besoin d’experts du système augmente. Ceci devrait se ressentir dans la composition de l’équipe de développement. Le développement de frameworks introduit de nouveaux aspects lors de la division du travail. L’idée principale d’un framework est de réunir les généralités d’un domaine ou un ensemble d’applications d’un domaine. Trouver des généralités nécessite une bonne vue d’ensemble du domaine mais aussi du système. Cet aspect rend le partage du travail moins facile à effectuer. Il y aura donc un compromis à faire entre un délai plus court, quand on divise le travail tôt, et un framework avec une bonne architecture stable, quand on ne travaille pas en parallèle. Le travail devrait donc être séparé entre diverses équipes le plus tard possible dans le cycle de développement. Ainsi, la structure du framework et les interfaces publiques des classes du framework devraient être stabilisées avant de diviser le travail (conformément à ce que nous avons déjà dit à ce sujet), mais il n’est pas nécessaire d’avoir défini en détails les objets et les classes. 1.2.1.3 Les équipes de développement « pour » et « avec » la réutilisation On peut dire qu’il y a deux façons d’organiser l’équipe lors de la réutilisation de frameworks. La première est de laisser les mêmes personnes créer et réutiliser le 21
    • framework. La seconde est d’avoir des équipes de développement et de réutilisation différentes. Si on a l’intention de vendre le framework en dehors de la compagnie, le choix de l’organisation de réutilisation est limité… Cependant, [Landin, Niklasson 95] pensent que la plupart des compagnies vont réutiliser leurs frameworks de façon interne et que le choix de l’organisation de réutilisation dépendra alors beaucoup de la politique de la compagnie. Le framework doit être considéré comme un produit même s’il est destiné à un usage interne. Il doit donc être bien documenté et le support du framework doit être planifié. Si les développeurs du framework sont les utilisateurs, ils connaîtront le fonctionnement de ce dernier ainsi que ses problèmes et limitations. De plus, ils auront moins de problème qu’un autre pour comprendre les intentions induites par l’architecture et les solutions. L’hésitation classique lors de la nécessité d’utiliser quelque chose développé par d’autres disparaît aussi, et le feedback nécessaire de la part de l’utilisateur pour le développeur est inévitablement présent… Les équipes de développement devraient, dans la mesure du possible, être constituées d’ingénieurs expérimentés, mais ceci n’est pas si simple étant donné d’éventuelles limites dans le nombre de personnel et d’un point de vue économique. Si l’on a des équipes différentes pour le développement et la réutilisation des frameworks, la connaissance des développeurs expérimentés ayant travaillé sur le développement sera transmise aux développeurs moins expérimentés qui réutiliseront ces frameworks. C’est là le principal argument en faveur de la séparation des équipes de développement et de réutilisation des frameworks. Nous avons donc vu ici qu’il y avait quelques différences entre le développement de logiciels traditionnels et le développement de frameworks qui pouvaient avoir un 22
    • impact sur l’organisation du projet. Lors du développement de frameworks, il est nécessaire de prêter attention à quelle fonctionnalité est générale et quelle autre fonctionnalité est spécifique, car ceci aura un impact sur l’organisation du travail. Maintenant que nous savons ce qu’il faut prendre en compte pour un projet de développement de framework, voyons comment on prépare un tel développement. 1.2.2 LA PRÉPARATION DU DÉVELOPPEMENT D’UN FRAMEWORK On va regarder ici quelles sont les activités effectuées avant de démarrer le processus de développement d’un framework, et ce qu’il est nécessaire de connaître avant de pouvoir démarrer ce processus. L’équipe de développement doit posséder de vastes connaissances du domaine que le framework doit englober. C’est pour cela qu’il est nécessaire d’effectuer une sorte d’analyse du domaine avant une quelconque initialisation du processus de développement. L’analyse du domaine sera une sorte de paramètre d’entrée du processus de développement du framework. Cependant, le processus de développement pourrait aussi retourner un feedback à l’analyse de domaine afin de l’affiner. D’après [Karlsson 95], une analyse de domaine est l’identification des classes et objets qui sont communs à toutes les applications d’un certain domaine. Une modélisation du domaine ne devrait prendre en compte que les artéfacts clé du domaine et ne pas traiter les détails. Un modèle du domaine est un bon outil lorsque l’on commence le développement d’une vue logique du domaine. Il devrait décrire les concepts que les personnes utilisent au sein du domaine, et faire du domaine d’analyse un instrument de communication entre les gens qui prennent part au développement du système, et ce en offrant une terminologie commune. Le modèle du domaine ne 23
    • devrait pas décrire le domaine du point de vue des développeurs, car cela pourrait gêner la communication et risquerait de donner trop d’importance à des détails trop tôt dans le processus de développement. Une analyse de domaine offre aussi un bon support quand on utilise une spécification à base de use cases. [Jacobson et al.92] De l’analyse de domaine devraient naître au moins deux documents : la portée du domaine et un modèle statique qui contienne les objets et classes importants du domaine. Il est important de réaliser un document de portée du domaine car il est impossible pour un framework de couvrir « le monde entier », en ce sens que le framework ne couvrira peut être pas tous les aspects du domaine considéré, et que dans certaines applications certains des aspects non couverts peuvent être importants. Ainsi, en précisant la portée du domaine, on sait ce que notre framework ne couvre pas. La portée du domaine a beaucoup d’importance dans les activités de découverte des besoins du processus de développement. Elle permet de se rendre compte facilement si un besoin fait partie du domaine et est donc valide, ou ne fait pas partie du domaine et est alors invalide. Elle servira aussi en tant qu’outil dans la réutilisation d’un framework, et ce lorsque l’on décidera s’il est judicieux ou non d’utiliser celui-ci dans une application donnée. Mais il est parfois difficile, lors de la rédaction de la portée du domaine, de choisir ce qui doit être dans le domaine et ce qui ne doit pas l’être. Il est plus aisé de développer un framework pour un domaine restreint que pour un vaste domaine. Il faut consacrer suffisamment de temps pour cette activité qui est des plus importantes. Le modèle statique devrait quant à lui contenir les plus importants objets et classes du domaine. Ce peut être des objets du monde réel et/ou des objets liés au monde de l’application. Ces objets et classes devraient porter des noms qui soient explicites pour 24
    • les utilisateurs puisque ce modèle sera un instrument de communication entre les développeurs et les utilisateurs de la future application. L’analyse du domaine produit donc les paramètres d’entrée du processus de développement de framework, en l’occurrence la portée du domaine et le modèle statique du domaine. La portée du domaine est un bon outil au moment de valider les besoins lors du processus de développement de framework. Elle est aussi utile lorsque l’on cherche à savoir quel framework pourrait être utile pour l’application que l’on souhaite développer. Le modèle statique contient tous les renseignements pratiques utiles pour permettre le développement. 25
    • 1.3 LA PHASE D’ANALYSE Cette phase est découpée en fait en deux parties : Les exigences du framework et l’analyse elle-même. Voyons d’abord où l’on se situe dans le développement du framework : 26
    • Figure 1- 5 : Plan de développement du Framework Analyse du domaine Exigences et phase d’analyse Design du framework Implémentation du Framework test Analyse de l’application Design de l’application Implémentation de l’application Intéressons nous d’abord à trouver les exigences pour le framework. 1.3.1 LES EXIGENCES POUR LE FRAMEWORK Le but de cette phase est de trouver toutes les exigences sur le système que l’on est en train de développer. Les inconsistances entre les exigences, les exigences qui sont contradictoires ou ambiguës doivent être trouvées et résolues dans cette phase. Le 27
    • processus de développement de découverte d’exigence peut se décomposer comme ceci : Figure 1- 6 : processus de développement des exigences Extraction Validation Spécification Les trois sous activités sont décomposées suivant [Loucopolos, Karakostas, 95] : • L’extraction des exigences est le fait de découvrir tout le savoir nécessaire qui est utilisé dans la production des spécifications des exigences. • La spécification des exigences est le processus qui reçoit en entrée les délivrables de l’extraction pour créer un modèle formel des exigences. • La validation des exigences est le processus qui tente de certifier que le modèle d’exigence formel est en accord avec les besoins des utilisateurs. Pour le choix des personnes, il faut la plus grande diversité possible afin que tous les utilisateurs, développeurs du framework soient représentés afin de prendre en compte leurs exigences pour le produit final (les développeurs pour le framework, les utilisateurs pour l’application qui en découle). La phase de découverte des exigences est très importante parce que si on ne trouve pas toutes ces exigences, ou si on ne trouve pas les bons, cela implique que l’on devra faire des changements plus tard dans le développement. Et le coût de ces changements est très élevé du fait qu’une grande partie du code et du design doit être réécrite. C’est 28
    • pourquoi une grand partie des efforts doit être mis en place lors de la phase d’analyse afin d’avoir une correcte, complète et consistante spécification d’exigences. Afin de rendre cette phase plus compréhensible pour les utilisateurs finaux des différents produits du framework, il est recommandé de créer des diagrammes use case spécifique à chacune des futures applications (connues lors de la création du framework) ainsi qu’un diagramme use case général que nous nommerons use case abstrait. Cela permettra aussi de trouver les différentes généralisations. 1.3.2 L’ANALYSE 29
    • Modèle d’exigences : Spécification d’exigences Modèle Use Case Exigences Analyse Modèle d’analyse : Modèle d’objet statique Modèle de flots de données Permet de trouver Design Figure 1- 7 : Les exigences et la phase d'analyse avec leurs produits Le but de l’analyse est de décrire un modèle du système qui est en accord avec les exigences trouvées. La phase d’analyse devrait se concentrer uniquement sur le problème et être faite sans aucune considération à-propos de l’environnement d’implantation. A ceci deux raisons, tout d’abord l’analyse restera ainsi correcte même si l’environnement change. De plus, si on si on pense aux détails d’implantation, il y a un risque que les développeurs se concentrent sur les problèmes d’implantation, ce qui entraînera que le système suppose résoudre le problème sera en dehors de ses exigences. En sortie de la phase d’analyse, on aura comme délivrables le modèle d’objet statique ainsi qu’éventuellement le modèle de flots de données par exemple. Le modèle d’analyse lorsque l’on crée un framework doit posséder la faculté de concentre 30
    • l’attention des développeurs sur ce qui est similaire dans les applications développées et sur ce qui ne l’est pas. La phase d’analyse a les étapes suivantes [Taligent, 94] : • Décrire la situation et le problème. • Examiner les solutions existantes. • Identifier les abstractions clés. • Identifier les abstractions de haut niveau. • Identifier avec quelles parties du problème le framework traitera. • Demander ce que veulent les clients et raffiner l’approche. Lors du raffinement, il faut trouver des classes qui viennent du modèle du domaine et qui n’ont pas besoin d’êtres enlevées. Toutes les nouvelles classes nécessaires devraient, quand c’est possible, être mises dans les hauts niveaux de l’abstraction. En effet, introduire des hauts niveaux d’abstraction conduit à accroître la généralisation du système. Lors de la phase d’analyse, il faut trouver des classes abstraites qui permettront de trouver les frameworks dans le système. 31
    • 1.4 LA PHASE DE DESIGN Après avoir fait la phase d’analyse, la phase suivante lors du développement orienté objet est la phase de design. Nous allons voir dans cette section ce qui différencie la phase de design d’un framework par rapport a une phase de design classique 32
    • Figure 1- 8 : Plan de développement du Framework Un design de framework est un design de logiciel qui, lorsque c’est implanté, Analyse du domaine Exigences et phase d’analyse Design du framework Implémentation du Framework test Analyse de l’application Design de l’application Implémentation de l’application procure les fonctionnalités générales et abstraites identifiées lors de la phase d’analyse. Il y a deux sous processus au design du framework, le design d’architecture et le design détaillé. Lors du design d’architecture, les objets ainsi que leurs collaborations seront changés, afin de coller avec l’environnement de d’implantation. Durant la phase de design détaillé, les objets trouvés lors de la phase de design d’architecture sont traduits dans le langage cible et si nécessaire, sont raffinés. Cela donne le schéma suivant : 33
    • Design d’architecture Identification des objets Distribution des responsabilités Définition des collaborations Design détaillé Examiner et Raffiner la hiérarchie d’héritage et les collaborations prototyper Implémentation Figure 1- 9 : la phase design et ses sous-processus La chose principale à faire lors du design d’un framework est de construire une base pour une implantation générique, afin qu’elle puisse marcher pour un nombre important d’applications similaires. Lors de la phase du design, de nombreuses abstractions vont être identifiées, c’est pourquoi le design doit être facile à changer. Il faut donc d’abord identifier les abstractions. Comme de toute façon la plupart des concepts communs doivent être trouvés lors de la phase d’analyse, les abstractions trouvées lors de cette phase seront de niveau moindre. Autrement, cela veut dire qu’il faut retourner dans la phase d’analyse. Comme les abstractions sont trouvées par des méthodes de bas vers le haut (exemples concrets), il faut donc qu’il y ait un design pour trouver ces abstractions [Johnson, 95]. Afin de ne pas refaire plusieurs fois le 34
    • même design, il est bon d’identifier les solutions de design génériques. Une bonne manière de traiter ce solutions générique est d’utiliser des « design patterns », dont les solutions qu’ils proposent sont bien prouvées, afin de faciliter la communication entre les différents teams de design et rendre le framework plus facile à comprendre. Figure 1- 10 : le design pattern « stratégie » appliqué dans le framework pour les jeux de dés Evidemment, si un design pattern existe pour une partie du design, il est important de s’y conformer. 1.4.1 LE DESIGN D’ARCHITECTURE Comme on l’a vu précédemment, cette phase compte trois sous-phases que l’on va détailler. Mais d’abord, que fait-on lors de cette phase ? On identifie les objets dont on a besoin pour implanter le système, ainsi que leur collaboration. On peut aussi diviser le système en sous-systèmes pendant cette phase s’il est trop gros. 35
    • La première phase est de raffiner le modèle d’objet qui vient de la phase d’analyse. Il faut ajouter des objets afin d’adapter le système à l’environnement de développement (par exemple pour l’utilisation des API graphiques). Afin de rendre plus compréhensible le système pour l’utilisateur final du framework, il faut essayer de garder pour les objets les mêmes noms que lors de la phase d’analyse pour ne pas perdre inutilement l’utilisateur. Enfin, si une classe a plus de 25 méthodes, cela veut dire qu’il va falloir la restructurer. Une fois cela fait, il faut assigner les responsabilités du systèmes à des objets spécifiques. Pendant l'identification des opérations un objet est responsable de l'exécution et de quelle connaissance il maintiendra. Une façon commune d'exprimer des responsabilités semblables doit être employée, puisque cela peut aider pour identifier des abstractions. Si on nomme les responsabilités de manière générale, les abstractions viendront plus facilement. Parfois on n’arrive pas à trouver où exactement mettre les responsabilités, il faut donc la distribuer. Le premier souci en distribuant les responsabilités doit être de créer des méthodes qui exécutent des opérations logiques sur les instances de la classe. Le fait de distribuer l’intelligence du système permet aussi de trouver des abstractions. Définir autant de classes abstraites aussi possible impliquent la mise en place d'autant de comportements communs que possible. Puis, il faut analyser les collaborations entre les classes. Un objet collabore avec un autre objet si il invoque au moins une méthode de l’autre objet afin de satisfaire ses responsabilités [Karl,95]. Afin de faciliter l’extension du framework, il est préférable de définir des collaborations entres des classes abstraites plutôt qu’entres des classes concrètes. Enfin, pendant tout cela, il est important de raffiner la hiérarchie de classe ainsi que les collaborations. Les hiérarchies de classe doivent être assez profondes et étroites. Des hiérarchies de classes peu profondes et larges indiquent que les abstractions doivent toujours être trouvées dans la hiérarchie. Il est aussi important de préserver les 36
    • abstractions identifiées lors de la phase d’analyse car ce sont les abstractions fondamentales si l’analyse a été bien faite. 1.4.2 LE DESIGN DÉTAILLÉ Ici, toutes les classes avec leurs attributs et leurs méthodes sont identifiées en utilisant le langage d’implantation [Kar, 95]. On va donc ici trouver les méthodes des classes. Les méthodes doivent avoir peu de paramètres (moins de cinq) afin que l’utilisateur final comprenne facilement. De même, une méthode ne doit faire qu’un tache afin encore une fois de faciliter la compréhension de l’utilisateur final. Si une méthode fait plusieurs taches, il est peut être bon de la diviser entre plusieurs classe, pour que chaque partie soit unique dans les classes. 37
    • 1.5 L’IMPLANTATION Analyse du domaine Exigences et phase d’analyse Design du framework Implémentation du Framework test Analyse de l’application Design de l’application Implémentation de l’application D’après Johnson : « A Framework is a generalisation of the implementation of several applications » soit, un framework est la généralisation de l’implantation de plusieurs applications [Johnson, 95]. Il faut d’abord définir une stratégie. Généralement, on fait une implantation du haut vers le bas, id est avec le développement des objets de haut niveaux d’abord. De plus, comme tous les objets de 38
    • bas niveaux ne sont pas présent lorsque l’on doit tester le framework, il faut trouver une manière de les remplacer. Soit on mets des stubs, soit on simule les appels de ces objets [Karl, 95] et [Som, 92]. Il faut remarquer que l’implantation est en lien très étroit avec les design détaillé (puisque si on trouve une inconsistance en développant, on reviens de facto dans le design, au moins implicitement) et avec le phase de test puisque généralement les test de classes se font juste après l’avoir implanté [Karl, 95]. L’input de la phase d’implantation est comme avec une application classique une description détaillée des classes, de leurs interfaces. L’output est l’ensemble des classes crées, prêtes à être testée. On le fait en deux étapes : • Mise en oeuvre de l'interface externe de la classe. L'interface, définie pendant la conception détaillée, est achevée pour inclure la définition interne de la classe, c'est-à-dire des attributs protégés et privés et des méthodes. • Mise en oeuvre des méthodes, commençant avec un corps de méthode vide avec type de retour correct. Le comportement interne est identifié en examinant les modèles dynamiques, c'est-à-dire les diagrammes d'interaction et les graphiques de transition d'état. Les diagrammes d'interaction peuvent aussi contenir le pseudo code, sur lequel la mise en oeuvre peut être basée. Le comportement entier des méthodes est mis en oeuvre dans cette étape. Voici quelque guides pour implanter un bon framework, partie la plus importante de la création. Tout d’abord, intéressons-nous aux relations entres les classes. Il faut que la structure de relations soit la plus simple possible parce que c’est la partie la plus ardue à comprendre. Si il y a des héritages multiples, il faut absolument commenter longuement ces héritages afin que l’utilisateur du framework en comprenne l’utilité. Un bon framework est un framework simple à comprendre, avec du code propre. Pour les 39
    • mêmes raisons, il vaut mieux éviter de faire des appels à des méthodes définies plus bas dans la hiérarchie de classe mais plutôt les mettre dans l’interface de la super classe. L’utilisation de classes friend doit être aussi évitée car cela passe outre l’encapsulation et donc cela peut générer des erreurs. Il vaut mieux mettre en friend seulement les méthodes de classes qui en ont besoin. Enfin les concepts d’héritage privés (qui n’est pas un concept orienté-objets mais un concept de C++) ainsi que le fait d’utiliser des héritages restrictifs ne doit pas être mis en œuvre dans un framework pour des raisons de compréhensions de l’usager final. Il faut plutôt restructure la hiérarchie d’héritage à ce moment là. Maintenant que nous avons vus les relations, intéressons nous aux classes et aux méthodes. Tout d’abord, voyons des conseils qui peuvent être vus pour tout application à créer mais qui sont très importants lors de la création de framework, afin d’éviter que l’utilisateur final ne comprenne pas ce qui est fait ou qu’il puisse faire de fausse manipulations. Ainsi toutes les classes abstraites ne doivent pas pouvoir être instanciées (par exemple en C++, il faut déclarer au moins une méthode virtual afin que la classe ne puisse être instanciée, ou alors si le constructeur est protégé), ceci afin que l’utilisateur ne le fasse par mégarde. De même toutes les méthodes qui devront être surchargée doivent être définies comme virtual. De même, il serait bon d’avoir un mécanisme qui empêche de surcharger des méthodes qui ne doivent pas l’être (mais ce n’est pas possible en C++ par exemple), afin de ne pas passer outre l’esprit du framework. Il est bon aussi de déclarer le plus possible les membres des méthodes en const, afin que la méthode ne change pas l’état de l’objet. Ceci était pour empêcher l’utilisateur de mal utiliser le framework. De même, il est important de spécifier tous les attributs de l’objet comme privés, afin de ne montrer que l’interface de l’objet et non comment on l’implante en pratique. Maintenant, il faut qu’il comprenne comment marche le framework, et pour cela, les méthodes ne devraient pas dépasser 20 lignes de codes, ou alors il faut les redessiner. Il est intéressant aussi d’enlever tous ce qui vérifie explicitement le type de l’objet afin d’utiliser au maximum les bénéfices du polymorphisme, concept très important lors de la création d’un framework, parce qu’il permet d’étendre facilement celui-ci en rajoutant simplement de 40
    • nouvelles sous-classes. Il est préférable d’utiliser un inline explicite qu’implicite, ceci afin de rendre l’interface la plus lisible possible, et donc de la rendre plus facilement compréhensible : class Kitty: public Money_Container { public: void Deposit(int const nAmount){ nSum = nSum+nAmount; } // Implicit inline } // File: file.h (header file) class Kitty: public Money_Container { public: void Deposit(int const nAmount); } // File: file.cc (source file): inline void Kitty::Deposit(int const nAmount){ nSum = nSum+nAmount; } //Explicit inline Figure 1- 11 : Utilisation d’un inline explicite Après les classes et les méthodes, finissons par les constructeurs et les destructeurs. Afin d’avoir le contrôle de son implantation, le concepteur doit explicitement créer les constructeurs et destructeurs de sa classe, ainsi que les opérateurs copie et assignement. De plus, si ces deux derniers opérateurs ne sont pas obligatoires, il vaut mieux les cacher dans le la partie privée de la spécification de la classe, afin que l’utilisateur ne puisse les utiliser. Enfin pour les super classes, le destructeur doit être virtual, afin que les sous-classes désalloue elle-même leur mémoire. 41
    • 1.6 VÉRIFICATION ET VALIDATION La vérification est le fait de vérifier que le système en construction va satisfaire toutes les exigences faites lors de la phase d’analyse. La validation est le fait de vérifier si le système en construction est le produit que les clients veulent vraiment. La validation et la vérification prenant une place importante dans les coûts de développements (en 30 et 50%) [Jacobson, 92], le fait de faire baisser le temps de cette partie aura un impact important sur le processus de développement. On peut diviser le processus de vérification et validation en trois : les tests d’unités, le test d’intégration, et enfin le test du modèle. 42
    • 43
    • 44
    • Analyse du domaine Exigences et phase d’analyse Design du framework Implémentation du Framework test Analyse de l’application Design de l’application Implémentation de l’application 1.6.1 TEST DES UNITÉS Ici, comme son nom l’indique, on ne teste qu’une unité à la fois (qui peut être une opération, une classe, un module contenant plusieurs classes, voire un framework). On vérifie qu’une unité bien définie avec des responsabilités bien définies satisfasse les exigences imposées sur cette unité. Selon Marciniak, Jacobson et Karlsson, il y a deux méthodes pour faire des tests d’unites [Marciniak, 94], [Jacobson, 92], [Karlsson, 95] : 45
    • • Le test de structure, qui exige la connaissance de la structure interne de l'unité, fournit la connaissance du code de l'essai et l'envergure de branche, qui indique la fiabilité de l'unité. • Le test de spécification, ou le test des fonctionnalités, qui est seulement basé sur les exigences imposées à l'unité. Aucune attention n'est payée à la structure interne du module, on s’intéresse seulement aux réponses de l'unité à certaines entrées. 1.6.2 TEST D’INTÉGRATION On teste ici comment les unités travaillent ensemble. [Jacobson, 92], [Karlsson, 95]. Un essai d'intégration peut, en même temps, être un essai d'unité, une unité peut consister en plusieurs sous unités. Jacobson recommande pour ces tests d’utiliser des diagrammes de uses case. Le test d'intégration final, quand tous les modules sont combinés pour former le système final, est parfois appelé le test du système. Le test du système vérifie si le système satisfait les exigences ou non. Si les exigences sont formulées comme des diagrammes use case, les résultats d'un certain use case donneront directement la satisfaction d'une exigence spécifique. L'essai de système sera la première possibilité d'évaluer si le système satisfera les exigences imposées au système. Le test d'intégration précédent satisfera seulement les exigences qui sont tirés des exigences de l’utilisateur, d’où l'importance de l'essai de système. 1.6.3 TEST DU MODÈLE Après avoir fait cela, il faut faire un test du modèle, et ce a la fois lors du développement puis lors de la réutilisation du framework. Le test du modèle consiste en un test de cas et un test bed [Karlsson, 95]. 46
    • Un test bed [Jacobson, 92] consiste a simuler tous ce qui entoure l’unité à tester. Le test fait les appels aux opérations de l’objet testé. Un test de cas consiste en une s Un test de cas consiste en une séquence d’action ou une séquence de stimulus, pour voir si l’unité répond de la manière prévue. Si l’on a utilisé des diagrammes use case dans le modèle d’exigence, ils seront une bonne base pour créer ces tests là. 1.6.4 SPÉCIFICITÉ DES FRAMEWORKS Maintenant que nous avons vus les différents types de tests, regardons quelles sont les spécificités du framework lors de cette phase. Par rapport à un test d’application normal, il n’y a pas beaucoup de différences. Mais tout d’abord, il faut voir qu’il y a deux questions principales lors des tests sur le framework. Premièrement, est-ce que le framework couvre bien le domaine comme on l’a voulu [Joh, 91] ? Ceci est vérifié si l’on réutilise souvent ce framework. Si le framework ne peut être utilisé lors du développement d’une application pourtant incluse dans son domaine d’application, le framework doit être repensé ou alors son domaine d’application changé. Ensuite, le framework doit satisfaire les parts des exigences de l’application qui sont dans son aire de responsabilité. Cela est vérifie une première fois lors du test du système. Un bon outil pour tester le système est le polymorphisme [Jacobson, 92]. Si des changements sont fait dans une sous-classe, il ne doit pas y avoir de changements à faire dans les classes du framework. Cela veut donc dire que si on change les sous- classes (et donc l’application), tout en restant dans le domaine d’application du framework, on ne doit faire que des tests d’unités sur ces sous-classes et il ne doit pas y avoir à retester le framework avec ces sous-classes. Il faudra juste à la fin faire un test d’intégration et un test de modèle. Il faut voir qu’il y a des difficultés à utiliser le polymorphisme par rapport aux traditionnelles procédures orientées objets. En effet, une des difficultés et de tester tous les chemins possibles avec le polymorphisme lors d’un test de structure. Quand on utilise un case comme avec les anciennes 47
    • techniques, tous les cas possibles sont montrés tandis qu’avec le polymorphisme, seule l’unité invoquée est montrée [Jacobson, 92]. Fichier Virtual: Si l’on utilise case : … Read() ; store : Fichier Write() ; … case store.type est    FichierDOS : readDOS(store);    FichierUNIX : readUNIX(store) ; Fin case Fichier DOS Fichier UNIX Polymorphisme : Virtual: Virtual: … store : fichier Read() ; Read() ; … Write() ; Write() ; store.Read() ; Figure 1- 12 : La différence entre un case et le polymorphisme De plus, l’héritage va diminuer la taille du code mais pas la taille des tests. Les méthodes héritées d’une super classe peuvent en effet marcher avec celle-ci et pas avec une de ses sous-classes [Jacobson, 92]. Les méthodes héritées doivent donc être testées aussi. 1.6.4.1 La certification de la fiabilité Avant de pouvoir réutiliser un composant, il est important que la personne le réutilisant puisse se faire une idée de sa fiabilité. La fiabilité est souvent critique car 48
    • l’échec d’un système va souvent coûter au réutilisateur de l’argent. Les exigences doivent donc clairement spécifier le degré de fiabilité du système [som, 92]. Voici quelques métriques utilisées pour tester la fiabilité [Sommerville, 92] : • La première métrique est l'échec de probabilité sur demande qui est une mesure de la probabilité que le système se comportera d'une façon inattendue quand il est appelé. • Le taux de présence d'échec est la seconde métrique qui est mesure combien de fois le système se comportera de façon inattendu par unité de temps. Selon Sommerville ce métrique est la plupart du temps la plus générale. • La troisième métrique est le temps moyen à l'échec, qui est une mesure du temps moyen entre deux échecs arrivant sur le système. • La disponibilité donne la probabilité que le système est prêt à être utilisé. 1.6.4.2 Les tests statistiques Pour trouver ces métriques, il faut faire des tests statistiques. Il y a quatre étapes dans le processus de tests statistiques [Sommerville, 92] : 1. Déterminer le modèle d’utilisation de l’unité. 2. Collecter et détecter les données de test qui identifient les tests de cas selon ce modèle. 3. Exécuter les tests de cas selon l’utilisation de ce modèle. Enregistrer le temps d’exécution jusqu'à ce qu’une erreur arrive. 4. Trouver la fiabilité du logiciel selon les résultats de test. 49
    • Un framework est réutilisé avec le but de développer de nouvelles appplications. Différentes applications peuvent avoir différents modèles d’utilisation, ce qui peut limiter l’utilisation des tests statistiques. Cependant, un travail qui approuve l'utilisation des tests statistiques comme une méthode pour la certification de fiabilité de composants de logiciel a été fait. Le test d'utilisation peut aussi être une méthode appropriée de certifier des frameworks aussi. 50
    • 1.7 LA MAINTENANCE Le dernier point du développement d’un framework est la maintenance. En plus des aspects de maintenance normaux, le framework a d’autres besoins pour la maintenance. Regardons lesquels ils sont. La maintenance faite pour améliorer le système sans changer ses fonctionnalité prend 65% du temps de maintenance, la maintenance pour corriger les erreurs 17% tandis que la maintenance destinée à adapter prend 18% du temps [Lientz, Swanson, 80]. La structure interne d’un framework consiste en une structure de classes abstraites et concrètes. Un bon framework est une structure qui est profondément héritée mais de manière étroite. Donc un changement fait dans une super classe va affecter toutes ses sous-classes, ce qui peut être gênant. Une manière de contourner cela, mais sur le court terme est de faire une sous-classe qui implante les changements et de la faire hériter de la super classe. Les changements pourront donc être aisément contrôlés et la possibilité de dépendances inconnues est réduite. Mais de telles modifications vont, sur le long terme, conduire à la dégénérescence des classes et de la structure d’héritage. A ce moment-là, il faut restructurer le framework régulièrement [Gam, 94]. Un framework est construit avec l'intention qu'il sera employé pour développer beaucoup d'applications. L'utilité d'un framework est reflété par combien de fois il est réutilisé et toutes ces applications dépendent de la structure. Les modifications d'interfaces et des noms sont cruciales et affecteront très probablement les applications dépendantes. Il faut donc lors du développement du framework porter le plus gros effort sur le choix des interfaces et des noms. Mais il faudra probablement changer des noms et des interfaces. Quand n'importe quelle demande de changement est trouvée valable il est meilleur de mettre en oeuvre 51
    • ces changements aussi rapidement que possible parce que encore plus d’applications dépendantes peuvent être développées en attendant, augmentant le nombre de systèmes dépendants. Par contre, les changements internes dans le framework ne devrait pas dans la plupart des cas affecter les interactions entre le framework et l’application. C’est pour cela que ces changements sont moins cruciaux. Chaque personne utilisant le framework doit être prévenue lorsque des modifications sont faites, spécialement lorsque des fautes ont corrigées [Karlsson, 95]. 52
    • 2 EXPÉRIENCE D’APPLICATION DES FRAMEWORKS Dans le domaine du génie logiciel, les « frameworks » orientés objets offrent une grande puissance compte tenu de la diversité de ceux-ci. Un framework fournit un squelette d’application donnant une base solide pour le développement de logiciel dans un domaine particulier. Cette technique se voit beaucoup plus puissante que la simple réutilisation des classes parce qu’elle offre également l’architecture haut niveau (design) du système à développer. C’est pourquoi nous nous attarderons sur les aspects permettant une réutilisation simple, efficace et sans ambiguïté. Premièrement, nous étudierons l’aspect de la réutilisabilité qui peut être vue sous deux angles différents. La première façon est de se demander, lors du développement d’un framework, la bonne démarche à suivre pour que notre système soit facilement réutilisable. L’autre façon de voir la réutilisabilité est lorsque le développement utilise un framework existant. En approfondissant ces deux aspects de la réutilisabilité, nous verrons qu’une part importante d’un bon framework est la façon dont il est documenté lors de la conception. Nous terminerons cette étude avec l’exemple d’un « Framework » bien documenté ce qui permet d’augmenter sa réutilisabilité. 53
    • 2.1 RÉUTILISABILITÉ 2.1.1 RÉUTILISABILITÉ LORS DU DÉVELOPPEMENT D’UN NOUVEAU FRAMEWORK Il y a typiquement deux façons d’organiser l’équipe de développement lors de la mise en oeuvre d’un nouveau framework. La première est de laisser aux mêmes personnes le soin de développer et de réutiliser le framework. L’autre façon est d’avoir deux organisations distinctes : l’une qui développe et l’autre qui réutilise. Si l’intention est de vendre ou de distribuer le framework, il n’y aura qu’une équipe qui développera le système. Cependant selon Landin et Niklasson (1995), la plupart des compagnies utiliseront leurs « frameworks » à l’interne. Ainsi, le choix de l’organisation de la réutilisation est intimement lié à la structure de la compagnie. Lorsque le framework est développé et utilisé par les mêmes personnes, ils sont en mesure de connaître les problèmes et les limitations du système. De plus, ils n’ont aucun problème à comprendre les intentions dernières l’architecture et la solution mise en oeuvre. Cependant, lorsque qu’une équipe de développement décide d’utiliser un framework existant, ils devront, lors de l’analyse et du design, prendre en considération la réutilisabilité. 2.1.1.1 L’analyse avec la réutilisation Le processus d’analyse doit acquérir les différentes exigences en plus de pouvoir obtenir une modélisation du monde d’application. En introduisant la réutilisabilité à l’étape d’analyse, le processus de développement se voit quelque peu modifié [Karl, 1995]. En effet, il faut identifier les opportunités de réutilisation durant la phase de spécification et identifier les exigences spécifiques qui les supportent [Nato, 1991]. 54
    • Il est important de formuler les exigences aussi générales que possible lorsque nous effectuons l’analyse. La raison est que si les exigences sont trop précises et détaillées, ils ne se superposeront pas sur des exigences déjà existantes. Le même problème peut être résolu de plusieurs façons différentes donc aucune solution de devrait être proposée à ce stade-ci. Afin d’augmenter l’adéquation de la réutilisabilité, nous ne décrierons que les fonctionnalités nécessaires. Ce type d’analyse s’appelle l’analyse du domaine et elle doit être utilisée pour déterminer si les composantes requises sont comprises dans un domaine déjà couvert. Si le domaine est couvert et qu’il existe des « frameworks » pouvant être utilisés, il faut les étudier avec soin. Dans le cas contraire, le design devra prendre en considération le développement des fonctionnalités nécessaires tout en assurant une bonne réutilisabilité. 2.1.1.2 Design avec la réutilisabilité Le design se découpe en deux phases : le design de l’architecture et le design détaillé. Le design de l’architecture devra définir une stratégie haut niveau pour résoudre le problème et implanter une solution. Selon Karlsonn, il y a deux principales difficultés pour la réutilisabilité à cette étape du design : • La difficulté de comprendre les solutions prédéfinies. • Appliquer la connaissance acquise pour structurer le problème de façon à ce qu’il puisse être solutionné par les solutions prédéfinies qu’offre les « frameworks » sur le marché. C’est pourquoi le rapport d’activité dans le développement du processus de réutilisation contribuera à augmenter la maturité du framework. En général, lorsqu’un framework est réutilisé, un rapport de réutilisation devrait être conçu avec les sections suivantes [Karl, 1995] : • Des informations sur l’environnement de réutilisation. 55
    • • Des informations sur les difficultés de compréhension du framework. • Des informations sur les difficultés rencontrées lors de l’adaptation du framework. • Le coût de réutilisation. • Toutes les modifications apportées au framework. Dans le cas où un framework est réutilisé pour la conception d’un système, le cycle de vie peut différer légèrement comparativement à un développement normal. Voici le cycle de vie proposé par Kirk (2001) : Phase 1 : Identification des objectifs Phase 2 : Identification des candidats pour la réutilisation • Recherche de « frameworks » • Expériences précédentes Phase 3 : Sélection du candidat réutilisable Phase 4 : Modification • Réutilisation direct • Modification • Création Phase 5 : Évaluation des modifications Figure 2- 13 : Cycle de réutilisation d’un framework La première phase définit les objectifs de la tâche à réaliser. C’est le processus qui identifie le problème et décrit une solution haut niveau pour le résoudre. 56
    • La prochaine phase tente de localiser les éléments d’un framework qui pourrait être applicable au problème présent. Les candidats sont choisis en recherchant parmi les composantes d’un framework par rapport au domaine du problème. Il existe deux méthodes pour la recherche d’un framework. Premièrement, il y a la stratégie « design first » qui crée une solution au problème avant de commencer la recherche d’un framework. Inversement, la méthode « framework first » crée une solution en identifiant des composantes utiles dans un framework et en essayant de les fusionner pour atteindre les exigences du système à développer. Selon Kirk, la méthode à prévilégier est de solutionner le problème avant d’effectuer la recherche de composantes. Ainsi, on peut avoir une idée précise des fonctionnalités recherchées et le développement est plus simple et moins décousu. La troisième phase sert à choisir l’un des candidats préalablement sélectionnés pour l’implantation. La sélection est une tâche difficile car le framework choisi influencera tout le reste du développement ainsi que le produit final (stabilité, fonctionnalité, ...). Un choix éclairé demande une bonne connaissance de l’architecture du framework ainsi que des interactions qu’il aura avec le reste du système. L’implantation est la quatrième phase de la réutilisation. Les composants sélectionnés peuvent être implantés au choix selon l’une des trois façons suivantes : • Si les composantes du framework correspondent exactement aux spécifications du problème à résoudre, il peut être utilisé directement. • Si le framework sélectionné est le plus près framework de la spécification pour la résolution du problème, il sera utilisé avec quelques modifications. • Finalement, si aucun framework n’a été identifié pour la tâche, il faudra créer le squelette de l’application à partir de zéro. 57
    • La dernière étape est celle où le produit doit être évalué. L’évaluation considère les effets du travail sur l’architecture du framework pour le présent problème. Cette phase est quelque peu subjective puisqu’il n’existe pas vraiment de méthode formelle pour effectuer l’évaluation du système. Il y a, dans la littérature, quelques chartes et quelques pistes mais il est du devoir des développeurs de s’assurer que le framework répond au problème de façon simple et efficace. 2.1.1.3 Problème de réutilisation De nombreux problèmes peuvent survenir lors du développement lorsqu’on réutilise un framework. Nous pouvons diviser ces problèmes en deux catégories : comprendre et localiser. La localisation de composantes à l’intérieur d’un framework semble être difficile dû au grand nombre de classes qu’il contient. La hiérarchie avec héritage rend la tâche ardue en camouflant les fonctionnalités dans les superclasses. Cela rend la compréhension des comportements des composantes encore plus difficile. Le problème de la compréhension peut être subdivisé en deux sous problèmes : compréhension des composantes et compréhension des interactions. Ce qui rend la compréhension des différentes parties d’un framework difficile, c’est tous les mécanismes mis en place pour assurer une bonne flexibilité : classes abstraites, « design patterns », héritage, compositions, etc. Ces mécanismes font que nous avons besoin d’une vue d’ensemble très détaillée pour être en mesure d’utiliser une sous-partie d’un framework. Les interactions causent aussi des problèmes lors du processus de réutilisation parce qu’il est difficile pour les développeurs de les visualiser. Beaucoup d’efforts sont déployés afin de reconstruire le flot de contrôle du framework. Il est assez facile de voir que tous ces problèmes pourraient être considérablement éliminés si une documentation appropriée avait été construite lors du développement du framework. Un framework ne peut être réutilisé que s’il est bien compris et c’est 58
    • suite à cela que nous allons nous pencher sérieusement sur la question de la documentation des « frameworks ». 59
    • 2.2 DOCUMENTATION Afin de devenir une tendance répandue, les techniques de réutilisation des « frameworks » doivent exiger que les concepteurs rendent leur compréhension sur le framework aussi accessible que possible. Un pont doit être mis en place entre le savoir des développeurs et la compréhension des utilisateurs sur le framework. Il n’y aura donc aucune surprise si nous insistons beaucoup sur l’importance d’une documentation simple, complète et précise. Selon [joh, 1991], un framework n’est pas complètement stable lors de sa première utilisation. Le framework aura besoin de modifications lorsqu’il sera réutilisé et chaque fois qu’il sera réutilisé, il deviendra de plus en plus stable. D’où l’importance de la bonne compréhension du framework puisqu’il nécessitera sûrement quelques ajustements. Dans cette section, nous allons présenter trois techniques de documentation qui semblent fondamentales. Premièrement, nous verrons l’approche cookbook, ensuite la technique avec les design patterns et finalement l’approche plus abstraite de Wilson & Wilson. La documentation d’une application classique orientée objet doit être décrite de différentes façons selon les différentes catégories du génie logiciel. Ceci est vrai aussi pour les librairies de classes ou les « frameworks ». Selon [Lin, 1990] l’information suivante devrait être présente dans la documentation pour la compréhension et l’utilisation des classes : • Information structurelle : il s’agit du nom de la classe, des superclasses s’il y en a, du type des paramètres d’instanciation plus les informations similaires sur les opérations. • Description, en langage naturel, de chaque classe. Cette description devra décrire l’essence de la classe et l’abstraction qu’elle représente. 60
    • • Usage : décrit si la classe doit être instanciée d’une façon ou à un moment particulier. • Configuration : décrit comment les classes sont reliées entre elles. • Assertions : documentation de contraintes sémantiques comme les préconditions, les postconditions et les invariants de classes. • Opérations : pour chaque opération, il faudra fournir de la documentation comme les paramètres, le résultat de l’opération et les types correspondants. Derrière cela, la documentation du framework doit décrire différents niveaux d’abstraction pour atteindre un plus grand nombre de développeurs et d’utilisateurs. Nous voulons surtout parler du niveau d’expérience des utilisateurs des « frameworks », car les besoins sont différents pour un utilisateur expérimenté des « frameworks » et celui qui utilise ce concept pour la première fois. Un framework doit contenir [joh, 1992] : • L’objectif du framework • Comment utiliser le framework • L’objectif des exemples d’applications • Le design du framework 2.2.1.1 Objectif du framework La première chose est évidemment de décrire l’objectif du framework, c’est-à-dire quels problèmes peut-il résoudre. Cette section doit vraiment être claire et doit 61
    • explicitement expliquer quel est le problème et quelle est la solution que le framework offre. Nous présenterons cette partie au début de la documentation pour que le lecteur détermine si le framework peu ou non satisfaire ces besoins. Si le framework n’est pas adapté aux besoins, le lecteur doit chercher ailleur donc il n’est pas nécessaire de continuer la lecture de cette documentation. 2.2.1.2 Comment utiliser le framework C’est problablement la partie la plus importante de la documentation pour un utilisateur. Plusieurs développeurs documenteront le framework en détaillant la structure et le fonctionnement de celui-ci sans toutefois expliquer comment nous pouvons nous en servir. Cette section doit donc expliquer, avec la description des classes et des méthodes, comment le framework peut être utilisé. Cette section n’abordera pas le fonctionnement à l’interne du framework. 2.2.1.3 L’objectif des exemples d’applications Les exemples d’application du framework doivent être présent tout au long de la documentation. Il est important, pour un utilisateur, de pouvoir se rattacher à des exemples. Ainsi, il pourra savoir si oui ou non il comprend bien le fonctionnement et l’utilisation de celui-ci. Les exemples peuvent être introduit dans une section spécifique ou tout simplement glissés tout au long de la documentation à des fin d’illustration. 2.2.1.4 Le design du framework La description détaillée du desgin doit contenir la description des classes et leurs relations. Il doit aussi en ressortir les différentes collaborations entre les classes. Les « frameworks » sont généralement de grande collections de classes donc les sutilisateurs prendront un certain temps pour se familiariser. Cependant, gardez toujours en tête que plus le framework est compris, plus il sera réutilisé. 62
    • Nous venons de présenter les différentes sections que la documnetation doit contenir. Maintenant, nous nous attarderons sur des approches de documentation qui ont été développées pour la conception de systèmes orientées objets. 2.2.2 LES APPROCHES COOKBOOK La plupart des utilisateurs de « frameworks » ne sont pas intéressés par les détails de la conception du framework. Ils sont plutôt à la recherche de la documentation qui décrit comment le framework peut être utilisé. Ils sont donc à la recherche de documentation du style « guide de cuisine (cookbook) ». Quelques approches utilisant l’approche cookbook existe dans la litérature [Krasner, 1988][Apple, 1989][Pree, 1994a]. 2.2.2.1 L’approche cookbook « model-view-Controller » La méthophore « model-view-controller » (MVC) tient ses origines de Smalltalk-80 et décrit comment décomposer une application ayant une interface utilisateur. Les trois composantes sont : • Le Modèle qui capture les fonctionnalités du domaine. • La Vue qui affiche l’état de l’application. • Le Controleur qui gère les interactions entre le modèle et la vue. L’approche de documentation commence avec une description de l’implantation de la métaphore MVC. La description est à un niveau très détaillée et présente de nombreux exemples. Les exemples décrivent comment le framework doit être utilisé. La faiblesse de cette approche est qu’elle décrit la voie normale dans laquelle le framework va être utilisé. Il n’y a aucune anticipation sur l’utilité du framework dans le futur. Le cookbook ne peut pas décrire tous les cas d’utilisation du framework car ce n’est pas l’intention de cette approche. 63
    • 2.2.2.2 L’approche cookbook « MacApp » MacApp est une interface utilisateur graphique développée par Apple Inc. Les deux approches, MacApp et MVC, sont des méthodes basées sur l’exemple. La principale différence est que MacApp est comme un livre de recettes où chaque recette résout un problème particulier. L’approche MVC décrivait plutôt la solution générale. La lacune de MacApp est qu’elle n’a pas la capacité de décrire les utilisations imprévues du framework mais, encore une fois, ce n’est pas l’objectif d’un « cookbook ». 2.2.2.3 L’approche cookbook Active Cette approche utilise les metapatterns pour la description des « frameworks » orientés [Pree, 1994a]. Chaque metapattern est rattaché à une partie du framework qui diffère sémantiquement des autres et il décrit de façon détaillée chaque classe et chaque méthode de la sous-partie avec des exemples. Ensuite, le design du framework et les metapatterns sont placés dans un système hypertexte. Le système hypertexte est utilisé comme un cookbook actif qui présente à l’utilisateur les parties du framework qui l’intéresse. 2.2.2.4 Discussion Les approches cookbook sont très lorsqu’il s’agit de présenter l’objectif du framework et de présenter des exemples. L’utilisation du système est bien expliquée et démontrée ce qui favorise l’utilisation rapide du framework. Si, par contre, le framework doit être modifié pour une raison quelconque, ce type de documentation ne nous est d’aucune utilité. La présentation du design et de l’architecture est souvent négligée ce qui force les développeurs à faire une trace du système pour bien comprendre. Finalement, pour utiliser ce genre d’approche, il est indispensable que le développement du framework ait atteint une très grande maturité pour ne pas effectuer des modifications inutiles. 64
    • 2.2.3 LES APPROCHES PAR PATTERN Les patterns existent sous diverses formes et quelques une d’entre elles sont très bien appropriées pour la documentation des « frameworks ». Le design de patterns orientés objets et les Motifs semblent être les deux patterns les plus prometteur pour la documentation. 2.2.3.1 L’approche motif L’approche de Johnson [Joh, 1992] utilise un type de pattern pour la documentation (motif) décrivant l’utilisation d’un framework. Tous les motifs ont une structure commune. Premièrement, une description du problème est formulée suivie par une discussion sur les différentes avenues possibles pour résoudre le problème. La discussion inclut des exemples et des pointeurs vers d’autres parties du framework. Le motif se termine avec un résumé de la solution et différents pointeurs vers d’autres motifs. Pour mieux comprendre la documentation par motif, nous présenterons un exemple de motif définit dans le projet HotDraw. HotDraw est un framework pour l’édition de graphique implanté en Samlltalk. La description du problème se trouve dans le premier motif de Hotdraw. HotDraw est un framework pour structurer les éditeurs de dessins. Il peut être utilisé pour construire des éditeurs spécialisés pour le dessins à 2 dimensions comme les diagrammes shématiques, la musique, le design de progamme, etc. Les éléments de ces dessins peuvent avoir des contraintes entre eux, ils peuvent réagir aux commandes de l’utilisateur et ils peuvent être animés. L’éditeur peut être une application complète ou être une petite partie d’un grand système. Traduit de [Joh, 1992]. Figure 2- 14 : Description du problème du premier motif de Hotdraw Motif 3 : Changement d’attribut d’un élément dessiné Il y a au moins trois voies pour éditer les attributs d’une figure : avec un identificateur (handle), avec un menu associé à la figure, ou avec un outils spécial. Chaque technique est appropriée suivant différents cas. 65
    • Les attributs numériques (taille d’une figure, etc.) seront édités avec un identificateur. Les attributs textuels (nom, date, etc.) seront édités en affichant le texte comme une partie de la figure et en laissant l’usager le modifier avec un « outil texte ». L’utilisation de « l’outil texte » implique que la figure est une « CompositeFigure » (voir Figures complexes (4)). ... Figure 2- 15 : Partie d’un motif du framework HotDraw [Joh, 1992] 2.2.3.2 L’approche de design de Pattern orientés objets Un pattern orienté objet décrit une partie du design. Il n’est pas approprié pour présenter le design entier avec une vue d’ensemble. Une classe dans un framework peut avoir différents rôles dépendemment du nombre de « design patterns » qui lui sont associé. Cela veut dire qu’il est difficile d’identifier les limites entre les différents « design patterns » dans un framework. Cette approche est très utilisée lorsqu’il est important de bien décrire les sections d’un framework avec des diagrammes et du nouveau vocabulaire. Dans certains cas, lorsque le framework offre la possibilité d’être adapté, la documentation par « design pattern » peut être très efficace. 2.2.3.3 Discussion Il est évident qu’une seule technique de documentation décrira généralement un seul aspect du framework. Pour être efficaces, des combinaisons doivent être envisagées lors de la rédaction de la documentation. Les motifs sont très pertinents pout introduire des exemples d’utilisation alors que les « design patterns » décrivent de façon détaillée les modules d’un framework. Habituellement, les design patterns sont utilisés tout au long du développement pour documenter pas-à-pas les modules. Vers les dernières itérations du cycle de vie, on commence à intégrer de la documentation contenant des exemples d’application et d’utilisation (Motif). 66
    • 2.2.4 L’APPROCHE « LANGAGE DE DESCRIPTION DE FRAMEWORKS » Il existe une autre approche proposée par Wilson et Wilson en 1993 qui s’appelle FDL (Framework Description Language). Selon eux, les relations d’héritages, les références et les séquences de création d’objets sont des items nécessaires pour décrire la façon de documenter un framework. Il doit aussi y avoir de l’information qui répond aux questions suivantes : • Quelles nouvelles classes devraient être fournies par le framework ? • Quelles classes devraient être utilisées ? • Quelles opérations sont souvent utilisées ? Suivant ces questions, un framework peut être vu comme un design abstrait qui décrit un concept dans un domaine d’application tout comme une classe abstraite. Cela implique que le développeur de l’application doit, conceptuellement, dériver son application de la classe abstraite qui est le framework. En procédant de cette façon, il faut se demander de quelles opérations nous auront besoin et quelles sont celles que nous devont « overrider » ? Pour répondre à ces questions, un « Framework Description Language » est proposé [Wilson, 1993]. Il s’agit d’un nombre de mots clés avec des entêtes de classe ressemblant au C++ mais appliqué aux « framwworks ». L’implantation des FDL décrit quelles opérations peut ou doit être utilisées ou réécrites dans le framework. Voici le Template d’une interface FDL : framework name  { 67
    •    mustInstanciate :    // Ensemble des classes qui doivent être instanciées       mayInstanciate :    // Ensembles des classes qui peuvent être instanciées    mustSubclass :    // Ensemble des classes qui doivent être des sous-classes    library :    // Ensembles des classes qui sont utilisées à partir d’une     // librairie (Donne de l’information pour le linkage de    // l’application développé).    private :    // Ensemble des classes qui sont internes au Framework. } ; Figure 2- 16 : Interface d’un template FDL Une amélioration à cette approche est d’ajouter un template « Framework Class Description (FCD) ». C’est une variante des entêtes de classe en C++ qui décrivent, pour chaque classe, quelles opérations doit ou peut être réécrites (overridden). Une documentation complète d’un framework décrite par Wilson & Wilson, devrait contenir : • Une description du framework en FDL • Un diagramme de classe • Des exemples de programmes • Des recettes d’utilisation 68
    • Après avoir identifié les principaux points de cette technique, nous sommes en mesure de dire qu’elle est similaire à l’approche des cookbooks à l’exeption du FDL. 2.2.5 CONCLUSION SUR LA DOCUMENTATION Nous avons présenté plusieurs techniques pour la documentation d’un framework qui décrivent bien l’ampleur qu’une bonne documentation peut avoir. Il n’existe pas d’approche miracle ou révolutionnaire pour la documentation d’un framework. La solution réside dans la combinaison de plusieurs méthode afin de fournir le maximum d’information sans toutefois dépenser trop d’argent. Pour un équipe de développeurs, la documentation est rarement une priorité mais ayez toujours en tête que pour mesurer la qualité d’un produit, il faut d’abord l’utiliser. 69
    • 2.3 EXEMPLE Toute cette théorie nous apprend bien des choses mais qu’en est-il vraiment dans l’industrie lorsqu’il s’agit de documentation ? Nous allons vous présenter un exemple de « frameworks » que nous analyserons selon les points suivants : • L’objectif du framework • Comment utiliser le framework • L’objectif des exemples d’applications • Le design du framework Nous allons tout d’abord présenter comment la documentation du framework JTGame répond aux objectifs et ensuite, une analyse de l’approche utilisée sera effectuée. 2.3.1.1 Objectif du framework L’introduction générale de la documentation décrit les différents modules qui composent le framework ainsi que les librairies utilisées. L’objectif est bien expliqué, l’information sur la nouvelle version est présente dans la section features et l’information générale sur le framework (nombre de classes, modules en développement, etc.). 70
    • Figure 2- 17: Introduction générale du framework 2.3.1.2 Comment utiliser le framework La description des concepts et des classes est exceptionnellement illustrée de façon détaillée et modulaire. Dans la Figure 2-18, on nous explique les différents concepts qui se retrouveront dans le framework (ce sont donc les classes qui devront être utilisées). 71
    • Figure 2- 18 : Présentation des concepts du module Dans la Figure 2-19, on entre dans la partie beaucoup plus technique sur l’utilisation des classes du framework (section reference). On y présente les différentes interfaces, les types utilisées, les fonctions, les macros, bref tout ce qui est nécessaire à l’utilisation du module. Chaque classe est détaillée d’une façon exemplaire (Figure 2-20). 72
    • 73
    • Figure 2- 19 : Présentation techniques du module Figure 2- 20 : Description d’une classe du framework 2.3.1.3 L’objectif des exemples d’applications Dans la documentation du framework, des exemples d’application ont été introduit ce qui est de plus en plus souhaité pour les utilisateurs. C’est évidemment un choix judicieux pour la bonne utilisation de ce framework très large et très complexe (environ 150 classes). La documentation contient une section tutorials et samples. La section tutorials présente de façon détaillée un cas d’utilisation du framework en montrant et documentant du code source (un exemple simple). La section samples implante des exemples d’application du framework beaucoup plus difficiles et réels compte tenu que 74
    • les tutoriels servent comme introduction. Nous avons donc beaucoup de ressources à notre disposition pour utiliser le framework judicieusement et rapidement. Figure 2- 21 : Présentation des tutoriels 2.3.1.4 Le design du framework L’architecture du framework est très bien décrite ce qui est assez rare. L’architecture est représentée par des diagrammes de classes qui sont découpées comme le montre la Figure 2-22 : 75
    • Figure 2- 22 : découpage des diagrammes 76
    • Figure 2- 23 : Architecture des classes d’affichage Les relations entre les classes sont très bien décrites ce qui nous donne une vision concrète de ce que nous utilisons. Nous n’avons aucune figure qui nous montre un diagramme de classe complet de JTGame. Le choix qui a été fait repose sur des diagrammes d’objets qui nous montrent bien les relations entre les différents objets. Voici la représentation plus « haut niveau » du framework : 77
    • Figure 2- 24 : diagramme d’objets de JTGame Un niveau beaucoup plus détaillée nous est aussi présenté pour que nous puissions bien comprendre les interactions entre les objets compte tenu que le framework possède environ 150 classes. 2.3.1.5 Analyse de la documentation du framework JTGame À prime abord, nous pouvons affirmer que la techniques de documentation se base sur la combinaison des approches de Pattern (Motifs et design patterns) et cookBook. La documenation nous permet d’utiliser facilement et rapidement le framework ce qui est très typique de l’approche CookBook où la conception du framework ne nous intéresse pas. Ce qui nous fait dire que la technique des patterns a été utilisée, c’est la façon avec laquelle le découpage est effectué (modules->classes->méthodes). 78
    • Ceci dit, la documentation de ce framework est vraiment complète, détaillée, structurée et simple. Une documentation de ce type est très coûteuse et nous pouvons imaginer que les développeurs se sont doter d’outils tel que web++ ou autre pour l’extraction de la documentation du code source en C++. Il est implrtant de considérer ces outils lors du développement car sinon, l’extraction peut être longue et coûteuse. La documentation décrit le design en entier ce qui est typique des « frameworks » gratuit. Les « frameworks » à but lucratif sont généralement moins bien documenté pour ce qui est de la structure et de l’architecture. Nous devons donc conclure en disant que la documentation de JTGame est exemplaire et très bien structurée. Toutes les informations sont présentes et bien présentés. 79
    • 2.4 CONCLUSION Nous avons présenté la réutilisabilité et nous avons vu que pour être en mesure de réutiliser efficacement un framework, il nous faut de l’information utiles. Cette information se trouve dans la documentation qui devrait inévitablement accompagner le framework. Nous avons donc présenté les différentes techniques de documentation et nous avons montré un exemple de documentation qui est, à toute fin pratique, parfaite. La plupart des concepts de documentation tournent autour de ce type de documentation qui présente des exemples, le design, la structure et la description des classes. Avec autant d’information, il devient facile pour un développeur d’utiliser un framework car n’oubliez jamais : « Pour qu’un framework soit utilisé, il doit d’abord être compris » [Perron, 2002] :-). 80
    • 3 FRAMEWORK JAFIMA POUR LES SYSTÈMES AGENT Les agents se retrouvent dans une grande variété d’applications. Le fait qu’ils soient très utilisés à amené plusieurs problèmes. Le premier problème est dans le manque de consensus dans la définition des agents et des différentes fonctionnalités qu’ils possèdent. Un second problème concerne la duplication de l’effort de développement causé par l’absence de techniques générales et du manque de réutilisation. De plus, il y avait une incapacité à satisfaire les besoins industriels d’intégration des agents, qui doivent répondre aux critères de sécurité, à l’intérieur d’infrastructures et de logiciels existants. Finalement, l’incompatibilité entre les différents agents développés confirma que la standardisation des systèmes agent était nécessaire à leur succès. Ces différents problèmes ont donc poussé les gens à développer des frameworks pour les systèmes agents. Plusieurs années de recherche, de développement et d’implémentation de systèmes agents furent nécessaire à l’élaboration de techniques, de méthodologies et d’outils de développement robustes pour les systèmes agents. Le framework étudié dans le cadre du chapitre « A Framewrok for Agent Systems » du livre [Fayad & al] est JAFIMA (Java Framework for Intelligent and Mobile Agents). Étant donnée la nature très diversifiée des agents, ce framework est orienté sur l’architecture. Les classes du framework doivent être adaptées selon l’application, au lieu d’adapter les données au framework. JAFIMA se distingue des autres parce qu’il est plus complet et tient compte de plusieurs aspects relatifs aux différents types d’agents. De plus, il met l’accent sur les problèmes d’intégration mentionnés ci-dessus. JAFIMA fournit une définition détaillée d’un agent qui est suffisamment flexible pour englober les agents simples et sophistiqués, ainsi que les sociétés d’agents. Le design 81
    • d’agent est une architecture en couches, constituées de sous-framework. Le code du framework est en Java. 82
    • 3.1 LE FRAMEWORK D’AGENT EN COUCHE Un agent faible est autonome, social, réactif et proactif et un agent fort ajoute à ces caractéristiques une base de connaissance et peut s’adapter ou apprendre. Un agent peu migrer et un système multi agents est ouvert, c’est-à-dire que les agents peuvent entrer et partir du système n’importe quand. Le framework doit donc tenir compte de ces différents comportements pour que son architecture puisse les supporter. Le modèle architectural d’agent en couche permet d’organiser et de structurer le comportement d’un agent simple ou sophistiqué et de définir la meilleure architecture pour supporter le comportement des agents. L’architecture doit permettre un comportement autonome, social, réactif et proactif. Il est nécessaire que les agents possèdent des senseurs et des effecteurs pour interagir avec leur environnement. De plus, l’architecture doit permettre aux agents la mobilité, la migration, la traduction des différentes ontologies entre les agents et la collaboration selon différentes approches. Les agents doivent être décomposés en couche parce que le comportement de haut- niveau dépend des capacités de plus bas niveau. Aussi, les niveaux dépendent seulement de leurs niveaux voisins et il y a un flux d’information dans les deux sens entre les niveaux voisins. Cette structure permet une bonne encapsulation des différents composants de l’agent. La Figure 3-25 suivante présente le modèle d’architecture d’agent en couche. La première couche est celle du senseur qui permet à l’agent d’obtenir des informations sensorielles de son environnement. La seconde couche est celle des croyances qui sont les modèles que l’agent possède de lui-même et de son environnement. La troisième couche est la couche raisonnement qui permet à l’agent de décider l’action suivante à poser, selon ses buts, ses plans, ses capacités et ses modèles. Ensuite, nous avons la couche d’action qui permet de réaliser les intentions de l’agent. Les intentions sont les plans instanciés de la couche précédente. Les actions en attentes pour l’agent proviennent de requêtes et sont mises dans une file. La couche 83
    • suivante est celle de collaboration. Cette couche détermine comment l’agent collabore avec un autre agent, incluant l’acceptation ou le rejet d’une requête de services. L’avant-dernière couche sert à la traduction. Celle-ci définit la manière de formuler un message pour un autre agent et permet de traduire un message dans une autre langue ou selon une sémantique différente. Finalement, nous avons la couche de mobilité qui permet aux agents de se déplacer dans différents endroits et d’envoyer des messages. Figure 3- 25 : Modèle architectural en couche d’agent La Figure 3-25 montre l’interaction entre les différentes couches selon le processus « Top Down », lorsque l’agent reçoit une requête externe et « Bottom Up » lorsque l’agent prend une décision à partir des informations sur son environnement obtenues par ses senseurs. Lorsque l’agent perçoit des informations sur son environnement, il met à jour ses croyances selon les nouvelles informations perçues. Puis, il raisonne sur ses croyances pour déterminer la prochaine action à effectuer. Les intentions produites par le raisonnement sont mises dans la file d’attente et sont effectuées. L’agent effectue les actions qu’il est capable d’accomplir lui-même. Si, par contre, il ne possède pas la capacité d’effectuer l’action, il tentera de négocier avec d’autres agents par la couche de collaboration. Le message est sera formulé et il sera traduit si les agents utilisent 84
    • différentes sémantiques. Les messages qui ont pour destinataire une société distante sont transmis par la couche de mobilité. Cette couche permet aussi à l’agent de migrer. Comme mentionné précédemment, l’interaction entre les couches se fait également dans le sens inverse. Cette seconde approche permet à l’agent d’obtenir un message distant par sa couche de mobilité. Le message est traduit pour l’agent. La couche de collaboration permet de stocker les contacts et les conversations avec les autres agents et détermine si l’agent doit ou pas traiter le message. Si le message doit être traité, il passe à la couche d’action et lorsque l’action arrive en début de file, elle passe à la couche de raisonnement. Le traitement peut continuer aux couches de croyance et de senseur, dépendamment du type de requête. Lorsqu’un plan est instancié en intention et qu’il est placé dans la liste, les services des couches inférieures ne sont pas requis. Les interactions entre les différentes couches décris ci-dessus montre très bien la puissance du flux bi-directionnel de l’information qu’offre cette architecture. Cette architecture peut bien sûr être adaptée selon les besoins d’un type d’agent spécifique. Par exemple, un agent statique n’aura pas besoin de la couche de mobilité. Certaines sociétés d’agents peuvent partager une couche de collaboration pour tous les agents. Aussi, un agent qui est dans un environnement fixe ne nécessitera pas de la couche senseur étant donnée que sa connaissance de l’environnement ne change pas. Dans cette section, nous avons exploré le framework général. Les sections 3.1.1 à 3.1.7 suivantes présenteront les différents sous-« frameworks » du framework global. 3.1.1 LA COUCHE SENSEUR La couche senseur sert à percevoir l’environnement et à mettre à jour les croyances de l’agent. L’abstraction clé de ce sous-framework est qu’un senseur doit coopérer avec les classes d’interface spécifiques au domaine. La Figure 3-26 montre le design de la couche senseur qui utilise le pattern « Adapter ». Ce sous-framework fournit une interface de senseur abstraite par la méthode Sense(). Le « Sensor Adaptor » doit être 85
    • spécifié selon le domaine par l’utilisateur du framework. Le Sensing Plan » contient une liste des objets externes qui peuvent être perçus. Figure 3- 26 : Diagramme de classes de la couche senseur Le diagramme de séquence de la Figure 3-27montre la séquence d’interaction entre les classes permettant d’aller chercher de l’information sur l’environnement à l’aide des senseurs. L’objet « Sensor » utilise le « SensingPlan » pour savoir quelle information (Belief_Id) doit être retrouvée. L’identifiant de la croyance en question est passé en paramètre à la fonction « Sense » du « SensorAdapter » qui utilise l’interface spécifique au domaine pour aller chercher l’information désirée. 86
    • Figure 3- 27 : Diagramme de séquence montrant l’acquisition d’une croyance par un senseur 3.1.2 LA COUCHE DES CROYANCES La couche des croyances sert à conserver et à maintenir l’ensemble des croyances qu’a un agent sur son environnement. Les croyances peuvent être primitives ou composites. Les croyances composites sont formées de plusieurs croyances primitives. Le design utilise deux patterns, le pattern « Composite » et le pattern « Observer ». La Figure 3-28 suivante présente la structure de cette couche. Elle montre comment la couche de raisonnement observe les croyances. 87
    • Figure 3- 28 : Diagramme de classes de la couche des croyances Le diagramme de séquence de la Figure 3-29 suivante montre comment une information acquise par un senseur permet de mettre à jour la croyance correspondante dans la représentation mentale de l’agent. L’identifiant de la croyance et sa nouvelle valeur sont passés en paramètre via l’interface de la couche des croyances. Cette couche se charge de mettre à jour la valeur, d’avertir les observateurs et d’envoyer la nouvelle valeur à la couche de raisonnement qui doit exécuter un cycle de raisonnement pour déterminer si le changement déclenche un ou des plans d’action. Le diagramme qui suit est semblable au premier, sauf qu’il montre la mise à jour d’une croyance lorsque celle-ci fait partie d’une croyance composée. L’état de la croyance composée doit être mis à jour suite à la modification d’une croyance primitive. 88
    • Figure 3- 29 : Diagramme de séquence pour la mise à jour d’une croyance primitive Figure 3- 30 : Diagramme de séquence pour la mise à jour d’une croyance composée 3.1.3 LA COUCHE DE RAISONNEMENT 89
    • La couche de raisonnement permet à l’agent de déterminer la prochaine action à effectuer. Pour ce faire, le raisonnement interprète les croyances et les requêtes. Pour les agents faibles, la couche de raisonnement ne fait qu’associer une action à un stimulus. Alors que pour les agents fort, la couche de raisonnement est plus sophistiquée, elle renferme des notions mentales qui permettent d’« imiter » le raisonnement humain. Le raisonnement défini des objets pour la grammaire utilisée pour définir des stimuli, des conditions, des buts et des actions desquels sont extrait des expressions et des plans. Les patterns « Interpreter » et « Strategy » sont utilisés par la couche de raisonnement illustrée dans la Figure 3-31 suivante. Les plans d’un agent sont représentés par des expressions et interprétés par le pattern « Interpreter ». « RegularExpression » est un clause générale, « LogicalExpression » implique un opérateur logique et « BeliefExpression » est un symbole terminal qui est un élément de croyance. Figure 3- 31 : Diagramme de classes de la couche de raisonnement 3.1.4 LA COUCHE D’ACTION La couche d’action permet d’exécuter un plan provenant de la couche de raisonnement. Un plan est instancié dans un « thread » « Intention ». Les plans sont spécifiques à l’application et il y en a deux types. Le premier type de plan est « Collaboration Intentions » qui utilise l’interface à la couche de collaboration (Top- 90
    • Down) et le second type de plan est « Reaction Intentions » qui utilise l’interface spécifique à l’environnement (Bottom-Up). La couche d’action est constituée de plusieurs patterns. Le pattern « Command » sert à transformer un plan en une commande. Le pattern « Abstract Factory » crée un objet plan basé sur une librairie donnée. Le pattern « Factory Method » crée les « threads » d’intention dynamiquement. Le pattern « Decorator » Implémente la gestion de priorité des actions. Les patterns « Future » et « Observer » exécutent de façon asynchrone l’invocation d’une méthode par un « thread » d’intention. Finalement, le pattern « Active Object » planifie les actions qui agissent sur l’environnement et les messages ou requêtes de la couche de collaboration à la couche de raisonnement. Les sections 3.1.4.1 à 3.1.4.6 décrivent plus en détail ces différents patterns. 3.1.4.1 Le pattern « Command » Les plans sont le point central de la couche d’action. Ils doivent être organisés dans une file, enregistrés et ils doivent pouvoir être défaits. Un plan spécifie des actions primitives qui doivent être effectuées soit par les effecteurs ou les collaborateurs. La structure d’un plan est l’abstraction clé dans ce pattern. En effet, un plan n’est pas connu d’avance, il l’est seulement à l’exécution, ce qui fait que sa structure doit fournir des opérations de haut-niveau basées sur les opérations primitives. Le pattern « Command » encapsule une requête dans un objet et est utilisée par la couche d’action. La Figure 3-32 présente ce pattern. Figure 3- 32 : Utilisation du pattern « Command » dans la couche d’action Chaque « ConcretePlan » est un objet commande qui implémente l’interface « ActionPlan » déclarant l’opération de haut-niveau Execute. Le récepteur du message est un objet « ConcretePlan » qui est une instance créée dynamiquement selon 91
    • l’information de configuration fournie par l’usager. Chaque « ConcretePlan » utilise des méthodes primitives de « EffectorInterface » dans la méthode Execute. 3.1.4.2 Le pattern « Abstract Factory » Les plans sont très spécifiques à l’application. Le framework doit donc fournir une interface abstraite qui est implémenté par chaque « ConcretePlan ». Chaque application doit fournir un ensemble de classes de plans et chacune de ces classes implémente l’interface « ActionPlan ». Le framework doit donc permettre d’instancier des plans avec des interfaces abstraites de commandes, indépendamment de l’implémentation. Le pattern « Abstract Factory » de la Figure 3-33 permet ce niveau d’abstraction en déclarant une interface qui instancie les « ConcretePlans ». La « ConcretePlanFactory » fournie l’implémentation, qui doit être définie par l’utilisateur du framework, requise pour instancier les plans. L’objet plan est ensuite utilisé par « IntentionThread ». Figure 3- 33 : Le pattern « Abstract Factory » qui instancie les « ConcretePlans » 3.1.4.3 Le pattern « Factory Method » Le pattern « Factory Method » sert simplement à déléguer les responsabilités d’instanciation des objets d’intention aux sous-classes respectives. La sous-classe instanciée est, soit « ReactionIntention », ou « CollaborationIntention », dépendamment du type de « Action Plan ». 92
    • 3.1.4.4 Le pattern « Decorator » Dans les systèmes basés-agents, les « threads » d’intention peuvent partager certaines ressources par exemple, les effecteurs. Les intentions doivent donc posséder différents niveaux de priorité. Lorsqu’un agent commence l’exécution d’un plan, il ne doit pas être arrêté. La gestion de la priorité doit donc se faire avant l’exécution du plan d’action. Cette gestion est effectuée par les objets de la classe « ConcretePrioritizer » et le pattern « Decorator » est utilisé pour affecter dynamiquement des responsabilités supplémentaires à un objet d’intention. La Figure 3-34 montre l’utilisation du pattern « Decorator » dans la couche d’action. Figure 3- 34 : Utilisation du pattern « Decorator » dans la couche d’action Chaque classe « ConcretePrioritizer » peut fournir différentes stratégies de gestion de priorité. Le « ConcretePrioritizer » appelle la méthode « run » de sa classe de base et ajoute la fonctionnalité de gestion de priorité avant ou après cet appel. La gestion de priorité peut être changée à l’exécution via le chargement dynamique de classe de Java, permettant ainsi le chargement et l’instanciation de plusieurs « ConcretePrioritizer ». 3.1.4.5 Les patterns « Future » et « Observer » L’architecture d’un agent nécessite que le « thread » des intentions et celui d’un serveur concurrent soient capable de communiquer de façon asynchrone quand un résultat est retourné du « thread » serveur. Il est donc nécessaire d’avoir un mécanisme 93
    • permettant les communications asynchrones lorsqu’un « thread » termine. Ce mécanisme doit simuler le retour d’une valeur car la méthode « run » de l’interface Java « Runnable » est de type void. Dans le pattern « Future », l’objet « Future » fournie un emplacement pour un résultat qui est attendu dans le futur. Le client exécute une opération asynchrone, « DoOperation », qui instancie un objet « Future » et retourne sa référence. La méthode « read » de la classe « Future » sert de sémaphore en bloquant l’exécution du « thread » si l’objet n’est pas son état de mise à jour. Le « thread » « CoexistingServer » est celui qui met à jour l’objet « Future ». Le pattern « Observer » est aussi utilisé afin que chaque objet « Future » soit observable ou soit un sujet pour les clients qui s’enregistre avec les objets « Futures » reliées. Quand un de ces objets est mis à jour, les observateurs sont informés par l’exécution de la méthode « update » du client et le « thread » suspendu du client reprend sont exécution par cette méthode. 94
    • Figure 3- 35 : Le pattern « Future » et le pattern « Observer » dans la couche d’action 3.1.4.6 Le pattern « Active Object » Les intentions d’un agent agissent concurremment dans différents « threads » de contrôles. Cependant, un objet de l’environnement peut avoir besoin de d’être affecté par l’agent suivant une certaine séquence d’action. Par conséquent, les intentions peuvent invoquer concurremment des méthodes pour affecter l’environnement alors que ces méthodes doivent être exécutées séquentiellement. Il est donc nécessaire qu’un mécanisme gère une file d’exécution des intentions pour que cette exécution soit séquentielle. Les effecteurs étant spécifiques à l’application et très diversifiés, ce framework peut seulement fournir une interface pour les effecteurs. Le pattern « Active Object » permet d’obtenir de remplir ces exigences en encapsulant un appel de méthode dans une méthode d’objet et les plaçant dans une file. Ensuite, il expédie les objets méthodes selon leur priorité. La Figure 3-36 montre le pattern « Active Object » dans la couche d’action. 95
    • Figure 3- 36 : L’utilisation du pattern « Active Object » dans la couche d’action Le pattern « Active Object » est constitué d’une interface client, un planificateur, une file, un objet méthode et une représentation de ressource. Le client utilise l’interface pour envoyer en messages qu’il veut être reçu par la représentation de ressource. Les messages sont encapsulés dans des objets méthodes et le planificateur leur donne une priorité et les place dans la file. Ensuite, le planificateur est en charge d’expédier, selon leur priorité, les objets méthodes à la représentation de ressource. L’« EffectorRepresentation » est l’interface client et un « ActionPlan » utilise ou envoie des messages à cette interface quand il doit modifier l’environnement. L’interface déclare plusieurs méthodes qui sont toutes des souches. La fonctionnalité réelle est fournie dans l’« EffectorRepresentation ». Les méthodes souches dans l’« EffectorRepresentation » instancie un « MethodObject » et le met dans la file en utilisant le « Scheduler ». Le « thread » d’expédition du planificateur exécute la méthode « Call » de chaque « MethodObject » à la file. Cette méthode envoie un message à l’« EffectorRepresentation ». Le diagramme de séquence de la Figure 3-37 suivante présente comment un plan instancié utilise un effecteur et comment le pattern « Active Object » est utilisé pour rendre séquentielle l’exécution d’un plan. 96
    • Figure 3- 37 : Diagramme de séquence pour l’exécution d’un plan 3.1.5 LA COUCHE DE COLLABORATION La couche de collaboration permet de négocier et d’échanger des services entre les agents. Elle détermine comment collaborer et procure différents protocoles de coordination. La couche de collaboration gère les requêtes envoyées, acceptées et rejetées ainsi que les réponses à ces requêtes. Il y a deux types d’approches pour la collaboration. Le premier type d’approches est centralisé et l’autre est décentralisé. 3.1.5.1 La collaboration centralisée La collaboration centralisée est gérée par un médiateur. Dans une société d’agents, chaque agent peut ne pas avoir la connaissance de tous les autres agents. Le médiateur 97
    • permet à des agents de collaborer même s’ils ne se connaissent pas directement. Le médiateur permet d’éviter de créer des interconnections et des dépendances, entre les agents, qui rendent la complexité plus grande et compliquent la maintenance et la réutilisabilité. 3.1.5.2 La collaboration décentralisée Dans la collaboration décentralisée (l’approche du framework étudié), les agents collaborent directement entre eux. Ils doivent garder des connaissances sur les autres agents et sur leurs capacités. Ils doivent communiquer via des messages structurés suivant les protocoles de communication. Les agents doivent aussi maintenir l’état de chaque conversation ou négociation pour éviter les boucles infinies. Ce type de collaboration est beaucoup plus complexe que l’approche centralisée. Le sous- framework est encore en développement. La couche de collaboration est composée de plusieurs patterns. Le pattern « Synchronized Singleton » gère les « threads » de collaboration pour centraliser le point d’accès. Le pattern « Decorator » change le comportement d’un « thread » dynamiquement afin qu’il puisse envoyer ou recevoir des messages. Le pattern « Active Object » planifie les requêtes envoyées par la couche d’action. Le pattern « Future » permet la combinaison avec l’observateur pour invocation de méthodes asynchrones. Le pattern « Strategy » sert à convertir un message dans le langage de l’agent destinataire. 3.1.5.2.1 Le pattern « Synchronized Singleton » La couche de collaboration permet plusieurs communications en même temps, cette couche est donc « multi-threads ». Il est nécessaire d’avoir un seul point d’accès pour qu’un « thread » soit en mesure de gérer un message. Chaque « thread » doit être maintenu et géré par un seul objet. Le pattern « Synchronized Singleton » est donc utilisé pour ces raisons. La Figure 3-38 suivante montre comment un seul objet de cette classe peut être instancié. En Java, les variables statiques sont partagées par toutes 98
    • les instances de la classe. Pour limiter à une seule instance, le constructeur vérifie donc que la variable statique n’est pas initialisée avant de créer une nouvelle instance. Ce mécanisme permet de savoir si une instance existe déjà ou non et de créer une instance seulement si aucune instance n’a déjà été crée. Figure 3- 38 : Le pattern « Synchronized Singleton » 3.1.5.2.2 Le pattern « Decorator » Les agents peuvent jouer le rôle de client et de serveur lors d’une même communication, dépendant des requêtes effectuées. Pour qu’un « thread » puisse envoyer et recevoir des messages, il est nécessaire de fournir des types de « threads » spécialisés, que sont les connecteurs et les accepteurs. Le pattern « Decorator » présenté dans la Figure 3-39 est utilisé pour attacher dynamiquement des responsabilités supplémentaires à un objet. 99
    • Figure 3- 39 : Le pattern « Decorator » dans la couche de collaboration La classe abstraite « Command » est redéfinie en trois sous-classes « AcceptorCommand », « ConnectorCommand » et « DecoratorCommand ». « AcceptorCommand » traite un message reçu par la méthode « execute ». La même méthode est utilisée par « ConnectorCommand » pour envoyer un message. « DecoratorCommand » contient une instance de sa classe de base utilisé pour stocker les accepteurs et les connecteurs. La méthode « execute » du « DecoratorCommand » exécute la méthode « execute » du « AcceptorCommand » ou du « ConnectorCommand » contenu. La sous-classe « ConcCommandDecorator » permet à l’utilisateur du framework d’ajouter des comportements supplémentaires au « thread ». L’utilisateur pourrait, par exemple, définir un algorithme d’authentification. Lorsque le « CollabThread » instancie un « ConcCommandDecorator », il passe un objet « Command », accepteur ou connecteur, au constructeur. 3.1.5.2.3 Les patterns « Active Object » et « Future » La « CollaborationInterface » gère l’ensemble des activités de la couche de collaboration. La couche d’action peut envoyer plusieurs messages concurremment à la couche de collaboration. Par contre, la « CollaborationInterface » peut nécessiter que la réception des messages de la couche d’action soit séquentielle. Il faut donc que la 100
    • méthode pour envoyer des messages de la « CollaborationInterface » puisse être appelée concurremment, mais que l’exécution des méthodes puissent être effectuée séquentiellement. La « CollaborationInterface » doit donc gérer la réception, l’insertion et l’enlèvement de messages de la file ainsi que l’envoie des messages. Un message envoyé peut être soit une requête pour commencer une nouvelle conversation ou une réponse à une conversation précédente. L’agent doit être capable de communiquer suivant plusieurs dialectes et protocoles, tel KQML, COOL et ACL. Le « thread » d’intention doit attendre la réponse de l’autre agent et doit pouvoir stocker ce message. Le pattern « Active Object » permet de résoudre les problèmes de synchronisation et de concurrence. Le pattern « Future », pour sa part, résout le problème de l’attente d’une réponse. La Figure 3-40 suivante présente le design de l’interface de collaboration. Pour la « CollaborationInterface », l’interface de « Active Object » a été modifiée pour qu’elle retourne un objet « Future » pour chaque « thread » d’intention. Le « FutureMesg » permet de stocker le message attendu par le « thread » d’intention. La « CollabInterface » fournie l’interface pour les « threads » d’intention de la couche d’action. Lorsque la méthode « collaborate » de la « CollabInterface » est appelée, celle- ci appelle la méthode « collaborate » du « CollabScheduler » qui construit un objet « Message » et « FutureMesg ». Le Message est mis dans la file « ActivVector » and l’objet « FutureMesg » est retourné au « thread » d’intention. Il y a une relation observateur-observable entre l’objet « FutureMesg » et le « thread » d’intention qui permet d’avertir le « thread » d’intention lorsque l’objet « FutureMesg » est mis à jour (voir section X.2.4.5). Lorsque la « CollabInterfaceRep » est disponible, un « Message » est enlevé de la file par le « CollabScheduler » et il est envoyé à la « CollabInterfaceRep ». 101
    • Figure 3- 40 : Design de l’interface de collaboration 3.1.5.2.4 L’interface de représentation de la collaboration et le pattern « Strategy » La Figure 3-41 montre le design de l’interface de représentation de la collaboration. La « CollabInterfaceRep » commence par vérifier l’identificateur de session pour déterminer si c’est une nouvelle session ou une session existante. Ensuite, elle délègue le message à « NewReqHandler » ou « ReplyAckHandler », selon que la session est nouvelle ou pas. Le « NewReqHandler » détermine quel agent peut remplir la requête et crée le « sessionID » et le « ReplyAckHandler » obtient le message en utilisant le décomposeur. Ensuite, la « CollabInterfaceRep » obtient trouve le protocole de l’agent destinataire via l’« InformationRepository », compose le message suivant ce protocole et envoie le message, le « futureID » et le « sessionID » au « MessageHolder ». Le « MessageHolder » est utilisé pour ne pas perdre le message dans le cas où le « ThreadPool » n’aurait pas de « thread », en attente, pouvant gérer le message. 102
    • Figure 3- 41 : Design de l’interface de représentation de la collaboration L’interface précédente permet l’envoie de messages. Maintenant, il faut d’autres objets pour accepter des messages. Les classes permettant de recevoir les messages sont présentées dans la Figure 3-42 suivante. Figure 3- 42 : Réception de message dans la couche de collaboration L’objet « Acceptor » comprend un port qui écoute constamment pour les requêtes de connections. Lorsqu’il reçoit une requête, l’accepteur envoie celle-ci à l’objet « MessageHolder » et retourne en attente d’une autre requête. Le « MessageHolder » demande un « thread » au « ThreadManager » pour traiter la requête. Quand l’« AcceptorCommand » reçoit un message d’un autre agent, il vérifie le « sessionID ». S’il y a un sessionID, la table de hachage « SidFuture » est vérifiée pour stocker le message dans le « Future » correspondant. S’il n’y a pas de « sessionID », l’« Acceptor » en crée un et envoie le message à la couche d’action. Lorsque la 103
    • « CollaborationInterface » envoie un message à l’objet « ConnectorCommand », elle insère un nouveau « sessionID » dans la table de hachage « SidFuture ». Le « ConnectorCommand » utilise l’« InformationRepository » pour trouver le port d’écoute de l’agent destinataire. Les diagrammes de séquence des Figure 3-43 et Figure 3-44 suivantes présentent la réception et l’envoie d’un message par la couche de collaboration présentée ci-dessus. Figure 3- 43 : Diagramme de séquence montrant l’assignation d’un message entrant à un « CollabThread » 104
    • Figure 3- 44 : Diagramme de séquence montrant comment un message sortant est stocké dans un « MesgHolder » et passé à un autre agent 3.1.6 LA COUCHE DE MOBILITÉ La couche de mobilité est partagée par plusieurs agents et sociétés d’agents. Elle permet la migration virtuelle en fournissant une transparence de la localité entre les agents qui collaborent et qui peuvent se retrouver sur différentes plateformes. Elle permet aussi la migration réelle en fournissant un framework pour cloner un agent dans un autre environnement. La Figure 3-45 montre l’architecture de la couche de mobilité qui est basée sur le pattern « Broker ». 105
    • Figure 3- 45 : Architecture de la couche de mobilité Les abstractions clés de cette couche sont les suivantes. Le « Client Proxy » s’occupe du service des requêtes, sert de chargeur de classes ainsi que de server proxy pour les couches inférieures, permettant la transparence de la localité. Le « Remote Configurator » permet la migration réelle en clonant un agent dynamiquement d’une façon qui peut être spécifique à la destination. Le « Broker » est l’objet central. Chaque objet agent, « Client Proxy » et « Remote Configurator » est enregistré par le « Broker » qui fournie aussi le bus de transactions interagents. L’« Information Repository » stocke l’information sur les objets enregistrés. La couche de mobilité est basée sur les patterns suivants. Le pattern « Factory Method » qui permet d’instancier les « handlers » de la migration virtuelle et réelle à l’exécution. Le pattern « Active Object » est utilisé pour partager les ressources, telle l’« InformationRepository ». Le pattern « Visitor » sert à la configuration distante. Finalement, le pattern « Proxy » est utilisé pour des aspects de la migration virtuelle. Le présent rapport ne détail pas plus ces différents patterns, étant donné que cette couche n’est pas nécessaire à toutes les applications. 106
    • 3.1.7 LE SOUS-FRAMEWORK DE CONFIGURATION ET D’INTÉGRATION D’AGENT Les patterns « Agent Builder » et « Layer Linker » sont utilisés pour la création d’un agent qui consiste en la création des différentes couches et en l’intégration de ces couches. 3.1.7.1 Le pattern « Agent Builder » La création d’un agent doit être un processus isolé pour que le même processus puisse générer différentes structures d’agent (fort, faible…). L’« AgentCreator » permet cela en prenant les détails de la configuration désirée par l’utilisateur et en instanciant le « Creator » avec sept objets « Configurator ». Les objets « Configurator » créent la structure de chaque couche selon l’information fournie sur la configuration. La Figure 3-46 montre le pattern « Agent Builder » qui permet d’isoler le processus de création d’un agent. Figure 3- 46 : La création des différentes couche de l’agent par le pattern « Agent Builder » 3.1.7.2 Le pattern « Layer Linker » Le pattern « Layer Linker » veille à la liaison des couches par leurs interfaces, tout en assurant qu’elles sont bien encapsulées. Chaque « Configurator » crée un objet 107
    • « Façade » ainsi que d’autres objets formant la structure demandée par l’utilisateur du framework. Le pattern « Façade », montré à la Figure 3-47, fournie une interface unifiée simple pour chaque couche et permet l’encapsulation des couches. Le pattern crée l’interface entre les couches voisines. Puis, le « Configurator » enregistre ces interfaces dans l’objet « LayerBConfigInfo ». Finalement, cette information est utilisée à la phase d’intégration pour obtenir la référence aux objets « Façade » qui est effectué par la méthode « integrate » de l’objet « Creator ». Figure 3- 47 : Design du pattern « Layer Linker » 108
    • 3.2 CONCLUSION SUR LE FRAMEWORK POUR LES SYSTÈMES AGENT Ce framework apporte une excellente contribution dans le domaine des systèmes agent. Cette contribution se situe non seulement au niveau du design et du développement mais, aussi pour la compréhension de tels systèmes. De plus, il montre que plusieurs patterns sont très utile pour arriver à construire un tel framework, facilitant ainsi des modifications et des ajouts futures. Comparé à d’autres framework pour des systèmes basés agents, tels que « KAoS », « Concordia », « ZEUS » et « dMARS », « JAFIMA » est le seul qui comprend toutes les couches nécessaires pour englober tous les types agents. Pour ce qui est des autres framework, ils ont soit des lacunes au niveau d’une couche ou plusieurs couche ou encore, ils se concentrent sur quelques couches seulement. Il est peut probable que ce framework soit totalement parfait pour le développement d’agent dans toutes les applications possible. Mais, le fait qu’il soit très modulaire permet de faciliter les modifications nécessaire, voir même le remplacement total d’une couche. Pour remplacer une couche, il suffit d’en créer une possédant les interfaces inter-couches requises, en s’assurant de la compatibilité avec le sous- framework de configuration et d’intégration d’agent. Par contre, le fait que le code est en Java pose certains problèmes mais, la structure pourrait assez facilement s’adapter en C++. Finalement, comme il a été mentionné au début du présent rapport, le framework JAFIMA est encore en développement. Ils veulent fournir les « proxies » et les effecteurs afin de standardiser le tous. Ensuite, il serait intéressant d’utiliser une base de données orientée objet pour représenter les croyances. Aussi, la collaboration des agents est un domaine de recherche très actif dans la gestion de conflits et d’opportunités. Le modèle de collaboration de JAFIMA est beaucoup trop simpliste 109
    • pour plusieurs applications. La couche de traduction reste à développer et demandera une quantité énorme de travail et de standardisation, a un tel point qu’elle semble irréaliste étant donnée que les dialectes et les protocoles change d’une application à l’autre. La couche de mobilité nécessite elle aussi de plus de travail au niveau de la compatibilité de CORBA pour la migration virtuelle ainsi que sur la sécurité 110
    • CONCLUSION 111
    • BIBLIOGRAPHIE [Apple, 1989] Apple Computer Inc. (1989) : MacAppII Programmer’s Guide. [Karl, 1995] Even-André Karlsson (1995) : Software Reuse, A Holistic Approach. John Wiley & Sons. [Landin & Niklasson, 1995] Niklas Landin & Axel Niklasson (1995) : Development of Object-Oriented Frameworks. Thèse de Lund Institute of Technology, Lund University, Sweden. [Nato, 1991] Nato Communications and Information Systems Committee (1991) : Software Reuse in NATO. 112
    • [Kirk, 2001] Douglas, Kirk (2001) : Framework reuse : Process, Problems and documentation. University of Strathclyde, UK. [Krasner, 1988] G. E. Krasner, S. T. Pope (1988) : A Cookbook for Using the Model-View-Controller User Interface Paradigm in Smalltalk-80. Journal of Object-Oriented Programming, Vol. 1, No. 3. [Joh, 1991] Ralph E. Johnson & Vincent F. Russo (1991) : Reusing Object-Oriented Designs. University of Illinois tech. report UIUCDCS 91-1696. [Joh, 1992] R.E. Johnson (1992) : Documenting Frameworks with Patterns, Proceedings of the 7th Conference on Object-Oriented Programming Systems, Languages and Applications, Vancouver, Canada. 113
    • [Lin, 1990] J.L. Lindskov-Knudsen, G. Hedin, B. Magnusson, R.H. Trigg, E. Sörensen- Sandvad (1990) : Documenting Object Oriented Systems, Proceedings of the Nordic Workshop on Programming Environments Research, Editors O. Solberg, A. Venstrand, Trondheim, Norway. [Pree, 1994a] W. Pree (1994a) : Framework Adaption via Active Cockbooks and Framework Construction via Relations. Demonstration Paper, The 8th European Conference on Object-Oriented Programming, Bologna, Italy. [Wilson, 1993] D. A. Wilson, S. D. Wilson (1993) : Writing Frameworks - Capturing Your Expertise About a Problem Domain. Tutorial notes, The 8th Conference on Object-Oriented Programming Systems, Languages and Applications, Washington. 114
    • [Jacobson et al.92] : Ivar Jacobson et al., 1992 : « Object-Oriented Software Engineering, A Use Case Driven Approach », Addison-Wesley. [Johnson, Foote 91] : Ralph E. Johnson, Brian Foote, Juin/Juillet1991 : « Designing Reusable Classes ». Journal of Object-Oriented Programming. [Johnson, Russo 91] : Ralph E. Johnson, Vincent F. Russo, 1991 : « Reusing Object-Oriented Designs ». University of Illinois tech. report UUIUCDCS 91-1696. [Karlsson 95] : Even-André Karlsson, 1995 : « Software Reuse, a Holistic approach », John Wiley & sons. [Landin, Niklasson 95] : Nicklas Landin, Axel Niklasson, 1995 : « Development of Object-Oriented Frameworks ».Thesis. [Mattsson 96] : Michael Mattsson, 1996 : « Object-Oriented Frameworks ». Thesis. [Meyers 88] : Ware Meyers, 1988 : « Interview with Wilma Osborne ». IEEE Software 5(3) : 104-105. 115
    • [Taligent 94a] : Taligent, 1994 : « Building object-oriented frameworks ». Taligent Inc. [Taligent 94b] : Taligent, 1994 : « Leveraging object-oriented frameworks ». Taligent Inc. Fayad Mohamed E., Schmidt Douglas C. & Johnson Ralph E., (1999) Implementig Application Frameworks : Object-Oriented Frameworks at Work. Wiley Computer Publishing. 116