Site Web Thierry Cros
Objets et Interactions
| Accueil | Extreme Programming | UML, Objet | Formation | Consulting | Liens | Contact |

 

Ce court papier a pour but de présenter les interactions entre objets, l'intérêt des diagrammes d'interactions dans un développement, les dangers d'une sous-utilisation de ces diagrammes. Il s'adresse en particulier

  • aux personnes qui découvrent depuis peu les joies de l'approche objet
  • à tous les utilisateurs de ces concepts qui voient dans le diagramme de classes l'outil idéal pour la conception de systèmes
  • ou bien qui ne voient pas l'intérêt des diagrammes d'interaction et de collaboration en particulier
  • ou même qui n'en viennent pas à bout.



Contenu

Quelques rappels
Typologie de diagrammes
Une démarche objet "Canada Dry"
Interactions en analyse et conception
Conclusion


Quelques rappels

Un objet est un élément distinct et insécable dans un système, qui possède un état et un ensemble de comportements. Un objet assume une responsabilité dans le système.
Il reste à préciser les termes état, comportement et responsabilité. Les définitions classiques (dictionnaire) sont généralement à prendre avec circonspection. Ici elles s'appliquent, je crois, tout simplement aux concepts informatiques. Etat est à prendre au sens classique, patient dans un état stationnaire, appareil en mode réglage, avion en vol...
Comportement est à prendre au sens : ce que l'objet veut bien montrer de ses opérations. Une voiture offre un comportement visible qui est un déplacement grosso modo horizontal. A l'intérieur, les opérations qui permettent d'obtenir ce comportement visible correspondent à de nombreux déplacements, en particulier les pistons qui bougent plutôt verticalement, les bielles qui transforment ce mouvement linéaire en mouvement rotatif ... Et plus simplement à une opération qui pourrait être tournerMoteur(). Le comportement est finalement la partie visible de l'iceberg. Plus tard, les opérations sont réalisées, mises en oeuvre dans les méthodes.
Les responsabilités des objets forment une excellente approche de ce qu'est un système : découvrir le rôle spécifique des objets dans le système. Exemple de responsabilité : un frein a pour rôle de ralentir un véhicule au point de l'arrêter.
Cette définition (état, comportement, responsabilité et identité) met l'accent sur la nature intrinsèque de l'objet et non pas sur sa structure en programmation : attributs, méthodes. Un objet joue un rôle dans un système. Que ce rôle soit assuré au moyen d'attributs ou d'opérations est une question de raffinage. Certains analystes, par exemple, préconisent de traduire - en analyse - un attribut :
x de type T qui doit être accédé par des méthodes setx(const T) et getx() : T
par simplement une visibilité "public" sur l'attribut et non plus les deux opérations d'accès. En résumé, un objet est plus qu'une structure à laquelle on "colle" des fonctions.

L'autre définition essentielle en objet est celle d'interaction ou de message qui matérialise l'interaction. Certains langages n'aident pas forcément à la compréhension de ce qu'est une interaction. Prenons le cas de C++. Supposons la classe Compte :

Class Compte {
public :
Créditer(float montant); // En euros
};

Si nous instancions cette classe, nous pouvons écrire :

Compte le_compte;
le_compte.Créditer(1000);
Compte *pointeur_compte = &le_compte;
pointeur_compte->Créditer(2000);

Le premier appel à Créditer(), qui a pour but de demander à l'objet de se créditer de 1000 euros, est en pratique un appel de sous-programme. Mais, d'un point de vue objet, il est le support d'un message envoyé à l'objet 'le_compte'. Il faut donc lire : j'envoie le message Créditer avec un flot de données qui est 1000 euros, à l'objet 'le_compte'. La deuxième syntaxe, basée sur le pointeur 'pointeur_compte' repose sur l'opérateur -> du C, qui offre visuellement une meilleure idée de ce qui se passe : toujours l'envoi d'un message. Ici, nous pourrions lire : objet pointé par 'pointeur_compte', je t'envoie le message Créditer avec un flot de données qui est 2000 euros. Dans tous les cas, l'objet destinataire déclenche une méthode en réaction à la réception du message. Là encore, ce type de syntaxe correspond simplement à un cas particulier d'envoi de message : il se trouve que la méthode déclenchée par le premier message est exactement Créditer() de la classe considérée. Les noms de message et de méthode déclenchée par la réception coïncident. Mais supposons maintenant que l'objet 'le_compte' est instance d'une sous-classe de Compte. De plus la fonction membre Créditer() devient virtuelle, autrement dit polymorphe. Dans ce cas, le pointeur de Compte pointeur_compte a toujours la possibilité de pointer vers le_compte. Mais l'envoi du message Créditer() déclenche une méthode qui est celle de la véritable classe de le_compte. Autrement dit, via la liaison dynamique du C++, le nom du message (qui dépend complètement de la sur-classe) déclenche une méthode qui n'est plus celle de la sur-classe. La restriction réside dans le fait que le polymorphisme suppose une signature identique pour toutes les versions de la fonction membre virtuelle, donc en particulier même nom. Mais cet exemple simple montre que, même en C++, l'envoi d'un message ne doit pas être confondu avec le traitement du message qui est l'exécution d'une méthode. Dans cet ordre d'idée, les interfaces graphiques sont un bon exemple de système objet. En effet, les messages sont des événements graphiques tels que clic souris, les méthodes déclenchées sont réellement des fonctions membres des objets graphiques. Ici, on distingue donc mieux message envoyé à l'objet et méthode déclenchée par l'objet en réaction à l'arrivée de ce message.

