Où la refactorisation et l'optimisation du code devraient-elles s'inscrire dans un calendrier de processus agile et en cascade?

10

Il semble y avoir cette notion parmi l'équipe de gestion de projet selon laquelle «ça marche» signifie qu'elle devrait alors être considérée comme terminée à 100%. La plupart des programmeurs savent que ce n'est pas toujours le cas. Si j'essaie d'autres approches pour faire fonctionner une fonctionnalité, cela ne signifie pas nécessairement que j'ai trouvé la meilleure solution, ou cela ne nécessitera pas de retouches après avoir été examiné avec d'autres développeurs. Je vais souvent en finir avec quelque chose, prendre du recul, puis me demander ce que je peux faire de mieux une fois que les règles commerciales sont satisfaites. Est-ce que ce temps «je peux faire mieux» devrait en fait s'inscrire quelque part dans la chronologie? Je suis d'avis que la meilleure approche est que vous laissez toujours le code mieux que lorsque vous l'avez trouvé (dans une certaine mesure), ce qui pourrait signifier une refactorisation après le lancement. cependant,


la source

Réponses:

13

Il y a un principe général qui régit le besoin de refactoriser et d'optimiser, à la fois en cascade et en Agile: YAGNI (You Ain't Gonna Need It). Un deuxième principe est le corollaire du premier: "L'optimisation prématurée est la racine de tout mal", l'équivalent codant du proverbe général "l'ennemi de l'excellence est la perfection".

Prenons les principes et appliquons-les. Vous devez créer un algorithme ETL qui prend un fichier d'un type particulier, extrait ses informations, puis place ces informations dans une base de données. Votre objectif pour cette semaine (pour nous, peu importe que vous soyez dans une boutique Agile ou SDLC) est de le faire.

Vous êtes un homme intelligent et vous avez eu un aperçu de la situation dans son ensemble. Vous savez que ce n'est pas le seul type de fichier pour lequel le projet aura besoin d'un ETL. Vous envisagez donc d'implémenter cet algorithme ETL pour travailler également sur un autre type de fichier, qui ne présente que des différences mineures. Cela violerait YAGNI. Votre travail n'est pas de développer l'algorithme pour cet autre fichier; c'est de développer l'algorithme pour le fichier qui est nécessaire d'ici la fin de la semaine. Pour atteindre cet objectif et réussir les tests d'acceptation, vous devez développer cet algorithme et le faire fonctionner correctement. Vous "n'aurez pas besoin" du code supplémentaire pour le faire fonctionner avec l'autre fichier. Vous pensez peut-être que cela vous fera gagner du temps pour l'incorporer maintenant, et vous avez peut-être raison, mais vous pouvez aussi avoir terriblement tort; l'algorithme de l'autre fichier devra peut-être être utilisé dans une zone du système que votre code ne peut pas être utilisé, ou les exigences pour le nouveau fichier peuvent être différentes de la vôtre d'une manière que vous ne connaissez pas (dans Agile, celles peut-être pas encore). En attendant, vous avez perdu du temps et augmenté inutilement la complexité de votre algorithme.

Maintenant, c'est la semaine prochaine, et en récompense douteuse de votre excellent travail sur le premier algorithme, vous avez été chargé de créer les algorithmes pour deux nouveaux types de fichiers. Maintenant, vous avez besoin de code supplémentaire pour que votre algorithme fonctionne avec plus de fichiers. Vous pouvez étendre votre algorithme existant à l'aide d'un modèle de méthode de modèle qui utilisera un modèle de base avec des étapes individuelles spécifiques au fichier, ou vous pouvez simplement dériver une interface commune à partir de votre algorithme existant, en développer deux nouvelles qui suivent l'interface et les connecter à un objet qui peut choisir l'algorithme à utiliser.

Pendant le développement, vous savez que vous avez besoin que le système puisse traiter 10 Ko de données brutes par seconde. Vous effectuez un test de charge et trouvez que votre projet d'algorithme initial gère 8 Ko / s. Eh bien, cela ne va pas passer les AAT. Vous regardez et voyez qu'il y a une structure de boucle de complexité O (mon Dieu) dans votre algorithme; vous le rationalisez et obtenez 12 Ko / s. "Assez bien", pensez-vous, "mais si j'avais une mauvaise boucle dans le code, que puis-je raser?". buzz Vous venez de violer la règle de "l'optimisation prématurée". Votre code fonctionne et répond à toutes les exigences. Vous avez terminé, jusqu'à ce que les exigences soient mises à jour pour exiger 15 Ko / s. Si et quand cela se produit, ALORS vous remontez le code et cherchez des choses à améliorer.

