I. Introduction

Les projets étant de plus en plus complexes et les équipes de développement réparties partout dans le monde, il devient de plus en plus important d'en suivre la qualité afin de corriger les problèmes le plus tôt possible.
Car comme vous avez du le lire, plus un bug est découvert tard dans le cycle de réalisation du logiciel, plus sa correction est coûteuse.

Image non disponible

Une politique de qualité doit être mise en place et comporter au moins ces 4 étapes :

  • Définition d'un objectif,
  • Choix d'une méthode,
  • Outillage de cette méthode,
  • Mise en place d'un processus de suivi de qualité.

Notre objectif sera de valider la définition de la qualité suivante.
On peut définir la qualité d'un code source par ces critères :

  • Un code documenté,
  • Un code respectant les standards (de Sun, de son entreprise, de son projet, ...),
  • Un code sans bug,
  • Un code maintenable, évolutif et simple,
  • Un code performant,
  • Un code testé.

Nous ne traiterons pas du choix des méthodes mais je vous conseille d'aller jeter un œil sur les méthodes agiles (Scrum, XP, ...), TDD et Lean.
Le choix de la méthode est important car l'outillage technique ne se substitue pas à la méthode choisie, il en est le complément.

L'outillage des tests revêt plusieurs aspects et vise plusieurs objectifs :

  • Réduction des charges de test,
  • Réduction des délais de test,
  • Amélioration de la couverture des tests,
  • Amélioration de la flexibilité des tests,
  • Meilleure appréciation de l'état du processus de test,
  • Meilleure motivation des testeurs par l'automatisation des tâches ingrates ou répétitives.

En Java de nombreux outils permettent de suivre la qualité des sources.
Parmi eux, nous utiliserons les plugins Maven2.

II. Introduction à Maven2

Maven2 permet grâce à la définition du projet dans le fichier pom.xml de gérer tout le cycle de vie du projet (compilation, test, packaging, installation...).
Plus d'information sur http://matthieu-lux.developpez.com/tutoriels/java/maven/?page=lifecycle-goal#L3.2

La partie qui nous intéresse est la partie de reporting et se configure dans le fichier pom.xml, rubrique reporting.

pom.xml
Sélectionnez
<reporting>
...
</reporting>

L'étape reporting consiste à la création d'un site Internet à l'aide de la commande "mvn site". Par défaut, un certain nombre de pages est crée automatiquement par le plugin "project-info-reports".

Image non disponible


Plus d'information sur http://maven.apache.org/plugins/maven-project-info-reports-plugin/

Pour ajouter les plugins de qualités que nous allons étudier, il faut ajouter dans la partie reporting la liste des plugins que nous voulons utiliser

pom.xml
Sélectionnez
<reporting>
	<plugins>
	...
	</plugins>
</reporting>

Le résultat se trouvera en dessous de la partie " project-info-reports ".

Image non disponible


Etudions maintenant ces plugins.

III. Présentation des plugins Maven2

III-A. Surefire

III-A-1. Présentation

Surefire permet d'avoir les rapports d'exécution de tests unitaires.
Il est compatible avec un certain nombre de frameworks de tests unitaires comme JUnit (3.8 et 4.x), TestNG.
Vous trouverez plus d'informations sur http://maven.apache.org/plugins/maven-surefire-plugin/

III-A-2. Installation

Dans la partie reporting du fichier pom.xml ajoutez le plugin

pom.xml
Sélectionnez
<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-surefire-report-plugin</artifactId>
	<version>2.4.3</version>
</plugin>

III-A-3. Rapport généré

Image non disponible

III-B. Cobertura

III-B-1. Présentation

Cobertura permet de connaître la couverture du code par les tests unitaires.
Cette information est importante car, même avec un nombre élevé de test unitaire, on n'a pas forcement une bonne couverture et certaines parties importantes peuvent se retrouver peu ou pas testées.

Vous trouverez plus d'informations sur http://cobertura.sourceforge.net/


III-B-2. Installation

Dans la partie reporting du fichier pom.xml ajoutez le plugin

pom.xml
Sélectionnez
<plugin>
	<groupId>org.codehaus.mojo</groupId>
	<artifactId>cobertura-maven-plugin</artifactId>
	<version>2.2</version>
