On écrit du code une fois, mais on le lit des centaines de fois. Le développeur qui écrit une fonction est rarement celui qui la débogue six mois plus tard, l'étend pour répondre à un nouveau besoin, ou doit en comprendre les cas limites lors d'un incident en production. Chaque décision prise lors de l'écriture du code – le nom d'une variable, la longueur d'une fonction, la structure d'une classe – facilite ou complique la tâche du lecteur suivant. Un code propre est la discipline qui consiste à systématiquement simplifier ce travail.
Le concept a été formalisé par Robert C. Martin, dit « Oncle Bob », dans son ouvrage *Clean Code : A Handbook of Agile Software Craftsmanship * (2008), qui demeure la référence incontournable en la matière. *Refactoring : Improving the Design of Existing Code* de Martin Fowler aborde le problème complémentaire : comment procéder lorsque du code existant n’est pas propre et doit l’être. Ensemble, ces deux ouvrages définissent les fondements intellectuels des bonnes pratiques du code propre. Ce guide présente leurs principes clés à l’aide d’exemples de code fonctionnels dans les langages les plus utilisés, notamment RPG et PL/I, à destination des développeurs assurant la maintenance des systèmes d’entreprise existants.
Corriger les violations de code invisibles
SMART TS XL Détecte la complexité, les duplications et le code mort dans COBOL, Java, Python, RPG et bien plus encore.
En savoir plusQu'est-ce qu'un code propre ?
Un code propre est un code source facile à lire, à comprendre, à tester et à modifier. Le terme « facile » prend ici tout son sens. Un code accepté par un compilateur n'est pas forcément propre. De même, un code qui réussit tous les tests n'est pas forcément propre. Un code est propre lorsqu'un autre développeur, qui ne l'a pas écrit, peut, dans un contexte non prévu lors de sa conception, en comprendre rapidement l'intention, le modifier avec assurance et l'étendre sans conséquences inattendues.
La définition de Martin Fowler est la plus citée : « N'importe quel imbécile peut écrire du code compréhensible par un ordinateur. Les bons programmeurs écrivent du code compréhensible par les humains. » La qualité d'un code se mesure à sa compréhension humaine, et non à son exécution par une machine.
Un code propre n'est pas une question d'esthétique. Il ne s'agit pas de suivre un guide de style pour le simple plaisir de le faire. Il s'agit des propriétés structurelles du code qui déterminent l'effort nécessaire pour chaque modification future. Un code qui enfreint les principes du code propre accumule constamment de la dette technique, le coût cumulatif des raccourcis passés, jusqu'à ce que chaque nouvelle fonctionnalité exige de comprendre et de naviguer avec précaution dans la complexité existante avant d'ajouter quoi que ce soit de nouveau.
Principes du code propre : Guide de référence rapide
Les principes de code propre de Robert C. Martin peuvent se résumer à un ensemble de lignes directrices concrètes. Le tableau ci-dessous associe chaque principe à sa règle fondamentale et au problème qu'il permet de prévenir :
| Principe | Règle de base | Problème qu'il prévient |
|---|---|---|
| Noms significatifs | Les noms doivent révéler l'intention, les variables, les fonctions et les classes. | Surcharge cognitive liée au décodage de quoi x, tmp, obj représente réellement |
| Petites fonctions | Chaque fonction a une seule utilité : tenir sur un seul écran. | Des monolithes impossibles à tester et illisibles qui mélangent les responsabilités |
| Responsabilité unique | Chaque classe/module a une raison de changer | Des classes divines qui se désagrègent lorsqu'une douzaine de choses sans rapport les unes avec les autres changent. |
| SEC (Ne vous répétez pas) | Chaque connaissance a une représentation | Corrections de bogues appliquées à une copie mais pas aux autres ; dérive logique |
| KISS (Keep It Simple) | Privilégiez la solution la plus simple qui fonctionne | Un code surdimensionné qui résout des problèmes que personne n'a |
| YAGNI (Tu n'en auras pas besoin) | N'ajoutez pas de fonctionnalités tant qu'elles ne sont pas nécessaires. | Du code spéculatif mort qui ajoute de la complexité sans aucun avantage |
| Principe ouvert/fermé | Ouvert à la prolongation, fermé à la modification | Code qui perturbe le comportement existant lors de l'ajout d'un nouveau comportement |
| Séparation des préoccupations | Des responsabilités différentes selon les lieux | Code complexe où la modification d'un élément en perturbe d'autres. |
| Évitez les commentaires du type « quoi » ; utilisez-les pour expliquer pourquoi. | Le code explique le quoi ; les commentaires expliquent le pourquoi | Des commentaires obsolètes qui induisent plus en erreur qu'ils n'informent. |
| Règle des scouts | Laissez le code plus propre que vous ne l'avez trouvé. | Dégradation progressive de la qualité par négligence croissante |
Explication des principes fondamentaux du code propre
DRY, ne vous répétez pas
Le principe DRY (Don't Repeat Yourself) stipule que chaque information doit avoir une représentation unique, non ambiguë et faisant autorité au sein d'un système. Lorsque la même logique apparaît à plusieurs endroits, ces représentations divergent inévitablement. La modification d'une règle métier se transforme alors en une opération de recherche et de remplacement dans plusieurs fichiers, et l'absence d'une seule copie engendre un bogue.
Le principe DRY ne se limite pas au code copié-collé. Il s'applique à la configuration, à la documentation et aux schémas de données. Si une même information doit être conservée à deux endroits, vous enfreignez le principe DRY, même si aucun code n'a été littéralement copié.
KISS, faites simple
KISS soutient que les systèmes fonctionnent mieux lorsqu'ils restent simples et que la simplicité doit être un objectif primordial lors de leur conception. La complexité n'est pas un signe de sophistication, mais plutôt la preuve qu'une idée aurait pu être exprimée plus clairement.
En pratique : si deux solutions permettent de résoudre un même problème, privilégiez la plus simple. La solution plus complexe peut gérer des cas particuliers que vous n’avez pas encore rencontrés, mais elle rendra assurément le code plus difficile à comprendre pour tous ceux qui l’utiliseront.
YAGNI, tu n'en auras pas besoin
YAGNI déconseille d'ajouter des fonctionnalités tant qu'elles ne sont pas nécessaires. Cette approche répond à la tendance courante à concevoir des systèmes flexibles et extensibles pour des besoins futurs anticipés qui ne se concrétisent jamais. Chaque abstraction, interface et option de configuration prévue pour un cas d'utilisation hypothétique représente une surcharge cognitive pour tout développeur qui consulte le code aujourd'hui.
Noms significatifs
Les noms constituent le principal mécanisme de communication dans le code source. Une fonction nommée process() ne communique rien sur ce qu'elle traite, quand, ni sur ce qu'elle renvoie. Une fonction nommée calculateMonthlyInterest() communique avec précision.
Les critères essentiels pour un nom : Peut-on deviner ce qu’il représente sans lire son implémentation ? Le nom révèle-t-il son objectif, ses paramètres et sa valeur de retour ? Un commentaire serait-il nécessaire pour expliquer son fonctionnement ?
Petites fonctions
La règle empirique de Robert C. Martin : les fonctions doivent être courtes, plus courtes que vous ne le pensez nécessaire. Une fonction qui effectue une seule tâche peut être nommée clairement, testée indépendamment et comprise sans lire son implémentation. Une fonction qui effectue plusieurs tâches exige de les comprendre toutes simultanément.
Le principe de responsabilité unique appliqué aux fonctions : une fonction doit faire une seule chose, bien la faire et ne faire que cela. Si l’on a besoin du mot « et » pour décrire ce que fait une fonction, c’est probablement qu’elle en fait trop.
Nettoyer le code en Java
La verbosité de Java rend la rigueur du code propre particulièrement importante. Le code répétitif qu'il impose peut masquer l'intention initiale s'il n'est pas géré avec soin.
Java
// Before: unclear names, mixed responsibilities, magic numbers
public double calc(int x, int y) {
double r = 0;
if (y > 1000) {
r = x * y * 0.1;
} else {
r = x * y * 0.05;
}
return r;
}
// After: meaningful names, single responsibility, named constants
private static final double PREMIUM_DISCOUNT_RATE = 0.10;
private static final double STANDARD_DISCOUNT_RATE = 0.05;
private static final int PREMIUM_THRESHOLD = 1000;
public double calculateDiscount(int quantity, int unitPrice) {
double subtotal = quantity * unitPrice;
return isPremiumOrder(unitPrice)
? subtotal * PREMIUM_DISCOUNT_RATE
: subtotal * STANDARD_DISCOUNT_RATE;
}
private boolean isPremiumOrder(int unitPrice) {
return unitPrice > PREMIUM_THRESHOLD;
}
Les bonnes pratiques de programmation propre en Java : privilégier la composition à l’héritage, utiliser les flux pour le traitement des données plutôt que les boucles verbeuses, extraire les nombres magiques dans des constantes nommées et veiller à ce que les classes soient dédiées à une seule responsabilité. Parmi les principes de programmation propre de Robert C. Martin pour Java figure la règle selon laquelle les classes doivent être petites, leur taille étant mesurée non pas en lignes de code, mais en responsabilités.
Java
// Clean Java: streams over imperative loops
List<String> activeUserEmails = users.stream()
.filter(User::isActive)
.map(User::getEmail)
.collect(Collectors.toList());
Nettoyer le code en Python
La philosophie de conception de Python, qui privilégie l'explicite à l'implicite et la simplicité à la complexité, s'aligne naturellement sur les principes du code propre. La PEP 8 est le guide de style officiel de Python et la base d'un code Python propre.
python
# Before: vague names, long function, no separation
def do_stuff(d):
res = []
for i in d:
if i['a'] > 18:
res.append(i['n'].upper())
return res
# After: meaningful names, separated concerns, Pythonic style
def get_adult_names_uppercase(users: list[dict]) -> list[str]:
return [
user["name"].upper()
for user in users
if user["age"] > 18
]
python
# Clean Python: context managers for resource handling
# Before: manual, error-prone
f = open("data.txt")
data = f.read()
f.close()
# After: guaranteed cleanup, self-documenting intent
with open("data.txt") as f:
data = f.read()
Le code propre Pythonique utilise des compréhensions de listes plutôt que des boucles manuelles pour les transformations simples, des indications de type pour des signatures de fonctions auto-documentées, des gestionnaires de contexte pour la gestion des ressources et des classes de données ou des tuples nommés au lieu de simples dictionnaires pour les données structurées.
Code propre en JavaScript et TypeScript
La flexibilité de JavaScript est à la fois sa force et son principal défi en matière de code propre. Sans rigueur, les bases de code JavaScript accumulent des incohérences, des conversions de type implicites et des chaînes de rappels complexes.
javascript
// Before: var, callback hell, no error handling
function getUser(id, cb) {
db.query('SELECT * FROM users WHERE id = ' + id, function(err, rows) {
if (err) cb(err);
cb(null, rows[0]);
});
}
// After: async/await, parameterized query, proper error handling
async function getUserById(userId: number): Promise<User | null> {
const [rows] = await db.execute(
'SELECT * FROM users WHERE id = ?',
[userId]
);
return rows[0] ?? null;
}
manuscrit
// Clean TypeScript: explicit types replace implicit any
// Before
function process(data) {
return data.map(x => x.v * 2);
}
// After
interface DataPoint {
value: number;
label: string;
}
function doubleValues(dataPoints: DataPoint[]): number[] {
return dataPoints.map(point => point.value * 2);
}
Utilisation de JavaScript propre const par défaut, let lorsque la reliure est nécessaire, et jamais varLes fonctions pures, qui produisent toujours la même sortie pour une même entrée et sans effets secondaires, constituent l'élément de base le plus propre de la logique JavaScript.
Nettoyer le code en C#
C# offre des fonctionnalités puissantes pour écrire du code clair et expressif. L'évolution du langage, LINQ, les enregistrements, la correspondance de modèles et les types référence nullables tendent constamment vers une syntaxe plus déclarative et lisible.
tranchant
// Before: magic numbers, verbose loop, mutable state
public double CalculateTotal(List<OrderItem> items)
{
double total = 0;
foreach (var item in items)
{
if (item.Quantity > 10)
total += item.UnitPrice * item.Quantity * 0.9;
else
total += item.UnitPrice * item.Quantity;
}
return total;
}
// After: named constant, LINQ, single expression
private const double BulkDiscountRate = 0.9;
private const int BulkDiscountThreshold = 10;
public double CalculateTotal(IEnumerable<OrderItem> items) =>
items.Sum(item => item.Quantity > BulkDiscountThreshold
? item.UnitPrice * item.Quantity * BulkDiscountRate
: item.UnitPrice * item.Quantity);
Principes de code propre en C# : utiliser des propriétés plutôt que des champs publics pour l’encapsulation, tirer parti de LINQ pour les opérations de données déclaratives, utiliser des enregistrements pour les structures de données immuables, préférer les interfaces aux types concrets dans les signatures de méthodes et utiliser des types référence nullables (string? vs string) pour rendre la sécurité nulle explicite.
Code propre en Kotlin
La conception de Kotlin réduit spécifiquement le code répétitif qui rend Java difficile à maintenir propre, tout en ajoutant des fonctionnalités, des classes de données, des fonctions d'extension, la sécurité contre les valeurs nulles, qui favorisent naturellement un code propre.
Kotlin
// Before: verbose Java-style Kotlin
class User {
var name: String = ""
var email: String = ""
var age: Int = 0
}
fun processUsers(users: List<User>): List<String> {
val result = mutableListOf<String>()
for (user in users) {
if (user.age >= 18) {
result.add(user.email)
}
}
return result
}
// After: idiomatic clean Kotlin
data class User(val name: String, val email: String, val age: Int)
fun getAdultEmails(users: List<User>): List<String> =
users.filter { it.age >= 18 }.map { it.email }
Kotlin data class Fournit automatiquement les méthodes equals, hashCode, copy et toString, éliminant ainsi le code répétitif qui rend les classes de données Java verbeuses et sujettes aux erreurs. Les fonctions d'extension permettent d'ajouter des méthodes utilitaires claires aux classes existantes sans héritage.
Code propre en RPG et PL/I : Langages anciens, principes modernes
Les principes du code propre s'appliquent à tous les langages, y compris les langages d'entreprise qui gèrent les systèmes financiers, les plateformes d'assurance et les applications gouvernementales à travers le monde. RPG (Report Program Generator) et PL/I sont encore activement maintenus dans de nombreuses organisations, et la même rigueur qui garantit la propreté du code en Java ou en Python assure la pérennité de RPG et PL/I.
Code propre en RPG (ILE RPG) :
rpg
// Before: cryptic two-character names, magic numbers
C EVAL D = Q * P * 1.05
C IF Q > 100
C EVAL D = Q * P * 0.95
C ENDIF
// After: meaningful names, named constants, clear intent
/free
dcl-c BULK_DISCOUNT_THRESHOLD 100;
dcl-c BULK_DISCOUNT_RATE 0.95;
dcl-c STANDARD_RATE 1.05;
dcl-proc CalculateOrderTotal;
dcl-pi *N packed(15:2);
quantity packed(7:0) value;
unitPrice packed(9:2) value;
end-pi;
if quantity > BULK_DISCOUNT_THRESHOLD;
return quantity * unitPrice * BULK_DISCOUNT_RATE;
else;
return quantity * unitPrice * STANDARD_RATE;
endif;
end-proc;
/end-free
Pratiques clés pour un RPG propre : utiliser le format libre d’ILE RPG (/free) privilégier une syntaxe plutôt qu'un format fixe pour une meilleure lisibilité, nommer les procédures de manière descriptive et remplacer les valeurs codées en dur par des constantes nommées. dcl-cet décomposer les longs programmes en procédures ciblées en utilisant dcl-proc.
Code propre en PL/I :
pli
/* Before: single-letter names, no structure */
CALC: PROC(X, Y) RETURNS(FLOAT);
DCL (X, Y, R) FLOAT;
IF Y > 1000 THEN R = X * Y * 0.1;
ELSE R = X * Y * 0.05;
RETURN(R);
END CALC;
/* After: meaningful names, named constants, clear intent */
DCL PREMIUM_THRESHOLD FIXED DECIMAL(7) INIT(1000);
DCL PREMIUM_RATE FLOAT INIT(0.10);
DCL STANDARD_RATE FLOAT INIT(0.05);
CALCULATE_DISCOUNT: PROC(QUANTITY, UNIT_PRICE) RETURNS(FLOAT);
DCL (QUANTITY, UNIT_PRICE) FLOAT;
DCL SUBTOTAL FLOAT;
SUBTOTAL = QUANTITY * UNIT_PRICE;
IF UNIT_PRICE > PREMIUM_THRESHOLD
THEN RETURN(SUBTOTAL * PREMIUM_RATE);
ELSE RETURN(SUBTOTAL * STANDARD_RATE);
END CALCULATE_DISCOUNT;
Les principes de code propre de PL/I reflètent ceux des langages modernes : des identificateurs significatifs (la limite de 31 caractères de PL/I est suffisante pour les noms descriptifs), des constantes nommées au lieu de nombres magiques, des procédures axées sur une seule tâche et une gestion explicite des erreurs à l’aide du système de condition ON.
Outils de code propre et analyse statique
L'application manuelle des principes de code propre par le biais de revues de code est nécessaire, mais insuffisante à grande échelle. Les outils d'analyse statique appliquent automatiquement les métriques de code propre, en signalant les violations avant leur intégration.
| Outil | Langues | Ce que cela impose |
|---|---|---|
| SonarQube / SonarCloud | Plus de 30 langues | Complexité, duplication, anomalies de code, sécurité |
| Style de contrôle | Java | Conventions d'appellation, formatage, structure |
| PMD | Java, Apex | Code dupliqué, variables inutilisées, complexité |
| ESLint + typescript-eslint | JavaScript, TypeScript | Style, complexité, code inutilisé, modèles asynchrones |
| Pylint + Radon | Python | PEP 8, complexité, indice de maintenabilité |
| ReSharper | C# | Style de code, code redondant, suggestions de refactorisation |
| Clippy | Se reposer | Expressions idiomatiques, erreurs courantes |
| SMART TS XL | COBOL, RPG, PL/I, Java, Python et bien plus encore | Complexité interlingue, duplication, code mort |
Les métriques de code propre les plus courantes mesurées par les outils sont : la complexité cyclomatique (nombre de branches de décision ; au-dessus de 10, il s’agit d’un avertissement ; au-dessus de 20, c’est critique), la complexité cognitive (difficulté à comprendre le code ; une métrique spécifique à SonarQube qui améliore la complexité cyclomatique pour la mesure de la lisibilité) et le taux de duplication (pourcentage de code dupliqué ; au-dessus de 3 %, il convient d’y prêter attention).
Comment SMART TS XL Garantit un code propre dans les bases de code d'entreprise.
Les outils de contrôle qualité mentionnés ci-dessus fonctionnent au sein d'un seul langage. Dans les environnements d'entreprise où coexistent services Java, pipelines Python, programmes batch COBOL, modules RPG et flux de travaux JCL, il est nécessaire de mesurer simultanément les violations de code propre de chaque langage, et les relations entre les composants, quel que soit le langage, sont tout aussi importantes que la qualité de chaque fichier pris individuellement.
SMART TS XL's analyse de code statique Applique des indicateurs de qualité de code à tous les langages de l'environnement simultanément. La complexité cyclomatique, les taux de duplication, l'identification du code mort et les indicateurs de couplage structurel sont calculés pour les programmes COBOL selon la même méthodologie que pour les classes Java, produisant ainsi des mesures de qualité comparables et unifiées pour l'ensemble du parc applicatif.
La fonctionnalité d'analyse d'impact permet de corriger les violations de code propre à l'échelle de l'architecture : lorsqu'un paragraphe COBOL est fortement couplé à des dizaines d'autres programmes, l'analyse d'impact indique précisément les composants affectés avant toute refactorisation. Ceci transforme la paralysie de refactorisation que rencontrent les équipes sur les grands projets en un programme de remédiation structuré et à périmètre défini.
La cartographie des dépendances applicatives identifie les violations architecturales du principe de code propre au niveau système : les composants devenus des classes omniprésentes à l’échelle de l’entreprise, les dépendances circulaires qui enfreignent le principe de séparation des préoccupations entre les langages, et les cas où la même logique métier est implémentée indépendamment dans plusieurs systèmes sans que les différentes versions n’aient connaissance des autres. Cette violation du principe DRY (Don’t Repeat Yourself) entre langages – la même règle métier maintenue séparément dans un programme COBOL, un service Java et un pipeline Python – est la catégorie de violation de code propre la plus coûteuse dans les systèmes d’entreprise, et elle est invisible pour tout outil monolangage.
Pour les équipes appliquant les principes du code propre pendant modernisation de l'héritage programmes, SMART TS XL fournit l'analyse préalable à la refactorisation qui rend le travail réalisable : le code mort est exclu du périmètre avant le début de la conversion, les composants les plus complexes sont identifiés pour une attention prioritaire et le graphe de dépendances complet est disponible avant toute modification.
Le développement propre est une discipline d'équipe, pas une pratique individuelle.
Les principes de ce guide sont plus faciles à énoncer qu'à appliquer. Tout développeur peut écrire une fonction propre individuellement. Le défi consiste à maintenir un code propre au sein d'une équipe, dans le temps et pour une base de code qui s'agrandit au gré des changements de contributeurs. Cela requiert trois éléments : des normes partagées, connues et approuvées par tous ; des outils qui appliquent automatiquement ces normes ; et une culture d'amélioration continue, la règle du « boy scout » appliquée avec constance, afin que chaque partie du code soit légèrement plus propre qu'à son arrivée.
La formule de Robert C. Martin reste la plus pertinente : « Un code propre donne toujours l’impression d’avoir été écrit par quelqu’un qui s’en soucie. » La preuve de ce souci du détail ne réside pas dans l’absence de bogues, mais dans la présence de noms explicites, de fonctions bien définies, d’une structure claire et d’une absence de mauvaises surprises. Ce sont ces éléments qui rendent un code source agréable à utiliser, à enrichir et à maintenir au fil des années et des changements d’équipe inhérents à tout système performant.


