CodeGym /Blog Java /Random-FR /Qu'est-ce qu'un anti-modèle ? Regardons quelques exemples...
John Squirrels
Niveau 41
San Francisco

Qu'est-ce qu'un anti-modèle ? Regardons quelques exemples (Partie 2)

Publié dans le groupe Random-FR
Qu'est-ce qu'un anti-modèle ? Regardons quelques exemples (Partie 1) Aujourd'hui, nous continuons notre examen des anti-modèles les plus populaires. Si vous avez raté la première partie, la voici . Qu'est-ce qu'un anti-modèle ?  Regardons quelques exemples (Partie 2) - 1Ainsi, les modèles de conception sont les meilleures pratiques. En d'autres termes, ce sont des exemples de bons moyens éprouvés pour résoudre des problèmes spécifiques. À leur tour, les anti-modèles sont leur exact opposé, en ce sens qu'ils sont des modèles d'embûches ou d'erreurs lors de la résolution de divers problèmes (modèles maléfiques). Passons au prochain anti-modèle de développement logiciel.

8. Marteau d'or

Un marteau d'or est un anti-modèle défini par la confiance qu'une solution particulière est universellement applicable. Exemples:
  1. Après avoir rencontré un problème et trouvé un modèle pour la solution parfaite, un programmeur essaie de coller ce modèle partout, en l'appliquant aux projets actuels et futurs, au lieu de rechercher les solutions appropriées pour des cas spécifiques.

  2. Certains développeurs ont créé une fois leur propre variante de cache pour une situation spécifique (car rien d'autre ne convenait). Plus tard, sur le projet suivant qui n'impliquait aucune logique de cache spéciale, ils ont de nouveau utilisé leur variante au lieu d'utiliser des bibliothèques prêtes à l'emploi (par exemple, Ehcache). Le résultat a été un tas de bugs et d'incompatibilités, ainsi que beaucoup de temps perdu et de nerfs frits.

    N'importe qui peut tomber dans cet anti-modèle. Si vous êtes débutant, vous ne connaissez peut-être pas les modèles de conception. Cela peut vous amener à essayer de résoudre tous les problèmes d'une manière que vous maîtrisez. Si nous parlons de professionnels, nous appelons cela déformation professionnelle ou nerdview. Vous avez vos propres modèles de conception préférés, et au lieu d'utiliser le bon, vous utilisez votre favori, en supposant qu'un bon ajustement dans le passé garantit le même résultat à l'avenir.

    Cet écueil peut produire des résultats très tristes - d'une mise en œuvre mauvaise, instable et difficile à maintenir à un échec complet du projet. Tout comme il n'existe pas de pilule unique pour toutes les maladies, il n'existe pas de modèle de conception unique pour toutes les occasions.

9. Optimisation prématurée

L'optimisation prématurée est un anti-modèle dont le nom parle de lui-même.
"Les programmeurs passent énormément de temps à réfléchir et à s'inquiéter des endroits non critiques dans le code et à essayer de les optimiser, ce qui n'affecte que négativement le débogage et le support ultérieurs. Nous devrions généralement oublier l'optimisation dans, disons, 97 % des cas. De plus , l'optimisation prématurée est la racine de tous les maux. Cela dit, nous devons prêter toute notre attention aux 3 % restants. —Donald Knuth
Par exemple, ajouter prématurément des index à une base de données. Pourquoi est-ce mauvais ? Eh bien, c'est mauvais en ce sens que les index sont stockés sous forme d'arbre binaire. Par conséquent, chaque fois qu'une nouvelle valeur est ajoutée et supprimée, l'arbre sera recalculé, ce qui consomme des ressources et du temps. Par conséquent, les index ne doivent être ajoutés qu'en cas de besoin urgent (si vous avez une grande quantité de données et que les requêtes prennent trop de temps) et uniquement pour les champs les plus importants (les champs les plus fréquemment interrogés).

10. Code des spaghettis

Le code spaghetti est un anti-modèle défini par un code mal structuré, déroutant et difficile à comprendre, contenant toutes sortes de branchements, tels que des exceptions d'emballage, des conditions et des boucles. Auparavant, l'opérateur goto était le principal allié de cet anti-modèle. Les instructions Goto ne sont plus vraiment utilisées, ce qui élimine heureusement un certain nombre de difficultés et de problèmes associés.

public boolean someDifficultMethod(List<String> XMLAttrList) {
           ...
   int prefix = stringPool.getPrefixForQName(elementType);
   int elementURI;
   try {
       if (prefix == -1) {
        ...
           if (elementURI != -1) {
               stringPool.setURIForQName(...);
           }
       } else {
        ...
           if (elementURI == -1) {
           ...
           }
       }
   } catch (Exception e) {
       return false;
   }
   if (attrIndex != -1) {
       int index = attrList.getFirstAttr(attrIndex);
       while (index != -1) {
           int attName = attrList.getAttrName(index);
           if (!stringPool.equalNames(...)){
           ...
               if (attPrefix != namespacesPrefix) {
                   if (attPrefix == -1) {
                    ...
                   } else {
                       if (uri == -1) {
                       ...
                       }
                       stringPool.setURIForQName(attName, uri);
                   ...
                   }
                   if (elementDepth >= 0) {
                   ...
                   }
                   elementDepth++;
                   if (elementDepth == fElementTypeStack.length) {
                   ...
                   }
               ...
                   return contentSpecType == fCHILDRENSymbol;
               }
           }
       }
   }
}
Ça a l'air horrible, n'est-ce pas ? Malheureusement, c'est l'anti-modèle le plus courant :( Même la personne qui écrit un tel code ne pourra pas le comprendre à l'avenir. D'autres développeurs qui verront le code penseront : "Eh bien, si cela fonctionne, alors d'accord - il vaut mieux ne pas y toucher". Souvent, une méthode est initialement simple et très transparente, mais au fur et à mesure que de nouvelles exigences sont ajoutées, la méthode est progressivement encombrée d'instructions de plus en plus conditionnelles, la transformant en une monstruosité comme celle-ci. Si une telle méthode apparaît, vous devez le refactoriser complètement ou au moins les parties les plus déroutantes. Généralement, lors de la planification d'un projet, du temps est alloué pour le refactoring, par exemple, 30 % du temps de sprint est pour le refactoring et les tests. Bien sûr, cela suppose qu'il n'y a pas de précipitation (mais quand cela arrive-t-il jamais).ici .

11. Numéros magiques

Les nombres magiques sont un anti-modèle dans lequel toutes sortes de constantes sont utilisées dans un programme sans aucune explication de leur but ou de leur signification. C'est-à-dire qu'ils sont généralement mal nommés ou dans les cas extrêmes, il n'y a aucun commentaire expliquant ce que sont les commentaires ou pourquoi. Comme le code spaghetti, c'est l'un des anti-modèles les plus courants. Quelqu'un qui n'a pas écrit le code peut avoir ou non une idée des nombres magiques ou de leur fonctionnement (et avec le temps, l'auteur lui-même ne pourra pas les expliquer). Par conséquent, la modification ou la suppression d'un nombre entraîne l'arrêt magique du code. Par exemple, 36 et 73. Pour lutter contre cet anti-modèle, je recommande une révision du code. Votre code doit être examiné par des développeurs qui ne sont pas impliqués dans les sections pertinentes du code. Leurs yeux seront frais et ils se poseront des questions : qu'est-ce que c'est et pourquoi as-tu fait ça ? Et bien sûr, vous devez utiliser des noms explicatifs ou laisser des commentaires.

12. Programmation par copier-coller

La programmation par copier-coller est un anti-modèle dans lequel le code de quelqu'un d'autre est copié et collé sans réfléchir, ce qui peut entraîner des effets secondaires imprévus. Par exemple, copier et coller des méthodes avec des calculs mathématiques ou des algorithmes complexes que nous ne comprenons pas entièrement. Cela peut fonctionner pour notre cas particulier, mais dans d'autres circonstances, cela pourrait entraîner des problèmes. Supposons que j'ai besoin d'une méthode pour déterminer le nombre maximum dans un tableau. En fouillant sur Internet, j'ai trouvé cette solution :

public static int max(int[] array) {
   int max = 0;
   for(int i = 0; i < array.length; i++) {
       if (Math.abs(array[i]) > max){
           max = array[i];
       }
   }
   return max;
}
Nous obtenons un tableau avec les nombres 3, 6, 1, 4 et 2, et la méthode renvoie 6. Super, gardons-le ! Mais plus tard, nous obtenons un tableau composé de 2,5, -7, 2 et 3, puis notre résultat est -7. Et ce résultat n'est pas bon. Le problème ici est que Math.abs() renvoie la valeur absolue. L'ignorance de cela mène au désastre, mais seulement dans certaines situations. Sans une compréhension approfondie de la solution, il existe de nombreux cas que vous ne pourrez pas vérifier. Le code copié peut également aller au-delà de la structure interne de l'application, à la fois stylistiquement et à un niveau architectural plus fondamental. Un tel code sera plus difficile à lire et à maintenir. Et bien sûr, nous ne devons pas oublier que copier directement le code de quelqu'un d'autre est une forme particulière de plagiat.

13. Réinventer la roue

Réinventer la roue est un anti-modèle, aussi parfois appelé réinventer la roue carrée. Essentiellement, ce modèle est l'opposé de l'anti-modèle copier-coller considéré ci-dessus. Dans cet anti-modèle, le développeur implémente sa propre solution à un problème pour lequel des solutions existent déjà. Parfois, ces solutions existantes sont meilleures que ce que le programmeur invente. Le plus souvent, cela n'entraîne qu'une perte de temps et une baisse de productivité : le programmeur peut ne pas trouver de solution du tout ou peut trouver une solution qui est loin d'être la meilleure. Cela dit, nous ne pouvons pas exclure la possibilité de créer une solution indépendante, car cela est une voie directe vers la programmation par copier-coller. Le programmeur doit être guidé par les tâches de programmation spécifiques qui se présentent afin de les résoudre avec compétence, que ce soit en utilisant des solutions toutes faites ou en créant des solutions personnalisées. Très souvent, la raison de l'utilisation de cet anti-modèle est simplement la hâte. Le résultat est une analyse superficielle de (recherche) de solutions toutes faites. Réinventer la roue carrée est un cas où l'anti-modèle considéré a un résultat négatif. Autrement dit, le projet nécessite une solution personnalisée et le développeur la crée, mais mal. En même temps, une bonne option existe déjà et d'autres l'utilisent avec succès. Résultat : une énorme quantité de temps est perdue. Premièrement, nous créons quelque chose qui ne fonctionne pas. Ensuite, nous essayons de le refactoriser, et finalement nous le remplaçons par quelque chose qui existait déjà. Un exemple est l'implémentation de votre propre cache personnalisé lorsque de nombreuses implémentations existent déjà. Quel que soit votre talent en tant que programmeur, vous devez vous rappeler que réinventer une roue carrée est à tout le moins une perte de temps. Et, comme vous le savez, le temps est la ressource la plus précieuse.

14. Problème de yo-yo

Le problème du yo-yo est un anti-modèle dans lequel la structure de l'application est trop compliquée en raison d'une fragmentation excessive (par exemple, une chaîne d'héritage trop subdivisée). Le "problème yo-yo" survient lorsque vous avez besoin de comprendre un programme dont la hiérarchie d'héritage est longue et complexe, créant des appels de méthode profondément imbriqués. En conséquence, les programmeurs doivent naviguer entre de nombreuses classes et méthodes différentes afin d'inspecter le comportement du programme. Le nom de cet anti-motif vient du nom du jouet. A titre d'exemple, regardons la chaîne d'héritage suivante : Nous avons une interface Technologie :

public interface Technology {
   void turnOn();
}
L'interface Transport en hérite :

public interface Transport extends Technology {
   boolean fillUp();
}
Et puis nous avons une autre interface, GroundTransport :

public interface GroundTransportation extends Transport {
   void startMove();
   void brake();
}
Et à partir de là, nous dérivons une classe abstraite Car :

public abstract class Car implements GroundTransportation {
   @Override
   public boolean fillUp() {
       /* some implementation */
       return true;
   }
   @Override
   public void turnOn() {
       /* some implementation */
   }
   public boolean openTheDoor() {
       /* some implementation */
       return true;
   }
   public abstract void fixCar();
}
Vient ensuite la classe Volkswagen abstraite :

public abstract class Volkswagen extends Car {
   @Override
   public void startMove() {
       /* some implementation */
   }
   @Override
   public void brake() {
       /* some implementation */
   }
}
Et enfin, un modèle spécifique :

public class VolkswagenAmarok extends Volkswagen {
   @Override
   public void fixCar(){
       /* some implementation */
   }
}
Cette chaîne nous oblige à rechercher des réponses à des questions telles que :
  1. Combien de méthodes a- VolkswagenAmarokt-il?

  2. Quel type doit être inséré à la place du point d'interrogation afin d'obtenir une abstraction maximale :

    
    ? someObj = new VolkswagenAmarok();
           someObj.brake();
    
Il est difficile de répondre rapidement à de telles questions - cela nous oblige à jeter un coup d'œil et à enquêter, et il est facile de s'embrouiller. Et que se passe-t-il si la hiérarchie est beaucoup plus grande, plus longue et plus compliquée, avec toutes sortes de surcharges et de remplacements ? La structure que nous aurions serait obscurcie en raison d'une fragmentation excessive. La meilleure solution serait de réduire les divisions inutiles. Dans notre cas, nous laisserions Technologie → Voiture → VolkswagenAmarok.

15. Complexité accidentelle

La complexité inutile est un anti-modèle dans lequel des complications inutiles sont introduites dans une solution.
"N'importe quel imbécile peut écrire du code qu'un ordinateur peut comprendre. Les bons programmeurs écrivent du code que les humains peuvent comprendre." — Martin Fowler
Qu'est-ce donc que la complexité ? Il peut être défini comme le degré de difficulté avec lequel chaque opération est effectuée dans le programme. En règle générale, la complexité peut être divisée en deux types. Le premier type de complexité est le nombre de fonctions qu'un système possède. Il ne peut être réduit que d'une seule manière - en supprimant certaines fonctions. Les méthodes existantes doivent être surveillées. Une méthode doit être supprimée si elle n'est plus utilisée ou est encore utilisée mais sans apporter de valeur. De plus, vous devez évaluer comment toutes les méthodes de l'application sont utilisées, afin de comprendre où les investissements seraient intéressants (beaucoup de réutilisation de code) et à quoi vous pouvez dire non. Le deuxième type de complexité est la complexité inutile. Il ne peut être guéri que par une approche professionnelle. Au lieu de faire quelque chose de "cool" (les jeunes développeurs ne sont pas les seuls sensibles à cette maladie), il faut réfléchir à comment faire le plus simplement possible, car la meilleure solution est toujours simple. Par exemple, supposons que nous ayons de petites tables associées avec des descriptions de certaines entités, comme un utilisateur : Qu'est-ce qu'un anti-modèle ?  Regardons quelques exemples (Partie 2) - 3Ainsi, nous avons l'identifiant de l'utilisateur, l'identifiant de la langue dans laquelle la description est faite, et la description elle-même. De même, nous avons des descripteurs auxiliaires pour les tables cars, files, plans et customers. Alors, à quoi cela ressemblerait-il d'insérer de nouvelles valeurs dans de telles tables ?

public void createDescriptionForElement(ServiceType type, Long languageId, Long serviceId, String description)throws Exception {
   switch (type){
       case CAR:
           jdbcTemplate.update(CREATE_RELATION_WITH_CAR, languageId, serviceId, description);
       case USER:
           jdbcTemplate.update(CREATE_RELATION_WITH_USER, languageId, serviceId, description);
       case FILE:
           jdbcTemplate.update(CREATE_RELATION_WITH_FILE, languageId, serviceId, description);
       case PLAN:
           jdbcTemplate.update(CREATE_RELATION_WITH_PLAN, languageId, serviceId, description);
       case CUSTOMER:
           jdbcTemplate.update(CREATE_RELATION_WITH_CUSTOMER, languageId, serviceId, description);
       default:
           throw new Exception();
   }
}
Et en conséquence, nous avons cette énumération :

public enum ServiceType {
   CAR(),
   USER(),
   FILE(),
   PLAN(),
   CUSTOMER()
}
Tout semble simple et bon... Mais qu'en est-il des autres méthodes ? En effet, ils auront également tous un tas d' switchinstructions et un tas de requêtes de base de données presque identiques, ce qui à son tour compliquera et gonflera considérablement notre classe. Comment tout cela pourrait-il être simplifié ? Améliorons un peu notre énumération :

@Getter
@AllArgsConstructor
public enum ServiceType {
   CAR("cars_descriptions", "car_id"),
   USER("users_descriptions", "user_id"),
   FILE("files_descriptions", "file_id"),
   PLAN("plans_descriptions", "plan_id"),
   CUSTOMER("customers_descriptions", "customer_id");
   private String tableName;
   private String columnName;
}
Désormais, chaque type a les noms des champs d'origine de sa table. En conséquence, la méthode de création d'une description devient :

private static final String CREATE_RELATION_WITH_SERVICE = "INSERT INTO %s(language_id, %s, description) VALUES (?, ?, ?)";
public void createDescriptionForElement(ServiceType type, Long languageId, Long serviceId, String description) {
   jdbcTemplate.update(String.format(CREATE_RELATION_WITH_SERVICE, type.getTableName(), type.getColumnName()), languageId, serviceId, description);
   }
Pratique, simple et compact, vous ne trouvez pas ? L'indication d'un bon développeur n'est même pas la fréquence à laquelle il utilise des modèles, mais plutôt la fréquence à laquelle il évite les anti-modèles. L'ignorance est le pire ennemi, car vous devez connaître vos ennemis de vue. Eh bien, c'est tout ce que j'ai pour aujourd'hui. Merci tout le monde! :)
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION