Les pires anti-schémas que vous ayez rencontrés [fermé]

9

Quels sont les pires anti-patterns que vous ayez rencontrés dans votre carrière de programmeur?

Je suis principalement impliqué dans java, bien qu'il soit probablement indépendant de la langue.

Je pense que le pire est ce que j'appelle le principal anti-modèle . Cela signifie un programme composé d'une seule classe extrêmement grande (parfois accompagnée d'une paire de petites classes) qui contient toute la logique. Généralement avec une grande boucle dans laquelle toute la logique métier est contenue, ayant parfois des dizaines de milliers de lignes de code.

стривігор
la source

Réponses:

38

Code commenté. Des blocs, peut-être des centaines de lignes. La théorie étant, hé, elle est commentée, elle ne fait aucun mal et peut-être en aurons-nous besoin à l'avenir.

Navi
la source
7
Eh bien, au moins, vous pouvez le supprimer en toute sécurité. Contrairement à quelqu'un avec qui j'ai travaillé, cela renommait fréquemment les procédures et laissait le code mort accessible. Blech.
Jay
@Cyrena, tu as aussi travaillé avec Eric?!?
CaffGeek
J'ai eu une fois un tas de code qui utilisait #ifdef COMMENT pour verrouiller les choses. Fonctionne très bien jusqu'à ce que quelqu'un définisse COMMENTAIRE.
Michael Kohne
9
C'est un autre cas où l'utilisation du contrôle de version est payante. Vous pouvez supprimer le code sans avoir à vous demander si vous en aurez besoin à l'avenir, car il peut être récupéré à nouveau en quelques touches.
Jason B
5
Je pense que le code commenté a sa place, si vous le préfixez avec un commentaire qui explique pourquoi il est là. Parfois, je laisse un bloc commenté qui représente une route potentielle que je pensais emprunter, et je laisse un commentaire expliquant pourquoi je ne l'ai pas fait. @ Jason, je vous entends certainement dire que c'est le rôle du contrôle de version, mais le code supprimé dans le contrôle de version n'est pas très détectable.
nlawalker
19

J'en frapperai une autre évidente avec des "copier-pâtes". Copier du code presque identique à ce que vous voulez, puis changer quelques éléments (au lieu de l'extraire dans une méthode).

Ceci est particulièrement répandu dans certains codes de test fonctionnel et API de la fin des années 90: littéralement des centaines (voire des milliers) de cas de test presque identiques qui auraient pu être décomposés en quelques fonctions qui prennent 3 ou 4 paramètres - ou, mieux encore , quelque chose basé sur les données. Mon premier travail hors de l'université a été littéralement 8 mois de réécriture et de refactorisation de milliers de lignes de pâtes à copier qui utilisaient des méthodes obsolètes. Au moment où j'ai terminé, les fichiers de test étaient inférieurs à un dixième de leur taille d'origine et beaucoup plus faciles à maintenir (et lisibles!).

Ethel Evans
la source
16

Je pense que je peux écrire beaucoup sur Pattern Mania et des solutions qui pourraient être résolues avec beaucoup moins d'efforts, mais je préfère pointer vers un excellent article que j'ai lu récemment avec un exemple fantastique de la façon dont une solution simple peut être trop compliquée. .

Comment (pas) écrire Factorial en Java ou alors nous mettons une usine dans votre algorithme

Andrey Taptunov
la source
3
Impressionnant! Maintenant, où est le FactorialWebService? : P
FrustratedWithFormsDesigner
1
Je l'appelle Pattern Fever ... tout le monde l'obtient à un moment de sa carrière. Les meilleurs d'entre nous grandissent au-delà. J'ai eu une interview où le gars m'a demandé quand devrais-je penser aux modèles. Je lui ai dit que je les laissais évoluer dans le système. Il a dit "Non, tu devrais utiliser des modèles dès le début."
Michael Brown
FactoryFactories n'est qu'un symptôme de vouloir différer le choix réel autant que possible, mais il finit toujours par le coder en dur ou par mapper une valeur de chaîne externe à un morceau de code. L'injection de dépendance est une meilleure solution.
Les motifs sont des artefacts de bonne conception - ils doivent être traités comme tels. J'aime les décrire comme des définitions plutôt que comme des solutions. Ils sont utiles lors de la communication, mais pas nécessairement lors de la conception.
Michael K
Merci pour ça, bonne lecture.
Syg
14

