Les odeurs de code sont un classique.
Ça sent mauvais parce qu'il y a probablement de nombreux cas où il pourrait être modifié ou amélioré.
La plupart de ces odeurs ne sont que des indices de quelque chose qui pourrait ne pas fonctionner. Ils ne sont pas obligatoirement corrigés en soi… (Vous devriez cependant y jeter un coup d'œil.)
Odeurs de code précédentes
- Première partie
- Partie II
- Partie III
- Partie IV
- Partie V
- Partie VI
- Partie VII
- Partie VIII
- Partie IX
- Partie X
- Partie XI
- Partie XII
- Partie XIII
- Partie XIV
- XVe partie
- Partie XVI
- Partie XVII
- Partie XVIII
- Partie XIX
- Partie XX
- XXIe partie
Nous allons continuer...
Code Odeur 106 - Code dépendant de la production
N'ajoutez pas de vérification IF pour l'environnement de production.
TL ; DR : évitez d'ajouter des conditions liées à la production
Problèmes
- Violation du principe d'échec rapide
- Manque de testabilité
Solutions
- Si nécessaire, modélisez des environnements et testez-les TOUS .
Le contexte
Parfois, nous devons créer des comportements différents dans le développement et la production.
Par exemple la force des mots de passe.
Dans ce cas, nous devons configurer l'environnement avec la stratégie de force et tester la stratégie et non l'environnement lui-même.
Exemple de code
Mauvais
def send_welcome_email(email_address, environment): if ENVIRONMENT_NAME == "production": print(f"Sending welcome email to {email_address} from Bob Builder <[email protected]>") else: print("Emails are sent only on production") send_welcome_email("[email protected]", "development") # Emails are sent only on production send_welcome_email("[email protected]", "production") # Sending welcome email to [email protected] from Bob Builder <[email protected]>
Droit
class ProductionEnvironment: FROM_EMAIL = "Bob Builder <[email protected]>" class DevelopmentEnvironment: FROM_EMAIL = "Bob Builder Development <[email protected]>" # We can unit test environments # and even implement different sending mechanisms def send_welcome_email(email_address, environment): print(f"Sending welcome email to {email_address} from {environment.FROM_EMAIL}") # We can delegate into a fake sender (and possible logger) # and unit test it send_welcome_email("[email protected]", DevelopmentEnvironment()) # Sending welcome email to [email protected] from Bob Builder Development <[email protected]> send_welcome_email("[email protected]", ProductionEnvironment()) # Sending welcome email to [email protected] from Bob Builder <[email protected]>
Détection
- [x] Manuel
C'est une odeur de design.
Nous devons créer des configurations de développement/production vides et les déléguer avec des objets polymorphes personnalisables.
Mots clés
- Couplage
Conclusion
Évitez d'ajouter des conditions non testables.
Créez des configurations en déléguant les règles métier.
Utilisez des abstractions, des protocoles et des interfaces, évitez les hiérarchies strictes.
Rapports
Code Smell 56 - Préprocesseurs
Plus d'informations
Crédits
Photo par Birmingham Museums Trust sur Unsplash
Ce tweet a été inspiré par @ Jan Giacomelli
La complexité est un signe d'immaturité technique. La simplicité d'utilisation est le vrai signe d'un produit bien conçu qu'il s'agisse d'un ATM ou d'un missile Patriot.
Daniel T.Ling
Excellentes citations de génie logiciel
Code Smell 107 - Réutilisation des variables
La réutilisation des variables rend les portées et les limites plus difficiles à suivre
TL ; DR : ne lisez pas et n'écrivez pas la même variable à des fins différentes
Problèmes
- Lisibilité
- Problèmes cachés
Solutions
- Ne réutilisez pas les variables
- Méthode d'extraction pour isoler les portées
Le contexte
Lors de la programmation d'un script, il est courant de réutiliser des variables.
Cela conduit à la confusion et rend le débogage plus difficile.
Nous devons réduire le champ d'application autant que possible.
Exemple de code
Mauvais
// print line total double total = item.getPrice() * item.getQuantity(); System.out.println("Line total: " + total ); // print amount total total = order.getTotal() - order.getDiscount(); System.out.println( "Amount due: " + total ); // variable is reused
Droit
function printLineTotal() { double total = item.getPrice() * item.getQuantity(); System.out.println("Line total: " + total ); } function printAmountTotal() { double total = order.getTotal() - order.getDiscount(); System.out.println( "Amount due: " + total ); }
Détection
- [ ] Automatique
Les linters peuvent utiliser l'arbre d'analyse pour trouver la définition et les utilisations des variables.
Mots clés
- Lisibilité
Conclusion
Évitez de réutiliser les noms de variables. Utilisez des noms plus spécifiques et différents.
Rapports
Code Smell 03 - Les fonctions sont trop longues
Plus d'informations
Refactoring 002 - Méthode d'extraction
Crédits
La simplicité avant la généralité, l'usage avant la réutilisation.
Kevlin Henney
Excellentes citations de génie logiciel
Code Smell 108 - Assertions flottantes
Affirmer que deux nombres flottants sont identiques est un problème très difficile
TL; DR : Ne comparez pas les flotteurs
Problèmes
- Résultats de test erronés
- Essais fragiles
- Violation du principe d'échec rapide
Solutions
- Évitez les flotteurs à moins que vous n'ayez de VRAIS problèmes de performances
- Utiliser des nombres de précision arbitraires
- Si vous avez besoin de comparer des flottants, comparez avec la tolérance.
Le contexte
La comparaison des nombres flottants est un vieux problème informatique.
La solution habituelle consiste à utiliser des comparaisons de seuil.
Nous vous recommandons d'éviter du tout les flottants et d'essayer d'utiliser des nombres de précision infinie.
Exemple de code
Mauvais
Assert.assertEquals(0.0012f, 0.0012f); // Deprecated Assert.assertTrue(0.0012f == 0.0012f); // Not JUnit - Smell
Droit
Assert.assertEquals(0.0012f, 0.0014f, 0.0002); // true Assert.assertEquals(0.0012f, 0.0014f, 0.0001); // false // last parameter is the delta threshold Assert.assertEquals(12 / 10000, 12 / 10000); // true Assert.assertEquals(12 / 10000, 14 / 10000); // false
Détection
- [ ] Automatique
Nous pouvons ajouter une vérification avec assertEquals() sur nos frameworks de test pour éviter de vérifier les flottants.
Mots clés
- Tester les odeurs
Conclusion
Il faut toujours éviter de comparer les flottants.
Rapports
Code Smell 71 - Des flotteurs magiques déguisés en nombres décimaux
Plus d'informations
Crédits
Photo de Mika Baumeister sur Unsplash
Dieu a fait les nombres naturels; tout le reste est l'œuvre de l'homme.
Léopold Kronecker
Excellentes citations de génie logiciel
Code Odeur 109 - Propriétés automatiques
Que se passe-t-il si vous combinez 4 odeurs de code ?
TL; DR : évitez les getters, évitez les setters, évitez la métaprogrammation. Pensez au comportement.
Problèmes
- Violation de la dissimulation d'informations
- Mutabilité
- Violation du principe Fail Fast
- Dupliquer le code lors de la définition des propriétés
Solutions
Le contexte
Les setters et les getters sont une mauvaise pratique de l'industrie.
De nombreux IDE favorisent cette odeur de code.
Certains langages fournissent un support explicite pour créer des modèles anémiques et des DTO.
Exemple de code
Mauvais
class Person { public string name { get; set; } }
Droit
class Person { private string name public Person(string personName) { name = personName; //imutable //no getters, no setters } //... more protocol, probably accessing private variable name }
Détection
- [ ] Automatique
Il s'agit d'une fonctionnalité linguistique.
Nous devrions éviter les langages immatures ou interdire leurs pires pratiques.
Mots clés
- Encapsulation
Conclusion
Nous devons bien réfléchir avant d'exposer nos propriétés.
La première étape consiste à cesser de penser aux propriétés et à se concentrer uniquement sur le comportement.
Rapports
Code Smell 70 - Générateurs de modèles anémiques
Code Smell 01 - Modèles anémiques
Plus d'informations
- Écoles W3
- Paresse I - Métaprogrammation
- Paresse II - Assistants de code
- Refactoring 001 - Supprimer les setters
- Le pouvoir maléfique des mutants
- Échec rapide
Crédits
Rien n'est plus difficile que de travailler dans un délai serré et de prendre le temps de nettoyer au fur et à mesure.
Kent Beck
Excellentes citations de génie logiciel
Code Smell 110 - Commutateurs avec valeurs par défaut
Par défaut signifie "tout ce que nous ne savons pas encore". Nous ne pouvons pas prévoir l'avenir.
TL; DR : N'ajoutez pas de clause par défaut à vos dossiers. Changez-le pour une exception. Soyez explicite.
Problèmes
- Couplage
- Violation du principe Fail Fast
- Violation du principe ouvert fermé
Solutions
- Remplacer si et cas par polymorphisme
- Changer le code par défaut en une exception
Le contexte
Lors de l'utilisation de cas, nous ajoutons généralement un cas par défaut afin qu'il n'échoue pas.
Échouer est toujours mieux que de prendre des décisions sans preuves.
Puisque le boîtier et les interrupteurs sont aussi une odeur, nous pouvons les éviter.
Exemple de code
Mauvais
switch (value) { case value1: // if value1 matches the following will be executed.. doSomething(); break; case value2: // if value2 matches the following will be executed.. doSomethingElse(); break; default: // if value does not presently match the above values // or future values // the following will be executed doSomethingSpecial(); break; }
Droit
switch (value) { case value1: // if value1 matches the following will be executed.. doSomething(); break; case value2: // if value2 matches the following will be executed.. doSomethingElse(); break; case value3: case value4: // We currently know these options exist doSomethingSpecial(); break; default: // if value does not match the above values we need to take a decision throw new Exception('Unexpected case ' + value + ' we need to consider it'); break; }
Détection
- [x] Semi-automatique
Nous pouvons dire à nos linters de nous avertir des utilisations par défaut, sauf exception.
Mots clés
- Échec rapide
Conclusion
L'écriture de code robuste ne signifie pas que nous devons prendre des décisions sans preuves.
Rapports
Code Smell 36 - Déclarations Switch/case/elseif/else/if
Plus d'informations
Crédits
Photo de Joshua Woroniecki sur Unsplash
Le coût d'ajout d'une fonctionnalité n'est pas seulement le temps qu'il faut pour la coder. Le coût comprend également l'ajout d'un obstacle à l'expansion future. L'astuce consiste à choisir les fonctionnalités qui ne se combattent pas.
Jean Carmack
Excellentes citations de génie logiciel
Et c'est tout pour le moment...
Le prochain article expliquera 5 autres odeurs de code !