Suivez ce processus simple lors du développement, que ce soit en Agile ou dans des SDLC traditionnels: "Au premier passage, faites-le fonctionner. Au deuxième passage, faites-le joli. Au troisième passage, rendez-le SOLIDE." Cela signifie que, lorsque vous créez une ligne de code pour la première fois, faites en sorte que ce code fasse son travail correctement et sans bogue, mais ne prêtez pas trop d'attention aux règles de conception dans ce code, comme pour tout ce que vous savez en ce moment, vous ' Je ne toucherai plus jamais cette zone. La prochaine fois que vous visiterez cette ligne de code, vous aurez juste fait vos preuves; ce n'est plus une pièce unique du système. Refactorisez-le pour la lisibilité, la concision du code et / ou les principes DRY (vous pouvez avoir copié-collé du code pour faire quelque chose cinq fois; refactorisez-le en une boucle et / ou un appel de méthode). La troisième fois que vous travaillez dans ou autour de cette ligne de code,

KeithS
la source
3
+1 car O(my God)-complexitysi rien d'autre ne m'a fait rire!
Joel C
+1 pour le faire fonctionner en premier. Trop de gens essaient d'écrire des modèles et d'optimiser prématurément au départ.
Justin Shield
Je trouve que c'est l'un des problèmes les plus difficiles à surmonter en tant que programmeur. Les ingénieurs ont un désir inné d'expérimenter, de développer et d'affiner, mais au bout du compte, vous êtes payé pour la productivité. À quoi sert un produit parfait si vous dépensez tellement de temps et / ou d'argent qu'il est annulé en raison de dépassements?
ToddR
J'aime l'approche pragmatique mais j'ai un problème avec "Lors de la deuxième passe, faites-la jolie": si la deuxième passe est un an plus tard et que vous ne vous assurez pas que les noms de variable et de méthode sont significatifs et que les nombres magiques ont été remplacés par des constantes symboliques vous avez probablement des problèmes pour comprendre le code. Comment y faire face? "Faites-le joli" 1 heure après "faites-le fonctionner" est beaucoup moins cher que "faites-le joli" après un mois ou après un an. Je suis d'accord que "make it pretty" lorsque le prochain changement de code est nécessaire est utile si "make it pretty" n'a pas été fait en premier lieu.
k3b
Dans Agile / TDD, d'après mon expérience, la deuxième passe se produit généralement peu de temps après la première. Dans les SLDC Waterfall-ish, vous avez plus raison; la fonction a tendance à être écrite une fois, puis reste là jusqu'à ce que la prochaine série d'exigences arrive à travers qui touche cette méthode. Ainsi, certaines bonnes pratiques de codage doivent se produire la première fois, comme le code auto-documenté, afin que lorsque vous revenez un an plus tard, vous puissiez vous rappeler ce que fait le code et pourquoi vous l'avez écrit de cette façon.
KeithS
10

si cela fonctionne et a été testé, alors pourquoi le réparer?

Cela peut aller à l'encontre de votre tempérament personnel en tant qu'ingénieur / programmeur, mais si cela fonctionne, quelle valeur commerciale avez-vous pour continuer à l'affiner? Sera-t-il plus facile à entretenir avec le temps? Si c'est le cas, alors en travaillant selon la méthodologie agile, vous devriez être en mesure de créer de nouveaux éléments dans votre backlog pour affiner et refactoriser votre code existant, et ceux-ci seraient priorisés avec les autres éléments du backlog. Cela fait partie de la valeur du processus agile: l'équipe décide ensemble de ce qui est le plus important et de ce qui sera fait ensuite.

Notre équipe suit également ce que nous appelons la «dette technique», donc si vous faites fonctionner quelque chose mais que vous savez que cela pourrait être mieux fait, vous l'enregistrez comme dette technique. Nous utilisons la mêlée, et parfois vous finirez tout le travail dans un sprint tôt (vous devriez terminer un peu tôt environ la moitié du temps si vous êtes assez proche des estimations), mais vous n'avez pas assez de temps pour tirer une toute nouvelle histoire d'utilisateur, nous passons donc le temps supplémentaire à revenir en arrière et à réduire notre dette technique. Il n'est pas suivi officiellement comme nos histoires d'utilisateurs dans notre backlog, et nous pouvons à peu près y travailler chaque fois que nous avons du temps.