Marteau d'or

"J'ai un marteau et tout le reste est un clou."

Maglob
la source
14

Régions

En C #, vous pouvez définir une région de code qui peut être réduite dans l'IDE, le masquant ainsi à moins que vous ne vouliez traiter ce code. J'ai été (je suis actuellement sur) un projet où les régions s'étalaient sur des centaines de lignes (j'aurais aimé exagérer) et il y avait plusieurs régions dans une fonction à mille lignes (encore une fois, je voudrais plaisanter).

En revanche, le développeur qui a créé la région a très bien identifié les fonctions spécifiques d'une région. À tel point que j'ai pu faire une méthode d'extraction sur la région et passer à autre chose.

Les régions encouragent les développeurs à "cacher" leurs conneries à la vue.

Michael Brown
la source
15
+1 pour les régions encourage les développeurs à "cacher" leurs conneries à la vue. Cependant, lorsqu'il est utilisé correctement, je trouve que les régions aident à regrouper logiquement le code et à le retrouver facilement plus tard.
Darren Young
Cela a longtemps été un problème avec les éditeurs pliants. J'avais l'habitude de faire le même genre de chose lors de ma dernière programmation dans OCCAM.
Michael Kohne
2
J'adore les régions ... mais seulement pour l'organisation ... sans cacher les rames numériques de code.
IAbstract
3
+1. C'est également pourquoi l'utilisation de régions enfreint la règle StyleCop SA1124 DoNotUseRegions.
Arseni Mourzenko
1
J'ai des projets qui fonctionnent avec un grand nombre de champs en SQL, et le code qui le met à jour / le crée est composé de nombreuses lignes. Une région le #region SQL Updaterend pliable, donc moins de défilement est nécessaire.
JYelton
12

Pour moi, le pire modèle est le copier / coller .

LennyProgrammers
la source
28
Pour moi, le pire modèle est le copier / coller.
Andrew Arnold
9

Pas de méthodes de surcharge:

// Do something
public int doSomething(Data d);

// Do same thing, but with some other data
public int doSomething2(SomeOtherData d);

Montre clairement que le programmeur n'a pas compris la surcharge.

Michael K
la source
5

Séquences de commutateur de boucle

http://en.wikipedia.org/wiki/Loop-switch_sequence

Ils m'ennuient sans fin et montrent vraiment à quel point le développeur était inexpérimenté

CaffGeek
la source
Ah, une machine à états terminale :)
Pourquoi devez-vous évoquer ces souvenirs enfouis? Je passais une si belle journée.
Malachi
5

Le codage logiciel , c'est-à-dire lorsque les programmeurs font tout leur possible pour éviter le codage en dur et se retrouvent de l'autre côté de l'échelle - les dépendances "codées en dur".

AareP
la source
4

Gardez l'état dans le client.

Une fois travaillé avec une application Web où tout état était conservé dans le navigateur. (Pour garantir une évolutivité sans problème, toutes les exceptions ont été ignorées).

user1249
la source
Pourriez-vous s'il vous plaît développer? À mon humble avis, pour une application Web, tout va bien lorsque le seul état se trouve dans le navigateur (c.-à-d. Les cookies) et que le serveur ne «partage rien». Ou voulez-vous dire «état» comme dans «la base de données des applications»?
keppla
État: comme dans les données réelles à utiliser.
OO vous avez mes plus sincères sympathies.
keppla
4

Checkins massifs

Je déteste quand je vois qu'un développeur ne s'est pas enregistré depuis plus d'une semaine. Cela signifie qu'il est coincé et n'a pas cherché d'aide, ou qu'il regroupe un tas de fonctionnalités en un seul enregistrement. (J'ai laissé de côté le pire des cas, il ne fait rien du tout. C'est facile à résoudre ... deux mots semblent être embauchés.)