La notation UML offre les représentations d'objets et de messages. Ces représentations (rectangle pour un objet, flèche pour un message) sont regroupées dans des diagrammes de base proposés par UML, les diagrammes d'interaction qui sont :

  • Diagrammes de Collaboration
  • Diagramme de Séquence.

J'ajouterai le diagramme d'activités qui, à mon humble avis, s'apparente plutôt à un diagramme d'interaction qu'à un diagramme Etat/Transition. Enfin, le diagramme d'objets est finalement un diagramme de collaboration... sans collaboration. Les trois premiers diagrammes cités (collaboration, séquence, activité) sont relativement interchangeables. Chacun met l'accent sur une vision particulière de l'interaction modélisée. Le diagramme de séquence met visuellement l'accent sur le temps, qui coule de haut en bas du diagramme. Ce qui frappe l'oeil à la lecture de ce type de diagramme, c'est la chronologie des messages échangés. Le diagramme de collaboration met à l'inverse l'accent sur le côté spatial : les objets eux-mêmes. C'est peut-être pour cela qu'ils ont une réputation de diagramme "difficile" : les diagrammes de collaboration imposent une vision objet. C'est là que l'on est face visuellement face aux objets. Ceci étant vous noterez que le diagramme de séquence montre aussi les objets. Enfin, le diagramme d'activité est en quelque sorte un compromis synthétique des deux. Il montre plusieurs objets (les swimlanes), les messages entre les objets et les opérations déclenchées par la réception des messages. Choisir tel ou tel diagramme est donc, au-delà de leurs spécificités, un peu une affaire de goût. 


Typologie de diagrammes

L'objectif n'est pas de créer une n-ième terminologie mais simplement de voir quelle est la finalité des différents diagrammes.

Le diagramme de cas d'utilisation joue un rôle particulier car il n'est pas constitué d'objet mais de classificateurs : acteurs et cas. Il traduit les fonctions du système.

Les diagrammes de déploiement et de composants représentent par nature les éléments physiques du système tels que : matériels, fichiers source ... Ces deux diagrammes sont d'ailleurs intimement liés et un diagramme de déploiement contient aussi bien des noeuds que des composants.

Les autres diagrammes représentent les éléments logiques. Les diagrammes d'interaction - collaboration et séquence - d'activité et d'objets ont un point commun. Ils sont dessinés dans le cadre d'un scénario particulier. Ils sont un outil d'étude du système. Au contraire, les diagrammes de classe et d'Etat/Transition sont une compilation de différents diagrammes d'objets. A ce titre, ils sont indispensables pour comprendre le système. Ils en forment la synthèse : aspects structurel et dynamique du système.

Il reste les diagrammes que chacun peut créer à partir des formalismes UML. Par exemple, un diagramme "de classes" qui ne contiendrait que les paquetages (catégories) de classes d'analyse ou de conception et qui représente donc l'architecture logicielle.


Une démarche objet "Canada Dry"

Venons-en maintenant à la mise en pratique. Supposons une démarche qui est :

  • Obtenir les structures (au sens C)
  • Obtenir les fonctions qui manipulent ces structures
  • Dessiner dans des rectangles qui ont trois compartiments : le nom de la structure, les champs de la structure et finalement les fonctions de manipulation.

