Quelle est la pessimisation la plus ridicule que vous ayez vue?

Nous soaps tous que l’optimisation prématurée est la racine de tout mal car elle conduit à un code illisible / impossible à maintenir. Pessimisation est encore pire, quand quelqu’un implémente une “optimisation”, car il pense que ce sera plus rapide, mais cela finit par être plus lent, en plus d’être bogué, inaltérable, etc. Quel est l’exemple le plus ridicule que vous ayez vu? ?

Je pense que l’expression “optimisation prématurée est la racine de tout le mal” est bien trop utilisée. Pour de nombreux projets, il est devenu une excuse de ne pas prendre en compte la performance avant un projet.

Cette phrase est souvent une béquille pour que les gens évitent de travailler. Je vois cette phrase utilisée quand les gens devraient vraiment dire “Gee, on n’a pas vraiment pensé à ça d’avance et on n’a pas le temps de s’en occuper maintenant”.

J’ai vu beaucoup plus d’exemples “ridicules” de problèmes de performance stupides que des exemples de problèmes introduits en raison de la “pessimisation”

  • Lire la même clé de registre des milliers (ou des dizaines de milliers) de fois lors du lancement du programme.
  • Chargement de la même DLL des centaines ou des milliers de fois
  • Gaspiller des méga octets de mémoire en conservant inutilement les chemins d’access complets aux fichiers
  • Ne pas organiser les structures de données pour qu’elles prennent plus de mémoire que nécessaire
  • Dimensionnement de toutes les chaînes qui stockent les noms de fichiers ou les chemins d’access à MAX_PATH
  • Interrogation gratuite pour une chose qui comporte des événements, des rappels ou d’autres mécanismes de notification

Ce que je pense être une meilleure affirmation est le suivant: “l’optimisation sans mesure et compréhension n’est pas du tout l’optimisation – c’est juste un changement aléatoire”.

Bon travail de performance prend du temps – souvent plus que le développement de la fonctionnalité ou du composant lui-même.

Les bases de données sont des playland de pessimisation.

Les favoris incluent:

  • Divisez un tableau en multiples (par plage de dates, plage alphabétique, etc.) car il est “trop ​​gros”.
  • Créez une table d’archivage pour les enregistrements retirés, mais continuez avec UNION avec la table de production.
  • Dupliquer des bases de données complètes par (division / client / produit / etc.)
  • Résistez à l’ajout de colonnes à un index car il le rend trop gros.
  • Créez beaucoup de tableaux récapitulatifs car le recalcul à partir de données brutes est trop lent.
  • Créez des colonnes avec des sous-champs pour économiser de l’espace.
  • Dénormaliser en champs-comme-un-tableau.

C’est de ma tête.

Je pense qu’il n’y a pas de règle absolue: certaines choses sont optimisées au départ, d’autres non.

Par exemple, j’ai travaillé dans une entreprise où nous recevions des paquets de données provenant de satellites. Chaque paquet coûtant beaucoup d’argent, toutes les données étaient hautement optimisées (c.-à-d. Emballées). Par exemple, la latitude / longitude n’a pas été envoyée en tant que valeurs absolues (flottantes), mais en tant que 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’autre part, nos architectes de 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 firebase database en tant que telles (au lieu de stocker chaque champ 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 était que nos paquets de 16 octets étaient transformés en documents de 2 Ko stockés dans une colonne, et même pour des requêtes simples, nous devions 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).

Donc, encore une fois, il n’y a pas de règle absolue. Oui, l’optimisation parfois trop tôt est une erreur. Mais parfois, la devise “cpu / espace disque / mémoire est bon marché” est la vraie racine de tout le mal.

Oh mon Dieu, je pense les avoir tous vus. Plus souvent qu’autrement, il s’agit d’un effort pour résoudre les problèmes de performance par quelqu’un qui est trop fainéant pour résoudre le problème de performance ou même pour rechercher s’il existe un problème de performance. Dans beaucoup de ces cas, je me demande si cette personne ne veut pas seulement essayer une technologie particulière et cherche désespérément un clou qui corresponde à son nouveau marteau shiny.