</plugin>


III-B-3. Rapport généré

Image non disponible


III-C. CheckStyle

III-C-1. Présentation

CheckStyle permet de contrôler le respect des conventions de codage et d'avoir quelques métriques.
Ce contrôle est fait avec 126 règles et cela va du plus simple comme la longueur d'une ligne à des choses plus compliquées comme la complexité cyclomatique d'une classe.

Le plugin Maven met à disposition 4 fichiers de règles :

De nombreux fichiers de règles peuvent se trouver sur Internet permettant d'être plus ou moins souple avec le standard de codage.
Et si ces règles ne vous conviennent pas, vous pouvez créer les vôtres et/ou paramétrer celles qui existent déjà.

Vous trouverez plus d'informations sur http://checkstyle.sourceforge.net/
Et la description des règles sur http://checkstyle.sourceforge.net/availablechecks.html


III-C-2. Installation

Dans la partie reporting du fichier pom.xml ajoutez le plugin

pom.xml
Sélectionnez
<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-checkstyle-plugin</artifactId>
	<version>2.2</version>
	<configuration>
		<configLocation>config/sun_checks.xml</configLocation>
		</configuration>
</plugin>


III-C-3. Rapport généré

Image non disponible

III-D. PMD/CPD

III-D-1. Présentation

PMD va analyser le code afin de trouver des problèmes potentiels tel que :

  • Bugs possibles,
  • Code mort,
  • Code non optimal,
  • Expressions trop compliquées,
  • Problèmes de sécurité,
  • Problèmes de couplage entre objet/package,
  • ...
Règle Définition
Basic JSF rules Règles pour JSF.
Basic JSP rules Règles pour JSP.
Basic Rules Règles basiques listant un certain nombre de bonnes pratiques.
Braces Rules Règles sur l'utilisation des parenthèses.
Clone Implementation Rules Règles sur l'utilisation de la méthode clone().
Code Size Rules Règles concernant la taille du code.
Controversial Rules Règles considérées controversées.
Coupling Rules Règles sur le couplage.
Design Rules Règles sur l'architecture.
Finalizer Rules Règles sur l'utilisation des finalizers.
Import Statement Rules Règles sur la partie "import" du code.
J2EE Rules Règles pour J2EE
JavaBean Rules Règles sur l'utilisation des JavaBeans.
JUnit Rules Règles sur l'utilisation de JUnit.
Jakarta Commons Logging Rules Règles pour les Commons Logging.
Java Logging Rules Règles pour l'utilisation des Logging.
Migration Rules Règles pour la migration d'un JDK à une autre version.
Naming Rules Règles sur la nomenclature des objets/packages/...
Optimization Rules Règles pour la performance du code.
Strict Exception Rules Règles sur l'utilisation des Exceptions.
String and StringBuffer Rules Règles sur l'utilisation de String et StringBuffer.
Security Code Guidelines Règles sur la sécurité http://java.sun.com/security/seccodeguide.html#gcg
Unused Code Rules Règles pour la détection du code mort.

CPD va analyser le code afin de trouver les morceaux de code dupliqué.

Vous trouverez plus d'informations sur http://pmd.sourceforge.net/

III-D-2. Installation

Dans la partie reporting du fichier pom.xml ajoutez le plugin

pom.xml
Sélectionnez
<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-pmd-plugin</artifactId>
	<version>2.4<version>
	<configuration>
		<rulesets>
			<ruleset>/rulesets/basic.xml</ruleset>
			<ruleset>/rulesets/imports.xml</ruleset>
			<ruleset>/rulesets/unusedcode.xml</ruleset>
			<exclude name="UnusedPrivateField" />
			<ruleset>/rulesets/finalizers.xml</ruleset>
		</rulesets>
	</configuration>
</plugin>

III-D-3. Rapports générés

PMD

Image non disponible


CPD

Image non disponible


III-E. Findbugs

III-E-1. Présentation

Findbugs va trouver les bugs potentiels en analysant le bytecode Java. Pour cela il s'appuie sur une notion de 'bug patterns'.