Les deux premières étapes peuvent être confondues. A première vue, le résultat est un diagramme de classes. Mais est-ce vraiment le concept de classe, autrement dit de regroupement d'objets identiques qui est représenté ? Certainement pas, un diagramme de classes n'est pas toujours le résultat d'une analyse objet. Ici, l'étape qui consiste à obtenir les objets a été ignorée. De ce fait, les classes sont obtenues "à l'aveuglette". Cette démarche est plutôt ici une décomposition en modules. Surtout, la dynamique inhérente à l'objet est délaissée et plus tard (lorsque, en conception, il faudra bien finir par établir le dialogue entre objets pour les programmer) les relations entre objets au sens échange de messages seront difficiles à détecter. Ce type de démarche (ici un brin caricaturale) est l'un des pièges de OMT qui propose d'obtenir d'abord le diagramme de classes puis d'injecter les opérations. Si ce type d'approche permet de transiter vers l'objet, et ce n'est pas le moindre mérite de OMT qui continue d'évoluer aujourd'hui, il existe désormais des process plus "objet". Je crois que distinguer trop tôt attributs et opérations n'est pas un signe flagrant d'approche objet. Se préoccuper tout de suite des attributs est plus une démarche "classe" voire "données" qu'objet. D'un autre côté, découvrir les   comportements au travers de scénarii, et en particulier les modificateurs (mutators) qui font évoluer l'état de l'objet, paraît plus en conformité avec le concept d'objet au sens dynamique en particulier. Ce type de démarche basé sur les classes donc "objet Canada dry" est risquée car elle dénote une préférence pour la composante statique du système et non pas la composante dynamique. Or, c'est la dynamique qui est l'essence même du système. Dans le cas d'une voiture, une fois que l'on a pu s'extasier devant la beauté de la carrosserie ou de l'architecture moteur, c'est au volant en conduisant, finalement dynamiquement, que le système révèle ses qualités et son avantage pour l'utilisateur. Le diagramme de classes est là pour synthétiser l'aspect structurel. C'est un peu la différence entre une photographie et un film.


Interactions en analyse et conception

Les diagrammes d'interaction, y compris les collaborations sont utiles dès la phase d'analyse.
Première idée forte : il vaut mieux détecter les objets du système petit à petit au travers de différents scénarii - depuis les cas d'utilisation - et ensuite regrouper les objets (en classes) dans des diagrammes de classes partiels (qui vont se compléter les uns les autres), plutôt que de tenter d'obtenir le diagramme de classes directement et de façon plus ou moins intuitive. Nous savons que "les substantifs sont de bons candidats". Est-ce que cela aide vraiment ? Même si le diagramme ainsi obtenu est fondamentalement correct, cette modélisation correspond-elle aux besoins ? Comment en être sûr ? Quelle est la traçabilité depuis les cas d'utilisation ?
Par ailleurs, pourquoi brûler l'étape qui consiste à découvrir les objets du système avant de les regrouper en classes ? En dernière analyse, le système est constitué d'objets, pas de classes. C'est une vision réaliste du système. Par ailleurs, les objets s'échangent des messages, pas les classes. Autrement dit, d'un point de vue purement formel, il est naturel d'échanger des messages entre objets dans des diagrammes d'interactions, qui sont justement prévus pour cela. Au contraire, un diagramme de classes contient des relations intrinsèquement permanentes : associations, héritage. Ce type de diagramme n'est donc pas prévu pour restituer des scénarii. De même, un diagramme de cas d'utilisation contient - entr'autres - des "classificateurs" ou types : acteurs et cas d'utilisation, et des associations entre acteurs et cas. Là encore, il n'est pas possible d'indiquer des échanges d'information. L'association est une relation permanente entre classificateurs. L'acteur est d'ailleurs ici confondu avec le rôle du classificateur.