C'est aussi plus ou moins un appel au jugement de votre part lorsque vous appelez la tâche "terminée"; si vous n'êtes pas à l'aise avec l'état dans lequel se trouve votre code, ne marquez pas la tâche comme terminée.

Joel C
la source
2
Je suis devenu fan du concept de «dette technique», +1 pour l'avoir évoqué dans ce contexte.
Patrick Hughes
J'ai complètement oublié l'idée de «dette technique»; bon terme. Mais, on m'a appris que tout ce qui pouvait être qualifié de «dette technique», ce qui signifiait qu'il faudrait des cycles de développement importants pour refactoriser, devait être évité; "faites-le léger" signifiait toujours "faites-le bien", ne faites pas "tour d'ivoire" avec un code qui pourrait être unique.
KeithS
5

Est-ce que ce temps «je peux faire mieux» devrait en fait se situer quelque part dans la chronologie?

Oui.

Juste avant de commencer à coder la prochaine version.

Ne refactorisez pas basé sur "l'intuition".

Refactor basé sur les histoires réelles du prochain sprint.

S.Lott
la source
2

Ne marquez pas le code comme terminé à 100% tant que vous n'êtes pas satisfait de la refactorisation. Il vous suffit d'évaluer constamment le rapport coût / bénéfice de la refactorisation du code, car si vous étudiez suffisamment, vous verrez toujours des moyens d'améliorer le code.

J'utilise la méthode de refactorisation rouge vert de TDD. Mon refactoring est donc intégré à mon développement. Pour les grands refactorings comme le changement du modèle sous-jacent ou quelque chose de similaire, je demanderais à la direction d'accepter de passer le temps en premier.

mpenrow
la source
1
Le code n'est pas "complet à 100%" jusqu'à ce que tous les produits dans lesquels il réside soient morts. Tout comme vous n'êtes pas "complet" en tant que personne jusqu'à ce que votre cœur cesse de battre de façon permanente; vous absorberez toujours de nouvelles informations et serez obligé de faire des choses spécifiques que vous n'avez jamais faites auparavant, ou de faire la même chose d'une manière plus efficace ou moins coûteuse. De même, votre base de code aura TOUJOURS besoin de travail - de nouvelles fonctionnalités et d'anciens correctifs - jusqu'à ce que personne n'utilise plus le logiciel.
KeithS
2

La «refactorisation après le lancement» a un coût caché dans les tests de régression et le temps de contrôle qualité que vous ignorez, en plus elle comporte le coût d'opportunité de ne pas travailler sur les bogues signalés et les fonctionnalités et modifications nouvelles / demandées. TANSTAAFL

Si cela en vaut la peine, cela vaut la peine de faire une tâche pour obtenir la priorité via votre processus normal et non comme une exception spéciale. Vous faites partie d'une équipe, après tout, et travaillez sur des objectifs communs et étendez arbitrairement votre horaire pour s'adapter à la correction du code de travail.

Donc, pour une vraie réponse: si vous savez que vous voudrez refactoriser alors planifier ce temps dans le cadre de la tâche. Si vous faites de la mêlée / agile, définissez une tâche de nettoyage. Si vous êtes en cascade / en spirale, faites en sorte que le refactorisateur fasse partie du processus pour réviser le code et accepter les modules.

Patrick Hughes
la source
0

Si j'essaie d'autres approches pour faire fonctionner une fonctionnalité, cela ne signifie pas nécessairement que j'ai trouvé la meilleure solution,

... Dans ce cas, vous n'avez pas encore terminé à 100% ...

ou cela ne nécessitera pas de retouches après avoir revu avec d'autres développeurs.

Si les révisions de code et les retouches ultérieures font partie de votre cycle de vie de développement, encore une fois, la fonctionnalité n'est pas exécutée tant que toutes ces opérations ne sont pas terminées.

Je vais souvent en finir avec quelque chose, prendre du recul, puis me demander ce que je peux faire de mieux une fois que les règles commerciales sont satisfaites. Est-ce que ce temps «je peux faire mieux» devrait en fait se situer quelque part dans la chronologie?

Ça dépend. Si cela signifie une refactorisation, cela devrait faire partie de la tâche de développement d'origine. Si cela signifie expérimenter avec un algorithme potentiellement meilleur, cela pourrait être une tâche distincte.

Je suis d'avis que la meilleure approche est que vous laissez toujours le code mieux que lorsque vous l'avez trouvé (dans une certaine mesure), ce qui pourrait signifier une refactorisation après le lancement. Cependant, les équipes de projet sont souvent extrêmement mal à l'aise avec cette approche, car là encore, si elle fonctionne et a été testée, pourquoi la corriger?

En bref, car le code peut être cassé à plusieurs niveaux.

C'est une chose que cela fonctionne en ce moment. C'est une chose entièrement différente, qu'elle soit propre, extensible et maintenable à long terme.

Pour des réponses plus détaillées, consultez ce fil .

Péter Török
la source
0

Pour autant que je puisse voir et lire, c'est une question non résolue. Par conséquent, les réponses d'évitement comme «YAGNI» et les réponses «faites-le bien la première fois». Le fait est qu'il n'y a pas de place dans Agile pour la refactorisation - mais je dirais qu'il devrait y en avoir.

La meilleure réponse jusqu'à présent mentionne la dette technique. Ceci, malheureusement, est une triste réalité des logiciels dans de nombreuses entreprises, où la précipitation à faire avancer les choses, que ce soit dans une méthodologie agile ou non agile est tout à fait commune - mais sous Agile les solutions rapides et sales sont rationalisés comme étant quelque chose de bien: "répond aux exigences commerciales minimales" et "YAGNI" (en ce qui concerne la propreté du code).

Ce serait génial si tout le monde faisait TDD, et ce serait génial si tous les développeurs refactorisaient la deuxième ou la troisième fois comme suggéré par une réponse. Mais cela ne se produit tout simplement pas dans le monde réel. Les développeurs de différents niveaux de compétence ont presque toujours trouvé des coins ronds dans la recherche de solutions rapides. En conséquence, le code se désintègre en montagnes de code incontrôlable qui prend des jours aux nouveaux développeurs juste à déchiffrer, ce qui nuit à la productivité et retarde les délais. Par "non maintenable", j'entends des solutions de copier-coller, 5000 classes de ligne, etc. Et tout ce code et ces correctifs sont tous au cœur de l'entreprise! - Dans ces cas de solutions additives, je dirais, il n'y a rien de tel que YAGNI! Vous allez avoir besoin d'un code propre - TOUJOURS. Si le code n'est pas propre, vous n'en aurez certainement pas besoin - voyez la prophétie auto-réalisatrice? Les développeurs se donneraient beaucoup de mal pour ne pas utiliser ce code du tout parce que c'est trop pénible à regarder. Et le cercle vicieux continue indéfiniment jusqu'à ce que toute la grosse boule de boue doive être jetée et réécrite.

Donc je dis - bien que le refactoring de code ne soit pas un concept Agile de type propre, distinct, digne de sa propre histoire - nous devrions prendre le temps de refactoriser. Certains magasins demandent désormais aux équipes de consacrer 20% de leurs sprints à l'endettement technique. Espérons que les partisans agiles changeront d'avis à propos de YAGNI et feront un lieu de refactorisation en tant qu'activité distincte allouée. Et s'ils l'ont déjà fait et que je n'en ai pas entendu parler, veuillez indiquer où cela est décrit, car je suis très intéressé de savoir.

blindcodifier9734
la source
"Le fait est qu'il n'y a pas de place en Agile pour le refactoring" - je ne pense pas que ce soit une vraie affirmation. En agile, il y a une place pour tout type de développement, y compris le refactoring, tant qu'il y a une analyse de rentabilisation pour cela. S'il n'y a pas d'analyse de rentabilisation, pourquoi le faites-vous?
Bryan Oakley
Je suppose que vous avez un point si un peu simpliste. En théorie, un développeur pourrait fabriquer une analyse de rentabilisation pour corriger du code de mauvaise qualité même si cela ne produit aucun changement fonctionnel, mais cela ne coïnciderait pas avec l'esprit d'agilité - en utilisant l'entreprise comme proxy pour justifier le travail. Je dirais alors que l'activité de refactoring se situe en dehors du domaine de l'agile - une sorte d'activité CYA si vous le souhaitez - corrigeant du code incontrôlable afin qu'il ne coûte pas cher à l'entreprise à long terme et que les développeurs soient blâmés. Appelez cela un «sprint de refactoring» ou autre chose, mais il doit y avoir une place formelle pour cela.
blindcodifier9734