Ces bugs sont classés en plusieurs catégories :

  • Correctness
      Regroupe les bugs généraux. Par exemple les boucles infinies, mauvaises utilisations de equals(), ...
     
  • Bad practice
      Regroupe les mauvaises pratiques. Par exemple les problèmes d'Exception, de ressources non fermées, mauvaises utilisations de comparaison de chaîne de caractères, ...
     
  • Performance
      Regroupe les problèmes de performance. Par exemple la création d'objets inutiles.
     
  • Multithreaded correctness
      Regroupe les problèmes liés au code multithread.
     
  • Internationalization
      Regroupe les problèmes liés à l'internationalisation d'une application.
     
  • Malicious code vulnerability
      Regroupe les problèmes de vulnérabilité. Par exemple du code qui pourrait être détourné de son utilisation, ...
     
  • Security
      Regroupe les problèmes de sécurité. Par exemple les problèmes liés au protocole http, les SQL injections, ...
     
  • Dodgy
      Regroupe le "smell code". Par exemple les comparaisons redondantes avec null, variables non utilisées, ...
     

Il existe un autre paquet de règles.
On peut le trouver au format jar sur http://fb-contrib.sourceforge.net/

Vous trouverez plus d'informations sur http://findbugs.sourceforge.net/factSheet.html

III-E-2. Installation

Dans la partie reporting du fichier pom.xml ajoutez le plugin

pom.xml
Sélectionnez
<plugin>
	<groupId>org.codehaus.mojo</groupId>
	<artifactId>findbugs-maven-plugin</artifactId>
	<version>1.0.0<version>
</plugin>

III-E-3. Rapport généré

Image non disponible

III-F. JDepend

III-F-1. Présentation

