Refactoring .NET avec UML, 1ère partie

le 29/10/2007 par Alain Buzzacaro
Tags: Software Engineering

UML s'est toujours voulu expressif. A sa naissance, le choix d'un langage graphique pour UML a été délibéré. Aujourd'hui, UML et ses outils atteignent-ils cet objectif ? En particulier, UML et ses outils permettent-ils de représenter et comprendre des patterns de conception ? Si oui, UML permet-il de remanier des erreurs de conception, passage obligé dans la vie de nos logiciels ?

Nous vous proposons une analyse originale de patterns de conception à travers l'histoire revisitée d'un refactoring croustillant. Nous explorerons donc quelques patterns de conception dans un logiciel existant, et à l'aide de diagrammes de classes UML.

Article paru en presse dans "Programmez !" en octobre 2007, dossier consacré à UML.

Petits rappels sur l'expressivité et sur UML

UML, kesako ?
UML n'est pas une méthode, ni un outil commercial, ni un générateur de code, ni un langage de programmation. UML est l'acronyme d'Unified Modeling Language. Une analyse simple de ces trois termes nous indique qu'il s'agit d'un langage unifié de modélisation d'applications. Comme présenté dans notre Livre Blanc Architecture de Systèmes d'Information, ce langage procède par manipulation de modèles graphiques, à vocation expressive. Ceux-ci sont matérialisés par 13 diagrammes dans la dernière version d'UML (v. 2.1) : statiques, dynamiques, d'organisation de modules. Dans la pratique, les cas d'utilisation, les diagrammes de classes, de séquence et d'interaction figurent parmi les plus utilisés en développement.

L'expressivité, kesako ?
Par expressivité d'un langage, on entend à la fois la puissance et la qualité d'expression. C'est à la fois la capacité à exprimer un concept ou une opération complexe par un formalisme aussi concis que possible, et le fait que le formalisme suggère aussi directement que possible sa signification au développeur.

Octopus en bref
Octopus est un logiciel de micro crédit développé en open source par OCTO Technology en partenariat avec une organisation non gouvernementale, ACTED(1). Il est écrit en .NET 2. Très schématiquement, Octopus permet :

  • d'établir des contrats de micro crédit entre une agence ACTED et les clients (produits packagés ou exotiques/sur mesure, échéanciers de remboursement, gestion des clients, .) ;
  • de traduire des évènements, qui surviennent durant la vie du contrat, en écritures comptables. Par exemple, un évènement de type « remboursement total anticipé » se traduira par une paire d'écritures comptables, et de la mise à jour de l'échéancier de paiement, et de la clôture du contrat ;
  • d'exporter les écritures comptables vers un logiciel de comptabilité dédié.


Figure 1 : Vue d'ensemble d'Octopus

Une erreur de conception ? Refactorons !
Il faut savoir qu'une erreur de conception a longtemps existé au cœur même d'Octopus (2). Les écritures comptables vont toujours par paires : une écriture de débit (D) sur un compte s'accompagne toujours d'une écriture de crédit (C) sur un autre compte. Ce sont 2 « mouvements élémentaires ». A l'origine, ils étaient conçus en 2 instances de mouvements élémentaires contenant les informations suivantes : compte, montant et un sens : D ou C. Pour différentes raisons, ils auraient dû être conçus comme un seul mouvement élémentaire avec les informations suivantes : compte à créditer, compte à débiter et montant.
Pour ce refactoring (3) de mouvements élémentaires, nous allons essayer de découvrir et de comprendre le cœur de conception d'Octopus. Cela devrait nous permettre de savoir où et comment refactorer Octopus à l'aide d'UML.
Pour cela, considérons trois niveaux de code, plus ou moins lourds :

  • Le niveau que nous appellerons « macroscopique », tel que la couche métier d'Octopus. Cette couche s'appelle le « Core Domain », et pèse facilement plus de cent classes ;
  • Le niveau « microscopique », tel que le répertoire de gestions des évènements « Event », qui compte une dizaine de classes dans le Core Domain ;
  • Le niveau « nanoscopique », comme la classe EventProcessor qui compte quelques dizaines de lignes de code.

Octopus étant développé en .NET 2, il nous est possible d'utiliser certains outils UML pour rétro concevoir son code.

Octopus en images
Lorsqu'il est supporté par l'outil, le rétro engineering n'a rien de très compliqué : quelques clicks suffisent à produire un diagramme UML de classes du Core Domain. Les outils produisent des résultats contrastés.
Par défaut, ils représentent généralement une toile d'araignée illisible. Certains outils produisent aussi des diagrammes sans valeur ajoutée : des carrés déliés et simplement côte à côte. Dans ces 2 cas, nous pouvons toujours réarranger le diagramme pour tâcher d'y comprendre quelque chose, mais cela prend tout de même quelques heures...

-
Figure 2 : Des layouts parfois illisibles, ou sans valeur ajoutée.

Certains outils intègrent des « layouts » originaux et efficaces pour représenter le Core Domain. Par exemple, Visual Paradigm et Magic Draw intègrent des layouts suivants : hiérarchique, circulaire, organique, orthogonal, ou encore arborescent. Le layout le plus efficace dépend généralement de la forme de conception du logiciel même (en rateau, complexe, en arbre, .) et aussi du volume de classes. Dans notre cas, après quelques essais plus ou moins fructueux, la disposition dite « circulaire » de Visual Paradigm s'avère parmi les plus efficaces pour le Core Domain d'Octopus.

Octopus à première vue
La vue macroscopique du diagramme de classes obtenu (4) est la suivante :


Figure 3 : Le layout « circulaire » adapté à des designs complexes

Le diagramme de 184 classes a été généré quasiment tel quel. Seuls le passage en vue circulaire et la mise en transparence des paquetages ont été nécessaires (compter 15 minutes).

Qu'observons-nous ?
A première vue, le diagramme est complexe : de nombreuses classes organisées par espaces de nommage fonctionnels sont présentes, et de nombreux liens les relient. Le diagramme est complexe, mais pas confus, ni chaotique. A la différence d'un diagramme en forme d'étoile d'araignée, cette forme est équilibrée et structurée : de nombreuses formes « en soleil » avec une classe centrale et des classes satellites apparaissent.

Les principaux domaines fonctionnels apparaissent : ils correspondent souvent à des soleils assez proches. Par navigation de relation en relation, on trouve les classes des domaines métier suivants : les contrats, les évènements, les clients et personnes, la consolidation, les quittances. Contrairement à une lecture de centaine de classes dans Visual Studio 2005, on s'y retrouve assez facilement en navigant intuitivement par association et héritage.

Les centres de gravité du Core Domain d'Octopus sont aux centres des soleils. Par exemple, le plus grand soleil figurant en haut à gauche est centrée sur la classe CreditContract. Visuellement, on identifie aussi facilement : Accounting, Event, CalcuateInstallment et Consolidation par exemple.

Par contre, en UML, les classes sont toutes représentées de la même manière, indépendamment de leur importance. On pourrait par exemple tenir compte de leur nombre de relations, de leur complexité cyclomatique, de la force de leurs couplages afférent et efférent ou encore de leur volume de code (5) pour les agrandir, ou les mettre en gras par exemple. Les classes centrales deviendraient facilement identifiables et gagneraient à être testées unitairement, avec un fort taux de couverture des tests par exemple.

Accessoirement, une myriade de petites classes apparaît en bas à droite du diagramme. Isolées et minuscules, elles ne servent pas à la compréhension d'Octopus.

Dans la seconde et dernière partie de cet article, nous zoomerons sur différentes parties du diagramme macroscopique.
On verra si l'on parvient à comprendre des patterns métiers ou techniques d'Octopus.
On verra aussi si UML permet d'arriver au bout de notre refactoring du Core Domain... ou pas.

A suivre...

-- Messaoud OUBECHOU et Guillaume HOLLER, architectes.
Centre de Compétences .NET

(1) Vous voulez en savoir plus ? Rendez-vous sur : http://www.octo.com/omfs/index.html
(2) Hé oui, Mesdames, Messieurs, personne n'est parfait. :-) !
(3) Qui a réellement existé : http://forge.octo.com/jira/browse/OMFS-200
(4) Les diagrammes suivants proviennent de Visual Paradigm Enterprise 6.1 sur CoreDomain.dll.
(5) L'outil d'analyse de code NDepend sait représenter les surfaces de classes en fonction de leurs poids par exemple.