Qualité de code — Checkstyle et SpotBugs
Un code qui compile et fonctionne n'est pas forcément un bon code. Des outils d'analyse statique permettent de détecter automatiquement les problèmes de style, les bugs potentiels et les mauvaises pratiques sans exécuter le programme.
Notions théoriques
Pourquoi l'analyse statique ?
Relire le code manuellement est lent et subjectif. Les outils d'analyse statique :
- appliquent les conventions de façon objective et systématique
- détectent des bugs que les tests ne couvrent pas encore
- s'intègrent dans le build Maven pour bloquer le déploiement si des problèmes existent
Checkstyle — Respect des conventions
Checkstyle vérifie que votre code respecte un ensemble de règles de style. Il ne cherche pas de bugs, mais garantit la cohérence du code dans une équipe.
Configuration Maven
<!-- Dans pom.xml <plugins> -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.3.1</version>
<configuration>
<configLocation>checkstyle-google.xml</configLocation>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
</configuration>
<executions>
<execution>
<id>validate</id>
<phase>validate</phase>
<goals><goal>check</goal></goals>
</execution>
</executions>
</plugin>
Téléchargez checkstyle-google.xml depuis le dépôt GitHub de Checkstyle et placez-le à la racine de votre projet.
Règles Google Java Style vérifiées
| Catégorie | Règle |
|---|---|
| Nommage | Classes en PascalCase, variables et méthodes en camelCase |
| Nommage | Constantes en UPPER_SNAKE_CASE |
| Format | Longueur de ligne ≤ 100 caractères |
| Imports | Pas d'imports * (import java.util.* interdit) |
| Structure | Une seule instruction par ligne |
| Javadoc | Javadoc obligatoire sur les méthodes publiques |
Lancer Checkstyle
mvn checkstyle:check # vérifier uniquement
mvn checkstyle:checkstyle # générer le rapport HTML
mvn checkstyle:check fait échouer le build si des violations sont trouvées (comportement configuré avec failsOnError: true). C'est voulu : aucun code non conforme ne doit pouvoir être livré.
Exemples de violations courantes
// VIOLATION : nom de variable en PascalCase (devrait être camelCase)
String NomPersonnage = "Aragorn";
// VIOLATION : import wildcard
import java.util.*;
// VIOLATION : ligne trop longue
public Personnage creerPersonnageAvecTousLesParametres(String nom, int force, int defense, int mana) {
// CORRECTION
public Personnage creerPersonnage(
String nom, int force, int defense, int mana) {
Désactiver une règle ponctuellement
// CHECKSTYLE:OFF
// Code généré automatiquement — règle désactivée ici
private static final long serialVersionUID = -7043994889789898773L;
// CHECKSTYLE:ON
N'utilisez // CHECKSTYLE:OFF qu'en dernier recours pour du code généré automatiquement ou des contraintes externes. Ne jamais l'utiliser pour contourner une règle applicable.
SpotBugs — Détecter les bugs potentiels
SpotBugs (successeur de FindBugs) analyse le bytecode Java compilé à la recherche de patterns de bugs connus.
Configuration Maven
<!-- Dans pom.xml <plugins> -->
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>4.8.4.0</version>
<executions>
<execution>
<phase>verify</phase>
<goals><goal>check</goal></goals>
</execution>
</executions>
</plugin>
Catégories de bugs détectés
| Catégorie | Exemple |
|---|---|
| Null deref | Appel de méthode sur une valeur potentiellement null |
| Equals sans hashCode | equals() redéfini mais pas hashCode() |
| Ressource non fermée | Connection ou InputStream jamais fermé |
| Synchronisation | Variable partagée sans synchronisation |
| Mauvaise comparaison | == sur des objets String au lieu de .equals() |
// BUG SpotBugs : comparaison d'objets avec ==
String nom = getNom();
if (nom == "Aragorn") { // FAUX : compare les réf érences, pas les valeurs
System.out.println("Trouvé");
}
// CORRECTION
if ("Aragorn".equals(nom)) { // correct
System.out.println("Trouvé");
}
// BUG SpotBugs : equals() sans hashCode()
public class Personnage {
@Override
public boolean equals(Object o) { ... }
// MANQUE : hashCode() non défini → bug si utilisé dans une HashMap
}
Lancer SpotBugs
mvn spotbugs:check # vérifier (échoue si bugs trouvés)
mvn spotbugs:spotbugs # générer le rapport
mvn spotbugs:gui # ouvrir l'interface graphique
Le rapport HTML est généré dans target/site/.
Supprimer un faux positif
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@SuppressFBWarnings(
value = "EQ_DOESNT_OVERRIDE_EQUALS",
justification = "hashCode non nécessaire car non utilisé dans collections"
)
public class Personnage { ... }
Ne supprimez une alerte SpotBugs qu'après avoir compris pourquoi elle est levée et vérifié qu'elle est bien un faux positif. Les vraies alertes signalent de vrais bugs.
Exemple pratique
// Code avec problèmes — avant correction
public class personnageService { // CHECKSTYLE : classe en minuscule (devrait être PascalCase)
private List personnages; // SPOTBUGS : type raw sans générique
public Personnage TrouverParNom(String nom) { // CHECKSTYLE : méthode en PascalCase
for (int i = 0; i < personnages.size(); i++) {
Personnage p = (Personnage) personnages.get(i); // cast dangereux (raw type)
if (p.getNom() == nom) { // SPOTBUGS : == sur String
return p;
}
}
return null; // SPOTBUGS : risque NullPointerException à l'appelant
}
}
// Code corrigé — après Checkstyle + SpotBugs
public class PersonnageService {
private List<Personnage> personnages = new ArrayList<>();
public Optional<Personnage> trouverParNom(String nom) {
return personnages.stream()
.filter(p -> nom.equals(p.getNom()))
.findFirst();
}
}
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des problèmes
Vous allez configurer Checkstyle et SpotBugs dans le projet RPG, puis corriger les problèmes détectés.
Étape 1 — Configurer Checkstyle dans pom.xml
Ajoutez le plugin maven-checkstyle-plugin avec la configuration Google Style.
En liant Checkstyle à la phase validate (la première phase Maven), le build échoue immédiatement si le code n'est pas conforme. Cela empêche de continuer à compiler, tester et packager du code non conforme, économisant du temps en CI/CD.
Étape 2 — Identifier et corriger une violation Checkstyle
Voici du code avec des violations. Corrigez le nom de la méthode.
// Code actuel avec violations
public class PersonnageService {
public Personnage TrouverParNom(String nom) { // violation : PascalCase
// ...
}
}
En Java : classes → PascalCase (PersonnageService), méthodes et variables → camelCase (trouverParNom), constantes → UPPER_SNAKE_CASE (MAX_FORCE). Cette convention est universelle et rend le code immédiatement lisible par tout développeur Java.
Étape 3 — Corriger un bug détecté par SpotBugs
SpotBugs a signalé l'alerte ES_COMPARING_STRINGS_WITH_EQ dans ce code. Corrigez-le.
L'opérateur == compare les références (les adresses mémoire) et non les valeurs. Deux String "Aragorn" créées séparément peuvent avoir des références différentes mais des valeurs identiques. Utilisez toujours .equals() pour les objets, jamais ==.