Devrais-je refactoriser le code marqué «ne change pas»?


148

Je traite avec une assez grosse base de code et on m'a donné quelques mois pour refactoriser le code existant. Le processus de refactorisation est nécessaire car nous aurons bientôt besoin d'ajouter de nombreuses nouvelles fonctionnalités à notre produit et, pour l'instant, nous ne sommes plus en mesure d'ajouter aucune fonctionnalité sans casser autre chose. En bref: un code énormément volumineux, complexe, que beaucoup d’entre nous ont vu dans leur carrière.

Pendant le refactoring, je rencontre de temps en temps la classe, la méthode ou les lignes de code qui ont des commentaires comme

Délai d'attente défini pour donner au module A un peu de temps pour faire des choses. Si ce n'est pas chronométré comme ça, ça va casser.

ou

Ne changez pas cela. Croyez-moi, vous allez casser des choses.

ou

Je sais que l'utilisation de setTimeout n'est pas une bonne pratique, mais dans ce cas, je devais l'utiliser

Ma question est la suivante: dois-je reformuler le code lorsque je rencontre de tels avertissements de la part des auteurs (non, je ne peux pas contacter les auteurs)?


157
Toutes nos félicitations! Vous êtes maintenant l'auteur du code.

12
Vous ne pouvez pas résoudre le problème tant que vous ne savez pas ce qu'il est censé faire et ce qu'il fait réellement (vous devez connaître ce dernier afin de comprendre toutes les conséquences de vos modifications). Le problème semble être lié à la synchronisation et à la suppression de ces problèmes. devrait être refactoring job # 1, sinon les choses vont empirer à chaque changement. La question que vous devriez vous poser est comment faire cela. La question dépend beaucoup de la langue et de la plate-forme. par exemple: stackoverflow.com/questions/3099794/finding-threading-bugs
sdenham

14
Pour faire suite au commentaire de @ sdenham: si vous ne possédez pas déjà de tests unitaires automatisés qui exercent votre code base, je vous suggère de passer votre temps à créer de tels tests unitaires, au lieu de perdre votre temps à une "chasse aux sorcières" avec AFAICT sans objectifs clairs. à l'esprit. Une fois que vous avez une série de tests unitaires qui exercent votre base de code de manière approfondie , vous aurez un moyen objectif de savoir si votre code fonctionne toujours si / quand vous devez réécrire des morceaux de celui-ci. Bonne chance.
Bob Jarvis

17
Si les auteurs sont tellement paranoïaques que le code se brisera si quelqu'un respire autant qu'il le respire, il est probablement déjà cassé et le comportement indéfini se passe juste comme il le souhaite. Ce premier titre en particulier ressemble à une condition de concurrence qu'ils ont assommée, alors ça marche la plupart du temps. Sdenham a raison. Déterminez ce qu'il est censé faire et ne supposez pas que c'est ce qu'il fait réellement.
Ray

7
@Ethan Ce n'est peut-être pas si simple. Changer de code peut le casser d'une manière qui ne soit pas immédiatement apparente. Parfois, il se casse longtemps après que vous ayez oublié que le présent refactor aurait pu le causer. Vous n'avez donc qu'un "nouveau" bug dont la cause est mystérieuse. Ceci est particulièrement probable quand c'est lié au timing.
Paul Brinkley

Réponses:


225

Il semble que vous refactoring "au cas où", sans savoir exactement quelles parties de la base de code seront modifiées en détail lors du développement de la nouvelle fonctionnalité. Autrement, vous sauriez s'il est vraiment nécessaire de refactoriser les modules fragiles ou si vous pouvez les laisser tels quels.

Pour dire ceci directement: je pense que c'est une stratégie de refactoring condamnée . Vous investissez temps et argent dans votre entreprise pour des projets dans lesquels personne ne sait si cela va réellement rapporter un avantage, et vous êtes sur le point de faire empirer les choses en introduisant des bogues dans le code qui fonctionne.