Voici un exemple récent:

L’architecte de données vient à moi avec une proposition élaborée pour 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: La table X est trop large, nous la partitionnons pour des raisons de performances.

Moi: Qu’est ce qui te fait penser que c’est trop large?

Lui: Le consultant a dit que c’était trop de colonnes à avoir dans un tableau.

Moi: Et cela affecte la performance?

Lui: Oui, les utilisateurs ont signalé des ralentissements intermittents dans le module XYZ de l’application.

Moi: Comment savez-vous que la largeur de la table est la source du problème?

Lui: C’est la table de clés utilisée par le module XYZ, et il s’agit de 200 colonnes. Ce doit être le problème.

Moi (Explication): 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’elle souhaite afficher dans cette table. Il est probable que 95% du temps, nous nous retrouverons de toute façon réunis, ce qui nuirait aux performances.

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, ni parlé à l’équipe de développement.

Lui: Eh bien, nous ne les avons pas encore engagés. Cela fait partie d’une proposition qu’ils ont proposée, mais ils ont insisté sur le fait que nous devions réorganiser cette firebase database.

Moi: Euh hein. Ainsi, le consultant qui vend des services de reconception de bases de données pense que nous avons besoin d’une nouvelle conception de la firebase database.

La conversation a continué comme ça. Par la suite, j’ai jeté un autre coup d’oeil sur le tableau en question et j’ai déterminé que cela pourrait probablement être réduit par une simple normalisation sans recourir à des 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 déclarés) et les ai retracés jusqu’à deux facteurs:

  1. Index manquants sur quelques colonnes clés.
  2. Quelques analystes de données malhonnêtes qui verrouillaient périodiquement les tables de clés (y compris la table «trop large») en interrogeant la firebase database de production directement avec MSAccess.

Bien sûr, l’architecte continue de préconiser un partitionnement vertical de la table qui rest lié au méta-problème «trop large». Il a même renforcé sa position en obtenant une proposition d’un autre consultant en firebase database qui a pu déterminer que nous avions besoin de modifications majeures de la conception de la firebase database sans regarder l’application ni effectuer d’parsing de performance.

J’ai vu des personnes utilisant alphadrive-7 incuber totalement le CHX-LT. Ceci est une pratique rare. La pratique la plus courante consiste à initialiser le transformateur ZT afin de réduire la mise en tampon (en raison d’une plus grande résistance nette à la surcharge) et de créer des octets de graphique de style Java.

Totalement pessimiste!

Rien de plus renversant, je l’avoue, mais j’ai attrapé des personnes utilisant SsortingngBuffer pour concaténer des chaînes en dehors d’une boucle en Java. C’était quelque chose de simple comme tourner

Ssortingng msg = "Count = " + count + " of " + total + "."; 

dans

 SsortingngBuffer sb = new SsortingngBuffer("Count = "); sb.append(count); sb.append(" of "); sb.append(total); sb.append("."); Ssortingng msg = sb.toSsortingng(); 

Auparavant, il était courant d’utiliser la technique en boucle, car elle était beaucoup plus rapide. Le truc, c’est que SsortingngBuffer est synchronisé, donc il y a en fait une surcharge supplémentaire si vous concaténez seulement quelques chaînes. (Sans compter que la différence est absolument sortingviale à cette échelle.) Deux autres points à propos de cette pratique:

  1. SsortingngBuilder n’est pas synchronisé. Vous devriez donc le préférer à SsortingngBuffer dans les cas où votre code ne peut pas être appelé à partir de plusieurs threads.
  2. Les compilateurs Java modernes transformeront la concaténation de chaînes lisible en un bytecode optimisé lorsque cela est approprié.

