Le plus drôle et ce qui m’ahurit d'ailleurs que cela fasse débat ici, c'est que je me moque royalement d'optimisation. Je le dis plus haut, j'ai appris a travailler en blocs de code avec son sempiternel bloc d'initialisation, de traitement et de sortie et ne dépendant les uns des autres que pour ce qui est strictement nécessaire. J'ai même une phobie, je l'avoue, je met un point d'honneur a rendre un bloc de code le plus indépendant possible de son "environnement", m'entêtant parfois même inutilement (mais bon chacun ses tares )
A la lecture des commentaires, ça confirme quelque peu mes inquiétudes, que ces "habitudes", ces simples réflexes de bon sens ont totalement disparu. Un IDE c'est bien, mais ça ne m'empêche pas de poser mon problème sur une simple feuille de papier et si mon outil de développement me permet aujourd'hui de "compiler à la volée", voir d'interpréter en temps réel, ce n'est pas pour autant que je ne pose pas le problème a tête reposée, mains loin du clavier, comme a la vieille époque où les cycles de compilation/run/tests l'imposaient.
Je remercie l'époque où je devais très sérieusement préparer mes batchs de calculs (pas de l'info, du calcul scientifique) pendant toute la journée pour m'éviter au mieux de perdre une journée de plus (car les runs étaient lancés en nuit, coût de gros calculateurs obligeaient). Ca m'a apporté quantités de réflexes que tous les IDE du monde n'ont pas réussi a me faire perdre
Tout à fait, cependant la négliger est tout aussi nul...
Pour un algo génétique sur lequel j'ai eu à travailler, juste factoirser les calculs d'adresses (au lieu de référencer tab[i+..][j+...][k+...] = tab1[i+..][j+...][k+...]...) a fait passer le prog de 4h de CPU à 20 secondes.. (ben oui, si i,j,k = 100000 et qu'on a un tableau 3D à parcourir, et à minimiser, donc N iterations....)
Ce que voulais dire par mon exemple plus haut, c'est que dans le cadre d'un programme présenté comme optimisé, réérencer .getX au lieu de x est assez surprenant...
L'argument de Bousk sur le gain de 0.0001 seconde n'est valable que lorsque le nombre est petit et la contrainte de temps négligeable... 10 millions d'appels avec 500 références par appel, on verra une belle différence...
En bref, oui il y a la règle des 80/20. Cependant les 20 ne sont pas négligeables pour faire un bon soft...
Si le gain en temps de développement est stratégique, alors oui il faut mettre le paquet, quitte à avoir une dette technique colossalle après coup. Je n'ai JAMAIS été dans cette situation-là. Mais c'est fréquent dans les startup. Par exemple Amazon. Quand on lit Steve Yegge(c'est touffu), qui y a été les premières années, Jeff Bezos a mené une stratégie hyper-agressive pour occuper le terrain. Et ça a marché. Au prix d'une dette technique(en termes fleuris, d'une base de code imbitable) collossale. Mais celà en valait la peine.
Encore une fois, celà n'a de sens que si l'aspect délai est une question de vie ou de mort. Même si on ne suit pas son délire pro-LISP, Paul Graham explique bien que sa start-up a bouffé les autres grâce à sa rapidité de mise en oeuvre.
Dans tous les autres cas, la propreté est essentielle, on est d'accord. Mais l'analyse de la valeur ne préjuge pas de la qualité de ce qu'on fait. Si un hack horrible permet de gagner deux jours sur la concurrence, et que ces deus jours donnent un avantage concurrentiel, alors il faut le faire. Je n'en ai jamais été réduit à celà. Mais je ne me l'interdis pas.Envoyé par Paul Graham
J'en ai été réduit "à ça", travailler vite et parfois, oui, salement mais en pleine connaissance de cause. Trop souvent, j'ai constaté que cela servait de mauvaise excuse car on peut, le plus souvent, travailler vite ET proprement et d'ailleurs ça se nourrit mutuellement car travailler proprement est un moyen efficace pour travailler plus vite (valable pas seulement en programmation et pourtant je ne suis pas un modèle de rigueur!).
Dans le registre des "je comprends pas (trop les développeurs d'aujourd'hui!)", toujours très mal a l'aise face a un dev qui m'explique qu'il lui faut autant de temps pour recoder un programme alors qu'on lui demande juste un petit lifting, sauf cas très particulier, ça me dit clairement que le code initial était de mauvaise qualité et là où ça m'inquiète, c'est que je sais déjà que le nouveau code ne sera pas mieux
Et pour finir (parce que je sens que mon ulcère revient à la surface...), ce qui est malheureusement vrai en informatique l'est aussi souvent dans d'autres domaines :
- c'est pas grave de fixer une lamelle d'alu avec des rivets à la con, c'est pas moi qui réparerai après. Crash du Concorde et 150 morts.
- Ca coute cher de chauffer le sang transfusé, pas grave, y a pas de risque. Des milliers de personnes contaminées et condamnées à mort.
- Si on fait des tests anti-SIDA sur le sang transfusé, on va perdre du temps et du coup on devra verser des dividendes çà une société US. Des milliers de personnes contaminées et condamnées à mort.
- Pas la peine de s'occuper de l'amiante, les autres le feront bien après. Des milliers de personnes contaminées et condamnées à mort.
- Je suis un état et je veux faire plaisir à tout le monde, j'emprunte bien au dessus de ce que je peux supporter. Pas grave, les suivants se démerderont. La Grêce est au bord de la faillite, entrainant avec elle 350 millions de personnes.
- Ma fonction de calcul n'est pas initialisée avec une valeur de sortie par défaut compatible. Pas grave, l'appelant n'a qu'à se débrouiller pour vérifier. Sauf que le taux valant 0, ça a planté et ça a scotché 10 personnes pendant toute une nuit pour récupérer le coup.
Vous en voulez d'autres ? Je peux y passer la nuit...
Non. Je fais un truc rapide parceque si je perds du temps à faire "propre", je suis mort(c'est spécifique aux start-up).
Encore une fois, moi, je n'ai jamais été dans cette situation-là. Même sous pression(tu nous fais ce programme de 10 jours en deux jours), j'ai toujours pu me permettre de faire de la présentation, un peu d'archi, un peu de commentaire. De la doc, faut pas rêver, hélas. De toutes façons, les rares fois ou j'ai eu l'occasion d'en faire, elle a été perdue, alors... Mais j'ai toujours codé/commenté en me disant "si je reviens dans dix ans, qu'est-ce que je vais retrouver?"
Celà étant, je comprends ta fureur. Je fais surtout de la maintenance, et les développeurs "trop fort pour perdre leur temps en maintenance" qui crachent des immondices inmaintenables en croyant être des surdieux alors qu'ils ne sont que des surboulets, ça rejoint ce que tu décris.
Mais c'est plus, à mon sens, une question de parcours personel qu'une question de formation ou de méthodes : une fois qu'on a forçé le gars à maintenir un gros monstre hideux, qu'il aura vu les limites de ses architectures astronautiques, et compris pourquoi un code doit être compréhensible même par un imbécile, alors il fera mieux. Seulement, à force de persuasion, ils sont nombreux à toujours y échapper.
Il y a aussi de développeur qui sort d'école/fac, qui a la tête pleine de beaux principes, et que l'on fout sur un projet sans supervision(sinon c'est trop cher). Fatalement, il va faire "au mieux", c'est-à-dire qu'il va surconcevoir et surcharger son système, tout en s'appliquant.
Et de toutes façons, qui que ce soit qui fasse "au mieux", ça sera toujours de la merde pour les autres.....
Ce que je voulais illustrer, c'est qu'il en va de même pour un code propre (j'entends par la lisible, et surtout débuggé au maximum, le programme parfait n'existant pas) que pour le reste : on va gentiement vers un laxisme généralisé ou "pas grave de faire attention, les autres régleront le problème".
Faire un soft pas optimisé, en soi n'est pas grave, jusqu'au moment ou ce manque d'optimisation pénalise la suite. Ce qui à la fin finit bien souvent par arriver. Et là l'argument imparable : " ben oui mais moi j'ai pas de budget pour corriger". Alors que si on fait les choses proprement dès le départ...
Pour moi, appeler le même getter avec les mêmes paramètres dans une boucle, c'est pas une source (potentielle d'après certains) d'optimisation, c'est de l'incompétence profonde.
De la même façon que ce code là :
devrait être remplacé par (ou plutôt dès le départ) :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 For i := 0 to XMLDoc.root.node('Toto').node('Tata').childs.count - 1 do Begin showmessage(XMLDoc.root.node('Toto').node('Tata').childs[i].Text); end;
On gagnera dans ce cas à chaque fois le parcours partiel de l'arbo XML...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 Var Monnode : XmlNode; MonNode := XMLDoc.root.node('Toto').node('Tata'); For i := 0 to MonNode.childs.count - 1 do Begin showmessage(MonNode.childs[i].Text); end;
Sans parler des blocs Try-Except-Finally qu'on va économiser. Encore que moi j'utilise pas donc...
C'est marrant, en fait, on est presque d'accord...
C'est juste là que nous avons une différence. Il peut arriver que si on prend le temps de faire les choses proprement, on soit mort.
Mais bon, ça n'est pas le cas général. Le cas général, c'est que la boite va probablement survivre, et que le code va donc probablement survivre. Dans ces conditions(qui sont les plus fréquentes), il FAUT faire propre.
+1
C'est un peu comme mon exemple, ou on économise des parcours du tableau EXCEL. Mais j'insiste : il faut faire de l'analyse de la valeur, et savoir ce qui est le plus important.
Tiens, tu appartiens à l'école anti-exceptions de Joel Spolsky?
EDIT : tiens, tant que j'y pense, en football, on apprend aux débutants à ne JAMAIS utiliser la pointe du pied pour tirer : c'est moche, et surtout c'est imprécis. Un jeu propre implique d'utiliser systématiquement l'intérieur du pied, bien plus précis. Le pointu, c'est un peu le GOTO du football.
En finale de la coupe du monde 2002, le but vainqueur a été inscrit par Ronaldo. Sur un vilain pointu méchant. Parceque le ballon était fuyant et que Ronaldo ne pouvait pas se permettre de le jouer de l'intérieur du pied, le temps de contrôler, le gardien aurait été sur lui.
Donc, mon argument, c'est que dans des circonstances exceptionelles, on peut être amené à s'assoir sur les règles. Mais évidemment, il faut considérer que les circonstances exceptionelles, euh, en général, c'est pas maintenant. Et appliquer les règles. Et tirer de l'intérieur du pied.
Comme quoi de temps en temps...
Heu... Non... juste un peu fainéant... En même temps, je développe pour moi et mes potes, donc mon soft peut ne pas être très solide si on taquine ses fichiers de données, c'est pas trop grave. Après moi le déluge...
Toute blague mise à part, en environnement pro, je pense pas qu'on puisse se permettre ce genre de légèreté.
Bonjour
arkhamon, pour ton exemple je suis tout à fait d'accord. D'ailleurs je n'appelle pas ça de l'optimisation ça fait parti de l'algo lui même ce genre de problème.
Il ne faut pas confondre parcours de listes et filtres sur ces même listes avec un simple accesseur. J'ai dit plus haut que getXxxx devrait, dans l'idéal, seulement retourner Xxxx.
Dans ton exemple la méthode s'appellerait plutôt findNode(nodeName) et là, il n'y a pas d'excuse si le développeur l'appelle dans la boucle (et c'est même pire que de l'incompétence à mon avis, à moins que ce soit une étourderie). Perso, je n'ai pas de collègues qui font ce genre d'erreurs.
En fait, elle s'appelle SelectSingleNode car je n'utilise pas la librairie intégrée de FireMonkey elle est trop pourrie. J'utilise OmniXML de Ondrej Pokorny qui est largement meilleure. Mais l'esprit est le même...
Moi non plus je te rassure, ils ne font pas ça. Ils font pire...
Dans l'exemple que je cite plus haut, il s'agit d'une équipe, et d'ailleurs différente dans le temps. Une partie a écrit le layer bdd, d'autres l'utilisent et, a quelques mauvais choix de nom de méthode près (get vs load par exemple) fait la boulette et l'accentue en pensant qu'un getXXX ne fait que retourner un attribut alors qu'elle attaque à chaque fois la BDD, au sacro saint principe qu'il faut avoir des données "à jour" et quand tu dis ensuite que la bdd est trop chargée, on t'explique qu'il "suffit" de rajouter des serveurs bdd et te sortent toute une théorie sur la répartition de charge ... (a laquelle d'ailleurs le plus souvent, ils n'entendent pas grand chose, chacun son job!)
Souvenir d'une astuce utilisée alors où je m'étais contenté de mettre en cache (accroché au thread java! pas beau, c'est en plein dans le sujet) et où j'avais divisé par deux ou par trois la charge bdd en 10 lignes de code. Sacré économie pour quelques lignes ...
Errare humanum est, perseverare diabolicum.
D'autant plus que dans un paragraphe donné(fonction, méthode, que sais-je, un paquet de code unitaire quelconque), l'algorithme présuppose généralement que la donnée de change pas. Il peut y avoir des exceptions, mais il me semble que, dans le cas général, si l'entrée change en cours de paragraphe, on est mal.
Si je commence à afficher la cliente Mademoiselle Martin, et qu'en cours de traitement, elle devient Madame Michu, on aura un affichage incohérent(du genre Mademoiselle Michu pour un getTitre & getPatronyme). Mieux vaut un affichage obsolète(au pire, l'agent rafraichit son écran, et Madame Michu remplace Mademoiselle Martin) qu'incohérent.
Pour en revenir aux performances, sous COBOL/MVS, 99,9% des soucis de performances viennent des accès référentiels. De ce que je lis ici ou là, dans d'autres technologies, c'est presque autant. C'est encore une raison pour laquelle le vieil adage "(1)dont optimize; (2 - experts only), don't optimize yet" ne s'applique pas aux référentiels. Et c'est là qu'on en revient au sujet de base de ce fil : quand les appels référentiels sont complètement masqués par des surcouches nombreuses et peu maitrisées, on en arrive à du Bloatware. Qui est souvent(pas toujours) facile à éviter.
Sur mon exemple des 6 heure d'accès référentiel, j'ai mis cinq fois dix lignes(une fois par référentiel appelé), et j'ai gagné 1 heure. (hyper compliqué : je copie la zone d'entrée et la zone de sortie, et si la zone d'entrée est la même que précédemment, je met la zone de sortie au lieu de mouliner). C'est facile, lisible, et ça rapporte gros(les gens qui valident les résultats sont contents de l'avoir à 16 heures au lieu de 17 heures). A noter que mes accès sont en grande partie masqués : je fait appel à un module d'accès qui me renvoie les données. Je ne sais pas ce qu'il y a dedans. Un peu comme ma fonction Excel qui me renvoie la dernière ligne utile du tableau.
Mais je SAIS que c'est du référentiel. Donc je fais gaffe quand même. La bufferisation de l'appel précédent est presque toujours une bonne habitude - facile, pas cher, lisible, et qui rapporte gros. MaDonnee = GetMaDonnee(param), c'est une forme primitive, brutale, mais hypersimple et très efficace de bufferisation.
Ca rejoint le commentaire d'arkhamon "après moi le déluge", comme gérer la cohérence coté applicatif, ça peut devenir compliqué (surtout si on fait aucun effort!), je laisse la BDD s'en débrouiller et après j'engueule les opé et cette même BDD parce qu'elle ne parvient pas a s'en sortir ...
Sur un service web, c'est pas idiot de faire une "photo" des données à l'entrée d'une requête, surtout qu'elle doit répondre, par principe, dans un temps très court. Ca dépend du type de service, mais j'ai travaillé sur des implémentations de cache dits "dirty", où on met à jour certaines données, pas du tout critiques, a des périodes données indépendamment du trafic. C'est facile, ça coute pas cher (genre if elapsed() > ...) et ça peut faire un bien fou a une plateforme.
Mais ma remarque rejoint mes posts plus hauts où j'ai le sentiment que, certains, développeurs n'ont pas grossièrement en tête le coût des traitements qu'ils codent. Il est parfois difficile de se l'imaginer "a priori", raison de plus pour avoir quelques bonnes habitudes qui prémunissent en partie de certaines surprises.
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager