les derniers
articles

Index &
Sommaire
 

Articles « Info » : Développeur

 


DÉCOLLAGE !


Présentation du
site WEB AILES
 


Dépendance entre packages


Tous ceux d'entre vous qui ont déjà participé à d'important développement s'en sont rendus compte : tout faire d'un coup n'est pas possible : il faut subdiviser.
cette opération se fait à plusieurs niveaux :
- à haut niveau (
spécifications - partie Analyse - )
- à plus bas niveau (
conception et codage )
C'est dans ce dernier niveau, au moment de la conception et du codage, que vous devez regrouper vos classes en package (notion officiellement reconnue depuis Java, mais déjà présente bien avant).
Cet article n'explique pas comment faire un "bon" package, mais insiste sur l'importance que prennent les dépendances entre packages au cours de la vie d'un logiciel (aussi bien dans sa phase de développement que dans sa maintenance, donc aussi bien avant que après sa livraison au client).


 



Lisez-moi et
réagissez !



Écrivez à AILES !



Article suivant :
Chef de projet
 
Pourquoi des packages ?
    A haut niveau (spécification) , il s'agit de résoudre un sous-problème, ce qui est plus simple que de s'attaquer à tout.
La difficulté de cet exercice réside dans la détermination des services que doit rendre un package.
    A bas niveau (conception - codage), il s'agit pour vous, jeune programmeur de la vie de tous les jours, de livrer pour l'avant-veille une librairie de classes qui, compilée avec d'autres, permet d'obtenir un exécutable.
La difficulté de cet exercice, c'est que le bon fonctionnement de votre librairie repose sur d'autres librairies développées par d'autres équipes, et que vous devez rester compatibles avec elles au jour le jour...
Cet article aborde deux grands problèmes connus avec la manipulation de ces ensembles de classes :
-
l'organisation des packages
-
le degrés de dépendance des packages

Des packages de packages ?
    Depuis le début de cet article, il est fait allusion à deux "niveaux" (haut niveau et bas niveau). Si ces termes vous gênent, vous pouvez également les interpréter comme les niveaux "logique" et "physique" ou "abstraits" et "concrets" ou "théoriques" et "pratiques" ou ...
    Bref, dans le premier (où l'on analyse, une fois l'expression des besoins clairement identifiée), il est concevable d'imaginer des packages de packages. Il s'agit d'une démarche naturelle "en profondeur d'abord" où l'on part du problème général pour aller vers des problèmes plus spécifiques.
    Les ennuis arrivent au deuxième niveau, celui auquel les programmeurs se trouvent confrontés alors qu'ils n'ont parfois qu'une vague notion des spécifications (quand ils ont la chance d'en avoir tout court!).
Ils ont alors tendance d'adopter une démarche similaire qui peut se révéler... très gênante :
Imaginez que vous soyez chargé de développer deux packages A1 et A2 que vous les regroupiez sous le package unique A

A votre niveau (conception-codage), cela va vite poser un problème d'organisation pratique :
    Que se passe-t-il lorsqu'un de vos collègues, ébloui par le package "A2" (qui répond pile-poil à ses besoins), veut vous le prendre ?
Sera-t-il obliger de créer un sur-package "A" dont il n'a que faire ?
    De plus, certains langages ont besoin d'un chemin précis pour inclure les classes d'un autre package dont A2 pourrait dépendre. Imaginez que A2 dépendent de A1. Le code que vous lui livrez comporte donc des chemins d'inclusion du type "A/A1/class1".
Et alors ? Il lui suffit, à votre collègue, de se créer un répertoire "A" dans lequel il mettra vos bô packages! Oui, mais : il a déjà un répertoire "A" qui a, pour lui, une signification toute autre que celle que vous lui avez donné dans votre conception. Et il a déjà mis 125 autres packages qui n'ont pas grands liens logiques avec les deux packages que vous devriez lui livrer...
    Tout cela pour dire quoi ?
    Pour dire qu'au niveau du code, vos ensembles de classes devraient être organisés en packages feuilles. Vous devriez avoir une collection de packages sous une racine commune. Les avantages sont les suivants :