Voici une meilleure stratégie: utilisez votre temps pour

  • ajoutez des tests automatiques (probablement pas des tests unitaires, mais des tests d'intégration) aux modules à risque. Surtout les modules fragiles que vous avez mentionnés nécessiteront une suite de tests complète avant de modifier quoi que ce soit.

  • refactorisez uniquement les éléments nécessaires à la mise en place des tests. Essayez de minimiser les changements nécessaires. La seule exception est lorsque vos tests révèlent des bogues - corrigez-les immédiatement (et modifiez-les au degré requis pour le faire en toute sécurité).

  • Apprenez à vos collègues le "principe du scoutisme" (AKA, "refactoring opportuniste" ). Ainsi, lorsque l'équipe commencera à ajouter de nouvelles fonctionnalités (ou à corriger des bugs), elle devrait améliorer et refactoriser exactement les éléments de la base de code à modifier, pas moins, pas plus.

  • obtenir une copie du livre de Feather "Travailler efficacement avec le code hérité" pour l'équipe.

Alors, le moment venu, quand vous saurez avec certitude que vous devez changer et refactoriser les modules fragiles (soit à cause du développement de nouvelles fonctionnalités, soit parce que les tests que vous avez ajoutés à l'étape 1 révèlent des bugs), alors vous et votre équipe êtes prêts à refactoriser les modules et ignorer plus ou moins les commentaires d’avertissement.

En réponse à certains commentaires : pour être juste, si l’on suspecte un module d’un produit existant d’être la cause régulière de problèmes, en particulier un module portant la mention "ne touche pas", je suis d’accord avec tous les toi. Il devrait être revu, débogué et très probablement refactoré dans ce processus (avec l’appui des tests que j’ai mentionnés, et pas nécessairement dans cet ordre). Les bugs sont une justification solide du changement, souvent plus forte que les nouvelles fonctionnalités. Cependant, il s’agit d’une décision prise au cas par cas. Il faut vérifier très attentivement si cela vaut vraiment la peine de changer quelque chose dans un module qui a été marqué comme "ne touchez pas".


70
Je suis tenté de passer au vote contraire, mais je vais m'abstenir. J'ai vu cette mentalité sur plusieurs projets conduire à un produit bien pire. Une fois que les échecs ont finalement eu lieu, ils sont souvent catastrophiques et beaucoup plus difficiles à réparer en raison de leur enracinement. Je corrige régulièrement les boues que je vois, et cela semble poser au pire autant de problèmes qu’ils résolvent ou au mieux ne laissent pas de problèmes connus; C'est globalement un énorme avantage. ET le code est alors meilleur pour le développement futur. Un point à gagner économise neuf, mais un problème ignoré peut s'aggraver.
Aaron

98
Je dirais que tout code marqué avec un commentaire "Time out défini pour donner au module A un peu de temps pour faire des choses. S'il n'est pas chronométré de la sorte, il se cassera" a déjà un bogue. Ce n'est que par chance que le bogue ne soit pas touché.
17 du 26

10
@ 17of26: pas nécessairement un bug. Parfois, lorsque vous travaillez avec des bibliothèques tierces, vous êtes obligé de faire toutes sortes de concessions «d’élégance» dans le but de le faire fonctionner.
Whatsisname

30
@ 17 sur 26: si un module en jeu est suspecté d'avoir des bogues, l'ajout de tests avant tout type de refactoring est encore plus important. Et lorsque ces tests révèlent le bogue, vous devez modifier ce module et donc une légitimation pour le refactoriser immédiatement. Si les tests ne révèlent aucun bogue, laissez le code tel quel.
Doc Brown

17
@Aaron: Je ne comprends pas pourquoi vous pensez que l'ajout de tests ou le respect du principe de scoutisme réduirait la qualité du produit.
Doc Brown

142

Oui, vous devez refactoriser le code avant d'ajouter les autres fonctionnalités.

Le problème avec de tels commentaires est qu'ils dépendent de circonstances particulières de l'environnement dans lequel la base de code est exécutée. La temporisation programmée à un moment donné était peut-être vraiment nécessaire lors de la programmation.

Mais il y a un certain nombre de choses qui pourraient changer cette équation: modifications du matériel, modifications du système d'exploitation, modifications non liées à un autre composant du système, modifications des volumes de données types, vous l'appelez. Il n’existe aucune garantie que cela soit encore nécessaire aujourd’hui ou qu’il soit encore suffisant (l’intégrité de la chose qu’elle était supposée protéger aurait pu être brisée pendant longtemps - sans tests de régression appropriés, vous pourriez ne jamais le remarquer). C'est pourquoi la programmation d'un délai fixe afin de permettre à un autre composant de se terminer est presque toujours incorrecte et ne fonctionne que de manière accidentelle.

Dans votre cas, vous ne connaissez pas les circonstances initiales et vous ne pouvez pas non plus demander aux auteurs originaux. (Vous n'avez probablement pas non plus les tests de régression / d'intégration appropriés, ou vous pouvez simplement continuer et laisser vos tests vous dire si vous avez cassé quelque chose.)

Cela pourrait ressembler à un argument pour ne rien changer par prudence; mais vous dites qu'il faudra de toute façon des changements majeurs, de sorte que le danger de perturber le délicat équilibre qui existait auparavant à cet endroit existe déjà. Il est bien mieux de bouleverser le panier de pommes maintenant , lorsque la seule chose que vous faites est le refactoring, et assurez-vous que si les choses se cassent, c'est le refactoring qui l'a provoqué, plutôt que d'attendre que vous apportiez des modifications supplémentaires en même temps et jamais. etre sur.


46
Meilleure réponse ici; dommage que c'est un outsider. La réponse acceptée ci-dessus n’est pas un bon conseil, en particulier l’accent mis sur "condamnés". J'ai passé la dernière année à travailler sur le code le plus important (~ 10 ^ 6LOC juste pour ma partie), le plus hérité du passé et le plus épouvantable que j'ai jamais vu, et je prends l'habitude de réparer les épaves de train que je vois quand j'ai le temps, même si cela ne fait pas partie de la composante sur laquelle je travaille. En faisant cela, j'ai trouvé et corrigé des bogues dont l'équipe de développement n'était même pas au courant (bien que nos utilisateurs finaux l'étaient probablement). En fait, je suis chargé de. Le produit est amélioré en conséquence.
Aaron

10
Je n'appellerais pas cela le refactoring, mais la correction de bugs, cependant.
Paŭlo Ebermann

7
Améliorer la conception d'une base de code est un refactoring. Si la refonte révèle des bugs qui peuvent être corrigés, c'est la correction de bugs. Mon argument est que le premier mène souvent au second et que le second est souvent très difficile sans le premier.
Kramii

10
@Aaron, vous avez la chance de pouvoir compter sur le soutien de la direction et des développeurs. Dans la plupart des environnements, les bugs connus et inconnus causés par une mauvaise conception et un mauvais code sont acceptés comme un ordre naturel.
Rudolf Olah

5
@nocomprende Je dirais que si vous ne comprenez pas suffisamment le système pour écrire des tests, vous n'avez pas à changer son fonctionnement.
Patrick M

61

Ma question est la suivante: devrais-je refactoriser le code lorsque je rencontre de tels avertissements de la part des auteurs?

Non, ou du moins pas encore. Vous sous-entendez que le niveau de test automatisé est très faible. Vous avez besoin de tests avant de pouvoir refacturer en toute confiance.

pour l'instant nous ne sommes plus en mesure d'ajouter une fonctionnalité sans casser quelque chose d'autre

À l’heure actuelle, vous devez vous concentrer sur l’augmentation de la stabilité et non sur la refactorisation. Vous pouvez effectuer une refactorisation dans le cadre d’une augmentation de la stabilité, mais c’est un outil pour atteindre votre véritable objectif: une base de code stable.

Il semble que cela soit devenu une base de code héritée, vous devez donc le traiter un peu différemment.

Commencez par ajouter des tests de caractérisation. Ne vous inquiétez pas des spécifications, ajoutez simplement un test qui affirme le comportement actuel. Cela aidera à éviter que de nouveaux travaux ne cassent des fonctionnalités existantes.

Chaque fois que vous corrigez un bogue, ajoutez un scénario de test prouvant qu'il est corrigé. Cela empêche les régressions directes.

Lorsque vous ajoutez une nouvelle fonctionnalité, ajoutez au moins quelques tests de base indiquant que la nouvelle fonctionnalité fonctionne comme prévu.

Peut-être obtenir une copie de "Travailler efficacement avec le code hérité"?

On m'a donné quelques mois pour refactoriser le code existant.

Commencez par obtenir une couverture de test. Commencez par les zones qui cassent le plus. Commencez par les domaines qui changent le plus. Ensuite, une fois que vous avez identifié les mauvais modèles, remplacez-les un à un.

Vous ne faites presque jamais un seul refactor, mais un flux constant de petits refactors chaque semaine. Un grand refactor présente un risque énorme de casser des choses et il est difficile de bien tester.


10
+1 pour l'ajout de tests de caractérisation. C'est à peu près le seul moyen de minimiser les régressions lors de la modification de code hérité non testé. Si les tests commencent à échouer une fois que vous avez commencé à apporter des modifications, vous pouvez alors vérifier si le comportement précédent était réellement correct compte tenu des spécifications ou si le nouveau comportement modifié est correct.
Leo

2
Droite. Ou bien, s'il n'y a pas de spécification utilisable, si le comportement précédent est réellement souhaité par les personnes payant ou ayant un intérêt pour le logiciel.
bdsl

Peut-être obtenir une copie de "Travailler efficacement avec le code hérité"? Combien de semaines lui faudra-t-il pour lire ce livre? Et quand: pendant les heures de travail sur le lieu de travail, la nuit quand tout le monde dort?
Billal Begueradj

23

Rappelez - vous la clôture du GK Chesterton : ne pas abattre une clôture obstruant une route avant d'avoir compris pourquoi elle a été construite.

Vous pouvez trouver le ou les auteurs du code et les commentaires en question et les consulter pour en comprendre le sens. Vous pouvez consulter les messages de validation, les fils de discussion ou les documents s'ils existent. Ensuite, vous pourrez soit refactoriser le fragment marqué, soit écrire vos connaissances dans les commentaires, de sorte que la prochaine personne chargée de la maintenance de ce code puisse prendre une décision plus éclairée.

Votre objectif est de comprendre ce que fait le code, pourquoi il a été marqué d’un avertissement à l’époque et ce qui se passerait si cet avertissement était ignoré.

Avant cela, je ne toucherais pas le code qui est marqué "ne touche pas".


4
OP dit "non, je ne peux pas contacter les auteurs".
FrustratedWithFormsDesigner

5
Je ne peux pas contacter les auteurs et il n'y a aucune documentation.
kukis

21
@ kukis: Vous ne pouvez pas contacter les auteurs, ni les experts du domaine, ni trouver d'emails / wiki / docs / tests concernant le code en question? Eh bien, il s’agit d’un projet de recherche complet en archéologie logicielle et non d’une simple tâche de refactoring.
9000

12
Il n'est pas rare que le code soit ancien et que les auteurs soient partis. S'ils ont fini par travailler pour un concurrent, alors en discuter peut violer la NDA de quelqu'un. Dans quelques cas, les auteurs sont indisponibles en permanence: vous ne pouvez pas interroger Phil Katz à propos de PKzip car il est décédé il y a des années.
pjc50

2
Si vous remplacez "trouver l'auteur" par "comprendre quel problème le code a résolu", alors c'est la meilleure réponse. Parfois, ces bouts de code constituent la solution la moins horrible aux bugs qui ont nécessité des semaines, voire des mois de travail, pour trouver, localiser et traiter, souvent des bugs que les types de tests unitaires normaux ne peuvent pas trouver. (Bien qu'ils soient parfois le résultat de programmeurs qui ne savaient pas ce qu'ils faisaient. Votre première tâche consiste à comprendre ce que c'est.)
grahamparks

6

Code avec des commentaires tels que ceux que vous avez affichés serait en haut de ma liste de choses à refactoriser si, et seulement si j'ai une raison de le faire . Le fait est que le code pue tellement que vous le sentez même à travers les commentaires. Il est inutile d'essayer de mélanger toute nouvelle fonctionnalité dans ce code, ce code doit mourir dès qu'il doit changer.

Notez également que les commentaires ne sont d'aucune utilité: ils ne donnent que des avertissements et aucune raison. Oui, ce sont les signes avant-coureurs autour d'un réservoir de requins. Mais si vous voulez faire quelque chose dans les environs, essayez de nager avec les requins. A mon avis, vous devriez d'abord vous débarrasser de ces requins.

Cela dit, vous devez absolument disposer de bons cas de tests avant de pouvoir oser travailler sur un tel code. Une fois que vous avez ces cas de test, assurez-vous de comprendre chaque petit détail que vous modifiez pour vous assurer que vous ne modifiez pas vraiment le comportement. Faites-en votre priorité absolue de garder toutes les particularités comportementales du code jusqu'à ce que vous puissiez prouver qu'elles sont sans aucun effet. N'oubliez pas que vous avez affaire à des requins - vous devez faire très attention.

Donc, dans le cas du délai d'expiration: laissez-le jusqu'à ce que vous compreniez précisément ce que le code attend, puis corrigez la raison pour laquelle le délai d'expiration a été introduit avant de procéder à sa suppression.

Assurez-vous également que votre supérieur hiérarchique comprend les efforts que vous entreprenez et pourquoi vous en avez besoin. Et s'ils disent non, ne le fais pas. Vous avez absolument besoin de leur soutien à cet égard.


1
Parfois, le code finit par être un gâchis parce qu’il doit fonctionner correctement sur des échantillons de silicium de pré-production dont le comportement réel ne correspond pas à la documentation. En fonction de la nature des solutions de contournement, remplacer le code peut être une bonne idée si le code ne doit jamais être exécuté sur des puces boguées, mais changer le code sans le niveau d'analyse technique requis par le nouveau code n'est probablement pas une bonne chose. idée.
Supercat

@supercat L'un de mes arguments était que la refactorisation devait parfaitement préserver le comportement. Si cela ne préserve pas le comportement, c'est plus que refactoriser dans mon livre (et extrêmement dangereux quand on traite avec un tel code hérité).
cmaster

5

Ce n'est probablement pas une bonne idée de refactoriser le code avec de tels avertissements, si les choses fonctionnent correctement telles quelles.

Mais si vous devez refacturer ...

Commencez par rédiger des tests unitaires et des tests d'intégration pour tester les conditions sur lesquelles les avertissements vous avertissent. Essayez de reproduire autant que possible les conditions de production . Cela implique de refléter la base de données de production sur un serveur de test, d'exécuter les mêmes services sur la machine, etc., quoi que vous puissiez faire. Ensuite, essayez votre refactoring (sur une branche isolée, bien sûr). Ensuite, lancez vos tests sur votre nouveau code pour voir si vous pouvez obtenir les mêmes résultats qu'avec l'original. Si vous le pouvez, vous pouvez probablement implémenter votre refactoring en production. Mais soyez prêt à annuler les changements si les choses tournent mal.


5

Je dis allez-y et changez-le. Croyez-le ou non, tous les codeurs ne sont pas des génies et un tel avertissement signifie que cela pourrait être un point d'amélioration. Si vous trouvez que l'auteur avait raison, vous pouvez (haleter) DOCUMENTER ou EXPLIQUER le motif de l'avertissement.


4

J'élargis mes commentaires en une réponse parce que je pense que certains aspects du problème spécifique sont soit négligés, soit utilisés pour tirer des conclusions erronées.

À ce stade, la question de savoir s'il faut ou non refactoriser est prématurée (même si une forme spécifique de «oui» y répondra probablement).

Le problème central ici est que (comme indiqué dans certaines réponses) les commentaires que vous citez indiquent fortement que le code a des conditions de concurrence ou d'autres problèmes de simultanéité / synchronisation, tels que discutés ici . Ce sont des problèmes particulièrement difficiles, pour plusieurs raisons. Premièrement, comme vous l'avez constaté, des modifications apparemment non liées peuvent déclencher le problème (d'autres bogues peuvent également avoir cet effet, mais les erreurs de concurrence le sont presque toujours.) Deuxièmement, elles sont très difficiles à diagnostiquer: le bogue se manifeste souvent à un endroit éloigné dans le temps ou le code de la cause, et tout ce que vous faites pour la diagnostiquer peut la faire disparaître ( Heisenbugs). Troisièmement, les bogues d'accès simultané sont très difficiles à trouver dans les tests. Cela est dû en partie à l'explosion combinatoire: c'est assez mauvais pour un code séquentiel, mais l'ajout des interconnexions possibles d'une exécution simultanée le fait exploser au point que le problème séquentiel devient insignifiant en comparaison. De plus, même un bon cas de test ne peut occasionnellement déclencher le problème - Nancy Leveson a calculé que l'un des insectes mortels du Therac 25s'est produite dans 1 des 350 passages environ, mais si vous ne savez pas quel est le bogue, ni même s'il en existe un, vous ne savez pas combien de répétitions font un test efficace. En outre, seuls les tests automatisés sont réalisables à cette échelle et il est possible que le pilote de test impose des contraintes de minutage subtiles de sorte qu'il ne déclenche jamais le bogue (Heisenbugs à nouveau).

Il existe certains outils de test de concurrence dans certains environnements, tels que Helgrind pour le code utilisant des pthreads POSIX, mais nous ne connaissons pas les détails ici. Les tests doivent être complétés par une analyse statique (ou est-ce l'inverse?), S'il existe des outils adaptés à votre environnement.

Pour ajouter à la difficulté, les compilateurs (et même les processeurs, au moment de l'exécution) sont souvent libres de réorganiser le code de manière à rendre le raisonnement sur la sécurité des threads très contre-intuitif (le cas le plus connu est peut-être le double contrôle). verrouiller l' idiome, bien que certains environnements (Java, C ++ ...) aient été modifiés pour l'améliorer.)

Ce code peut avoir un problème simple qui est la cause de tous les symptômes, mais il est plus probable que vous ayez un problème systémique susceptible d'empêcher vos projets d'ajouter de nouvelles fonctionnalités. J'espère vous avoir convaincu que vous pourriez avoir un problème sérieux, peut-être même une menace existentielle pour votre produit, et la première chose à faire est de savoir ce qui se passe. Si cela révèle des problèmes de simultanéité, je vous conseille vivement de les résoudre avant de vous poser la question de savoir si vous devez effectuer une refactorisation plus générale et avant d'essayer d'ajouter d'autres fonctionnalités.


1
Où voyez-vous "condition de concurrence" dans les commentaires? Où est-ce même impliqué? Vous faites énormément d'hypothèses techniques sans même avoir l'avantage de voir le code.
Robert Harvey

2
@RobertHarvey "Le délai d'attente est défini pour donner au module A un peu de temps pour effectuer des tâches." - à peu près la définition d’une condition de concurrence critique, et les délais d’attente ne sont pas une façon imparable de les gérer. Je ne suis pas le seul à tirer cette conclusion. S'il n'y a pas de problème, c'est très bien, mais le questionneur doit le savoir, car ces commentaires sont un signal d'alarme pour une synchronisation mal gérée.
sdenham

3

Je traite avec une assez grosse base de code et on m'a donné quelques mois pour refactoriser le code existant. Le processus de refactor est nécessaire car nous devrons bientôt ajouter de nombreuses nouvelles fonctionnalités à notre produit [...]

Pendant le refactoring, je rencontre de temps en temps la classe, la méthode ou les lignes de code qui ont des commentaires comme ["ne touchez pas ça!"]

Oui, vous devriez refactoriser ces parties en particulier . Les précédents auteurs ont placé ces avertissements dans le sens suivant: "Ne modifiez pas inutilement ces informations, elles sont très complexes et entraînent de nombreuses interactions inattendues". Alors que votre entreprise envisage de développer davantage le logiciel et d'ajouter de nombreuses fonctionnalités, elle vous a spécifiquement confié le nettoyage de ces éléments. Donc, vous ne le modifiez pas inutilement , vous êtes délibérément chargé de le nettoyer.

Découvrez ce que font ces modules compliqués et divisez-le en problèmes plus petits (ce que les auteurs originaux auraient dû faire). Pour obtenir du code maintenable dans un gâchis, les bonnes parties doivent être refactorisées et les mauvaises parties doivent être réécrites .


2

Cette question est une autre variante du débat sur quand / comment refactoriser et / ou nettoyer le code avec un tiret de "comment hériter du code". Nous avons tous des expériences différentes et travaillons dans différentes organisations avec des équipes et des cultures différentes. Il n'y a donc pas de bonne ou de mauvaise réponse à part "faites ce que vous pensez devoir faire, et faites-le de manière à ne pas vous faire virer" .

Je ne pense pas que de nombreuses organisations seraient bien disposées à laisser tomber un processus métier, car l'application associée aurait besoin d'un nettoyage ou d'une refactorisation du code.

Dans ce cas particulier, les commentaires de code soulignent le fait que la modification de ces sections de code ne doit pas être effectuée. Donc, si vous poursuivez, et que l’entreprise tombe de son côté, non seulement vous n’avez rien à montrer pour appuyer vos actions, mais en réalité un artefact va à l’encontre de votre décision.

Ainsi, comme toujours, vous devez procéder avec précaution et apporter des modifications uniquement après avoir compris tous les aspects de ce que vous êtes sur le point de modifier, et trouver le moyen de la tester, en accordant une attention particulière à la capacité, aux performances et au calendrier, en raison de: les commentaires dans le code.

Néanmoins, même dans ce cas, votre direction doit comprendre le risque inhérent à ce que vous faites et convenir que ce que vous faites a une valeur commerciale qui l’emporte sur le risque et que vous avez fait tout ce qui peut être fait pour le réduire.

Maintenant, revenons à nos propres TODO et les choses que nous savons peuvent être améliorées dans nos propres créations de code si seulement nous avions plus de temps.


1

Oui absolument. Ce sont des indications claires que la personne qui a écrit ce code était insatisfaite de ce code et l’a probablement piquée jusqu’à ce qu’elle fonctionne. Il est possible qu'ils n'aient pas compris quels étaient les véritables problèmes ou, pire, les aient compris et étaient trop paresseux pour les résoudre.

Cependant, c'est un avertissement qu'il faudra beaucoup d'efforts pour les réparer et que de tels problèmes comporteront des risques.

Idéalement, vous serez en mesure de comprendre le problème et de le résoudre correctement. Par exemple:

Délai d'attente défini pour donner au module A un peu de temps pour faire des choses. Si ce n'est pas chronométré comme ça, ça va casser.

Ceci suggère fortement que le module A n'indique pas correctement quand il est prêt à être utilisé ou quand il a fini de traiter. Peut-être que la personne qui a écrit ceci ne voulait pas se soucier de réparer le module A ou ne pouvait pas le faire pour une raison quelconque. Cela ressemble à une catastrophe imminente car il suggère une dépendance au timing traitée par la chance plutôt que par un séquencement approprié. Si je voyais cela, je voudrais vraiment le réparer.

Ne changez pas cela. Croyez-moi, vous allez casser des choses.

Cela ne vous dit pas grand chose. Cela dépend de ce que le code faisait. Cela pourrait signifier qu'il comporte des optimisations qui semblent évidentes et qui, pour une raison ou une autre, vont réellement casser le code. Par exemple, une boucle peut laisser une variable à une valeur particulière dont dépend un autre morceau de code. Ou bien une variable peut être testée dans un autre thread et le fait de changer l'ordre des mises à jour de variable peut endommager cet autre code.

Je sais que l'utilisation de setTimeout n'est pas une bonne pratique, mais dans ce cas, je devais l'utiliser.

Cela ressemble à un facile. Vous devriez pouvoir voir ce qui setTimeoutse passe et peut-être trouver un meilleur moyen de le faire.

Cela dit, si ces types de correctifs sortent du cadre de votre refactor, ce sont des indications selon lesquelles essayer de le refactoriser à l'intérieur de ce code peut augmenter considérablement la portée de vos efforts.

Au minimum, examinez de près le code concerné et voyez si vous pouvez au moins améliorer le commentaire au point qu'il explique plus clairement le problème. Cela pourrait sauver la prochaine personne de faire face au même mystère que vous affrontez.


2
Il est possible que les conditions aient changé au point que les anciens problèmes n'existent plus du tout et que les commentaires d'avertissement soient devenus comme l'endroit sur les anciennes cartes qui disent: "Sois ici des dragons". Plongez et apprenez quelle était la situation ou voyez qu'elle est passée à l'histoire.

2
Dans le monde réel, certains appareils ne fournissent pas d'indication de disponibilité fiable, mais spécifient plutôt une durée maximale non préparée. Les indications de disponibilité fiable et efficace sont bien, mais parfois on est coincé en utilisant des choses sans elles.
Supercat

1
@supercat Peut-être, peut-être pas. Nous ne pouvons pas dire du commentaire ici. Il est donc intéressant d’enquêter pour, si rien d’autre, améliorer le commentaire avec des détails.
David Schwartz

1
@DavidSchwartz: Le commentaire pourrait certainement être plus utile, mais il est parfois difficile de savoir combien de temps un programmeur devrait consacrer à la définition de tous les moyens par lesquels un périphérique ne respecte pas ses spécifications, en particulier s'il est difficile de déterminer si le problème est attendu. être une chose temporaire ou permanente.
Supercat

1

L'auteur des commentaires n'a probablement pas bien compris le code eux-mêmes . S'ils savaient vraiment ce qu'ils faisaient, ils auraient écrit des commentaires réellement utiles (ou n'auraient pas introduit les conditions de course en premier lieu). Un commentaire du type " Fais-moi confiance, tu vas casser des choses ", indique-t-il que l'auteur tente de changer quelque chose qui a causé des erreurs inattendues qu'il n'a pas bien comprises.

Le code est probablement développé par devinettes et essais et erreurs sans une compréhension complète de ce qui se passe réellement.

Ça signifie:

  1. Il est risqué de changer le code. Évidemment, il faudra du temps pour comprendre, et cela ne suit probablement pas de bons principes de conception et peut avoir des effets et des dépendances obscurs. Il est très probablement insuffisamment testé, et si personne ne comprend parfaitement ce que fait le code, il sera difficile d'écrire des tests pour s'assurer qu'aucune erreur ou changement de comportement n'est introduit. Les conditions de course (comme les commentaires auxquels il est fait allusion) sont particulièrement pénibles - c’est un endroit où les tests unitaires ne vous sauveront pas.

  2. Il est risqué de ne pas changer le code. Le code a de fortes chances de contenir des bugs obscurs et des conditions de course. Si un bogue critique est découvert dans le code, ou si un changement d’exigence hautement prioritaire l’oblige à modifier ce code dans un bref délai, vous avez de graves problèmes. Maintenant, vous avez tous les problèmes décrits dans 1, mais sous la pression du temps! De plus, de telles "zones sombres" dans le code ont tendance à se propager et à infecter d'autres parties du code qu'il touche.

Une complication supplémentaire: les tests unitaires ne vous sauveront pas . Généralement, l’approche recommandée pour ce code hérité de correctif consiste à ajouter d’abord des tests unitaires ou d’intégration, puis à isoler et à refactoriser. Mais les conditions de course ne peuvent pas être capturées par des tests automatisés. La seule solution consiste à s'asseoir et à réfléchir au code jusqu'à ce que vous le compreniez, puis à le réécrire pour éviter les conditions de course.

Cela signifie que la tâche est beaucoup plus exigeante que la simple refactorisation de routine. Vous devrez le planifier comme une vraie tâche de développement.

Vous pourrez peut-être encapsuler le code affecté dans le cadre d'une refactorisation régulière afin qu'au moins le code dangereux soit isolé.


-1

La question que je voudrais poser est pourquoi quelqu'un a écrit, NE PAS ÉDITER en premier lieu.

J'ai travaillé sur beaucoup de code, dont certains sont laids et ont nécessité beaucoup de temps et d’efforts pour fonctionner, dans les limites des contraintes imposées à l’époque.

Je parie que dans ce cas, cela est arrivé et la personne qui a écrit le commentaire a découvert que quelqu'un le changeait et devait ensuite répéter tout l'exercice pour le remettre dans l'ordre, afin que tout fonctionne correctement. Après cela, par frustration de cisaillement, ils ont écrit ... NE PAS ÉDITER.

En d'autres termes, je ne veux pas avoir à régler ce problème car j'ai de meilleures choses à faire avec ma vie.

En disant NE PAS ÉDITER, c'est une façon de dire que nous savons tout ce que nous allons savoir aujourd'hui et que, par conséquent, nous n'apprendrons jamais rien de nouveau.

Il devrait y avoir au moins un commentaire sur les raisons de ne pas éditer. C'est comme dire "ne pas toucher" ou "ne pas entrer". Pourquoi ne pas toucher la clôture? Pourquoi ne pas entrer? Ne vaudrait-il pas mieux dire: "Clôture électrique, ne touchez pas!" ou "Mines terrestres! N'entrez pas!". Ensuite, il est évident pourquoi, et pourtant vous pouvez toujours entrer, mais au moins, vous devez connaître les conséquences avant de le faire.

Je parie également que le système n’a aucun test autour de ce code magique et que, par conséquent, personne ne peut confirmer que le code fonctionnera correctement après toute modification. Placer des tests de caractérisation autour du code du problème est toujours une première étape. Reportez-vous à «Utilisation du code hérité» de Michael Feathers pour obtenir des conseils sur la manière de supprimer les dépendances et d'obtenir le code sous test avant de commencer à le modifier.

Je pense qu’en fin de compte, il est difficile de restreindre la refactorisation et de laisser le produit évoluer de manière naturelle et biologique.


2
cela ne semble pas offrir quoi que ce soit de substantiel sur les points évoqués et expliqués dans les 9 réponses précédentes
gnat
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.