Si vous effectuez un enregistrement important, vous perdez de nombreux avantages de SCM, comme la possibilité de lier un ensemble de modifications à une fonctionnalité spécifique. De plus, vous aurez probablement beaucoup de fusion à faire et ce n'est pas nécessairement facile de bien faire les choses.

Michael Brown
la source
1
Ne rien faire n'est pas toujours le pire des cas. Parfois, il vaut mieux devoir l'écrire à partir de zéro que d'avoir du code à réécrire ...
Malachi
4

Actuellement, je travaille avec un morceau de code hérité et j'aime la façon dont le codeur précédent obtient le premier élément d'une liste:

String result;
for(int i = 0; i < someList.size(); i++) {
    result = someList.get(i);
    break;
}

Mais à mon humble avis, le pire que j'ai vu dans ce code est de définir des classes de pages JSP en ligne, d'écrire tout le HTML, CSS et Javascript en utilisant le scriptlet et out.println :-(

SourceRebels
la source
4

L'un des pires anti-modèles comportementaux que j'ai vus était un magasin qui ne permettait que le code à vérifier dans le contrôle de version après sa production. Couplé avec des extractions exclusives dans VSS, cela a conduit à un processus compliqué d'annulation des extractions si un défaut de production devait être corrigé avant la prochaine version, sans parler de plus d'une personne devant modifier un fichier donné pour la prochaine version.

Le fait qu'il s'agissait d'une politique ministérielle l'a rendu encore pire que le cas d'un seul développeur se comportant de cette façon.

Malachi
la source
3

Verrouillage d'un littéral de chaîne

synchronized("one") { /* block one A*/ }

synchronized("one") { /* block one B*/ }

Noms de classe très longs. (dans le JRE)

com.sun.java.swing.plaf.nimbus.
InternalFrameInternalFrameTitlePaneInternalFrameTitlePaneMaximizeButtonWindowNotFocusedState

Mauvaise structure d'héritage

com.sun.corba.se.internal.Interceptors.PIORB extends
com.sun.corba.se.internal.POA.POAORB extends
com.sun.corba.se.internal.iiop.ORB extends
com.sun.corba.se.impl.orb.ORBImpl extends
com.sun.corba.se.spi.orb.ORB extends
com.sun.corba.se.org.omg.CORBA.ORB extends 
org.omg.CORBA_2_3.ORB extends
org.omg.CORBA.ORB

Une exception qui ne l'est pas.

public interface FlavorException { }

Gestion des erreurs inutiles et cryptiques

if (properties.size() > 10000)
   System.exit(0);

Création inutile d'objets

Class clazz = new Integer(0).getClass();
int num = new Integer(text).intValue();

Lancer une exception à d'autres fins

try {
    Integer i = null;
    Integer j = i.intValue();
} catch (NullPointerException e) {
    System.out.println("Entering "+e.getStackTrace()[0]);
}

Utilisation d'objets d'instance pour des méthodes statiques.

Thread.currentThread().sleep(100);

Synchronisation sur un champ non final

synchronized(list) {
   list = new ArrayList();
}

Copie inutile d'une chaîne constante

String s = new String("Hello world");

Appel inutile à String.toString ()

String s = "Hello";
String t = s.toString() + " World";

Appels à System.gc () pour libérer de la mémoire

Définition de la variable locale sur null pour libérer de la mémoire

    // list is out of scope anyway.
    list = null;
}

Utiliser ++ i au lieu d'i ++ pour des raisons de performances (ou toute autre micro-micro-optimisation)

Peter Lawrey
la source
Ce ne sont pas nécessairement des anti-modèles, juste un mauvais codage.
Gary Willoughby
@Gary, ou mauvais schémas de développement que je vois répétés. Peut-être pas dans la définition stricte d'un anti-modèle.
Peter Lawrey
1
@Peter: "Appels à System.gc () pour libérer de la mémoire", j'ai vu une fois où .NET explosait avec l'exception OutOfMemory sauf si GC était appelé explicitement. Bien sûr, il s'agissait davantage d'une exception que d'une règle.
Coder
3