Voyons maintenant la démarche d'analyse générale suivante, qui suppose un première modélisation des besoins en cas d'utilisation. Notez que les cas n'ont pas à être exhaustifs pour démarrer l'analyse.

  • Identifier les scénarii pertinents à partir des cas d'utilisation
  • Les étudier au travers de diagrammes de séquence qui montrent simplement les interactions entre un objet de type acteur et un objet qui représente le système, si cela vous semble utile. Quelquefois, ce type de diagramme de séquence n'offre pas une valeur ajoutée significative dans la mesure où ils restituent simplement les échanges décrits dans les cas
  • Identifier les objets collaborants grâce à des stéréotypes tels que ceux de Unified Process (par ex) et pour cela dessiner "obligatoirement" les diagrammes de collaboration (ils ont le mérite d'être centrés sur les objets, pas le temps qui passe ! ).
  • Regrouper les objets dans des diagrammes de classes partiels.
  • Au fur et à mesure, regrouper et organiser les diagrammes de classes partiels en paquetages (catégories) pour obtenir l'architecture logicielle. Maintenir le diagramme des paquetages de classes.

Cette démarche a pour avantage d'une part de penser le système en terme d'objets (et non plus en terme de classes, encore une fois, le système contient des objets pas des classes), d'autre part de s'en tenir aux objets réellement pertinents pour les besoins. D'où la deuxième idée forte qui est une question essentielle : quels sont les objets du système qui collaborent au scénario ? Quels messages échangent-ils ? D'où les diagrammes de collaboration. Ils permettent de dessiner les objets, donc de les visualiser. A partir de là, il est plus facile de se poser des questions telles que : quelle est la demande que tel objet envoie à tel autre pour participer au scénario ? Cela suppose une idée générale des responsabilités des objets. Certains (pas tous) diagrammes d'interactions seront ensuite jetés car ils n'ont plus d'intérêt une fois que l'étude est accomplie. Les diagrammes de classes représentent alors la synthèse - nécessaire - de différentes collaborations. UML version 1.3 propose un quatrième compartiment dans le formalisme de représentation de classes. Ce quatrième compartiment permet de décrire les responsabilités des classes. Ils peuvent être renseignés dès le départ, les attributs et opérations sont alors une traduction des rôles de la classe ; ou bien ils peuvent être remplis après l'obtention des attributs et opérations, ils permettent alors de vérifier la cohérence de la classe : chaque attribut ou opération est-elle cohérente avec les responsabilités ?

En conception, les interactions ont de nombreuses utilisations. Premièrement, les échanges entre objets de conception (qui tiennent compte -eux - des impératifs d'implémentation) seront réglés par ce type de diagramme. Les échanges physiques entre composants (process) ou bien entre noeuds (machine cliente, machine serveur par exemple) peuvent aussi être étudiés, mis au point, finalement représentés par des diagrammes d'interaction. Imaginez une documentation des IPC d'Unix (ou de tout autre mécanisme d'échange entre process tels que le protocole TCP par exemple). Un bon diagramme de séquence ne serait-il pas le bienvenu pour appréhender plus rapidement le fonctionnement de ces systèmes ?


Conclusion

Grâce à une approche graduelle à partir des scénarii, dont le résultat est un ensemble de diagrammes d'interactions synthétisés dans des diagrammes de classes (et d'état/transition), l'analyse et la conception objet ne relèvent plus des travaux d'Hercule. Au contraire, le système se construit progressivement, cas d'utilisation après cas d'utilisation. Surtout, vous pouvez tracer naturellement les besoins, au moyen du stéréotype <<trace>> prévu de base dans UML. En tenant compte des responsabilités des différents objets qui doivent être à la fois limitées (pas de classe avec une dizaine de responsabilités par exemple) et cohérente entre elles (d'où la nécessité de séparer l'interface utilisateur des objets métier par exemple), vous devriez obtenir une conception qui ne sera peut-être pas optimum mais qui aura su éviter les pièges les plus grossiers.

Les interactions constituent une clé du rapprochement informatique / systémique. Plus généralement, ce concept d'interaction ou en clair de "relation dynamique" est inhérent à toute science ou toute technique. Les physiciens emploient les termes de :

  • interaction gravitationnelle pour nommer la relation entre objets tels que Terre et Lune
  • interaction électronucléaire pour les relations au sein de la matière.

Les sciences humaines font appel aux relations entre objets. Les relations sociales, professionnelles ou familiales ne sont-elles pas des exemples typiques d'interactions entre objets ? La difficulté qu'a un sociologue à détecter les relations plus ou moins subtiles entre groupes sociaux n'est-elle pas à comparer avec la difficulté d'un architecte informatique qui tente de régler les relations entre des clients et des serveurs dans une architecture n-tiers ?

Les interactions représentent le coeur du système, son essence même en terme de fonctionnement. Une utilisation régulière des diagrammes d'interaction est signe d'une véritable approche objet. A l'inverse, une étude "objet" sans ce type de diagramme peut être révélatrice d'une approche non-objet.

Pourquoi ne pas imaginer, pour terminer, une métrique qui mesurerait la complexité d'un logiciel non plus uniquement à partir du nombre de classes mais de la quantité ou de la qualité  des interactions entre objets ?
 
 

Commentaires bienvenus   —  Thierry Cros, 1999


^ top ^       Retour articles UML, objet       Retour page d'accueil        © 1999 - Contact