JDepend analyse le code pour en calculer des métriques (l'extensibilité, la réutilisabilité et la maintenabilité des sources) sur la qualité du design pour les packages du projet.

Ces métriques sont :

  • Nombre de classes et d'interfaces (TC = CC + AC)
    Le nombre de classes concrètes et abstraites (incluant les interfaces) dans un package est un indicateur de l'extensibilité d'un package.
    -> Plus ce nombre est important, plus les entités qu'elles implémentent peuvent être étendues indépendamment les unes des autres.
     
  • Couplage par dépendance ascendante (Ca ou Afferent Coupling)
    Le nombre de packages tiers utilisant un package donné est un indicateur de la responsabilité d'un package. Cela permet de mettre en évidence qu'un package est au centre de l'application ou une mauvaise gestion des packages.
    -> Ce nombre doit être le plus petit possible.
     
  • Couplage par dépendance descendante (Ce ou Efferent Coupling)
    Le nombre de packages tiers utilisés par un package donné est un indicateur d'indépendance du code.
    -> Ce nombre doit être le plus petit possible.
     
  • Degré d'abstraction (A ou Abstractness)
    Le degré d'abstraction correspond au pourcentage entre le nombre de classes abstraites (plus les interfaces) dans le package analysé par rapport au nombre total de classes de ce package.
    Cette métrique peut varier de 0 à 1. 0 indique qu'un package est concret, tandis que 1 indique un package abstrait.
    -> Ce nombre doit être proche d'une des 2 bornes.
     
  • Instabilité (I ou Instability)
    C'est le ratio I = Ce / (Ce + Ca). Cette métrique est un indicateur de stabilité par rapport à la mise jour d'autres packages.
    Cette métrique peut varier de 0 à 1. 0 indique qu'un package est complètement stable, tandis que 1 indique un package complètement instable.
     
  • Distance normale (D ou Distance from the main sequence)
    Cette métrique correspond à la distance de la droite perpendiculaire à la droite idéale A+I=1. C'est un indicateur d'équilibre d'un package entre l'abstraction et l'instabilité.
    Les packages supposés idéaux sont soit complètement abstraits et stables (A=0,I=1) soit complètement concrets et instables(A=0,I=1).
    -> Ce nombre doit être proche de 0.
     
  • Volatility (V)
    La volatilité d'un package est sa tendance à évoluer au fil du temps.
    -> 0 indique que le package est le centre de l'application.
     

Vous trouverez plus d'informations sur http://clarkware.com/software/JDepend.html

III-F-2. Installation

Dans la partie reporting du fichier pom.xml ajoutez le plugin

pom.xml
Sélectionnez
<plugin>
	<groupId>org.codehaus.mojo</groupId>
	<artifactId>jdepend-maven-plugin</artifactId>
	<version>2.0-beta-2<version>
</plugin>

III-F-3. Rapport généré

Image non disponible

IV. Attention à ne pas activer toutes les règles

A moins de vouloir décourager toute l'équipe (y compris vous), n'activez pas toutes les règles d'un coup.
Il vaut mieux choisir certaines règles à activer au début. Une fois ces règles validées (ou du moins un certain pourcentage atteint), ajouter d'autres règles et ainsi de suite.
Je préconise d'activer les règles sur les Exceptions et de la gestion des traces (log) dès le début.

Pour sélectionner les règles à utiliser pour chaque plugin, voir les parties en gras dans la partie précédente afin de bien configurer chaque plugin.

Sur http://wiki.netbeans.org/ActionPMD vous trouverez un exemple de règles que le projet Netbeans exclu lors de son utilisation de PMD.

Ces plugins Maven2 existent aussi au format plugin pour la majorité des IDE.
Il est utile d'installer ces plugins sur chaque IDE des postes de développement.

Cela a plusieurs avantages :

  • Intégration aux IDE et donc une utilisation plus simple,
  • Responsabilisation des développeurs aux problèmes de qualité,
  • Les développeurs vérifient leur code avant de faire un commit.

V. Tableaux de bord

Une fois Maven2 mis en place avec tout ses plugins, il est judicieux d'avoir un tableau de bord regroupant le maximum d'informations utiles en une seule page.
Pour cela il existe un certain nombre de plugins Maven2 qui permettent de créer ce tableau de bord.

V-A. QALab

Outil intéressant mais semble ne plus être maintenu.
Pour plus d'informations : http://qalab.sourceforge.net/index.html

V-B. XRadar

Outil intéressant mais j'attends qu'il prenne en charge FindBugs.
Pour plus d'informations : http://xradar.sourceforge.net/

V-C. Sonar

Semble prometteur, vivement que la version 1.5 sorte afin qu'il prenne en compte plus de métriques et le support de plugins externes comme FindBugs, JDepend.
Site officiel : http://sonar.codehaus.org/
Pour plus d'informations : http://linsolas.developpez.com/articles/java/qualite/sonar/

V-D. Maven Dashboard

Maven Dashboard permet de centraliser un certain nombre de rapports crées par Maven. De plus il y a une option pour historiser les statistiques.
Pour plus d'informations : http://mojo.codehaus.org/dashboard-maven-plugin/

V-E. SonarJ

Permet d'avoir un contrôle plus poussé sur l'architecture du projet en définissant les droits de communication entre chaque couche.
Pour plus d'informations : http://www.hello2morrow.com/products/sonarj

VI. Intégration continue

Tout est en place. Il reste juste un dernier détail : on est obligé de lancer manuellement la commande "mvn site" pour créer les rapports.
La solution à ce problème est de mettre en place l'intégration continue sur votre projet.

Le principe est d'exécuter les étapes (goals) de votre fichier pom.xml de Maven2 automatiquement.
Les déclencheurs de cette exécution peuvent être :

  • A date fixe (toutes les nuits),
  • Après un commit,
  • A la demande,
  • ...

Plus d'informations sur : http://conception.developpez.com/cours/?page=tools-cat#ci

Maintenant que tous les outils ont été présentés et installés, nous allons valider la définition de la qualité définie en début de l'article.

VII. Un code documenté

Outil utilisé : CheckStyle

Les règles concernant le contrôle de la JavaDoc se trouvent à l'adresse http://checkstyle.sourceforge.net/config_javadoc.html

Voila les recommandations de Sun pour bien écrire ces JavaDoc http://java.sun.com/j2se/javadoc/writingdoccomments/index.html

L'écriture et la maintenance de la JavaDoc pouvant devenir facilement chronophages, il est inutile d'avoir une couverture de 100%, en particulier si les noms des paramètres/classes/... sont bien choisis.
Par exemple, les getters ou setters d'une classe.

Pour éviter d'écrire toute la documentation, il est possible de générer une partie de la documentation UML et du schéma de la base de données par rétro documentation (voir les annexes A et B).

VIII. Un code respectant les standards (de Sun, de son entreprise, de son projet, ...)

Outil utilisé : CheckStyle

Il y a un fichier de configuration livré avec CheckStyle reprenant les conventions Sun.
De plus on peut facilement ajouter d'autres conventions.
Il est conseillé de configurer sur chaque poste votre IDE pour qu'il puisse automatiquement formater le code source afin de respecter ces standards.

IX. Un code sans bugs

Outils utilisés : CheckStyle, PMD, Findbugs

Avant de corriger un bug, bien penser à écrire le test unitaire associé s'il n'existe pas.
Pour cette partie, il faut faire attention aux faux positifs (l'outil va détecter un bug qui n'en est pas). Une fois cette vérification faite, la plupart du temps il suffit de corriger le bug comme indiqué par le plugin.

Voici quelques bugs trouvés avec FindBugs sur divers projets open source.

1. [RV] La méthode ignore une valeur de retour [RV_RETURN_VALUE_IGNORED]

 
Sélectionnez
value.replaceAll("/", "//");

Solution possible

 
Sélectionnez
value = value.replaceAll("/", "//");

2. [RpC] Repeated conditional tests [RpC_REPEATED_CONDITIONAL_TEST]

 
Sélectionnez
if (vertices[i].z == Float.MAX_VALUE || vertices[i].z == Float.MAX_VALUE)
	ptXY += i + 1;

Solution possible

 
Sélectionnez
if (vertices[i].z == Float.MAX_VALUE) {
	ptXY += i + 1;
}

3. [FE] Test d'égalité avec NaN erroné [FE_TEST_IF_EQUAL_TO_NOT_A_NUMBER]

 
Sélectionnez
if (translucentLevel != Float.NaN)

Solution possible

 
Sélectionnez
if (!Float.isNaN (translucentLevel))

4. [OBL] Method may fail to clean up stream or resource [OBL_UNSATISFIED_OBLIGATION]

 
Sélectionnez
static void writeFile(String fileName, String text) {
	try {
		FileOutputStream os = new FileOutputStream(fileName);
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os), 8192);
		bw.write(text);
		bw.close();
		os = null;
	} catch (IOException e) {
		Logger.error("IO Exception: " + e.toString());
	}
}

