Patterns de packaging SDP et SAP pour concevoir des logiciels de qualité

Clean Code Architecture SDP & SAP
Par Ayyoub KRICH il y a 3 ans 7 minutes

Stable Dependencies Principale (SDP) consiste à concevoir un logiciel de manière à ce qu'un composant donné dépende toujours d'autres composants qui sont plus stables que ce dernier. En d'autres termes, les dépendances au sein d'une architecture de composants doivent aller dans le sens d'une stabilité accrue. Ainsi, les composants qui doivent changer fréquemment seront faciles à modifier et les composants stables dont dépendent les autres ne changeront pas aussi souvent. Ce principe de couplage des composants améliorera la flexibilité de votre logiciel en facilitant les modifications fréquentes. Il permettra également d'isoler les fonctionnalités dont dépendent d'autres parties du système, ce qui contribuera à minimiser l'impact des changements. Ce principe favorise une architecture faiblement couplée et est obtenu par une gestion efficace des dépendances.

Stabilité VS instabilité ?

Lorsque vous construisez des composants logiciels, préférez-vous dépendre d'un composant stable ou d'un composant instable ? En d'autres termes, préférez-vous dépendre d'un composant difficile à modifier (c'est-à-dire stable) ou d'un composant facile à modifier (c'est-à-dire instable) ?

Si vous y réfléchissez suffisamment, vous arriverez probablement à la conclusion qu'il serait plus juste de dépendre d'un composant difficile à modifier. En effet, à chaque fois qu'il changera, cela signifiera plus de travail pour vous. En suivant l'économie du changement, il est préférable que vous dépendiez d'un composant qui est si difficile à changer que cela leur causera plus de peine à eux qu'à vous. Egalement, vous voudrez que tous les composants dont vous dépendez changent le moins souvent possible.

Qu'est-ce qui rend un composant stable me direz-vous alors ? Un composant peut être difficile à modifier pour un certain nombre de raisons s'il est :

  • Très complexe,
  • Mal écrit,
  • Ou simplement très gros.

Mais en réalité, la stabilité d'un composant se résume à sa structure de dépendance.

Dans la figure 1 ci-dessous, le composant S a plusieurs dépendances entrantes provenant de composants qui en dépendent. C'est ce que nous appelons le couplage afférent (Afferent coupling) ou Ac. Si vous devez modifier le composant S, vous devrez vous assurer que vous ne cassez aucun des autres composants qui en dépendent, chose qui est difficile à faire, ce qui rend ce composant difficile à modifier. Par conséquent, le composant S est stable.

image

Figure 1 : Un composant stable

 

Dans la figure 2 ci-dessous, le composant I a plusieurs dépendances sortantes sur d'autres composants. C'est ce que nous appelons le couplage efférent (Efferent coupling) ou Ec. Il n'y a pas de dépendances entrantes qui empêchent le composant I de changer mais il y a plusieurs dépendances sortantes qui sont susceptibles de le faire changer. Ce composant est facile à modifier et est susceptible de changer. Par conséquent, le composant I est instable.

image

Figure 2 : Un composant instable

 

Comment peut-on donc mesurer la stabilité d'un composant ? Une des façons de le faire est de compter le nombre de dépendances qui entrent et qui sortent de ce composant. Ce compte nous permettra de calculer la stabilité du composant.

Nous voulons que certains composants soient instables car c'est là ou nous placerons le code qui change fréquemment. Les composants stables sont difficiles à modifier, ce n'est donc pas là ou nous allons placer le code qui change souvent.

Calcul de l'instabilité

Ac = le nombre de classes extérieures à ce composant mais qui dépendent de classes qui sont à l’intérieur du composant. Ec = le nombre de classes à l’intérieur du composant mais qui dépendent d’autres classes qui sont à l’extérieur du composant. Donc, l’instabilité I = Ec / Ac + Ec Ce calcul est compris entre [0,1], I = 0 indique un composant maximalement stable, I = 1 indique un composant maximalement instable. The Stable Abstractions Principle (SAP) consiste à concevoir un logiciel de manière à ce que les composants soient aussi abstraits que stables. Cela permet d'appliquer le principe des dépendances stables et de favoriser la flexibilité en veillant à ce que les composants stables soient faciles à étendre, même s'ils sont difficiles à modifier. Pour ce faire, nous appliquerons le principe "ouvert/fermé" (Open/Closed principale), qui nous permettra d'étendre facilement les fonctionnalités sans modifier le code existant. Cette approche fonctionne également mieux lorsqu'on adhère au principe d'inversion des dépendances, qui stipule que les dépendances doivent pointer vers des abstractions et non des concrétions. Cela permet une gestion très efficace des dépendances pour les composants logiciels.

Assurer la stabilité

Vous pouvez construire des systèmes flexibles, faiblement couplés et hautement extensibles en veillant à ce que vos classes stables et abstraites se trouvent à la base de la structure de vos composants. Ces composants encapsulent les classes qui sont difficiles à modifier. Pas de problèmes, car c'est là ou nous allons placer le code qui n'a pas besoin d'être modifié souvent. Si nous concevons bien notre système, ils n'auront pas besoin de changer du tout s'il nous arrive de les rendre ouverts à l'extension. Nos composants stables peuvent maintenant supporter les composants instables situés près du sommet de notre structure de composants. Avec peu ou pas de dépendances entrantes, ces composants encapsulent des classes faciles à modifier. Et c'est là ou nous allons placer le code qui change souvent. image

Calcul de l’abstraction

Sa valeur est simplement le rapport entre le nombre de classes abstraites dans un composant et le nombre total de classes.

Nc = Nombre de classes dans le composant. Na = Nombre de classes abstraites dans ce composant. Rappelons-le, une classe abstraite est une classe avec au moins une méthode abstraite. A (l’Abstraction) = Na / Nc Ce calcul est compris entre [0,1], I = 0 indique un composant avec aucune méthode abstraite, I = 1 indique un composant avec uniquement des classes abstraites.

Nous avons donc notre valeur d’instabilité I = Ce / Ca + Ce plus notre valeur d’abstraction A = Na / Nc En représentant tout cela maintenant sur un repère cartésien, nous obtenons ceci :

image

Considérons un composant dans la zone proche de (0,0), ce composant est très stable et concret. Un tel composant n'est pas désiré parce qu'il est rigide. Il ne peut pas être étendu parce qu'il n'est pas abstrait et il est très difficile à changer à cause de sa stabilité. Ainsi, ne nous attendons pas à voir des composants bien conçus près de (0,0), la zone proche de (0,0) étant donné que c'est une zone d'exclusion (THE ZONE OF PAIN). Considérons un composant près de (1,1). Cet emplacement est indésirable parce qu'il est maximalement abstrait et pourtant n'a aucun dépendant. De tels composants sont inutiles, ceci est d'ailleurs appelé la zone d'inutilité (THE ZONE OF USELESSNESS).

Un composant qui se trouve sur la Main sequence n'est ni trop abstrait pour sa stabilité, ni trop instable pour son abstraction. Il n'est donc ni inutile ni particulièrement pénible à maintenir. Il est clair que la position la plus souhaitable pour un composant se situe dans l'une des deux extrémités de la Main Sequence.

Calcul de la Distance par rapport à la Main sequence

S’il est souhaitable qu'un composant se trouve sur ou près de la séquence principale, nous pouvons créer une métrique qui mesurera la distance d'un composant par rapport à cet idéal. D = |A + I - 1|

Laissez-moi vous répondre : Evidement !

Avec l’outil NDepend, l’un des outils les plus rarissimes qui existent et qui peuvent nous fournir un rapport détaillé de l’état de santé de notre projet avec sa main sequence. Prêt pour passer à l'action ? Pour le besoin de cette démonstration, j’utiliserai le code source de nopCommerce

Commençons par l’installer : Rendez-vous donc ici

Vous aurez donc affaire a ce formulaire ci-dessous, remplissez les champs demandés puis cliquez sur start 14-day trial.

image

Ensuite, cliquez sur le lien de téléchargement comme indiqué ci-dessous :

image

Vous aurez donc téléchargé les fichiers d’installation NDepend. Il faut ensuite extraire le .zip et cliquer sur le fichier d’installation NDepend comme illustré ci-dessous :

image

Cliquer dessus, puis suivez les instructions d’installations jusqu’à la fin. Par la suite, ouvrez Visual Studio. Allez dans ExtensionsNDepend ⇒ More… ⇒ Run Analysis and build report comme indiqué ci-dessous.

image

Après avoir cliqué, NDepend va prendre le temps d’analyser tous les fichiers du projet et va vous ouvrir un rapport détaillé :

image

Le voilà donc notre rapport tant attendu, ensuite il faut cliquer sur le visuel Abstractness vs Instability.

image

La voilà notre main sequence avec une zone de douleur (zone of pain) et une zone d’inutilité (zone of uselessness) et nous constatons que pour le projet RestSharp par exemple, son niveau d’abstraction est égal à 0,13, son instabilité est égale à 0,93 et sa distance par rapport à la main sequence est égale à 0,05. Nous concluons que ce projet est dans le vert pas loin de la main sequence.

Conclusion :

Ces deux principes s'imbriquent très bien l’un dans l’autre, chacun soutenant les principes et les pratiques de l’autre. La création de logiciels de haute qualité (c'est-à-dire faiblement couplés, adaptables, extensibles, testables, maintenables, évolutifs, résilients) est grandement simplifiée par l'application de ces principes et pratiques. La clé est de savoir répondre à certaines questions :

  • Pourquoi vous devez les utiliser ?
  • Comment fonctionnent-ils ?
  • Et comment les mettre en œuvre ?

Conquérez cela et vous serez sur la bonne voie pour créer d'excellents logiciels. 😉

A vous de jouer !