Code saupoudré de:

// TODO: 

ou

// TODO: implement feature 

sans aucune information supplémentaire.

Malachie
la source
2

Itérateur pour les nuls:

Iterator iCollection = collection.iterator();
for(int i = 0 ; i < collection.size() ; i++ ){
    if(collection.get(i) == something){
       iCollection.remove();
    }
 }

Singletono-Factory:

public class SomeObject{
   private SomeObject() {}
   public static SomeObject getInstance(){
       return new SomeObject();
   }
}

développement axé sur le cas contraire (également appelé principe de fermeture ouverte - ouvert à la modification proche à la compréhension):

if (sth1){
...  
}else if(sth2){
..
}
...
..
else if(sth1000000000000){
...
}

StringPattern (également appelé StringObject):

a) sendercode
if(sth1)
   str+="#a";
if(sth2)
   str+="#b";
...
if(sth1000)
   str+="#n";

b) receiver
   regexp testing if str contains #a, #b, ... #n
Marcin Michalski
la source
C'est else ifsouvent alors le seul moyen de faire avancer les choses. Je pense aux cordes; ne peut pas utiliser un interrupteur. Les conditions doivent être similaires pour qu'il soit utile.
Michael K
À mon humble avis, si / autre peut être remplacé par une simple cartographie ou un modèle de visiteur. Dans le cas de chaînes, c'est-à-dire que vous pouvez avoir un fichier de propriétés comme: someString1 = some.package.ObjectToHandleSomeString1
Marcin Michalski
2
Le singleton est une usine . Il n'y a rien de mal à ce code. La seule chose qui pourrait être erronée est que le code extérieur fait l'hypothèse que chaque appel à getInstancerenvoie la même instance. Une telle hypothèse briserait l'encapsulation et est en fait l'un des anti-schémas les plus courants.
back2dos
c'est précisément pourquoi c'est si déroutant :) si la méthode était appelée create () ou qu'elle retournerait la même instance chaque fois que tout irait parfaitement bien
Marcin Michalski
2

Ce n'est pas tellement un modèle de codage mais un modèle de comportement, c'est assez mauvais cependant: modifier quelque chose dans le code (disons que les exigences ont changé), puis peaufiner tous les tests unitaires jusqu'à ce que le code le réussisse. Ajuster ou simplement supprimer tout le code de test de la méthode de test, mais en laissant la méthode là.

Ceci est lié à un modèle plus générique, le modèle That'll Do , voici une ligne de code représentative:

int num = new Integer( stringParam ).parseInt( stringParam );

Cela fonctionne, après tout.

biziclop
la source
2

Je méprise absolument l'inversion d'abstraction , ou la réinvention de primitives de bas niveau par-dessus les primitives de haut niveau. Parfois, cependant, cela est dû à de mauvais concepteurs de langage, pas à de mauvais programmeurs. Exemples:

  1. Utiliser une seule classe de méthode sans variable membre et une interface correspondante, (implémentée en termes de tables de pointeurs de fonction), au lieu d'un pointeur de fonction. Notez que dans des langages comme Java, vous n'avez peut-être pas le choix.

  2. Dans MATLAB et R, l'insistance que tout est un vecteur / matrice plutôt qu'une primitive.

  3. Pendant que nous dénigrons MATLAB, qu'en est-il du fait qu'il n'a pas d'entiers, donc quand vous avez besoin d'un entier, vous devez utiliser un double.

  4. Langages purement fonctionnels où vous devez utiliser des appels de fonction pour écrire une boucle.

dsimcha
la source
1

Ce serait certainement copier / coller, j'ai vu beaucoup de mauvais code se faire à cause de cela, cela et le codage cowboy et tout ce qui en découle. (Classes divines, méthodes extra larges, algorithmes mal pensés, etc.)

Et si les modèles de conception sont autorisés, je dirais: faire un projet comme un ensemble d'actions à partir d'un plan, sans faire de conception ou d'analyse de domaine.

Coyote21
la source
1

Haricot Java multi-usage -