J’ai déjà vu une firebase database MSSQL qui utilisait une table ‘Root’. La table racine comportait quatre colonnes: GUID (uniqueidentifier), ID (int), LastModDate (datetime) et CreateDate (datetime). Toutes les tables de la firebase database étaient étrangères à la table racine. Chaque fois qu’une nouvelle ligne était créée dans une table de la firebase database, vous deviez utiliser deux procédures stockées pour insérer une entrée dans la table racine avant de pouvoir accéder à la table dont vous vous occupiez (plutôt que de faire la tâche par la firebase database). vous avec quelques déclencheurs simples déclencheurs).

Cela a créé un gâchis inutile et des maux de tête inutiles, exigé que tout ce qui est écrit soit utilisé pour utiliser sprocs (et éliminer mes espoirs d’introduire LINQ dans la société. C’était possible, mais ça ne valait pas la peine) 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 car nous n’utilisions pas de Guids sur les tables (mais … un GUID n’est-il pas généré dans la table Root pour chaque ligne que nous créons?) , en quelque sorte amélioré les performances, et rendu “facile” l’audit des modifications apscopes à la firebase database.

Oh, et le diagramme de la firebase database ressemblait à une araignée mutante de l’enfer.

Qu’en est-il de POBI – pessimisation évidemment intentionnelle?

Collegue of Mine dans les années 90 était fatigué de se faire lancer dans le cul par le PDG simplement parce que le PDG a passé le premier jour de chaque logiciel ERP (un logiciel personnalisé) à repérer les problèmes de performance dans les nouvelles fonctionnalités. Même si les nouvelles fonctionnalités réduisaient les gigaoctets et rendaient l’impossible possible, il a toujours trouvé un détail, voire un problème apparemment majeur, à se plaindre. Il croyait savoir beaucoup de choses sur la programmation et a fait ses preuves en donnant des coups de pieds aux programmeurs.

En raison de la nature incompétente des critiques (il était PDG, pas un informaticien), mon collègue n’a jamais réussi à bien faire les choses. Si vous n’avez pas de problème de performance, vous ne pouvez pas l’éliminer …

Jusqu’à une seule version, il a mis beaucoup d’appels de fonction Delay (200) (c’était Delphi) dans le nouveau code. Il n’a fallu que 20 minutes après la mise en service et il a reçu l’ordre de se présenter au bureau du PDG pour aller chercher ses insultes en retard.

Ce qui était inhabituel jusqu’à présent, c’était que mes collègues étaient muets en rentrant, souriant, plaisantant, sortant pour un BigMac ou deux alors qu’il mettait normalement les tables à la porte, flambait au sujet du PDG et de la société et passait le rest de la journée .

Naturellement, mon collègue s’est reposé pendant un ou deux jours à son bureau, améliorant ses compétences de ciblage dans Quake – puis le deuxième ou troisième jour, il a supprimé les appels de délai, les a reconstruits et a publié un «patch d’urgence». qu’il avait passé 2 jours et 1 nuit pour réparer les trous de performance.

Ce fut la première (et la seule) fois que le diabolique PDG a dit “super boulot!” à lui. C’est tout ce qui compte, non?

C’était un vrai POBI.

Mais c’est aussi une sorte d’optimisation des processus sociaux, donc c’est 100% ok.

Je pense.

“Indépendance de la firebase database”. Cela signifiait pas de procs, sortingggers, etc. stockés – même pas de clés étrangères.

 var ssortingngBuilder = new SsortingngBuilder(); ssortingngBuilder.Append(myObj.a + myObj.b + myObj.c + myObj.d); ssortingng cat = ssortingngBuilder.ToSsortingng(); 

Meilleure utilisation d’un SsortingngBuilder que j’ai jamais vu.

Utiliser une regex pour diviser une chaîne quand une simple ssortingng.split suffit

Personne ne semble avoir mentionné le sorting, alors je le ferai.

Plusieurs fois, j’ai découvert que quelqu’un avait fabriqué un bubbleort à la main, car la situation “ne nécessitait pas” un appel à l’algorithme de sorting rapide “trop ​​sophistiqué” qui existait déjà. Le développeur a été satisfait lorsque leur bulles d’artisanat a bien fonctionné sur les dix lignes de données qu’il utilise pour les tests. Cela ne s’est pas passé aussi bien après que le client ait ajouté quelques milliers de lignes.

