Overblog
Editer l'article Suivre ce blog Administration + Créer mon blog
Laurent COCAULT

Structures logicielles et outillage - épisode 6

L'analyse de dépendances proposée dans l'épisode précédent de la série sur l'outillage d'analyse des structures logicielles ne concernait que les dépendances internes du composant. Cette approche est plus intéressante lorsqu'elle considère les dépendances externes. La nouvelle version de l'outil CodeMap intègre cette analyse des dépendances externes de chaque type du composant.

Cette fonction d'analyse des dépendances externes est particulièrement utile pour maitriser les adhérences technologiques de chaque module du composant. Si on reprend l'exemple du composant JAM déjà utilisé dans l'article précédent, on peut définir les dépendances légales entre les quatre modules "model", "view", "control", "core" et les technologies supports.

  • Désormais, il est nécessaire, pour ne pas lever de violations, de déclarer les dépendances vers les paquetages de l'API Java standard. On sera dans ce cas assez permissif dans la mesure où la plupart des classes, quel que soit leur rôle, peuvent avoir un intérêt légitime à utiliser des classes de "java.lang" ou des collections de "java.util". En revanche, on pourra se montrer plus sélectif pour les adhérences avec des paquetages tels que "java.io", "java.net" ou encore "java.sql" qui témoignent d'adhérences plus étroites avec le système hôte.
  • Dans le cas de JAM qui est avant tout un composant IHM, les adhérences avec la technologie IHM (dans notre cas, il s'agit de JavaFX) doivent être déclarées. Au niveau des modules "view" et "control" il est légitime d'accepter une dépendance assez large ; pour le module "model", cette adhérence est moins facilement justifiable et si elle existe doit être ciblée. En revanche, "core" doit être totalement agnostique de la technologie IHM.
  • En revanche, dans le module "core" on pourra accepter des dépendances plus spécifiques qui sont liées au métier. Dans notre cas, n'étant pas parti vers une modularisation fine ou une architecture hexagonale, c'est au niveau du noyau qu'on pourra accepter la prise en charge des interactions avec le bus série (pour rappel, JAM est un composant qui permet à un programme Java de communiquer avec une carte Arduino via liaison série).

La mise en place des règles de dépendances technologiques pour l'analyse JAM aboutit à la configuration suivante :

# MVC dependencies
fr\.arduino\.jam\.view\..*;fr\.arduino\.jam\.model\..*
fr\.arduino\.jam\.view\..*;fr\.arduino\.jam\.control\..*
fr\.arduino\.jam\.control\..*;fr\.arduino\.jam\.model\..*
fr\.arduino\.jam\.model\..*;fr\.arduino\.jam\.core\..*
# Java standard dependencies
.*;java\.lang\..*
.*;java\.text\..*
.*;java\.util\..*
fr\.arduino\.jam\.core\..*;java\.io\..*
fr\.arduino\.jam\.core\..*;java\.net\..*
# JavaFX dependencies
fr\.arduino\.jam\.control\..*;javafx\..*
fr\.arduino\.jam\.model\..*;javafx\.beans\.property\..*
fr\.arduino\.jam\.view\..*;javafx\..*
# Other technological dependencies
fr\.arduino\.jam\.core\..*;gnu\.io\..*
fr\.arduino\.jam\.model\..*;javax\.xml\..*

En menant l'analyse de dépendances avec ces règles on obtient le résultat suivant :

=================================================
=== Violations
=================================================
List of illegal dependencies
- From fr.arduino.jam.view.ChartView to fr.arduino.jam.core.ParameterListener
- From fr.arduino.jam.model.ParameterOccurrenceDelegator to javafx.application.Platform
- From fr.arduino.jam.view.ListView to fr.arduino.jam.core.ParameterOccurrence
- From fr.arduino.jam.view.MimicView to fr.arduino.jam.core.ParameterOccurrence
- From fr.arduino.jam.model.ParameterOccurrenceRelay to javafx.collections.ObservableList
- From fr.arduino.jam.view.MimicView to fr.arduino.jam.core.ParameterListener
- From fr.arduino.jam.view.Jam to fr.arduino.jam.core.ParameterOccurrence
- From fr.arduino.jam.model.JamModel to java.io.File
- From fr.arduino.jam.view.ChartView to fr.arduino.jam.core.ParameterOccurrence
- From fr.arduino.jam.view.MimicView to java.io.File

La coloration des lignes du rapport ci-dessus permet de distinguer différents cas de figure :

  • En bleu, on retrouve les violations de nos règles de structure interne déjà évoquées dans l'article précédent (le module "view" ne devrait pas dépendre directement du module "core" mais systématiquement passer par le "model").
  • En mauve, des dépendances non anticipées du "model" vers le framework graphique. Dans les règles proposées ci-dessus, seule la dépendance vers les propriétés des Beans représentées au niveau graphique avait été déclarée. Ici, on voit que le "model" dépend également des collections observables proposées par JavaFX ainsi que de la plateforme elle-même. Une analyse du code source permet de confirmer qu'il s'agit de dépendances justifiées. La conclusion logique est alors de mettre à jour le fichier de règles pour déclarer les dépendances comme légales.
  • En rouge, des dépendances du "model" et de la "view" vers la classe "File" de "java.io". Dans notre architecture intentionnelle, les dépendances vers le système sont prises en charge par le module "core". On pourrait donc dans ce cas adopter une stratégie différente du cas précédent, à savoir externaliser l'accès aux ressources locales nécessaires à la vue et au modèle dans le noyau.

Cet exemple illustre l'utilisation de l'outil CodeMap dans une démarche de gestion des couplages externes et des adhérences technologiques. Habituellement, on peut se contenter d'un contrôle du gestionnaire de dépendances (Maven dans notre cas, mais ce pourrait être de l'OSGi ou du NPM dans un contexte JavaScript). Mais cette approche classique pose un double problème :

  • D'une part, la dépendance est assez grossière puisqu'elle porte sur le module dans sa globalité et ne permet pas d'affiner les règles au niveau des paquetages ou des classes.
  • D'autre part, le système de dépendances en cascade peut masquer des dépendances indirectes qu'on pourrait considérer comme indésirables.

Le système proposé par CodeMap se rapproche plutôt du concept de module introduit dans Java 9. Dans un projet exclusivement basé sur ce langage, on pourra d'ailleurs préférer ce mécanisme standard. Mais si le projet est antérieur à Java 9, qu'on souhaite avoir une centralisation des dépendances légales ou s'affranchir de la nécessité d'expliciter les export, l'utilisation de CodeMap peut être la solution.

Le contrôle des dépendances à la fois internes et externes que propose l'outil permet d'assurer le respect d'une architecture intentionnelle basée sur des règles de dépendances strictes. Par exemple, prenons l'architecture hexagonale suivante:

Structures logicielles et outillage - épisode 6

Avec cette architecture intentionnelle, il est possible d'utiliser CodeMap pour :

  • Définir les dépendances internes légales :
    • "REST" dépend de "core"
    • "DB" dépend de "core"
    • "gRPC in" dépend de "core"
    • "gRPC out" dépend de "core"
  • Définir les dépendances technologiques légales :
    • "REST" dépend par exemple de SpringBoot
    • "gRPC in" dépend de gRPC
    • "gRPC out" dépend de gRPC
    • "DB" dépend de JPA/Hibernate

Il devient alors possible de vérifier régulièrement que l'architecture effective respecte bien l'architecture intentionnelle.

Partager cet article
Repost0
Pour être informé des derniers articles, inscrivez vous :
Commenter cet article