Un bean java avec beaucoup de variables, utilisé dans différents types d'opérations. Chaque opération utilise un sous-ensemble arbitraire des variables du bean et ignore les autres. Quelques variables pour l'état de l'interface graphique, quelques variables jetées pour le passage entre les composants, quelques-unes qui ne sont probablement plus utilisées. Les meilleurs exemples n'ont pas de documentation, ce qui entraverait l'appréciation du modèle.

Aussi, je ne peux pas oublier le bien-aimé

try{ 
   ... //many lines of likely dangerous operations
}
catch(Exception e){}
Steve B.
la source
À mon humble avis, les exceptions puent. Ils sont trop difficiles à comprendre et ils ajoutent un faux sentiment de sécurité.
Coder
Quelle que soit votre opinion sur la puanteur des exceptions, avaler en silence doit puer davantage.
Steve B.
1

Un ancien collègue avait l'habitude de réutiliser des objets en écrasant leurs propriétés, au lieu d'en créer simplement de nouvelles. Je n'aurais jamais pu imaginer la quantité de problèmes que cela a causés lors de la mise en œuvre de nouvelles fonctionnalités.

deltreme
la source
1

Quelque chose qui m'a causé beaucoup de chagrin est le motif "Grande carte dans le ciel". Lancer autour d'une carte au lieu d'utiliser des objets appropriés. Vous n'avez aucune idée des «variables» qu'il contient sans débogage et vous ne savez pas ce qu'il pourrait contenir sans remonter le code en arrière. Mappe généralement les chaînes aux objets, ou les chaînes aux chaînes, que vous êtes censé potentiellement analyser en primitives.

Buhb
la source
Cela ressemble un peu à s'appuyer sur Session et ViewState dans ASP.NET pour passer des quantités de données entre les pages, ce qui est malheureusement souvent nécessaire ...
Wayne Molina
1

L'un de mes modèles anti-développement préférés est l'utilisation d'une «conception» de base de données qui nécessite l' ajout continu de colonnes supplémentaires à une ou plusieurs tables par programme . Il s'agit d'un cousin de la "conception" qui crée une nouvelle table pour chaque instance d'une entité. Les deux atteignent inévitablement les limites du serveur de base de données, mais généralement pas avant que le système soit en production depuis un certain temps.

Malachi
la source
0

Je pense que l'un des pires anti-modèles que j'ai vus implique l'utilisation d'une table de base de données comme stockage temporaire au lieu d'utiliser la mémoire de l'ordinateur.

Le domaine du problème est propriétaire, ce qui m'interdit de l'expliquer, mais il n'est pas nécessaire de comprendre le problème de base. Il s'agissait d'une application graphique écrite en Java avec une base de données backend. Il s'agissait de prendre certaines données d'entrée, de les manipuler puis de valider les données traitées dans la base de données.

Notre projet a un algorithme assez compliqué qui enregistre des valeurs intermédiaires pour un traitement ultérieur. Au lieu d'encapsuler les objets temporaires dans ... des objets, une table de base de données a été créée comme "t_object". Chaque fois qu'une valeur était calculée, elle était ajoutée à ce tableau. Une fois que l'algorithme a terminé son travail, il sélectionnerait toutes les valeurs intermédiaires et les traiterait toutes dans un grand objet Map. Une fois tout le traitement terminé, les valeurs restantes marquées pour être enregistrées seraient ajoutées au schéma de base de données réel et les entrées temporaires dans la table "t_object" seraient supprimées.

Le tableau était également utilisé comme une liste unique, les données ne pouvaient exister qu'une seule fois. Cela aurait pu être une caractéristique décente de la conception si nous avions implémenté des contraintes sur la table, mais nous avons fini par parcourir toute la table pour voir si les données existaient ou non. (Non, nous n'avons même pas utilisé de requêtes utilisant des clauses where avec CONTAINS)

Certains des problèmes que nous avons rencontrés en raison de cette conception étaient spécifiquement le débogage. L'application a été conçue pour acheminer les données de sorte qu'il y ait plusieurs interfaces graphiques graphiques qui pré-traiteraient les données avant d'arriver à cet algorithme. Le processus de débogage consistait à traiter un cas de test, puis à faire une pause juste après avoir terminé la section ci-dessus. Ensuite, nous interrogions la base de données pour voir quelles données étaient contenues dans ce tableau.

