Je suis un fervent partisan du code propre et de l'artisanat du code, même si je suis actuellement dans un travail où cela n'est pas considéré comme une priorité absolue. Je me retrouve parfois dans une situation où le code d'un pair est criblé avec une conception désordonnée et très peu de souci pour la maintenance future, bien qu'il soit fonctionnel et contient peu ou pas de bogues.
Comment proposez-vous des améliorations dans une révision de code quand vous croyez qu'il y a tant de choses à changer et qu'une échéance approche? Gardez à l'esprit que suggérer que les améliorations soient apportées après la date limite peut signifier qu'elles seront complètement priorisées à mesure que de nouvelles fonctionnalités et corrections de bogues arriveront.
Vérifiez votre motivation. Si vous pensez que le code devrait être changé, vous devriez être en mesure d'articuler une raison pour laquelle vous pensez qu'il devrait être changé. Et cette raison devrait être plus concrète que "je l'aurais fait différemment" ou "c'est moche". Si vous ne pouvez pas mettre en évidence certains avantages qui découlent de votre changement proposé, alors il ne sert à rien de passer du temps (alias de l'argent) à le changer.
Chaque ligne de code du projet est une ligne qui doit être maintenue. Le code doit être aussi long qu'il doit l'être pour faire le travail et être facilement compris, et non plus. Si vous pouvez raccourcir le code sans sacrifier la clarté, c'est bien. Si vous pouvez le faire tout en augmentant la clarté, c'est bien mieux.
Le code est comme du béton: il est plus difficile de changer après avoir été assis un moment. Suggérez vos changements tôt si vous le pouvez, afin que le coût et le risque des changements soient tous deux minimisés.
Chaque changement coûte de l'argent. Réécrire du code qui fonctionne et qui n'a probablement pas besoin d'être modifié pourrait être un effort inutile. Concentrez votre attention sur les sections les plus susceptibles d'être modifiées ou les plus importantes pour le projet.
La forme suit la fonction, et parfois vice versa. Si le code est en désordre, il est plus probable qu'il contienne également des bogues. Recherchez ces bogues et critiquez la fonctionnalité défectueuse plutôt que l'attrait esthétique du code. Suggérer des améliorations qui améliorent le fonctionnement du code et facilitent la vérification du code.
Faites la différence entre la conception et la mise en œuvre. Une classe importante avec une interface merdique peut se propager à travers un projet comme le cancer. Cela diminuera non seulement la qualité du reste du projet, mais augmentera également la difficulté de réparer les dommages. D'un autre côté, une classe avec une interface bien conçue mais une implémentation moche ne devrait pas être un gros problème. Vous pouvez toujours réimplémenter la classe pour de meilleures performances ou fiabilité. Ou, s'il fonctionne correctement et est assez rapide, vous pouvez le laisser tranquille et vous sentir en sécurité en sachant que sa cruauté est bien encapsulée.
Pour résumer tous les points ci-dessus: Assurez-vous que vos modifications proposées ajoutent de la valeur.
Il y a un endroit idéal pour ajouter de la valeur grâce au refactoring. Les changements doivent accomplir trois choses:
Considérations:
Si le code fonctionne sans bogues sérieux et qu'un délai important (comme dans les effets P&L ou PR d'entreprise) est imminent, il est trop tard pour suggérer des améliorations qui nécessitent des changements majeurs. Même les améliorations du code peuvent créer des risques pour le déploiement du projet. Le temps des améliorations était plus tôt dans le projet, quand il y avait plus de temps à investir dans la future robustesse de la base de code.
La révision du code sert 3 objectifs:
Recherche de bugs
Vérification pour voir où le code pourrait être amélioré
Outil pédagogique pour celui qui a écrit le code.
L'évaluation de la qualité de la conception/du code concerne bien sûr les points 2 et 3.
En ce qui concerne # 2:
Expliquez TRÈS clairement quels sont les avantages des modifications proposées par rapport aux coûts à corriger. Comme pour toute décision commerciale, il doit s'agir d'une analyse coûts/avantages.
Par exemple. "L'approche X de la conception réduirait considérablement la probabilité que le bogue Y se produise lors de la modification de Z, et nous savons que ce morceau de code subit des modifications de type Z toutes les 2 semaines. Le coût de la gestion de la panne de production du bogue Y + la recherche du bogue + fixer et libérer le coût d'opportunité de correction + de ne pas livrer la prochaine série de feux est $A
; alors que le coût du nettoyage du code maintenant et le coût d'opportunité (par exemple, le prix d'expédition tardif ou avec moins de fonctionnalités) est $B
. Maintenant, évaluez - ou plutôt demandez à votre chef d'équipe/manager - évaluez $A
contre $B
et décidez.
Cela aidera l'équipe intelligente à gérer efficacement cette situation. Par exemple. ils prendront une décision rationnelle en utilisant des informations complètes
Cela (surtout si vous parlez bien) augmentera VOTRE statut - par exemple vous êtes quelqu'un d'assez intelligent pour voir les avantages d'une meilleure conception ET assez intelligent pour ne pas l'exiger religieusement sans peser les considérations commerciales.
ET, dans le cas probable où le bogue Z se produirait, vous gagnez beaucoup plus d'effet sur la prochaine série de suggestions.
En ce qui concerne # 3:
Je commence toujours mon commentaire par "je le ferais", ce qui indique que le mien est simplement l'un des nombreux points de vue.
J'inclus également toujours une raison.
"je voudrais extraire ce bloc dans une méthode parce que de lisibilité."
Je commente tout; grand et petit. Parfois, je fais plus d'une centaine de commentaires sur un changement, auquel cas je recommande également la programmation par paires et je m'offre en tant qu'ailier.
J'essaie d'établir un langage commun pour des raisons; lisibilité, SEC, SRP, etc.
J'ai également créé une présentation sur Clean Code et Refactoring expliquant pourquoi et montrant comment, que j'ai tenue à mes collègues. Je l'ai tenu trois fois jusqu'à présent, et un consultant que nous utilisons m'a demandé de le garder à nouveau pour eux.
Mais certaines personnes n'écouteront pas de toute façon. Ensuite, je me retrouve avec le rang de tirage. Je suis le responsable du design. La qualité du code est ma responsabilité. Ce changement ne se fera pas sur ma montre dans son état actuel.
Veuillez noter que je suis plus que disposé à revenir sur tout commentaire que je fais; pour des raisons techniques, des délais, des prototypes, etc. J'ai encore beaucoup à apprendre sur le codage et j'écouterai toujours la raison.
Oh, et j'ai récemment proposé d'acheter le déjeuner au premier membre de mon équipe qui a soumis un changement non trivial sur lequel je n'avais aucun commentaire. (Hé, tu dois aussi t'amuser. :-)
Choisissez vos batailles, si une date limite approche, ne faites rien. La prochaine fois que quelqu'un d'autre examine ou gère le code et qu'il continue d'avoir des problèmes avec lui, approchez-le avec l'idée qu'en tant qu'équipe, vous devriez être plus concentré sur la qualité du code lors de la révision du code afin de ne pas avoir autant de problèmes plus tard.
Ils devraient voir la valeur avant de faire le travail supplémentaire.
[Cette réponse est un peu plus large que la question posée à l'origine, car il s'agit de la redirection pour tant d'autres questions sur les revues de code.]
Voici quelques principes que je trouve utiles:
Critiquez en privé, louez en public. Informez quelqu'un sur un bogue dans son code. S'ils ont fait quelque chose de brillant ou ont entrepris une tâche que personne ne voulait, félicitez-les lors d'une réunion de groupe ou dans un courriel envoyé à l'équipe.
Partagez vos propres erreurs. Je partage l'histoire de ma première révision de code désastreuse (reçue) avec les étudiants et les collègues juniors. J'ai également fait savoir aux élèves que j'avais attrapé leur bogue si rapidement parce que je l'avais fait avant moi. Dans une revue de code, cela pourrait se présenter comme suit: "Je pense que vous avez mal fait les variables d'index ici. Je vérifie toujours cela à cause du temps où j'ai mal mes index et fait tomber un centre de données." [Oui, c'est une histoire vraie.]
N'oubliez pas de faire des commentaires positifs. Un bref "Nice!" ou "astuce soignée!" peut faire la journée d'un programmeur junior ou peu sûr.
Supposons que l'autre personne soit intelligente mais parfois imprudente. Ne dites pas: "Comment voulez-vous que l'appelant obtienne la valeur de retour si vous ne le faites pas? en fait le retourner?! " Dites: "On dirait que vous avez oublié la déclaration de retour." N'oubliez pas que vous avez écrit un code affreux à vos débuts. Comme quelqu'un l'a dit un jour: "Si vous n'avez pas honte de votre code d'il y a un an, vous n'apprenez pas."
Enregistrez le sarcasme/le ridicule pour les amis qui ne sont pas sur votre lieu de travail. Si le code est épouvantablement horrible, plaisantez à ce sujet ailleurs. (Je trouve pratique d'être marié à un collègue programmeur.) Par exemple, je ne partagerais pas les dessins animés suivants (ou celui-ci ) avec mes collègues.
Votre question est "Comment coder la révision d'un code mal conçu?":
La réponse IMO est simple. Parlez de la CONCEPTION du code et de la façon dont la conception est défectueuse ou ne répond pas aux exigences. Si vous signalez une conception défectueuse ou "ne répond pas aux exigences", alors le développeur sera forcé de changer son code car il ne fait pas ce qu'il doit faire.
Si le code est "fonctionnellement suffisant" et/ou "répond aux spécifications" et/ou "répond aux exigences":
Si vous êtes un pair de ce développeur, vous n'avez aucun pouvoir direct qui vous permettrait de "lui dire" d'apporter des modifications.
Il vous reste quelques options:
Je trouve qu'il n'y a pas de solution miracle. Vous devez utiliser les trois et vous devez être créatif dans votre utilisation des trois.
Je me retrouve parfois dans une situation où le code d'un pair est criblé de conception désordonnée et très peu soucieux de la maintenance future, bien qu'il soit fonctionnel et contient peu ou pas de bogues.
Ce code est fait. À un certain point, les remaniements deviennent trop coûteux à justifier. Si le code est déjà fonctionnel avec peu ou pas de bogues, alors ce sera une vente impossible. Suggérez quelques façons de nettoyer cela à l'avenir et passez à autre chose. Si/quand le code se brise à l'avenir, réévaluez la valeur d'une refonte alors. Il pourrait ne jamais se casser, ce qui serait formidable. Quoi qu'il en soit, vous êtes au point où il est logique de parier qu'il ne cassera pas, car le coût sera le même maintenant ou plus tard: une refonte longue et terrible.
Ce que vous devez faire à l'avenir, c'est avoir des itérations de développement plus strictes. Si vous aviez pu réviser ce code avant que tout le travail de correction des bogues n'ait été investi, il aurait été judicieux de suggérer une refonte. Vers la fin, il n'est jamais logique de procéder à une refactorisation majeure à moins que le code ne soit écrit d'une manière fondamentalement impossible à maintenir et que vous sachiez avec certitude que le code devra être modifié peu de temps après sa publication.
Étant donné le choix entre les deux options (refactoriser ou pas de refactor), pensez à ce qui semble être la vente la plus intelligente:
Hé patron, nous étions dans les temps et tout fonctionnait bien, mais maintenant nous allons reconstruire beaucoup de choses pour pouvoir ajouter la fonctionnalité X à l'avenir.
ou
Hé patron, nous sommes prêts à sortir. Si jamais nous devions ajouter la fonctionnalité X, cela pourrait nous prendre quelques jours supplémentaires.
Si vous avez dit l'un ou l'autre, votre patron dirait probablement:
Qui a parlé de la fonctionnalité X?
L'essentiel est que parfois un peu de dette technique a du sens, si vous n'étiez pas en mesure de corriger certains défauts quand elle était bon marché (premières itérations). La conception de code de qualité a des rendements décroissants à mesure que vous vous rapprochez d'une fonctionnalité terminée et de la date limite.
Quand une cuillerée de sucre aide le médicament à descendre et que ce qui ne va pas peut être exprimé succinctement - il n'y a pas 20 choses qui ne vont pas - je vais commencer avec une forme qui suggère que je n'ai aucun enjeu, aucun ego investi dans ce que je veux être entendu. Habituellement, c'est quelque chose comme:
Je me demande si ce serait mieux de ...
ou
Est-il sensé de ...
Si les raisons sont assez évidentes, je ne les énonce pas. Cela donne à d'autres une chance d'assumer une propriété intellectuelle de la suggestion, comme dans:
"Oui, c'est une bonne idée, car <votre raison évidente ici>."
Si l'amélioration est assez évidente, mais pas au point de me faire passer pour un idiot de ne pas y penser, et la raison de le faire reflète une valeur partagée avec l'auditeur, alors parfois je ne la suggère même pas:
je me demande s'il y a un moyen de ... <déclaration de valeur partagée ici>
Ce n'est que pour traiter avec des gens vraiment délicats - avec la plupart de mes pairs, je les laisse faire!
Les révisions de code ne visent pas toujours à apporter des améliorations.
Un examen vers la fin d'un projet, comme cela semble être le cas ici, est juste pour que tout le monde sache par où commencer quand les bogues arrivent (ou pour un projet mieux conçu ce qui peut être disponible pour une réutilisation ultérieure). Quel que soit le résultat de l'examen, il n'y a tout simplement pas le temps de changer quoi que ce soit.
Pour réellement apporter des modifications, vous devez discuter du code et de la conception beaucoup plus tôt dans le projet - le code est beaucoup plus facile à modifier lorsqu'il n'existe que lorsque vous parlez d'approches possibles.
Il y a deux problèmes notables dans la question, la partie avec tact et la partie date limite à venir. Ce sont des questions distinctes - la première est une question de communication et de dynamique d'équipe, la seconde est une question de planification et de priorisation.
Avec tact. Je suppose que vous voulez éviter les ego brossés et les retours négatifs contre les critiques. Quelques suggestions:
La deuxième partie est le priorisation. Vous avez de nombreuses suggestions d'amélioration, mais comme la date limite approche, il n'y a que le temps d'en appliquer quelques-unes.
Eh bien, vous voulez d'abord éviter que cela se produise en premier lieu! Pour ce faire, vous effectuez des révisions incrémentielles continues. Ne laissez pas un développeur travailler pendant des semaines sur une fonctionnalité, puis revoyez-la au dernier moment. Deuxièmement, les révisions de code et le temps nécessaire pour mettre en œuvre les suggestions de révision devraient faire partie de la planification et des estimations régulières de toute tâche. S'il n'y a pas assez de temps pour procéder à un examen adéquat, quelque chose s'est mal passé dans la planification.
Mais supposons que quelque chose a mal tourné dans le processus, et vous êtes maintenant confronté à un certain nombre de commentaires de révision, et vous n'avez pas le temps de les mettre en œuvre tous. Vous devez établir des priorités. Ensuite, optez pour les changements qui seront les plus difficiles et les plus risqués à changer plus tard si vous les remettez à plus tard.
La dénomination des identifiants dans le code source est extrêmement importante pour la lisibilité et la maintenabilité, mais il est également assez facile et peu risqué de changer à l'avenir. Idem avec le formatage du code. Alors ne vous concentrez pas sur ce genre de choses. D'un autre côté, la santé mentale des interfaces exposées publiquement devrait être la plus haute priorité, car elles sont vraiment difficiles à changer à l'avenir. Les données persistantes sont difficiles à modifier - si vous commencez par stocker des données incohérentes ou incomplètes dans une base de données, il est très difficile de les corriger à l'avenir.
Les zones couvertes par les tests unitaires présentent un faible risque. Vous pouvez toujours les corriger plus tard. Les zones qui ne le sont pas, mais qui pourraient être testées unitairement présentent un risque plus faible que les zones qui ne peuvent pas être testé à l'unité.
Supposons que vous ayez un gros morceau de code sans tests unitaires et toutes sortes de problèmes de qualité de code, y compris une dépendance codée en dur sur un service externe. En injectant plutôt cette dépendance, vous rendez le morceau de code testable. Cela signifie que vous pouvez à l'avenir ajouter des tests et puis travailler sur la résolution du reste des problèmes. Avec la dépendance codée en dur, vous ne pouvez même pas ajouter de tests. Alors optez d'abord pour ce correctif.
Mais essayez d'éviter de vous retrouver dans ce scénario en premier lieu!
En cas de conception paralysante, vous devez vous concentrer sur la maximisation de encapsulation. De cette façon, il devient plus facile de remplacer les classes/fichiers/sous-programmes individuels par des classes mieux conçues.
Veillez à ce que les interfaces publiques des composants soient bien conçues et que les rouages internes soient soigneusement dissimulés. En outre, les wrappers de stockage de données sont essentiels. (De grandes quantités de données stockées peuvent être très difficiles à modifier, donc si vous obtenez des "saignements d'implémentation" dans d'autres zones du système, vous avez des problèmes).
Une fois que vous avez levé les barrières entre les composants, concentrez-vous sur les composants les plus susceptibles de causer des problèmes majeurs.
Répétez jusqu'à la date limite ou jusqu'à ce que le système soit "parfait".
Au lieu de critiquer directement le code de quelqu'un, il vaut toujours mieux être cosntructif dans nos commentaires lors de la révision du code.
Une façon que je suis
De tels commentaires seront pris au sérieux même si vos échéances approchent. Et sera probablement mis en œuvre dans le prochain cycle de développement.
Augmentez la qualité des revues de code.
Outre la qualité du code examiné, il existe une qualité de la révision du code elle-même:
Il est beaucoup plus facile d'accepter une révision de code de bonne qualité que certains soins d'ego principalement douteux.
La révision du code doit être intégrée au cycle de culture et de développement pour fonctionner. Il est peu probable que la planification d'une révision de code importante à la fin du développement de la fonctionnalité X fonctionne. Tout d'abord, effectuer les changements sera plus difficile et quelqu'un se sentira probablement gêné - créant une résistance à l'activité.
Vous devriez avoir des validations précoces et fréquentes, associées à des révisions au niveau de la validation. Avec les outils d'analyse de code en place, la plupart des révisions seront rapides. Des outils automatisés d'analyse/de révision de code tels que FindBugs et PMD vous aideront à obtenir une grande classe d'erreurs de conception dès le départ. Cependant, ils ne vous aideront pas à repérer les problèmes de niveau architectural, vous devez donc avoir une conception solide en place et juger le système global par rapport à cette conception.