Très en retard sur ce sujet, je sais, mais je l’ai vu récemment:

 bool isFinished = GetIsFinished(); switch (isFinished) { case true: DoFinish(); break; case false: DoNextStep(); break; default: DoNextStep(); } 

Tu sais, juste au cas où un booléen aurait des valeurs supplémentaires …

Le pire exemple auquel je puisse penser est une firebase database 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. De nombreuses autres applications utilisent le service Web pour remplir des éléments tels que les champs de recherche / liste déroulante.

Le pessimisme est que le développeur pensait que les appels répétés au service Web seraient trop lents pour faire 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 se lit dans toute la firebase database et le convertit tous en objects en mémoire, stockés indéfiniment jusqu’à ce que le pool d’applications soit recyclé. Ce code était si lent qu’il fallait 15 minutes pour charger 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éclencherait plusieurs rechargements simultanés. Pour cette raison, les nouveaux employés n’apparaissaient pas dans la firebase database le premier jour de la création de leur compte et ne pouvaient donc pas accéder à la plupart des applications internes les deux 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 par crainte de casser les applications dépendantes, mais nous continuons à avoir des interruptions sporadiques au niveau de l’entreprise en raison de la mauvaise conception d’un composant aussi simple.

J’ai déjà travaillé sur une application pleine de code comme ceci:

  1 tuple *FindTuple( DataSet *set, int target ) { 2 tuple *found = null; 3 tuple *curr = GetFirstTupleOfSet(set); 4 while (curr) { 5 if (curr->id == target) 6 found = curr; 7 curr = GetNextTuple(curr); 8 } 9 return found; 10 } 

Il suffit de supprimer la found , de retourner la valeur null à la fin et de remplacer la sixième ligne par:

  return curr; 

Doubler les performances de l’application.

J’ai déjà essayé de modifier le code qui incluait ces gems dans la classe Constants

 public static Ssortingng COMMA_DELIMINATOR=","; public static Ssortingng COMMA_SPACE_DELIMINATOR=", "; public static Ssortingng COLIN_DELIMINATOR=":"; 

Chacun d’entre eux ont été utilisés plusieurs fois dans le rest de l’application à des fins différentes. COMMA_DELIMINATOR a jeté le code avec plus de 200 utilisations dans 8 packages différents.

Le grand numéro de tous les temps que je rencontre à maintes resockets 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 ultérieurement”.

Lis sur mes lèvres. Pour tout travail interne: IL NE S’AGIT PAS!

J’avais un collègue qui essayait de déjouer l’optimiseur et le code de réécriture de routine de notre compilateur C que lui seul pouvait lire. L’une de ses astuces favorites consistait à changer une méthode lisible comme (créer un code):

 int some_method(int input1, int input2) { int x; if (input1 == -1) { return 0; } if (input1 == input2) { return input1; } ... a long expression here ... return x; } 

dans ceci:

 int some_method() { return (input == -1) ? 0 : (input1 == input2) ? input 1 : ... a long expression ... ... a long expression ... ... a long expression ... } 

C’est-à-dire que la première ligne d’une méthode à lecture unique deviendrait ” return ” et que toute autre logique serait remplacée par des expressions terniaires profondément nestedes. Lorsque vous avez tenté de discuter de la manière dont cela était impossible à maintenir, il soulignait que le résultat de l’assemblage de sa méthode était trois ou quatre instructions d’assemblage plus courtes. Ce n’était pas nécessairement plus rapide mais c’était toujours un tout petit peu plus court. Il s’agissait d’un système embarqué où l’utilisation de la mémoire était parfois importante, mais il était beaucoup plus facile d’obtenir des optimisations qui auraient pu rendre le code lisible.

Puis, après cela, pour une raison quelconque, il a décidé que ptr->structElement était trop illisible, alors il a commencé à changer tous ces éléments en (*ptr).structElement en (*ptr).structElement du principe qu’il était plus lisible et plus rapide.

