Nous savons tous que l'optimisation prématurée est la racine de tout mal car elle conduit à un code illisible / non maintenable. La pessimisation est encore pire, quand quelqu'un met en œuvre une «optimisation» parce qu'il pense que ce sera plus rapide, mais que cela finit par être plus lent, en plus d'être bogué, impossible à maintenir, etc. Quel est l'exemple le plus ridicule que vous ayez vu ?
performance
optimization
dsimcha
la source
la source
Réponses:
Sur un ancien projet, nous avons hérité de certains (par ailleurs excellents) programmeurs de systèmes embarqués qui avaient une énorme expérience du Z-8000.
Notre nouvel environnement était Sparc Solaris 32 bits.
Un des gars est allé et a changé tous les entiers en shorts pour accélérer notre code, car saisir 16 bits de la RAM était plus rapide que saisir 32 bits.
J'ai dû écrire un programme de démonstration pour montrer que saisir des valeurs 32 bits sur un système 32 bits était plus rapide que saisir des valeurs 16 bits, et expliquer que pour saisir une valeur 16 bits, le processeur devait faire un 32 bits de large accès à la mémoire, puis masque ou décale les bits non nécessaires pour la valeur 16 bits.
la source
Je pense que l'expression "l'optimisation prématurée est la racine de tout le mal" est beaucoup trop utilisée. Pour de nombreux projets, c'est devenu une excuse pour ne pas prendre en compte la performance jusqu'à la fin d'un projet.
Cette phrase est souvent une béquille pour que les gens évitent le travail. Je vois cette phrase utilisée quand les gens devraient vraiment dire "Gee, nous n'avons vraiment pas pensé à cela d'avance et n'avons pas le temps de nous en occuper maintenant".
J'ai vu beaucoup plus d'exemples "ridicules" de problèmes de performances stupides que d'exemples de problèmes introduits en raison de la "pessimisation"
Ce que je pense être une meilleure affirmation est la suivante: "l'optimisation sans mesure ni compréhension n'est pas du tout une optimisation - c'est juste un changement aléatoire".
Un travail de bonne performance prend du temps - souvent plus que le développement de la fonctionnalité ou du composant lui-même.
la source
Les bases de données sont un terrain de jeu de pessimisation.
Les favoris incluent:
Cela me vient à l'esprit.
la source
Je pense qu'il n'y a pas de règle absolue: certaines choses sont mieux optimisées dès le départ, d'autres non.
Par exemple, j'ai travaillé dans une entreprise où nous recevions des paquets de données de satellites. Chaque paquet coûtait beaucoup d'argent, donc toutes les données étaient hautement optimisées (c'est-à-dire emballées). Par exemple, la latitude / longitude n'a pas été envoyée sous forme de valeurs absolues (flottants), mais sous forme de décalages par rapport au coin "nord-ouest" d'une zone "actuelle". Nous avons dû décompresser toutes les données avant de pouvoir les utiliser. Mais je pense que ce n'est pas de la pessimisation, c'est une optimisation intelligente pour réduire les coûts de communication.
D'un autre côté, nos architectes logiciels ont décidé que les données décompressées devraient être formatées dans un document XML très lisible, et stockées dans notre base de données en tant que tel (au lieu d'avoir chaque champ stocké dans une colonne correspondante). Leur idée était que "XML est l'avenir", "l'espace disque est bon marché" et "le processeur est bon marché", il n'y avait donc pas besoin d'optimiser quoi que ce soit. Le résultat a été que nos paquets de 16 octets ont été transformés en documents de 2 Ko stockés dans une colonne, et même pour des requêtes simples, nous avons dû charger des mégaoctets de documents XML en mémoire! Nous avons reçu plus de 50 paquets par seconde, vous pouvez donc imaginer à quel point la performance est devenue horrible (BTW, la société a fait faillite).
Encore une fois, il n'y a pas de règle absolue. Oui, parfois l'optimisation trop tôt est une erreur. Mais parfois, la devise "CPU / espace disque / mémoire est bon marché" est la véritable racine de tout mal.
la source
Oh mon Dieu, je pense que je les ai tous vus. Le plus souvent, il s'agit d'un effort pour résoudre les problèmes de performances par quelqu'un qui est trop paresseux pour dépanner leur chemin jusqu'à la CAUSE de ces problèmes de performances ou même rechercher s'il existe réellement un problème de performances. Dans beaucoup de ces cas, je me demande si ce n'est pas seulement le cas de cette personne qui veut essayer une technologie particulière et cherche désespérément un clou qui correspond à son nouveau marteau brillant.
Voici un exemple récent:
L'architecte de données me propose une proposition élaborée de partitionner verticalement une table de clés dans une application assez grande et complexe. Il veut savoir quel type d'effort de développement serait nécessaire pour s'adapter au changement. La conversation s'est déroulée comme suit:
Moi: Pourquoi envisagez-vous cela? Quel est le problème que vous essayez de résoudre?
Lui: table X est trop large, nous la partitionnons pour des raisons de performances.
Moi: Qu'est - ce qui vous fait penser que c'est trop large?
Lui: Le consultant a dit que c'était beaucoup trop de colonnes pour avoir dans une table.
Moi: Et cela affecte les performances?
Lui: Oui, les utilisateurs ont signalé des ralentissements intermittents dans le module XYZ de l'application.
Moi: Comment savez-vous que la largeur du tableau est la source du problème?
Lui: C'est la table clé utilisée par le module XYZ, et c'est comme 200 colonnes. Ça doit être le problème.
Moi (expliquant): Mais le module XYZ en particulier utilise la plupart des colonnes de cette table, et les colonnes qu'il utilise sont imprévisibles car l'utilisateur configure l'application pour afficher les données qu'il souhaite afficher à partir de cette table. Il est probable que 95% du temps nous finirions par rejoindre toutes les tables de toute façon, ce qui nuirait à la performance.
Lui: Le consultant a dit que c'était trop large et que nous devions le changer.
Moi: Qui est ce consultant? Je ne savais pas que nous avions embauché un consultant, et ils n'avaient pas du tout parlé à l'équipe de développement.
Lui: Eh bien, nous ne les avons pas encore embauchés. Cela fait partie d'une proposition qu'ils ont proposée, mais ils ont insisté sur le fait que nous devions restructurer cette base de données.
Moi: Euh hein. Ainsi, le consultant qui vend des services de refonte de base de données pense que nous avons besoin d'une refonte de base de données ...
La conversation a continué comme ça. Ensuite, j'ai jeté un autre regard sur le tableau en question et j'ai déterminé qu'il pourrait probablement être réduit avec une simple normalisation sans avoir besoin de stratégies de partitionnement exotiques. Ceci, bien sûr, s'est avéré être un point discutable une fois que j'ai enquêté sur les problèmes de performance (auparavant non signalés) et les ai traqués jusqu'à deux facteurs:
Bien sûr, l'architecte pousse toujours pour un cloisonnement vertical de la table accroché au méta-problème «trop large». Il a même renforcé sa thèse en obtenant une proposition d'un autre consultant en base de données qui a pu déterminer que nous devions apporter des modifications de conception majeures à la base de données sans regarder l'application ni exécuter d'analyse de performances.
la source
J'ai vu des gens utiliser alphadrive-7 pour incuber totalement CHX-LT. C'est une pratique rare. La pratique la plus courante consiste à initialiser le transformateur ZT afin que la mise en mémoire tampon soit réduite (en raison d'une plus grande résistance à la surcharge nette) et à créer des bytegraphications de style Java.
Totalement pessimiste!
la source
Rien de bouleversant, je l'admets, mais j'ai surpris des gens en train d'utiliser StringBuffer pour concaténer des chaînes en dehors d'une boucle en Java. C'était quelque chose de simple comme tourner
dans
C'était une pratique assez courante d'utiliser la technique en boucle, car elle était sensiblement plus rapide. Le fait est que StringBuffer est synchronisé, donc il y a en fait une surcharge supplémentaire si vous ne concaténez que quelques chaînes. (Sans compter que la différence est absolument insignifiante à cette échelle.) Deux autres points à propos de cette pratique:
la source
J'ai vu une fois une base de données MSSQL qui utilisait une table «Root». La table racine avait quatre colonnes: GUID (uniqueidentifier), ID (int), LastModDate (datetime) et CreateDate (datetime). Toutes les tables de la base de données étaient une clé étrangère vers la table racine. Chaque fois qu'une nouvelle ligne était créée dans une table de la base de données, vous deviez utiliser quelques procédures stockées pour insérer une entrée dans la table racine avant de pouvoir accéder à la table réelle qui vous intéressait (plutôt qu'à la base de données faisant le travail pour vous avec quelques déclencheurs simples).
Cela a créé un fouillis de maux de tête et d'écoutes inutiles, a nécessité tout écrit dessus pour utiliser des sprocs (et élimine mes espoirs d'introduire LINQ dans l'entreprise. C'était possible mais cela ne valait tout simplement pas le mal de tête), et pour couronner le tout, ça n'a pas été le cas. t même accomplir ce qu'il était censé faire.
Le développeur qui a choisi ce chemin l'a défendu en supposant que cela économisait des tonnes d'espace parce que nous n'utilisions pas de Guids sur les tables elles-mêmes (mais ... n'est-ce pas un GUID généré dans la table racine pour chaque ligne que nous créons?) , amélioré les performances en quelque sorte et rendu «facile» l'audit des modifications apportées à la base de données.
Oh, et le diagramme de la base de données ressemblait à une araignée mutante de l'enfer.
la source
Que diriez-vous de POBI - pessimisation évidemment par intention?
Mon collègue dans les années 90 était fatigué de se faire botter le cul par le PDG simplement parce que le PDG passait le premier jour de chaque version de logiciel ERP (une version personnalisée) à localiser les problèmes de performance dans les nouvelles fonctionnalités. Même si les nouvelles fonctionnalités grignotaient des gigaoctets et rendaient l'impossible possible, il trouvait toujours un détail, voire un problème apparemment majeur, sur lequel se plaindre. Il croyait en savoir beaucoup sur la programmation et a obtenu ses coups de pied en donnant des coups de pied aux programmeurs.
En raison de la nature incompétente de la critique (il était PDG, pas un informaticien), mon collègue n'a jamais réussi à faire les choses correctement. Si vous n'avez pas de problème de performances, vous ne pouvez pas l'éliminer ...
Jusqu'à une version, il a mis beaucoup d'appels de fonction Delay (200) (c'était Delphi) dans le nouveau code. Cela n'a pris que 20 minutes après la mise en service et il a reçu l'ordre de se présenter dans le bureau du PDG pour récupérer en personne ses insultes en retard.
La seule chose inhabituelle à ce jour était que mes collègues étaient muets quand il est revenu, souriant, plaisantant, sortant pour un BigMac ou deux alors qu'il donnait normalement des coups de pied aux tables, s'enflammait au sujet du PDG et de l'entreprise, et passait le reste de la journée à être rejeté à mort. .
Naturellement, mon collègue s'est maintenant reposé pendant un ou deux jours à son bureau, améliorant ses compétences de visée dans Quake - puis le deuxième ou le troisième jour, il a supprimé les appels Delay, reconstruit et publié un "patch d'urgence" dont il a fait passer le mot qu'il avait passé 2 jours et 1 nuit à réparer les trous de performance.
C'était la première (et la seule) fois que le PDG maléfique disait "super boulot!" à lui. C'est tout ce qui compte, non?
C'était du vrai POBI.
Mais c'est aussi une sorte d'optimisation des processus sociaux, donc c'est 100% ok.
Je pense.
la source
"Indépendance de la base de données". Cela signifiait pas de procs, déclencheurs, etc. stockés - pas même de clés étrangères.
la source
Meilleure utilisation d'un StringBuilder que j'ai jamais vu.
la source
Utiliser une expression régulière pour diviser une chaîne lorsqu'une simple chaîne.
la source
Très tard dans ce fil, je sais, mais j'ai vu cela récemment:
Tu sais, juste au cas où un booléen aurait des valeurs supplémentaires ...
la source
Le pire exemple auquel je puisse penser est une base de données interne de mon entreprise contenant des informations sur tous les employés. Il reçoit une mise à jour nocturne des ressources humaines et dispose d'un service Web ASP.NET en plus. De nombreuses autres applications utilisent le service Web pour remplir des éléments tels que des champs de recherche / déroulant.
Le pessimisme est que le développeur pensait que des appels répétés au service Web seraient trop lents pour effectuer des requêtes SQL répétées. Alors, qu'est ce qu'il a fait? L'événement de démarrage de l'application lit l'ensemble de la base de données et la convertit en objets en mémoire, stockés indéfiniment jusqu'à ce que le pool d'applications soit recyclé. Ce code était si lent qu'il faudrait 15 minutes pour se charger en moins de 2000 employés. Si vous avez recyclé par inadvertance le pool d'applications pendant la journée, cela peut prendre 30 minutes ou plus, car chaque demande de service Web démarre plusieurs recharges simultanées. Pour cette raison, les nouvelles recrues n'apparaîtraient pas dans la base de données le premier jour de la création de leur compte et ne seraient donc pas en mesure d'accéder à la plupart des applications internes les premiers jours, en se tournant les pouces.
Le deuxième niveau de pessimisme est que le responsable du développement ne veut pas y toucher de peur de casser des applications dépendantes, mais nous continuons à avoir des pannes sporadiques d'applications critiques à l'échelle de l'entreprise en raison de la mauvaise conception d'un composant aussi simple.
la source
Personne ne semble avoir mentionné le tri, alors je le ferai.
Plusieurs fois, j'ai découvert que quelqu'un avait fabriqué à la main un tri à bulles, parce que la situation «ne nécessitait pas» un appel à l'algorithme de tri rapide «trop sophistiqué» qui existait déjà. Le développeur a été satisfait de constater que leur trousse à bulles artisanale fonctionnait assez bien sur les dix lignes de données qu'ils utilisent pour les tests. Cela ne s'est pas passé aussi bien après que le client ait ajouté quelques milliers de lignes.
la source
J'ai déjà travaillé sur une application pleine de code comme celui-ci:
Supprimer simplement
found
, revenirnull
à la fin et changer la sixième ligne en:Les performances de l'application ont doublé.
la source
Une fois, j'ai dû essayer de modifier le code qui incluait ces gemmes dans la classe Constants
Chacun de ces éléments a été utilisé plusieurs fois dans le reste de l'application à des fins différentes. COMMA_DELIMINATOR a jonché le code avec plus de 200 utilisations dans 8 packages différents.
la source
Le grand numéro un de tous les temps que je rencontre maintes et maintes fois dans le logiciel interne:
Ne pas utiliser les fonctionnalités du SGBD pour des raisons de "portabilité" car "nous pourrions vouloir passer à un autre fournisseur plus tard".
Lis sur mes lèvres. Pour tout travail en interne: IL N'ARRIVERA PAS!
la source
J'avais un collègue qui essayait de déjouer l'optimiseur de notre compilateur C et le code de réécriture de routine que lui seul pouvait lire. L'une de ses astuces préférées était de changer une méthode lisible comme (créer du code):
dans ceci:
Autrement dit, la première ligne d'une méthode une fois lisible deviendrait "
return
" et toute autre logique serait remplacée par des expressions terniaires profondément imbriquées. Lorsque vous avez essayé de discuter du fait que cela était impossible à maintenir, il soulignait le fait que la sortie d'assemblage de sa méthode était plus courte de trois ou quatre instructions d'assemblage. Il n'a pas été nécessairement plus rapide , mais il a toujours été un petit peu plus court. Il s'agissait d'un système embarqué où l'utilisation de la mémoire importait parfois, mais il y avait des optimisations beaucoup plus faciles qui auraient pu être faites que celles-ci qui auraient laissé le code lisible.Puis, après cela, pour une raison quelconque, il a décidé que
ptr->structElement
c'était trop illisible, alors il a commencé à changer tout cela en(*ptr).structElement
sur la théorie que c'était plus lisible et plus rapide aussi.Transformer un code lisible en code illisible pour au plus une amélioration de 1%, et parfois même un code plus lent.
la source
if
. L'insistance sur les déclarations sur les expressions en C est un dogme culturel / religieux, pas une quelconque pratique objective. (Meilleure recommandation: si le ternaire imbriqué est trop long à lire, vous ne devriez pas l'utiliserif
non plus.)if
dans une fonction et de le remplacer par un ternaire. C'est bien, et souvent plus lisible. Je parle de remplacer une méthode entière de plus de 30 lignes par une seule instruction de retour et des ternaires imbriqués. Personne ne pensait que le nouveau code était plus lisible, mais un développeur pensait qu'il était plus rapide.Dans l'un de mes premiers emplois en tant que développeur à part entière, j'ai repris un projet pour un programme qui souffrait de problèmes de mise à l'échelle. Cela fonctionnerait raisonnablement bien sur de petits ensembles de données, mais tomberait complètement en panne lorsque de grandes quantités de données étaient fournies.
En creusant, j'ai trouvé que le programmeur d'origine cherchait à accélérer les choses en parallélisant l'analyse - en lançant un nouveau thread pour chaque source de données supplémentaire. Cependant, il avait commis une erreur en ce que tous les threads nécessitaient une ressource partagée, sur laquelle ils se bloquaient. Bien sûr, tous les avantages de la concurrence ont disparu. De plus, il a planté la plupart des systèmes pour lancer plus de 100 threads pour les verrouiller tous sauf un. Ma machine de développement robuste était une exception en ce sens qu'elle parcourait un ensemble de données de 150 sources en environ 6 heures.
Donc, pour résoudre ce problème, j'ai supprimé les composants multi-threading et nettoyé les E / S. En l'absence d'autres changements, le temps d'exécution sur l'ensemble de données de 150 sources est passé en dessous de 10 minutes sur ma machine et de l'infini à moins d'une demi-heure sur la machine moyenne de l'entreprise.
la source
Je suppose que je pourrais offrir ce bijou:
Puisque la racine carrée a été calculée à un endroit très sensible, j'ai eu la tâche de chercher un moyen de la rendre plus rapide. Ce petit refactoring a réduit le temps d'exécution d'un tiers (pour la combinaison du matériel et du compilateur utilisé, YMMV):
Bien sûr, il existe à la fois des moyens plus rapides ET meilleurs pour le faire, mais je pense que c'est un bel exemple de pessimisation.
Edit: À bien y penser, la boucle déroulée était en fait aussi une pessimisation soignée. En creusant le contrôle de version, je peux également présenter la deuxième étape de la refactorisation, qui a été encore meilleure que celle ci-dessus:
C'est exactement le même algorithme, bien qu'une implémentation légèrement différente, donc je suppose qu'il se qualifie.
la source
isqrt()
calculefloor(sqrt())
, mais pourquoi ce code fonctionne-t-il?Cela peut être à un niveau plus élevé que ce que vous recherchiez, mais le réparer (si vous y êtes autorisé) implique également un niveau de douleur plus élevé:
Insister sur le roulement d'un gestionnaire de relations d'objet / couche d'accès aux données au lieu d'utiliser l'une des bibliothèques établies, testées et matures (même après vous avoir été signalées).
la source
Toutes les contraintes de clé étrangère ont été supprimées d'une base de données, car sinon, il y aurait tellement d'erreurs.
la source
Cela ne correspond pas exactement à la question, mais je le mentionnerai quand même un récit édifiant. Je travaillais sur une application distribuée qui fonctionnait lentement et je me suis envolé pour DC pour participer à une réunion visant principalement à résoudre le problème. Le chef de projet a commencé à esquisser une ré-architecture visant à résoudre le retard. J'ai déclaré que j'avais pris des mesures au cours du week-end qui isolaient le goulot d'étranglement à une seule méthode. Il s'est avéré qu'il y avait un enregistrement manquant lors d'une recherche locale, obligeant l'application à se rendre sur un serveur distant à chaque transaction. En ajoutant l'enregistrement au magasin local, le retard a été éliminé - le problème a été résolu. Notez que la ré-architecture n'aurait pas résolu le problème.
la source
Vérifier avant TOUTES les opérations javascript si l'objet sur lequel vous travaillez existe.
Mon problème avec ce type de code est que personne ne semble se soucier que se passe-t-il s'il n'existe pas? Ne rien faire? Ne donnez pas la rétroaction à l'utilisateur?
Je conviens que les
Object expected
erreurs sont ennuyeuses, mais ce n'est pas la meilleure solution pour cela.la source
Et l'extrémisme YAGNI. C'est une forme de pessimisation prématurée. Il semble que chaque fois que vous appliquez YAGNI, vous finissez par en avoir besoin, ce qui entraîne 10 fois plus d'efforts pour l'ajouter que si vous l'aviez ajouté au début. Si vous créez un programme réussi, il y a de fortes chances que vous en ayez besoin. Si vous avez l'habitude de créer des programmes dont la durée de vie s'épuise rapidement, continuez à pratiquer YAGNI car alors je suppose YAGNI.
la source
Pas exactement une optimisation prématurée - mais certainement malavisée - cela a été lu sur le site Web de la BBC, à partir d'un article sur Windows 7.
Maintenant, je n'ai pas encore essayé Windows 7, donc je me trompe peut-être, mais je suis prêt à parier qu'il y a d'autres problèmes qui sont plus importants que le temps qu'il faut pour s'arrêter. Après tout, une fois que je vois le message «Arrêter Windows», le moniteur s'éteint et je m'éloigne - en quoi ces 400 millisecondes me profitent-elles?
la source
Quelqu'un dans mon département a déjà écrit une classe de chaînes. Une interface comme
CString
, mais sans la dépendance Windows.Une "optimisation" qu'ils ont faite était de ne pas allouer plus de mémoire que nécessaire. Apparemment, ne pas se rendre compte que la raison pour laquelle les classes comme
std::string
allouent un excès de mémoire est qu'une séquence d'+=
opérations peut s'exécuter en un temps O (n).Au lieu de cela, chaque
+=
appel a forcé une réallocation, qui a transformé des appendices répétés en un algorithme de Schlemiel le peintre O (n²) .la source
Un de mes anciens collègues (un soab , en fait) a été chargé de créer un nouveau module pour notre ERP Java qui aurait dû collecter et analyser les données des clients (commerce de détail). Il a décidé de diviser CHAQUE champ Calendrier / Date / Heure en ses composants (secondes, minutes, heures, jour, mois, année, jour de la semaine, bimestre, trimestre (!)) Parce que "comment pourrais-je demander" tous les lundis "?"
la source
Aucune offense pour personne, mais j'ai juste noté un devoir (java) qui avait ceci
la source