Séance émotion il y a deux jours. Avec un autre Nicolas (nous sommes 3 nicolas ici sur 16 personnes) nous nous attaquons à un chantier tout à fait intéressant qui fait partie de la vraie vie d’un Architecte : du dépoussiérage de code. Enfin quand je dis dépoussiérer, c’est pour rester poli. Notre objectif est de pouvoir rapidement tester deux solutions (Mule et TIBCO BusinessWorks) sur la plateforme de traitement financière de notre client, afin de réduire la dette technique et la quantité de code interne à maintenir.
Bref nous voilà plongé dans des discussions pour essayer de comprendre comment découper ce GrosMachin en PetitMachins. L’idée derrière sera ensuite de jeter des PetitsMachinsPourris et de remplacer le tout par des PetitsMachinsPropresEtNeufs… Oui car quelque chose que l’on ne vous dit pas tellement c’est que les 2/3 de notre boulot à nous, les « architectes » c’est plutôt de faire du ravalement de façade que de construire un nouvel immeuble hyper design. Nous nous efforçons de trouver des solutions d’architecture afin d’assurer la montée en charge de la plateforme et de réduire les coûts de support.
Or ces derniers mois, les chantiers que nous avons menés étaient plutôt axés sur la production, la compilation et l’intégration. Je me suis ensuite attaqué à la partie gestion d’équipe, en mettant en place Scrum avec succès. Notre prochaine mission consiste maintenant à revoir le traitement par Batch afin d’accélérer la plateforme. Le choix d’une architecture orientée Événement semble acquis afin d’effectuer le traitement de l’information au fil de l’eau. Il est temps maintenant de découper le système existant afin de venir greffer ces nouveaux composants.
Ce que vous allez croiser sur votre chemin (lorsque vous serez un maître Java)
Les logiciels créés sur des architectures J2EE EJB2.1 sont aujourd’hui matures. Ils constituent un bon nombre d’applications déployées chez les clients avec lesquels nous travaillons. Nous voyons sur le terrain des applications en production, avec bien souvent du Spring et de l’Hibernate ajoutés par la suite, afin de réduire le code technique. Mais force est de constater que cela rajoute parfois encore plus de travail, car la bonne maîtrise d’un outil de mapping relationnel ou d’un framework léger d’injection demande du temps.
Prenez le temps de parler avec des consultants et des indépendants, une bonne partie de l’activité aujourd’hui consiste à moderniser l’existant et à revoir l’architecture d’une plateforme. Bref nous sommes en plein dedans…
La taille du sabre laser ne compte pas
Après avoir migré vers maven2 l’ensemble du projet, avoir travaillé sur la mise en place de Bamboo et d’Hudson, avoir même pris du temps pour que les développeurs puissent utiliser une VirtualMachine avec un serveur Weblogic pré-installé, nous nous sommes assis devant le meilleur éditeur Java du monde pour commencer à regarder comment reprendre ces 11000 fichiers Java, sans bien évidemment tout casser.
A cet instant de la présentation il y a deux personnes : il y a un Nicolas conservateur et prudent, et il y a un Nicolas qui ferait bien tout tomber histoire de reprendre le code source. Bien entendu aucuns des deux n’a la bonne démarche, ce qu’il faut faire se situe quelque part entre les deux positions.
Si nous croyons fort à l’homéopathie, moi personnellement je ne crois pas que changer « un peu de code » et revoir progressivement l’ensemble soit la bonne solution. A contrario, mon idée de reprendre à zéro les packages, de remonter les modules maven2 proprement plutôt que de subir l’existant n’est pas non plus la meilleur idée : risque de ne pas réussir, temps nécessaire pour immobiliser l’ensemble du code, temps perdu à identifier du code « mort » inutilement refactoré, etc. Donc retenez ceci :
Ne sciez pas la branche où vous êtes assis mais ne prenez pas une pince à épiler pour retirer une poutre.
Alors quelque part entre ces 2 points, notre mission est d’extraire une partie du flot de traitement, afin de pouvoir le remplacer facilement et sans risques par une nouvelle architecture. Nous sommes dans un projet basé sur des EJB (des vieux) avec un habillage de Printemps, collection Spring. Le tout servi sur un serveur d’app, avec s’il-vous-plaît une couche Web et une couche Métier. Les gens de la Sécurité ont aussi demandé que la partie Web soit sur un réseau A et la partie Métier sur un réseau B, et que la base de données soit sur un réseau C… Et A n’a pas le droit d’aller discuter avec C. Vous commencez à visualiser un souci non ?
Pour remplir notre mission nous avons tout d’abord tenté l’aventure « on s’assoit et on réfléchit très fort » devant IDEA IntelliJ. Au bout de 2 heures avec quelques feuilles remplies de dessins, vu la complexité et de la sévérité du cas, nous n’avions pas tellement avancé. Notez que je joue la transparence en vous racontant que tout ne se passe pas bien dans la vraie vie.
Premier objectif : regrouper par module maven les grandes parties du projet. S’assurer que les dépendances transitives sont correctes afin que les modules de base comme « common » soient compilés avant la partie du domain, la couche service, pour terminer sur la couche de présentation. Découper ensuite verticalement par fonction. Mettre à feu doux, remuer de temps en temps, prier très fort, livrer tous les modules réorganisés aux développeurs. Attendre 3 ou 4 semaines, s’apercevoir que votre chef d’oeuvre est à nouveau tout pourri car Mike a tiré une dépendance de la couche domain vers la couche web, craquer nerveusement, partir, fin de l’histoire…
Ou sinon vous pouvez aussi demander à vos amis (si vous avez des bons amis) ce qu’ils en pensent. 2 mots arrivent dans la conversation : XDepend et SonarJ. Voilà de beaux couteaux pour découper proprement votre produit sans en mettre partout. Alors allons-y, leçon de cuisine avec le Touilleur Express.
XDepend, what else?
XDepend est littéralement l’équivalent d’un IRM pour vieux code fatigué. L’outil analyse votre structure de projet à partir des JAR de votre projet. C’est un outil destiné aux développeurs plutôt qu’au chef de projet. A ne pas confondre avec Sonar, ni avec SonarJ dont je vous parlerai plus loin. XDepend est le petit cousin de l’excellent outil NDepend, utilisé dans le monde .NET pour adresser le même besoin. NDepend est un outil créé par Patrick Smacchia. XDepend est commercialisé par OCTO Technology. L’outil permet d’extraire la structure d’un produit, d’analyser le code avec des metrics, d’identifier la structure et les dépendances dans le code afin de le ré architecturer ensuite correctement. Les points forts sont l’outil graphique et le langage de requête, auquel j’ajouterai la performance global de l’outil.
Pour effectuer mon test je suis parti d’un EAR, que j’ai extrait dans un répertoire de test. Après avoir téléchargé la version d’évaluation, j’ai commencé mon analyse en moins de 10 minutes. L’outil graphique facile à prendre en main propose différentes vues. L’affichage matriciel et la radarMap sont vraiment très pratiques. Tout d’abord une capture d’écran de l’affichage matriciel permet d’identifier les relations entre les différents JAR de l’EAR, afin de pouvoir ensuite factoriser le code et réduire les dépendances entre les différents modules.
Chaque colonne et chaque ligne contient les JAR packagés dans mon EAR. Chaque cellule de la matrice indique le nombre de dépendance. Il est très facile de naviguer afin de « descendre » dans un JAR pour identifier à la ligne de code prêt la dépendance. Grâce à cet outil j’ai tout de suite vu qu’un module X n’utilise pas le module Y, mais qu’il dépendait à 54% d’un module Z. J’ai donc rassemblé des modules qui n’ont pas lieu d’être individuellement.
Une originalité et une force du logiciel XDepend c’est aussi le langage CQL (Code Query Language). Grâce à ces requêtes il est possible de trouver facilement tout un ensemble de metrics, et de visualiser le résultat sur une cartographie de votre application. Dans l’exemple ci-dessous j’ai demandé à XDepend de m’afficher l’ensemble des méthodes de mon application dont la taille dépasse les 70 lignes de codes et qui sont public :
Un point plus difficile à traiter avec XDepend est l’isolation d’architecture basée sur les noms des packages. C’est un concept peu utilisé mais bien pratique, qui revient à dire que le nom d’un package permet de définir un domaine fonctionnel, le nom d’un sous-package permet ensuite de donner la couche technique.
Voici comment cela fonctionne : imaginons une application J2EE constituée d’une partie « GestionClient » et d’une partie « Administrateur » pour faire simple. Représentons verticalement ces tranches, et représentons horizontalement le découpage de l’application. Par exemple la couche Web, ensuite la partie service, le domaine et enfin une couche de fondation pour les classes utilitaires.
Voici ce que cela donnerait
L’idée de la gestion de l’isolation par package consiste à dire que chaque cellule de la matrice correspond à un pattern de packages Java. Par exemple *.dto pour le domaine, *.web.* pour la couche web, etc. Les flèches rouges représentent les interdictions. Il ne sera pas autorisé d’accéder à la couche Web à partir d’une classe du package common. Et ce, afin d’éviter bien entendu les dépendances cycliques. De même, on pourrait imaginer que les classes de la partie « Services » du domaine fonctionnel « Administrator » ne doivent pas dépendre de classes de « Domain/Gestion client », etc.
Avec Xdepend sous réserve de bien connaître les noms de vos packages, vous pouvez créer des requêtes CQL afin de vérifier ce genre de règles :
WARN IF Count > 0 IN SELECT PACKAGES WHERE IsDirectlyUsing "web" AND NameIs "common"
Quelques bémols cependant : difficile de s’y retrouver lorsque les noms des packages sont « artistiques ». De plus, si je prends 5 jours pour organiser le code, déplacer des classes, m’assurer du respect de mon schéma d’architecture, je n’ai pas envie de refaire la même chose dans 3 mois. Il faut donc une solution qui renforce l’architecture et le découpage au moment de l’écriture du code. Du côté d’IDEA IntelliJ, il n’y a pas de solutions de ce type. Seul le respect de bonnes pratiques, l’isolation dans l’usine de construction de code et l’analyse avec XDepend m’assure que le code restera propre. Bref des solutions à posteriori qui n’empêche pas un nouvel arrivant dans l’équipe d’importer une classe d’un lointain package par erreur…
SonarJ
Il est temps de vous (re)parler de SonarJ d’hello2morrow. J’avais rencontré l’équipe de SonarJ il y a presque un an. L’outil est séduisant car il s’intègre à Eclipse afin de vous notifier des violations d’architecture au moment même où vous tentez d’importer une classe. Il travaille aussi sur un modèle matriciel. Le découpage est plus facile qu’avec XDepend car SonarJ vous laisse décider pour chaque slice et chaque layer des packages à utiliser. Un système d’expression régulière permet de ranger dans la couche « gestionClient/Web » l’ensemble du code existant sans être obligé de changer votre code. Or le produit sur lequel je travaille en ce moment est dans ce cas. Certaines parties sont correctement découpées, le rangement par domaine puis par couche technique a été mis en place. Pour des parties plus anciennes ce n’est pas le cas. SonarJ serait donc un complément, après avoir défriché le code avec XDepend. J’ai par contre trouvé qu’XDepend était plus puissant et plus rapide, et qu’il me permettait de diagnostiquer plus facilement l’existant, sans passer par une étape de classement un peu longue avec SonarJ. Bref les 2 outils sont complémentaires.
A propos des metrics d’XDepend, des requêtes types permettent de gagner du temps. Par exemple, quelles sont les méthodes private qui ne sont jamais appelées dans le code ?
// <name>Potentially unused methods</name>
WARN IF Count > 0 IN SELECT TOP 10 METHODS WHERE
MethodCa == 0 AND // Ca=0 -> No Afferent Coupling -> The method is not used in the context of this application.
!IsPublic AND // Public methods might be used by client applications of your jars.
!IsClassConstructor // The IL code never explicitely calls class constructors.
Maven2
Un dernier mot aussi sur Maven2 qui propose 2 outils assez pratiques, que j’utilise en complément des outils cités ci-dessus. Le plugin « dependency » permet d’afficher la liste des dépendances directes et indirectes d’un module, et d’analyser l’usage ou l’oubli de dépendances.
Tout d’abord l’affichage de l’arbre des dépendances d’un module :
nicolas@macbookpro> mvn dependency:tree
C:\workarea\development\primeweb\projects\risk\services-ejb>mvn dependency:tree
[INFO] Scanning for projects...
INFO] ------------------------------------------------------------------------
[INFO] Building org.touilleur.article
[INFO] task-segment: [dependency:tree]
[INFO] ------------------------------------------------------------------------
[INFO] [dependency:tree]
[INFO] org.touilleur:article:ejb:0-DEV
[INFO] +- org.touilleur:module10:jar:0-DEV:compile
[INFO] | +- org.ostermiller:utils:jar:1.05.00:compile
[INFO] | +- commons-pool:commons-pool:jar:1.0.1:compile
[INFO] | +- jdbcappender:jdbcappender:jar:2.1.01:compile
[INFO] | \- org.springframework:spring:jar:2.5.5:compile
[INFO] +- org.touilleur:module20:jar:0-DEV:compile
[INFO] | +- cglib:cglib-nodep:jar:2.1_3:compile
[INFO] | +- asm:asm:jar:2.2.3:compile
[INFO] | +- asm:asm-commons:jar:2.2.3:compile
[INFO] | | \- asm:asm-tree:jar:2.2.3:compile
[INFO] | \- asm:asm-util:jar:2.2.3:compile
...
[INFO] +- hsqldb:hsqldb:jar:1.8.0.4:test
[INFO] +- dbunit:dbunit:jar:2.1:test
[INFO] +- com.mockrunner:mockrunner:jar:0.3.1:test
[INFO] +- j2ee:j2ee:jar:1.4:provided
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 30 seconds
[INFO] Finished at: Thu May 21 23:30:50 CEST 2009
[INFO] Final Memory: 16M/127M
[INFO] ------------------------------------------------------------------------
Mon module « article » dépend du module10 et du module20.
Ensuite l’analyse des dépendances se base sur le code compilé :
C:\workarea>mvn dependency:analyze
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'dependency'.
[INFO] ------------------------------------------------------------------------
[INFO] Building MonGrosProjet-core
[INFO] task-segment: [dependency:analyze]
[INFO] ------------------------------------------------------------------------
[INFO] Preparing dependency:analyze
[INFO] [resources:resources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:compile]
[INFO] Nothing to compile - all classes are up to date
[INFO] [resources:testResources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:testCompile]
[INFO] Nothing to compile - all classes are up to date
[INFO] [dependency:analyze]
[WARNING] Unused declared dependencies found:
[WARNING] org.subethamail:subethasmtp-smtp:jar:1.2:test
[WARNING] org.subethamail:subethasmtp-wiser:jar:1.2-java1.4:test
[WARNING] javax.mail:mail:jar:1.4:test
[WARNING] com.sun.xml.bind:jaxb-impl:jar:2.1.9:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 16 seconds
[INFO] Finished at: Fri May 22 10:50:07 CEST 2009
[INFO] Final Memory: 14M/127M
[INFO] ------------------------------------------------------------------------
L’analyse permet d’identifier les dépendances non déclarées dans le pom.xml mais pourtant bien utilisées par le bytecode, ainsi que d’afficher les dépendances inutiles. Attention cependant à ne pas couper trop vite vos dépendances, j’ai vu des cas mal gérés par le plugin, ou aussi le souci des tests d’intégration déclarés dans d’autres répertoires.
Conclusion
Le mot de la fin : dans notre métier une partie de notre activité est purement de l’innovation. Un peu comme descendre une piste de ski de neige fraiche, c’est le bonheur. Mais il y a aussi un besoin de compétences pour trouver rapidement des solutions d’architecture afin de réduire la dette technique, la complexité du code et améliorer la qualité globale. Il est donc important d’investir un peu de son temps pour apprendre à utiliser ces nouveaux outils. La liste des outils s’agrandit de jour en jour, je vous parlais il y a quelques semaines de Kalistick, Cédric Vidal un lecteur via Twitter m’a proposé de regarder aussi Lattix DSM, n’hésitez pas à parler dans les commentaires ci-dessous des outils que vous utilisez sur le terrain.
De mon côté j’hésite à acheter XDepend pour Innoteria afin de l’utiliser avec mon client, ou voir s’il serait intéressé pour l’acheter. M’est avis que j’aurai aussi vite fait de l’acheter… Mais c’est une autre histoire.
0 no like
Pour en revenir aux premières lignes du post, je suis intéressé par le comparatif mule et Tibco Businessworks (je suis architecte de plateforme à base de Tibco BusinessWorks )