* vous ne vous perdez pas en parcours d'arborescences compliquées : en un niveau, vous avez la classe cherchée.
* La classe du package A2 qui dépend du package "A1" (ou de n'importe quel autre package) a un chemin de dépendance simple qui ne comporte que deux éléments :
    1/ le nom de l'autre package,
    2/ le nom de l'autre classe
* La réutilisation de ce package dans d'autres projet est simple : il suffit de le recopier sous une racine unique, en compagnie de tous les autres packages propres au projet de votre collègue.
Ce principe n'est bien sûr pas à appliquer tout le temps : regrouper des classes dans des ensembles logiques qui eux même sont regroupés dans des sur-ensembles logiques est une démarche naturelle qui existe...
Mais considérez un instant où elle existe : l'exemple le plus fameux est celui des JDK (Java Development Kit) de Java. Toutes leurs classes sont organisées de façons arborescentes et non en râteau (packages feuilles) comme cela était préconisé dans le paragraphe précédent...
Oui mais : il s'agit la d'un produit fini, longuement mûri et "stabilisé", distribué dans le monde entier. Il s'agit alors de mettre à disposition la collection de packages précédemment évoquée d'une façon suffisamment pratique pour que les clients puissent s'y retrouver.
Donc ? Donc, tant que vos packages sont développés dans un environnement de travail (et non dans une version "release"), destinés à être réutilisés par par d'autres équipes internes à votre entreprise, la vision "collection de packages feuilles", en râteau sous une racine unique, reste préférable : chacun va "y faire ses courses" et importer le ou les packages dont il a besoin.
Un package qui dépend d'un autre package
    Faire dépendre un package d'un autre est une décision lourde de conséquences, qui renvoie au problème de couplage déjà évoqué en phases d'Analyse et de codage.
    La première question à bien se poser lorsque l'on choisit de faire dépendre un package "A" d'un autre "B" , c'est :
« pourrai-je facilement remplacer "B" par autre chose ? ». La réponse est oui si les services qu'offre le package "B" sont clairement identifiés, pas trop nombreux et adaptés. Si c'est la cas, cela veut dire que n'importe quel autre package offrant les mêmes services que "B" fera l'affaire.
Donc ? Donc on ne devrait dépendre d'un package que si les services proposés par ce dernier contribuent tous (ou au moins en très grande partie) à répondre aux demandes du premier package.
    La deuxième question se déduit de la première et repose sur le principe de stabilité. Si l'on considère la chaîne de dépendance suivante :

Il est très important de se demander si "D" est susceptible de "changer" souvent (nouveaux services, changement d'interface, de signatures de fonctions, besoin de dépendre à son tour d'autres packages dont l'utilisation pourraient se révéler incompatibles avec "A", "B" et "C", actuels utilisateurs de "D").
Normalement, "D" devrait être le package offrant des services clairement identifiés, stabilisés et évoluant peu. Dans l'idéal, "D" ne doit dépendre de rien d'autre.
    Pour ne pas changer, la troisième question se déduit de la deuxième et repose sur le principe d'abstraction. En fait, plus un package est dit "stable", plus il devrait être composé en grand nombre de classes abstraites. Les packages clients auraient la charge de fournir une implémentation concrète, implémentation susceptible de changer, entraînant une plus grande instabilité potentielle des services du packages.
Java a popularisé cette notion avec ses packages constitués uniquement d'interface dont chaque éditeur propose ensuite son implémentation.
    Après vous être posé ces trois questions, vous avez décidé de faire dépendre le package "C" du diagramme ci-dessus de "A'".
Il vous reste alors une dernière question à vous poser : « ne suis-je pas en train d'introduire un cycle de dépendances ? ». ce cycle se repère en "suivant les flèches", exercice facile dans le cas de notre exemple, mais très vite complexe lorsque le nombre de packages est élevé.

Si oui, cela est une très mauvaise idée car toute modification (pour quelque raison que ce soit) d'une des classes d'un des trois packages affectera potentiellement les deux autres.
Du coup, les enjeux exposés dans le paragraphe suivant seront beaucoup plus difficiles à atteindre.
Un politique courante consiste à les proscrire purement et simplement.

Enjeux
    Pourquoi se poser en permanence ces questions ? Trois grands enjeux en dépendent :
Evolutivité : un package aux services bien pensés doit pouvoir être soit enrichi facilement, soit pouvoir changer son mécanisme interne sans tout remettre en cause.
(Ré)-utilisation : vos packages vont être utilisés par d'autres programmeurs au sein même du projet auquel vous participez. Ou bien, ils vont être utilisés dans d'autres projets du même service informatique. Il est indispensable de leur fournir des services clairs, avec derrière une implémentation privée (interne au package) suffisamment souple pour être facilement modifiable et s'adapter à des exigences pas forcément prises en compte dès le départ (un exemple typique est le problème des performances! Ce que vous livrez répond bien au besoin mais se traîne lamentablement!).
Maintenance
: lorsqu'un bug arrive, c'est le moment de vérité.
Normalement, il ne doit affecter qu'un seul package. Sa correction ne devrait entraîner en principe aucune autre dépendance.
Dès que la correction d'un bug implique plus d'un package, les problèmes commencent, car, bien sûr, l'autre package concerné n'est pas toujours de votre ressort.
Pour conclure, respecter les principes précédemment évoqués, c'est s'épargner bien des angoisses et du temps dans les phases ultérieur du développement ou de la vie de votre logiciel...



               
 
Avertissement !
 
Décollage !  |  Présentation du site web "AILES"  | 
Infos générales  |  articles "Informatique"