Citation:
Envoyé par
fcharton
J'avoue avoir beaucoup de mal avec la viabilité de cette approche dans un cadre professionnel... Le respect des specs est forcément la première priorité (imagine toi disant à ton responsable : "non ça ne marche pas correctement, mais ca sera drolement facile à maintenir...")
Je vais donc justifier mon approche...
Je suis tout à fait d'accord sur le fait que, au même titre qu'un programme rapide qui ne fait pas ce que l'on attend de lui est inutile, il est tout à fait vrai qu'un code lisible qui ne fait pas ce que l'on attend de lui est tout à fait inutile.
Par contre, lorsque le programme ne fait pas ce que l'on attend de lui (ce peut être "simplement" du à l'inversion, dans une séquence, de deux ou plusieurs appels ;)), tu auras bien plus facile à "mettre la main" sur le problème si tu es confronté à un code lisible que si tu es confronté à un code plus ou moins obfusqué.
Il ne faut pas oublier que le propre d'un code source réside le plus souvent dans le "write once, read ever" et que, si tu passe chaque fois un quart d'heure à te gratter la tête pour essayer de comprendre ce qui est fait, tu va perdre au final bien plus de temps que ce que tu aurais pu perdre si tu avais "directement" pensé à écrire ton code de manière lisible ;)
C'est pourquoi, je reste convaincu que la lisibilité du code a une importance plus grande que le fait d'avoir un code qui fait ce que l'on attend de lui.
Citation:
Ensuite, la rapidité fait généralement partie des specs, ou du moins partiellement. Si la spec demande un recalcul automatique (par exemple qu'un tableau se mette à jour quand tu coches une case, ou quand tu glisses un élément), tu peux faire attendre ton utilisateur 1/2 seconde, éventuellement 2avec un sablier, mais certainement pas 15. Si ton programme test qui fonctionne sur une base de 1000 enregistrement met plusieurs secondes à faire un calcul, il est clair qu'il ne saura rien faire de la vraie base d'un million d'enregistrements sur lequel il doit fonctionner... Pour moi, les specs ont toujours un aspect vitesse (et volumétrie).
Et, personnellement, je remarque que, quand on présente un logiciel à un client, on est presque sur qu'on va conclure une vente quand il commence à dire : ça calcule très vite...
Je te l'accorde également, mais, s'il fait très vite quelque chose de travers, tu ne sera pas avancé non plus...
C'est pour cela que je mets les priorités dans cet ordre particulier, car, selon moi, on ne peut envisager de rejoindre l'une d'elles qu'en gardant celles que l'on a déjà rejoint:
- Ecrivons un code lisible
- Modifions, en cas de besoin, le code pour qu'il fonctionne correctement, en veillant à le garder lisible (sous entendu: si nous n'y sommes pas arrivé lors de la première mouture du code)
- Modifions en cas de besoin le code pour qu'il fonctionne rapidement, en continuant à faire ce que l'on attend de lui, ET en veillant à le garder lisible
Citation:
D'expérience, le problème est rarement l'algorithme, mais souvent des "opérations cachées" qui coutent affreusement cher. Recopies d'objets, recherches inutiles (par exemple sur une map), tris inutiles.
Effectivement, j'ai un peu hâtivement résumé la situation à l'algorithme...
Dans ma tête, il semble "logique" que les différents conteneurs utilisent différents algorithmes pour arriver à un résultat similaire (il est, par exemple, impossible d'effectuer une recherche dichotomique sur une liste, ce qui n'empêche nullement d'effectuer une recherche)...
Et donc, je reconnais que l'optimisation de l'algorithme peut régulièrement passer par... le choix d'une structure différente.
Il n'empêche qu'il faut à mon gout commencer à optimiser l'algorithme et les structures avant de vouloir optimiser le code qui met cet algorithme en oeuvre...
Sortir d'une boucle l'appel d'une fonction qui invoque une fonction de tri, ou préférer une valeur entière à une chaine de caractères comme clé de tri / comparaison font partie des optimisations à envisager bien avant de décider d'utiliser l'opérateur de post incrémentation au lieu de l'opérateur de pré incrémentation (par exemple)...
Citation:
L'inconvénient d'une certaine présentation du C++ (et d'autres langages de haut niveau) c'est qu'il cache ces aspects à l'utilisateur, du coup, on voit des programmeurs qui sont complètement perdus quand ils se trouvent face au problème. Comprendre l'approche 'bas niveau' du C permet souvent de voir la solution (même si on ne l'implémente pas en C).
Je te l'accorde...
Cependant, j'aurais plutôt tendance à dire que, bien plus que le fait de savoir "comment c'est fait en C", ce qui importe, c'est d'avoir une connaissance et une compréhension correcte des mécanismes mis en oeuvre en C++ et, pourquoi pas, des mécanismes internes de la S(T)L...
Cette connaissance des mécanismes internes de la S(T)L te fera, par exemple, préférer l'opérateur [] à la fonction at() lorsque tu travailles avec un std::vector<Type> et que tu sais pertinemment être dans les limites autorisée pour l'index ;)
Citation:
Quant à savoir ce qui pose problème, il y a des outils pour cela : les profileurs. A mon avis un profileur c'est au moins aussi important qu'un débugger, et il faut l'utiliser assez tot dans le développement.
Encore une fois nous sommes bien d'accord...
Je n'ai d'ailleurs jamais dit qu'il ne fallait pas utiliser un profiler ni veiller à apporter les optimisations nécessaires.
Ce sur quoi je met en garde, c'est sur la tentation d'apporter des optimisations prématurées.
Encore une fois, le choix d'utiliser un sucre syntaxique afin d'améliorer les performances est, à mon sens, une optimisation prématurée si l'on n'a pas la certitude d'avoir optimisé au mieux nos structures et nos algorithmes.
Ce ne sera qu'une fois que nous aurons la certitudes d'utiliser les meilleurs algorithmes avec les meilleurs structures en fonction de nos besoins que nous pourrons envisager de "traquer" les quelques fréquences d'horloges perdues à coup de sucre syntaxique... En veillant à faire en sorte que cela en vaille la peine :P