Solution possible

 
Sélectionnez
static void writeFile(String fileName, String text) {
	try {
		FileOutputStream os = new FileOutputStream(fileName);
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os), 8192);
		bw.write(text);
	} catch (IOException e) {
		Logger.error("IO Exception: " + e.toString());
	}
	finally {
		if (bw != null){
		bw.close();
		}
		if (os != null){
		os.close();
		}
	}
}

5. [DB] Méthode utilisant le même code pour deux branches [DB_DUPLICATE_BRANCHES]

 
Sélectionnez
if (this instanceof TraceRenderer) {
	madEnd = madBeg;
} else {
	madEnd = madBeg;
	}
}

Solution possible

 
Sélectionnez
if (this instanceof TraceRenderer) {
	madEnd = madBeg;
} else {
	// madEnd = autre chose
	}
}

6. [RCN] Test de nullité d'une valeur préalablement déréférencée [RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE]

 
Sélectionnez
public Object getResult() {
	Element e = params.get(0).getValue();
	Node n = e.getFirstChild();
	return (e == null) ? e.getTextContent() : n.getTextContent();
}

Solution possible
Le problème vient de la ligne suivante qui déclenche un NullPointerException si e == null

 
Sélectionnez
Node n = e.getFirstChild();

Et donc le test de la ligne suivante ne sert à rien

 
Sélectionnez
return (e == null) ? e.getTextContent() : n.getTextContent();

7. [EC] Appel de equals() avec un argument à null [EC_NULL_ARG]

 
Sélectionnez
if (object.equals(null))

Solution possible

 
Sélectionnez
if (object == null)

8. [DMI] Chemin absolu codé en dur dans le code [DMI_HARDCODED_ABSOLUTE_FILENAME]

 
Sélectionnez
final File dir = new File("C:\\temp\\test.txt");