Transformer le code lisible en code illisible pour au plus une amélioration de 1%, et parfois même un code plus lent.

Dans 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 d’échelle. Cela fonctionnerait raisonnablement bien sur de petits ensembles de données, mais tomberait complètement en panne avec de grandes quantités de données.

En creusant, j’ai trouvé que le programmeur d’origine cherchait à accélérer les choses en parallélisant l’parsing – en lançant un nouveau thread pour chaque source de données supplémentaire. Cependant, il avait fait une erreur dans la mesure où tous les threads nécessitaient une ressource partagée, sur laquelle ils étaient bloqués. Bien entendu, tous les avantages de la concurrence ont disparu. De plus, la plupart des systèmes se sont écrasés pour lancer plus de 100 threads, mais tous sauf un ont été verrouillés. Mon ordinateur de développement costaud a été une exception en ce sens qu’il a fait tourner un jeu de données de 150 sources en 6 heures environ.

Donc, pour le réparer, j’ai retiré les composants multi-threading et nettoyé les E / S. En l’absence d’autres modifications, le temps d’exécution sur l’dataset à 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.

Je suppose que je pourrais offrir ce bijou:

 unsigned long isqrt(unsigned long value) { unsigned long tmp = 1, root = 0; #define ISQRT_INNER(shift) \ { \ if (value >= (tmp = ((root << 1) + (1 << (shift))) << (shift))) \ { \ root += 1 << shift; \ value -= tmp; \ } \ } // Find out how many bytes our value uses // so we don't do any uneeded work. if (value & 0xffff0000) { if ((value & 0xff000000) == 0) tmp = 3; else tmp = 4; } else if (value & 0x0000ff00) tmp = 2; switch (tmp) { case 4: ISQRT_INNER(15); ISQRT_INNER(14); ISQRT_INNER(13); ISQRT_INNER(12); case 3: ISQRT_INNER(11); ISQRT_INNER(10); ISQRT_INNER( 9); ISQRT_INNER( 8); case 2: ISQRT_INNER( 7); ISQRT_INNER( 6); ISQRT_INNER( 5); ISQRT_INNER( 4); case 1: ISQRT_INNER( 3); ISQRT_INNER( 2); ISQRT_INNER( 1); ISQRT_INNER( 0); } #undef ISQRT_INNER return root; } 

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 le 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és, YMMV):

 unsigned long isqrt(unsigned long value) { unsigned long tmp = 1, root = 0; #define ISQRT_INNER(shift) \ { \ if (value >= (tmp = ((root << 1) + (1 << (shift))) << (shift))) \ { \ root += 1 << shift; \ value -= tmp; \ } \ } ISQRT_INNER (15); ISQRT_INNER (14); ISQRT_INNER (13); ISQRT_INNER (12); ISQRT_INNER (11); ISQRT_INNER (10); ISQRT_INNER ( 9); ISQRT_INNER ( 8); ISQRT_INNER ( 7); ISQRT_INNER ( 6); ISQRT_INNER ( 5); ISQRT_INNER ( 4); ISQRT_INNER ( 3); ISQRT_INNER ( 2); ISQRT_INNER ( 1); ISQRT_INNER ( 0); #undef ISQRT_INNER return root; } 

Bien sûr, il existe des moyens à la fois plus rapides ET meilleurs, mais je pense que c'est un exemple très intéressant de pessimisation.

Edit: En y pensant, la boucle déroulée était en fait aussi une pessimisation soignée. En fouillant dans le contrôle de version, je peux également présenter la deuxième étape du refactoring, qui a donné de meilleurs résultats que ci-dessus:

 unsigned long isqrt(unsigned long value) { unsigned long tmp = 1 << 30, root = 0; while (tmp != 0) { if (value >= root + tmp) { value -= root + tmp; root += tmp << 1; } root >>= 1; tmp >>= 2; } return root; } 

C'est exactement le même algorithme, mais une implémentation légèrement différente, donc je suppose que cela se qualifie.

Cela peut être à un niveau supérieur à ce que vous étiez après, mais le réparer (si vous êtes autorisé) implique également un niveau de douleur plus élevé:

Insister sur le déploiement d’un Object Relationship Manager / Data Access Layer au lieu d’utiliser l’une des bibliothèques établies, éprouvées et éprouvées (même après qu’elles vous ont été signalées).

Toutes les contraintes de clé étrangère ont été supprimées d’une firebase database, car sinon, il y aurait tellement d’erreurs.

Cela ne correspond pas exactement à la question, mais je le mentionnerai de toute façon comme une mise en garde. Je travaillais sur une application dissortingbuée qui fonctionnait lentement et je suis allée à DC pour assister à une réunion visant principalement à résoudre le problème. Le responsable du projet a commencé à décrire une nouvelle architecture visant à résoudre le retard. Je me suis porté volontaire pour prendre des mesures au cours du week-end qui ont isolé le goulot d’étranglement d’une méthode unique. Il s’est avéré qu’il manquait un enregistrement dans une recherche locale, ce qui obligeait l’application à accéder à un serveur distant à chaque transaction. En rajoutant l’enregistrement au magasin local, le délai a été éliminé – le problème a été résolu. Notez que la re-architecture n’aurait pas résolu le problème.

Vérifier avant toute opération javascript si l’object sur lequel vous travaillez existe.

 if (myObj) { //or its evil cousin, if (myObj != null) { label.text = myObj.value; // we know label exists because it has already been // checked in a big if block somewhere at the top } 

Mon problème avec ce type de code, c’est que personne ne semble se soucier de savoir s’il n’existe pas? Ne fais rien? Ne donnez pas le feedback à l’utilisateur?

Je suis d’accord que les erreurs Object expected sont ennuyeuses, mais ce n’est pas la meilleure solution pour cela.

Que diriez-vous de l’extrémisme de 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’effort que si vous l’aviez ajouté au début. Si vous créez un programme réussi, alors les chances sont que vous allez en avoir besoin. Si vous avez l’habitude de créer des programmes dont la vie s’épuise rapidement, alors continuez à pratiquer YAGNI car je suppose que YAGNI.

Pas exactement optimisation prématurée – mais certainement erronée – cela a été lu sur le site de la BBC, à partir d’un article traitant de Windows 7.

M. Curran a déclaré que l’équipe de Microsoft Windows s’intéressait à tous les aspects du système d’exploitation pour apporter des améliorations. “Nous avons pu réduire de 400 millisecondes le temps d’arrêt en coupant légèrement la musique d’arrêt du fichier WAV.

Maintenant, je n’ai pas encore essayé Windows 7, donc je peux me tromper, mais je suis prêt à parier que d’autres problèmes sont plus importants que le temps nécessaire pour arrêter. Après tout, une fois que je vois le message “Arrêt de Windows”, le moniteur est éteint et je m’éloigne – comment les 400 millisecondes me sont-elles utiles?

Quelqu’un dans mon département a écrit une fois un cours de cordes. Une interface comme CSsortingng , mais sans la dépendance Windows.

Une “optimisation” a été de ne pas allouer plus de mémoire que nécessaire. Apparemment, ne réalisant pas que les classes de raison comme std::ssortingng allouent l’excès de mémoire est telle qu’une séquence d’opérations += peut s’exécuter dans le temps O (n).

Au lieu de cela, chaque appel += forcé une réallocation, qui a été répétée dans un algorithme de O (n²) Schlemiel the Painter .

An ex-coworker of mine (a soab , actually) was assigned to build a new module for our Java ERP that should have collected and analyzed customers’ data (retail industry). He decided to split EVERY Calendar/Datetime field in its components (seconds, minutes, hours, day, month, year, day of week, bimester, sortingmester (!)) because “how else would I query for ‘every monday’?”

No offense to anyone, but I just graded an assignment (java) that had this

 import java.lang.*;