Lorsque j'écris du code, j'essaie toujours de rendre mon code aussi propre et lisible que possible.
De temps en temps, il arrive un moment où vous devez franchir la ligne et passer d'un code propre et agréable à un code un peu plus laid pour le rendre plus rapide.
Quand est-il possible de franchir cette ligne?
performance
optimization
quality
readability
maintainability
Ken Cochrane
la source
la source
Réponses:
Vous franchissez la ligne quand
Voici un exemple concret: un système expérimental que je suis en train de produire produisait des données trop lentement, prenant plus de 9 heures par cycle et utilisant seulement 40% du processeur. Plutôt que de trop gâcher le code, j'ai déplacé tous les fichiers temporaires vers un système de fichiers en mémoire. Ajout de 8 nouvelles lignes de code non moche, et l’utilisation du processeur est supérieure à 98%. Problème résolu; aucune laideur requise.
la source
foo
et la renommefoo_ref
- généralement, elle habite immédiatement au-dessusfoo
dans le fichier source. Dans mon harnais de test que j'appellefoo
etfoo_ref
pour la validation et la mesure de la performance relative.C'est une fausse dichotomie. Vous pouvez rendre le code rapide et facile à maintenir.
Vous le faites en écriture propre, en particulier avec une structure de données aussi simple que possible.
Ensuite, vous découvrez où se trouvent les drains temporels (en les exécutant, après les avoir écrits, pas avant), et vous les corrigez un par un. (Voici un exemple.)
Ajouté: Nous entendons toujours parler de compromis, n'est-ce pas, comme un compromis entre temps et mémoire, ou un compromis entre vitesse et facilité de maintenance? Bien que de telles courbes puissent bien exister, il ne faut pas supposer qu'un programme donné est sur la courbe , ni même à proximité.
Tout programme qui se trouve sur la courbe peut facilement (en le confiant à un certain type de programmeur) être rendu beaucoup plus lent et beaucoup moins gérable, et il sera alors loin de la courbe. Un tel programme a alors beaucoup de place pour être rendu plus rapide et plus facile à gérer.
D'après mon expérience, de nombreux programmes ont vu le jour.
la source
Dans mon existence de logiciel libre, je fais beaucoup de travail de bibliothèque axé sur la performance, qui est profondément lié à la structure de données de l' appelant (c'est-à-dire externe à la bibliothèque), sans (par définition) aucun mandat sur les types entrants. Ici, le meilleur moyen de rendre cette performance performante est la méta-programmation, qui (depuis que je suis en .NET-land) signifie IL-emit. C’est un code moche, moche, mais très rapide.
De cette façon, j’accepte volontiers que le code de bibliothèque puisse être "plus laid" que le code d’ application , simplement parce qu’il a moins (ou peut-être pas) de contrôle sur les entrées , il doit donc exécuter certaines tâches à travers différents mécanismes. Ou comme je l'ai dit l'autre jour:
Maintenant , le code des applications est légèrement différent, car c’est là que les développeurs «normaux» (raisonnables) investissent généralement une grande partie de leur temps collaboratif / professionnel; les objectifs et les attentes de chacun sont (IMO) légèrement différents.
OMI, les réponses ci-dessus suggérant qu'il peut être rapide et facile à gérer font référence à du code d' application dans lequel le développeur a plus de contrôle sur les structures de données et n'utilise pas d'outils comme la méta-programmation. Cela dit, il existe différentes façons de faire de la méta-programmation, avec différents niveaux de folie et différents niveaux de frais généraux. Même dans ce domaine, vous devez choisir le niveau d'abstraction approprié. Mais lorsque vous souhaitez activement, positivement et sincèrement, gérer de manière inattendue les données inattendues . ça peut devenir moche. Traiter avec elle
la source
Lorsque vous avez profilé le code et vérifié qu'il provoque effectivement un ralentissement important.
la source
Un code propre n'est pas nécessairement exclusif avec un code à exécution rapide. Le code normalement difficile à lire était écrit parce qu'il était plus rapide à écrire, pas parce qu'il s'exécutait plus rapidement.
Écrire du code "sale" pour tenter de l'accélérer est sans doute peu judicieux, car vous ne savez pas avec certitude que vos modifications améliorent réellement quelque chose. Knuth le dit mieux:
En d'autres termes, écrivez le code propre en premier. Ensuite, profilez le programme résultant et voyez si ce segment est en fait un goulot d'étranglement en termes de performances. Si tel est le cas, optimisez la section si nécessaire et veillez à inclure de nombreux commentaires dans la documentation (y compris éventuellement le code d'origine) pour expliquer les optimisations. Puis profilez le résultat pour vérifier que vous avez réellement apporté une amélioration.
la source
Puisque la question dit "vite difficile à lire le code", la réponse simple n'est jamais. Il n’ya jamais d’excuse pour écrire du code difficile à lire. Pourquoi? Deux raisons.
la source
Quand c'est du code jetable. Je veux dire cela littéralement: quand vous écrivez un script pour effectuer un calcul ou une tâche ponctuelle et que vous savez avec une telle certitude que vous ne devrez plus jamais faire cette action, vous pouvez «rm le fichier source» sans hésiter, alors vous pouvez choisir la route laide.
Sinon, c'est une fausse dichotomie - si vous pensez que vous devez faire en sorte que vous ne le fassiez pas pour le faire plus vite, vous le faites mal. (Ou vos principes sur ce qui est un bon code doivent être révisés. Utiliser goto est en fait assez élégant quand c'est la solution appropriée au problème. Cependant, c'est rarement le cas.)
la source
Chaque fois que le coût estimé d'une performance inférieure sur le marché est supérieur au coût estimé de la maintenance du code pour le module de code en question.
Les gens font toujours SSE / NEON / etc. Assemblée pour essayer de battre les logiciels de certains concurrents sur la puce à processeur populaire de cette année.
la source
N'oubliez pas que vous pouvez rendre le code difficile à lire facile à comprendre grâce à une documentation appropriée et à des commentaires.
En général, profilez après avoir écrit un code facile à lire qui remplit la fonction souhaitée. Les goulots d'étranglement peuvent vous obliger à faire quelque chose qui rend les choses plus compliquées, mais vous corrigez cela en vous expliquant.
la source
Pour moi, c'est une proportion de stabilité (comme dans le béton, l'argile cuite au four, gravée dans la pierre, écrite à l'encre permanente). Plus votre code est instable, plus il est probable que vous deviez le changer à l'avenir, plus il est pliable, comme l'argile humide, pour rester productif. J'insiste également sur la souplesse et non sur la lisibilité. Pour moi, la facilité de changement de code est plus importante que la facilité de lecture. Le code peut être facile à lire et un cauchemar à changer, et à quoi sert-il de pouvoir lire et comprendre facilement les détails de la mise en œuvre s'il s'agit d'un cauchemar à changer? Sauf s'il s'agit simplement d'un exercice académique, le point essentiel pour pouvoir comprendre facilement le code dans une base de code de production consiste à pouvoir le modifier plus facilement au besoin. S'il est difficile de changer, alors, une bonne partie des avantages de la lisibilité disparaissent. La lisibilité n’est généralement utile que dans le contexte de la souplesse et celle-ci n’est utile que dans le contexte de l’instabilité.
Naturellement, même le code le plus difficile à gérer que l'on puisse imaginer, qu'il soit facile ou difficile à lire, ne pose pas de problème s'il n'y a jamais de raison de le modifier, mais de l'utiliser. Et il est possible d'obtenir une telle qualité, en particulier pour le code système de bas niveau où les performances tendent souvent à compter le plus. J'ai le code C que j'utilise toujours régulièrement et qui n'a pas changé depuis la fin des années 80. Il n'a pas eu besoin de changer depuis. Le code est fugly, écrit dans les jours difficiles, et je le comprends à peine. Pourtant, il est toujours applicable aujourd'hui, et je n'ai pas besoin de comprendre son implémentation pour en tirer le meilleur parti.
Bien écrire des tests est un moyen d’améliorer la stabilité. Un autre est le découplage. Si votre code ne dépend pas d’autre chose, sa seule raison de changer est si elle-même doit changer. Parfois, une petite quantité de duplication de code peut servir de mécanisme de découplage pour améliorer considérablement la stabilité, ce qui en fait un bon compromis si, en échange, vous obtenez un code qui est maintenant complètement indépendant de tout le reste. Maintenant, ce code est invulnérable aux changements du monde extérieur. En attendant, le code qui dépend de 10 bibliothèques externes différentes a 10 fois plus de raisons de changer à l’avenir.
Une autre chose utile dans la pratique est de séparer votre bibliothèque des parties instables de votre base de code, voire même de la construire séparément, comme vous le feriez pour des bibliothèques tierces (qui sont également destinées à être simplement utilisées, pas modifiées, du moins pas par votre équipe). Seulement ce type d'organisation peut empêcher les gens de le manipuler.
Un autre est le minimalisme. Moins votre code essaie de faire, plus il est probable qu'il puisse faire ce qu'il fait bien. Les conceptions monolithiques sont presque définitivement instables, car plus elles ajoutent de fonctionnalités, plus elles semblent incomplètes.
La stabilité doit être votre objectif principal lorsque vous écrivez un code qui, inévitablement, sera difficile à modifier, comme le code SIMD parallélisé qui a été mis au point jusqu'à la mort. Vous surmontez la difficulté de maintenir le code en maximisant la probabilité que vous n'ayez pas à le modifier, et donc qu'il ne soit pas obligé de le conserver à l'avenir. Cela ramène les coûts de maintenance à zéro, quelle que soit la difficulté du code à maintenir.
la source