9. [NP] Déréférencement d'un pointeur null dans le chemin d'exception d'une méthode [NP_ALWAYS_NULL_EXCEPTION]

 
Sélectionnez
public final void start() {
	UIComponentFactory componentFactory = null;
	try {
		componentFactory = UIComponentFactory.createInstance(true);
    }
	catch (MalformedURLException e) {
	e.printStackTrace();
	componentFactory.getClass();
	}

Solution possible

 
Sélectionnez
public final void start() {
	UIComponentFactory componentFactory = null;
	try {
		componentFactory = UIComponentFactory.createInstance(true);
    }
	catch (MalformedURLException e) {
	e.printStackTrace();
	}

X. Un code maintenable, évolutif et simple

Outils utilisés : CheckStyle, PMD, Findbugs, JDepend, CPD

Comme pour la partie précédente, l'écriture de tests unitaires est fortement conseillée.
Voici les principales métriques à regarder.

X-A. Duplication de code

Outils utilisés : CheckStyle et CPD
Solutions : Extract Method, Pull Up Method, Form Template Method, Substitute Algorithm

Le gros problème du code dupliqué est que s'il y a un bug, il faut le corriger à tous les endroits où il a été dupliqué. Sans parler de l'augmentation du nombre de lignes de code dans le programme.

Il existe plusieurs solutions à ce problème, comme :

  • Créer une méthode et y faire appel (Extract Method),
  • Mettre le code dans la classe parente (Pull Up Method),
  • Changer d'algorithme,
  • Etc.

X-B. Complexité Cyclomatique (CCN)

Outils utilisés : CheckStyle et PMD
Solutions : Extract Method, Replace Conditional with Polymorphism Design Patterns : Strategy, Factory

La complexité cyclomatique représente le nombre de chemins indépendants à parcourir pour traverser une méthode du début à la fin en couvrant tous les cas possibles. Au dessus d'une valeur de 10 le code devient complexe à lire et il faut énormément de tests unitaires.

Il existe plusieurs solutions à ce problème, comme :

  • Créer une méthode et y faire appel (Extract Method),
  • Utiliser le polymorphisme (Strategy, ...),
  • Utiliser des Factory,
  • Etc.

X-C. Nombre de ligne dans une classe/méthode/... (SLOC)

Outils utilisés : CheckStyle et PMD
Solutions : Extract Method, Replace Temp with Query, Introduce Parameter Object, Preserve Whole Object, Replace Method with Method Object.
Design Patterns : Strategy.

Des classes/méthodes/... trop longues sont difficile à lire et peuvent être le résultat d'une classe/méthode ayant trop de responsabilités.

Il existe plusieurs solutions à ce problème, comme :

  • Créer une méthode et y faire appel (Extract Method),
  • Utiliser le polymorphisme (Strategy, ...),
  • Transformer une méthode en objet,
  • Etc.

X-D. Couplage entre objets (Ca, Ce)

Outils utilisés : CheckStyle, JDepend
Solutions : Move Method, Extract Class
Design Patterns : Strategy, Factory.

Cette mesure permet de déterminer l'indépendance d'une classe par rapport au reste du système. Elle est donc susceptible d'être modifiée si le reste du système change.

Il existe plusieurs solutions à ce problème, comme :

  • Déplacer la méthode qui est l'origine du couplage (Move Method),
  • Utiliser le polymorphisme (Strategy, ...),
  • Créer une classe à partir de la classe existante (Extract Class),
  • Utiliser des Factory,
  • Etc.

X-E. Code mort

Outils utilisés : PMD
Solutions : Supprimer le code

PMD permet de détecter le code mort (code qui n'est plus utilisé). Il suffit de le supprimer.

X-F. Depth of Inheritance Tree (DIT)

Outils utilisés : PMD
Solutions : Replace Inheritance with Delegation, Pull Up/Push Down Method
Design Patterns : Delegation

Cette mesure permet de déterminer la profondeur de la classe dans l'arbre d'héritage.
Une valeur maximum de 5 est conseillée.

Il existe plusieurs solutions à ce problème, comme :

  • Mettre le code dans la classe parente (Pull Up Method),
  • Mettre le code dans la classe fille (Push Down Method),
  • Utiliser la Delegation,
  • Etc.

Pour la liste des solutions (refactoring), allez sur http://www.refactoring.com/catalog/index.html

XI. Un code performant

Outils utilisé : PMD, Findbugs

Pour ce critère, le seul moyen fiable est d'utiliser un profiler et un outil de mesure (JMeter, …) afin d'avoir des mesures concrètes.
Les résultats permettront de détecter les problèmes s'ils existent.

Des solutions sans modifier le code source existent :

  • Utiliser une version plus récente de la JVM
  • Optimiser / Paramétrer la JVM
  • Optimiser / Paramétrer la base de données
  • Optimiser / Paramétrer le serveur d'application

Plusieurs bons articles sur les performances des applications Java EE se trouvent sur le blog de Xebia.

De même Sun met à disposition des documentations sur le sujet http://java.sun.com/performance/reference/whitepapers/tuning.html

La catégorie "Optimization Rules" de règles de PMD, ainsi que les catégories "Multithreaded correctness" et "Performance" de FindBugs pourront aider dans une moindre mesure.

XII. Un code testé

Outils utilisé : SureFire, Cobertura

Avec ces 2 plugins on pourra connaître :

  • Le taux d'échec des tests unitaires,
  • La couverture de ces tests unitaires.

Ces 2 métriques doivent être lues ensemble.
Il faut faire attention au fait que les tests unitaires sont du code à maintenir/refactorer/...
Et donc comme pour la documentation, une couverture de 100% est généralement illusoire et inatteignable.
Un outil qui permet de connaître la difficulté d'écriture des tests unitaires se trouve sur http://code.google.com/p/testability-explorer/
De même pour détecter les singletons http://code.google.com/p/google-singleton-detector/

Penser à utiliser les extensions de JUnit (DBUnit, ...), les mocks (EasyMock, JMock, ... permettant de simuler un objet sans instancier cette objet, ce qui permet de ne tester qu'une chose à la fois) et la programmation orientée aspect pour vous simplifier l'écriture des tests unitaires.

Pour la couche métier, FitNesse est très intéressant (un plugin pour Maven2 existe et sera traité dans un prochain article). Cet outil se présente sous la forme d'un wiki avec des tests intégrés exécutables sous la forme de tableaux (valeurs d'entrés et résultat attendus, ...). L'avantage est que ces tableaux peuvent être remplis par un non informaticien, par exemple l'utilisateur de l'application qui connait la partie métier.
Pour plus d'informations, http://www.fitnesse.org/

Un taux d'échec de 0% et une bonne couverture de ces tests demandera quand même de regarder manuellement le code des tests unitaires pour valider qu'ils soient bien écrits.

Un test unitaire bien écrit doit répondre aux critères suivant :

  • Etre rapide,
  • S'exécuter en isolation (ne tester qu'une partie),
  • Etre fragile (échouer si le comportement du code testé change),
  • Tester les conditions limites (par exemple tester avec une valeur null),
  • Etre indépendants les uns des autres,
  • ...

Voila un article regroupant un certain nombre de mauvaises pratiques de tests unitaire http://bruno-orsier.developpez.com/anti-patterns/james-carr/

Il ne faut pas oublier un certain nombre de tests (tests d'intégration, test de l'interface graphique, …) qui ne rentrent pas dans le calcul de couverture de Cobertura et qui sont quand même importants.

XIII. Conclusion

L'outillage vient en plus d'une politique globale de qualité, et seulement après la définition d'une méthode de développement axé sur la qualité, et non pour la remplacer.
Comme nous l'avons vu, il existe un certain nombre d'outils permettant de contrôler la qualité d'un projet. De plus, ces outils existent aussi en plugin pour votre IDE. Malheureusement ces outils ne sont pas suffisants pour tout contrôler et donc il y a quand même une partie manuelle à réaliser.
De plus, il est important de comprendre que de bonnes métriques ne sont pas le garant absolu d'un logiciel bien conçu et réalisé.
Malgré ça, ces mesures permettent de nous orienter pour le reste de l'audit.
Avec un peu d'expérience (utilisation de ces outils et une liste de contrôles manuels à faire) et la loi de Pareto (aussi appelée loi des 80/20), cela sera suffisant pour la majorité des cas.

XIV. Références

XV. Remerciements

Merci à Romain Linsolas, Ricky81, regis1512 pour leurs relectures et leurs conseils.

XVI. Annexe A : Génération du diagramme de classe

Un dessin valant mieux que du texte, avoir un diagramme UML d'une classe peut aider à une meilleure compréhension. Avec l'aide de Maven2 et d'UMLGraph, on peut facilement ajouter des diagrammes UML dans la javadoc.
Le principe est que à partir du code et de certaine balise Javadoc, il va faire du reverse engineering afin de créer ces diagrammes.

Puis dans le pom.xml, modifier/créer la partie reporting

pom.xml
Sélectionnez
<project...>
    ...
    <reporting>
        <plugins>
            <plugin>
                <artifactId>maven-javadoc-plugin</artifactId>
                <configuration>
                    <source>1.5</source>
                    <doclet>
                        gr.spinellis.umlgraph.doclet.UmlGraphDoc
                    </doclet>
                    <docletArtifact>
                        <groupId>gr.spinellis</groupId>
                        <artifactId>UmlGraph</artifactId>
                        <version>4.4</version>
                    </docletArtifact>
                    <additionalparam>
                        -inferrel -inferdep -quiet -hide java.*
                        -collpackages java.util.* -qualify
                        -postfixpackage -nodefontsize 9
                        -nodefontpackagesize 7 -attributes -operations
                        -enumerations -enumconstants -visibility 
                        -link "http://java.sun.com/j2se/1.5/docs/api/" 
                        -link "http://static.springframework.org/spring/docs/2.0.x/api/"
                        -link "http://www.hibernate.org/hib_docs/v3/api/"
                    </additionalparam>
                </configuration>
            </plugin>
        </plugins>
    </reporting>
    ...
</project>

Voila un exemple de ce que l'on peut obtenir

Image non disponible

URL d'UMLGraph : http://www.umlgraph.org/

XVII. Annexe B : Génération du schéma de la base de données

De nombreux outils permettent de faire du reverse engineering sur une base de données afin d'avoir le schéma de celle-ci. Parmi ces outils SchemaSpy a l'avantage d'avoir un plugin pour Maven2.

La première chose à faire est d'ajouter le login/password dans votre fichier setting.xml

setting.xml
Sélectionnez
<profiles><profile>
      <id>development</id>
      <activation>
         <activeByDefault>true</activeByDefault>
     </activation>
     <properties>
        <schemaspy.username>antonio</schemaspy.username>
        <schemaspy.password></schemaspy.password>
     </properties>
   </profile></profiles>  

Puis d'ajouter le Wakaleo repository (dans le fichier pom.xml)

pom.xml
Sélectionnez
<pluginRepositories>
	...
		<pluginRepository>
			<id>Wakaleo Repository</id>
			<url>http://maven.wakaleo.com/repos/</url>
		</pluginRepository>
	...             
</pluginRepositories>

Et enfin

pom.xml
Sélectionnez
  <build>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>com.wakaleo.schemaspy</groupId>
          <artifactId>maven-schemaspy-plugin</artifactId>
          <version>1.0</version>
        </plugin>
        ...
      </plugins>
    </pluginManagement>
    <plugins>
      <plugin>
        <groupId>com.wakaleo.schemaspy</groupId>
        <artifactId>maven-schemaspy-plugin</artifactId>
        <version>1.0</version>
      </plugin>
      ...
    </plugins>
  </build>
...
  <reporting>
    <plugins>

        <plugin>
            <groupId>com.wakaleo.schemaspy</groupId>
            <artifactId>maven-schemaspy-plugin</artifactId>
            <version>1.0</version>
            <configuration>
				<databaseType>mysql</databaseType>
				<database>antonio</database>     
				<host>localhost</host>
				<user>${schemaspy.username}</user>
				<password>${schemaspy.password}</password>
            </configuration>
        </plugin> 
    </plugins>
  </reporting>

La documentation générée se trouve dans le répertoire target/site/schemaspy et sera composée de plusieurs onglets.

Image non disponible

URL du plugin : http://maven.wakaleo.com/mojo/maven-schemaspy-plugin/index.html