Un autre problème que nous avons découvert était que les données n'étaient pas supprimées correctement de cette table temporaire, ce qui pourrait interférer avec les exécutions à l'avenir. Nous avons découvert que cela était dû au fait que les exceptions n'étaient pas correctement gérées et que, par conséquent, l'application ne se fermait pas correctement et ne supprimait pas les données de la table dont elle avait le contrôle.

Si nous avions utilisé la conception orientée objet de base et conservé tout en mémoire, ces problèmes ci-dessus ne se seraient jamais produits. Tout d'abord, le débogage aurait été simple car nous pourrions facilement configurer des points d'arrêt dans l'application, puis inspecter la mémoire dans la pile et le tas. Deuxièmement, en cas de sortie anormale de l'application, la mémoire java aurait été nettoyée naturellement sans avoir à se soucier de la supprimer de la base de données.

REMARQUE: je ne dis pas que ce modèle est intrinsèquement mauvais, mais dans cet exemple, je l'ai trouvé inutile lorsque les principes de base OO auraient suffi.

Je ne suis pas sûr d'un nom pour cet anti-modèle car c'est la première fois que je vois quelque chose comme ça fait. Y a-t-il de bons noms auxquels vous pouvez penser pour ce modèle?

jluzwick
la source
Je n'appellerais pas cela un problème de couverture. Cela dépend de la quantité de données temporaires stockées et de ce qui est fait avec.
GrandmasterB
Je devrais ajouter plus au message, mais le principal problème était qu'au lieu de modifier des objets et d'accéder aux données de la mémoire, les données étaient manipulées avec du code sql hack. Cela a entraîné une complexité accrue et de graves problèmes de performances.
jluzwick
2
Vous ne mentionnez pas votre domaine problématique, mais pas toujours une mauvaise chose, garder un état ailleurs comme celui-ci pourrait permettre aux processus d'évoluer et d'être introspection pendant de longues périodes, également pour aider au débogage. L'accès à la base de données était-il à l'origine de problèmes ou de problèmes de performances?
Jé Queue
J'ai édité l'article pour mieux refléter comment cela a été utilisé dans notre projet, mais nous avons eu de nombreux problèmes lors du débogage, en particulier parce que nous devions interroger la base de données pour voir les variables temporaires. Nous avons également rencontré de gros problèmes liés aux performances en raison de la recherche constante de données dans la base de données et de la vérification de l'existence de nouvelles données.
jluzwick
0

Chariot avant le cheval - alias YouMightNeedIt

Par exemple:

  • Créer un schéma RDMBs avec des concepts abstraits, des références croisées - essentiellement un cube de données trop généralisé ... Et PUIS écrire des fonctionnalités autour d'un modèle à tout faire.
Sheldon Warkentin
la source
Ce serait le frère jumeau maléfique de YAGNI, non?
Wayne Molina
0

L'OMI, le pire anti-modèle que j'ai vu, c'est l'anti-modèle "Nous n'avons pas besoin de modèles puants": L'idée que les modèles de conception sont des pertes de temps et que vous pouvez écrire du code plus rapidement en le coupant ensemble et en copiant / coller au besoin.

Une mention honorable va au code qui charge un objet à partir de la base de données en utilisant l'ancien style VB6 de:

Foobar oFoo = new Foobar();
oFoo.FooID = 42;
if (oFoo.Load()) { 
    // do something with oFoo
}

pas vraiment un anti-modèle en soi, mais montre un manque de tirer parti de l'architecture appropriée et de la séparation des préoccupations.

De plus, des choses comme ça:

// this name is misleading, we may not always want to stand in fire,
// we may want to stand in slime or voidzones or ice patches...
public Foobar StandInFire() { }

// why is this here???
public string BeatWithNerfBat(string whom) { }

// ????
public int GivePony(string to) { }
Wayne M
la source