Le principe DRY (Don’t Repeat Yourself) est un principe du développement logiciel qui favorise l’élimination des duplications de code et met l’accent sur l’importance d’éviter les répétitions inutiles d’informations ou de logique dans un système, car la duplication de code peut entraîner des problèmes de maintenance, une augmentation de la complexité et des incohérences.
Le principe DRY peut être résumé par la phrase suivante : « Toute partie du savoir doit avoir une représentation unique, non ambiguë et autoritaire dans le système ».
Ce principe a été popularisé par le livre The Pragmatic Programmer d’Andrew Hunt et David Thomas.
Voici quelques informations sur la manière dont le principe DRY agit, comment il fonctionne, comment il peut être utilisé et où il peut être appliqué :
- Éviter la duplication: Le principe DRY vise à éliminer la duplication de code, que ce soit sous forme de répétition littérale de fragments de code, de répétition d’une logique similaire ou de redondance d’informations. En évitant la duplication, le code devient plus concis, plus facile à maintenir et moins sujet à des erreurs.
- Centralisation du savoir: Le DRY encourage la centralisation du savoir en un seul endroit du système. Plutôt que d’avoir la même logique dispersée dans plusieurs lieux, il est préférable d’avoir un seul endroit où la logique est définie et référencée chaque fois que nécessaire. Cela facilite la maintenance et évite les incohérences.
- Réutilisation du code: Le DRY promeut la réutilisation du code existant. Plutôt que de dupliquer du code, il vaut mieux créer des abstractions ou des composants réutilisables qui peuvent être partagés dans différentes parties du système. Ainsi, une seule modification de ces composants affecte toutes leurs instances.
- Simplification et lisibilité: En éliminant la duplication, le code devient plus simple, concis et lisible. La logique est exprimée en un seul endroit, ce qui facilite la compréhension et le débogage. De plus, les modifications futures sont plus faciles à réaliser, car elles ne nécessitent d’être appliquées qu’à un seul endroit.
Le principe DRY peut être appliqué à différents niveaux dans le développement logiciel, depuis la granularité du code jusqu’à l’architecture du système. Voici quelques exemples d’endroits où DRY peut être utilisé :
- Éviter la répétition de blocs de code similaires dans diverses parties du système.
- Utiliser des fonctions, méthodes ou classes réutilisables afin d’éviter la duplication de logique.
- Centraliser les informations communes dans des constantes, des énumérations ou des paramètres de configuration.
- Utiliser l’héritage, les interfaces ou la composition pour partager des fonctionnalités entre différentes classes.
- Raffiner des segments de code dupliqués pour créer des abstractions et des composants réutilisables.
Voici quelques exemples basiques montrant comment appliquer ce principe :
1 : Éviter la duplication de code
| // Exemplo não DRY public void CalcularAreaCirculo(double raio) { double area = Math.PI * raio * raio; Console.WriteLine(“A área do círculo é: “ + area); }public void CalcularPerimetroCirculo(double raio) { double perimetro = 2 * Math.PI * raio; Console.WriteLine(“O perímetro do círculo é: “ + perimetro); } |
DRY :
| // Exemplo DRY public void CalcularCirculo(double raio) { double area = Math.PI * raio * raio; double perimetro = 2 * Math.PI * raio; Console.WriteLine(“A área do círculo é: “ + area); Console.WriteLine(“O perímetro do círculo é: “ + perimetro); } |
No exemplo ci-dessus, nous avons initialement deux fonctions distinctes pour calculer l’aire et le périmètre d’un cercle. Cela entraîne une duplication de code.
Dans l’exemple DRY, la duplication est éliminée, en créant une unique fonction CalcularCirculo qui calcule à la fois l’aire et le périmètre. Cela réduit la répétition de code et facilite la maintenance, puisque toute modification de la formule du cercle doit être effectuée à un seul endroit.
2 : Centraliser les informations communes
| // Exemplo não DRY public void ExibirErro(string mensagem) { Console.WriteLine(“Erreur: “ + mensagem); }public void ExibirAviso(string mensagem) { Console.WriteLine(“Avertissement: “ + mensagem); } public void ExibirInformacao(string mensagem) |
Utilisant DRY :
| // Exemplo DRY public void ExibirMensagem(string tipo, string mensagem) { Console.WriteLine(tipo + “: “ + mensagem); } |
Dans l’exemple ci-dessus, nous avions initialement trois fonctions distinctes pour afficher différents types de messages (erreur, avertissement et information). Cela entraîne une duplication de code.
Dans l’exemple DRY, la duplication est évitée en créant une unique fonction ExibirMensagem qui reçoit un paramètre supplémentaire indiquant le type de message à afficher. Cela centralise la logique commune et réduit la répétition de code.
3 : Réutilisation du code avec l’héritage
| // Exemplo não DRY public class Retangulo { public double Largura { get; set; } public double Altura { get; set; } public virtual double CalcularArea() { return Largura * Altura; } }public class Quadrado : Retangulo { public override double CalcularArea() { return Largura * Largura; } } |
Utilisant DRY :
| public class Figura { public double Largura { get; set; } public double Altura { get; set; } public virtual double CalcularArea() { return Largura * Altura; } }public class Quadrado : Figura { public override double CalcularArea() { return Largura * Largura; } } |
Dans cet exemple, nous avons d’abord deux classes, Retangulo et Quadrado, où Quadrado Hérite de Retangulo. Cependant, cette hiérarchie ne suit pas le principe DRY, car il y a duplication du code dans l’implémentation de CalcularArea.
Dans l’exemple DRY, la duplication est évitée en créant une classe de base Figura qui contient les propriétés Largura et Altura, ainsi que l’implémentation commune de CalcularArea. La classe Quadrado hérite de Figura et ne remplace que la méthode nécessaire, ce qui permet de garder le code plus clair et de réutiliser la logique de la classe de base.
4- Utiliser des constantes plutôt que des valeurs littérales répétées
| // Exemplo não DRY public double CalcularCircunferencia(double raio) { return 2 * Math.PI * raio; }public double CalcularAreaCirculo(double raio) { return Math.PI * raio * raio; } |
utilisant DRY :
| private const double Pi = Math.PI;public double CalcularCircunferencia(double raio) { return 2 * Pi * raio; } public double CalcularAreaCirculo(double raio) |
Dans cet exemple, nous avions initialement deux fonctions qui calculaient la circonférence et l’aire d’un cercle. Les deux utilisaient Math.PI à chaque fois, ce qui entraînait une répétition.
Dans l’exemple DRY, la valeur de Math.PI est stockée dans une constante Pi, évitant ainsi la répétition inutile.
5- Utiliser l’héritage pour partager un comportement commun
| // Exemplo não DRY public class Animal { public virtual void EmitirSom() { Console.WriteLine(“L’animal émet un son.”); } }public class Gato : Animal { public override void EmitirSom() { Console.WriteLine(“Le chat miaule.”); } } public class Cachorro : Animal |
utilisant DRY :
| public abstract class Animal { public abstract void EmitirSom(); }public class Gato : Animal { public override void EmitirSom() { Console.WriteLine(“Le chat miaule.”); } } public class Cachorro : Animal { public override void EmitirSom() { Console.WriteLine(“Le chien aboie.”); } } |
Ici, initialement nous avons une classe de base Animal et des sous-classes Gato et Cachorro, où chaque animal émet un son spécifique. Dans l’exemple DRY, la classe de base Animal est définie comme abstraite, avec une méthode abstraite EmitirSom().
Les sous-classes Gato et Cachorro héritent de Animal et fournissent leurs propres implémentations de la méthode EmitirSom(). Ainsi, le comportement commun est partagé à travers l’héritage, évitant ainsi la duplication inutile de code.
6- Utiliser des méthodes génériques pour éviter la répétition de code similaire
| // Exemplo não DRY public void ImprimirInteiros(List<int> numeros) { foreach (int numero in numeros) { Console.WriteLine(numero); } }public void ImprimirStrings(List<string> strings) { foreach (string str in strings) { Console.WriteLine(str); } } |
utilisant DRY :
| public void ImprimirElementos<T>(List<T> elementos) { foreach (T elemento in elementos) { Console.WriteLine(elemento); } } |
Dans cet exemple, nous avons d’abord deux fonctions qui impriment des éléments de listes spécifiques : une pour les entiers et une autre pour les chaînes de caractères.
Dans l’exemple DRY, la duplication est évitée en utilisant une méthode générique ImprimirElementos<T>() qui accepte une liste de n’importe quel type T et itère sur les éléments pour les imprimer. Cela élimine le besoin d’écrire des méthodes séparées pour chaque type spécifique.
Ces exemples démontrent différentes façons d’appliquer le principe DRY dans du code C#. L’objectif est d’éviter la duplication inutile de code, de centraliser les informations communes, de partager des comportements similaires et d’utiliser des abstractions appropriées afin de favoriser la réutilisation du code. Cela donne un code plus concis, lisible et facile à maintenir.
Et c’est tout bonnement discuté.




