Code Review en Java : quoi vérifier et comment donner un retour d'expérience en pratique
\n\nLe Code Review (revue de code) est une vérification systématique du code d'autrui visant à identifier les erreurs, améliorer la qualité et partager les connaissances. En développement Java, cela est particulièrement important en raison du typage strict, des particularités du multithreading et des exigences de performance. Cependant, de nombreux développeurs réduisent la revue à une simple vérification de style ou, au contraire, la transforment en critique toxique. Dans cet article, nous allons détailler ce qu'il faut exactement vérifier dans le code Java et comment donner un retour d'expérience qui soit bénéfique, et non douloureux.
\n\n1. Quoi vérifier dans le code Java : checklist pour le relecteur
\n\nPour qu'une revue soit efficace, il faut regarder non seulement la syntaxe, mais aussi l'architecture, la sécurité et les performances. Voici les principales catégories à vérifier.
\n\n1.1 Architecture et conception
\n- \n
- Principes SOLID : la classe ne viole-t-elle pas le principe de responsabilité unique ? L'interface ne se transforme-t-elle pas en « objet divin » ? \n
- Couplage et cohésion : les classes doivent être faiblement couplées (loose coupling) et avoir une forte cohésion interne (high cohesion). \n
- Utilisation des patrons : l'application de patrons complexes est-elle justifiée ? Parfois, un simple if-else est préférable à une fabrique avec une dizaine de classes. \n
// Mauvais : la classe fait tout à la fois\npublic class ReportService {\n public void generateReport() { /* génération */ }\n public void sendEmail() { /* envoi */ }\n public void saveToDatabase() { /* sauvegarde */ }\n}\n\n// Bon : séparation des responsabilités\npublic class ReportGenerator { ... }\npublic class EmailSender { ... }\npublic class ReportRepository { ... }\n\n\n1.2 Gestion des exceptions et des erreurs
\n- \n
- Suppression des exceptions : il ne faut pas écrire un
catch (Exception e)vide — cela masque les erreurs. \n - Spécificité : attrapez des exceptions spécifiques, pas
ExceptionouThrowable. \n - Journalisation : les exceptions doivent être journalisées avec un contexte suffisant (trace de la pile, données d'entrée). \n
// Mauvais : avaler l'exception\ntry {\n processFile(file);\n} catch (Exception e) {\n // on ne fait rien\n}\n\n// Bon : journalisation et relance\ntry {\n processFile(file);\n} catch (IOException e) {\n log.error("Erreur lors du traitement du fichier : {}", file, e);\n throw new ProcessingException("Impossible de traiter le fichier", e);\n}\n\n\n1.3 Performance et mémoire
\n- \n
- Opérations redondantes : création d'objets dans des boucles, copies inutiles de chaînes avec
new String(). \n - Utilisation des collections : le type est-il bien choisi (ArrayList vs LinkedList) ? Y a-t-il des synchronisations superflues ? \n
- Stream API : le stream ne dégrade-t-il pas la lisibilité ? Parfois, une boucle classique est plus compréhensible. \n
// Mauvais : création de chaîne dans une boucle\nString result = "";\nfor (String s : list) {\n result += s; // nouvelle chaîne à chaque fois\n}\n\n// Bon : StringBuilder\nStringBuilder sb = new StringBuilder();\nfor (String s : list) {\n sb.append(s);\n}\n\n\n1.4 Multithreading et synchronisation
\n- \n
- Utilisation correcte de synchronized : une trop grande portion de code n'est-elle pas verrouillée ? \n
- Collections concurrentes : utilisez-vous
ConcurrentHashMapau lieu d'une table de hachage avec synchronisation externe ? \n - Risque d'interblocage : les ressources ne sont-elles pas verrouillées dans un ordre différent ? \n
// Risque d'interblocage\nsynchronized (lockA) {\n synchronized (lockB) { ... }\n}\n// Dans un autre thread :\nsynchronized (lockB) {\n synchronized (lockA) { ... }\n}\n\n\n2. Comment écrire du code pour une revue facile
\n\nUne bonne revue commence par un bon code. A