Quel est le bon équilibre entre la cohérence du code et l'amélioration du code?


53

Récemment, j'ai eu une discussion avec un collègue concernant le style de code. Il a fait valoir que votre utilisation des API et les modèles généraux que vous utilisez devraient être aussi semblables que possible avec le code environnant, sinon avec la base de code dans son ensemble, comme vous le feriez avec l'apparence du code (positionnement d'accolade, capitalisation, etc.) . Par exemple, si j'ajoutais une méthode à une classe DAO en C #, j'essaierais d'utiliser LINQ le cas échéant pour rendre mon code propre et facile à gérer, même si aucune des autres méthodes de cette classe ne l'utilisait. Cependant, mon collègue soutiendrait que je ne devrais pas l'utiliser dans ce cas, car cela irait à l'encontre du style existant de cette classe et donc plus difficile à comprendre.

Au début, je trouvais sa position assez extrême, mais après y avoir réfléchi un peu, je commence à comprendre son argument. Avec l'exemple hypothétique LINQ, peut-être que cette classe ne le contient pas car mes collègues ne connaissent pas LINQ? Si tel est le cas, mon code ne serait-il pas plus facile à maintenir pour mes collègues développeurs si je ne l'utilisais pas? D'un autre côté, si je crois vraiment que l'utilisation d'une telle technique résulterait en un code plus propre, ne devrais-je pas l'utiliser même si elle diffère radicalement du code qui l'entoure?

Je pense que l'essentiel de l'argument de mon collègue est que si nous mettons tous en œuvre différentes fonctionnalités similaires dans une base de code, et que nous pensons tous que notre façon de procéder est la meilleure, le code dans son ensemble devient finalement plus difficile. comprendre. Cependant, pour le moment, je pense toujours que si nous suivons aveuglément le code existant, la qualité se détériorera lentement au fil du temps.

Dans quelle mesure les motifs font-ils partie du style de code et où devrions-nous établir une distinction entre rester cohérent et apporter des améliorations?


14
Alors, comment améliorer la qualité du code, si tout le monde se limitait à la "mauvaise" façon?
Izkata


Lorsque vous écrivez LINQ, ne voulez-vous pas dire LINQ to SQL? Si oui, je pourrais être d'accord avec votre ami. Si vous parlez de LINQ, je ne suis pas d'accord avec lui. Tout le monde doit connaître LINQ ces jours-ci. Ce n'est pas leur choix. Ils sont payés pour être familiers.
Piotr Perak

@Peri Je voulais dire simplement LINQ de base - je suppose que mon exemple aurait dû être de travailler avec IEnumerables plutôt qu'avec un DAO.
Robert Johnson

2
ICYMI - Bande dessinée Dilbert sur ce sujet: dilbert.com/strips/2013-09-21
Jim Bethancourt

Réponses:


53

Pour donner une réponse plus générale:

Dans un cas comme celui-ci, vous avez deux "pratiques recommandées" en matière de programmation qui s'opposent: la cohérence du code est importante, mais le choix de la meilleure méthode possible pour accomplir votre tâche. Il n'y a pas une seule réponse correcte à ce dilemme; cela dépend de quelques facteurs:

  • Comment bénéfique le "bon" moyen?

    • Parfois, les meilleures pratiques nouvelles et améliorées augmenteront considérablement les performances, élimineront les bogues, seront beaucoup plus faciles à programmer, etc. Dans ce cas, je miserais beaucoup pour l’utilisation de la nouvelle méthode. D'autre part , la "bonne façon" peut n'être qu'un peu plus qu'un sucre syntaxique ou une méthode idiomatique convenue pour faire quelque chose qui n'est pas réellement supérieur. Dans ce cas, la cohérence du code est probablement plus importante.
  • Quelle serait l'ampleur du problème qu'une incohérence créerait?

    • Quelle est l'interconnexion du nouveau code avec le code hérité? Votre nouveau code fait-il partie d'une bibliothèque? Crée-t-il un objet qui est transmis à de nombreuses parties du programme? Dans de tels cas, la cohérence est très importante. L'utilisation d'une nouvelle API, ou d'une nouvelle façon de faire les choses en général, peut créer des résultats légèrement différents qui brisent les hypothèses ailleurs dans votre programme. D'un autre côté , si vous écrivez un code assez isolé, les incohérences risquent moins de poser problème.
    • Quelle est la taille et la maturité de votre base de code? Combien de développeurs ont besoin de comprendre et de travailler dessus? Des normes uniformes convenues sont beaucoup plus importantes pour les grands projets.
    • Le code doit-il être exécuté dans des environnements plus anciens qui ne prennent peut-être pas en charge les dernières fonctionnalités?

Sur la base de ces problèmes, vous devez faire le bon choix quant à la route à suivre. Personnellement, je vois peu de valeur dans la cohérence pour la cohérence, et préférerais utiliser les meilleures méthodes les plus récentes, à moins que cela ne coûte très cher.

Bien sûr, il existe une troisième option: réécrire le code existant afin qu’il utilise les meilleures méthodes et soit cohérent. Il y a des moments où cela est nécessaire, mais cela a un coût élevé.


7
Très bonne réponse équilibrée (+1). D'après mon expérience, une équipe peut être plus productive si tous s'accordent sur un ensemble relativement restreint d'idiomes bien compris plutôt que si chaque membre de l'équipe est libre d'utiliser des idiomes nouveaux et différents que d'autres membres de l'équipe pourraient avoir du mal à comprendre. Un petit point concernant la déclaration "réécrire le code existant de manière à ce qu'il utilise les pratiques les plus récentes et soit cohérente": "dernières" n'implique pas automatiquement "meilleur". Il faut toujours décider au cas par cas.
Giorgio

1
@Giorgio, merci pour les commentaires; J'ai peaufiné la langue du dernier point.

6
Bonne réponse et bon commentaire de Giorgio. Cela vaut peut-être la peine de considérer que dans cet exemple, en fonction de l'équipe / de la culture, il est possible d'avoir une adoption d'équipe coordonnée plutôt que de commencer seul. Cela réduit certains des risques liés à la maintenance (tout le monde est à bord). (c.-à-d., mettez davantage l'accent sur les compétences réelles de l'équipe pour le moment, plutôt que sur le code qu'elles ont écrit dans le passé.)
Matt

+1 D'accord, une réponse complète et équilibrée - prise en compte d'une variété de scénarios. Encore une fois, bon commentaire de Giorgio.
Robert Johnson

1
Concernant l’adoption de nouveaux idiomes et de technologies: j’envisagerais le début d’un nouveau projet comme un bon point pour introduire de nouvelles choses. Ensuite, pendant toute la durée du projet, le style du code doit être maintenu aussi cohérent que possible. J'ai récemment découvert un code vieux de 5 ans et j'étais très heureux de pouvoir toujours me débrouiller avec ce code car toute l'équipe adhérait à une architecture commune et à un ensemble d'idiots sur lesquels nous nous étions mis d'accord (pas sans lutte!). ) au début du projet.
Giorgio

26

Rester cohérent a peu de valeur à mes yeux; faire des améliorations en continu est un must.

La position de votre collègue entrave réellement l'innovation. L'argument de cohérence vous met dans une situation où vous pouvez utiliser, par exemple, LINQ uniquement si vous migrez tout le code pour utiliser LINQ. Et bien, nous n'avons pas le temps pour ça, n'est-ce pas?

Je préférerais qu'il y ait incohérence lorsque du code est encore foreachutilisé dans ArrayLists et que d'autres parties utilisent LINQ sur IEnumerable<T>plutôt que de s'en tenir à la manière la plus ancienne de faire les choses jusqu'à la fin des temps.

Il incombe à vos collègues de rester pertinents et d’apprendre de nouvelles façons de faire les choses.


3
"Il incombe à vos collègues de rester pertinents et d'apprendre de nouvelles façons de faire.": Une possibilité consiste à utiliser de nouveaux idiomes et bibliothèques dans un nouveau code (nouveaux modules) et à conserver un style cohérent dans le code hérité.
Giorgio

8

La cohérence des API est très importante, tant pour les API publiques que pour les API internes.

La cohérence du formatage du code est importante et devrait idéalement être renforcée par un outil de formatage automatique avec les mêmes règles de formatage pour tout le monde. Facilite la vie avec une base de code partagée contrôlée par la version.

Les conventions de dénomination doivent être cohérentes, y compris pour des variables telles que les variables locales, etc.

Les outils d’analyse statique doivent être utilisés pour appliquer certaines autres conventions et bonnes pratiques (mais ne suivez pas aveuglément les valeurs par défaut de ces outils, ces valeurs pouvant parfois frôler la folie), mais si quelque chose l’exige, n’hésitez pas à en désactiver certaines. vérifiez (généralement avec une directive dans un commentaire) temporairement, si vous pouvez le justifier.

Ce qui se passe à l' intérieur des fonctions / méthodes , mis à part ce qui est répertorié ci-dessus, n'a pas besoin d'être cohérent de quelque manière que ce soit, tant qu'il s'agit d'un bon code en soi . Un code correct, compréhensible et bien commenté est très important, mais après cela, si le compilateur et les outils d’analyse statique pensent que le code est cohérent, c’est suffisamment cohérent.


Concernant les nouvelles fonctionnalités langagières telles que LINQ (enfin, ce n’est pas tout à fait nouveau), la seule chose à prendre en considération est la suivante: une nouvelle version suffisante de langages / bibliothèques sera-t-elle utilisée partout où le code sera utilisé? En cas de doute, restez sur les fonctionnalités connues pour être compatibles. Bien entendu, cela ne vous empêche pas de mettre à niveau une version améliorée de tout le système, vous pouvez donc commencer à utiliser les nouvelles fonctionnalités.

Et tous les développeurs travaillant avec du code doivent rester à jour, de sorte que tout développeur .NET doit connaître LINQ. Sinon, il devrait être obligé d’apprendre, pour son propre bien (on ne sait jamais quand on cherchera un nouveau travail dans cette entreprise, pour une raison ou une autre).


6

La réponse à cette question est simple.

La cohérence est d'une importance primordiale.

mais il vient avec une mise en garde ...

Vous et votre collègue êtes probablement obsédés par le mauvais type de cohérence

Les implémentations sont jetables. Ils peuvent être complètement révisés avec plus ou moins de facilité en fonction de la qualité et de l’exhaustivité de la suite de tests. S'inquiétant de choses telles que "Devrait-il s'agir d'une propriété?", "Ce code ne devrait-il pas utiliser LINQ au lieu d'une construction de niveau inférieur?" est de valeur douteuse. Il est difficile de lier les mesures à la valeur de cohérence au niveau de la mise en œuvre. Une question bien meilleure à poser à ce niveau est "Ce code fonctionne-t-il comme annoncé?". TL: la cohérence de la mise en œuvre de la DR est le lieu où les "petits esprits" obtiennent leur hobgobelin.

Pourquoi la cohérence n'est-elle pas aussi importante ici? Les implémentations ont généralement un petit nombre de contributeurs. La plupart des méthodes sont écrites et ne sont plus jamais touchées. Parmi le code restant, le nombre de méthodes ayant deux contributeurs est presque certainement majoritaire. Ce modèle continue à l' infini . Dans ce contexte, la cohérence n’est tout simplement pas si importante. Si la durée de conservation du code est assez courte ( quelques années ), les gains d'une cohérence agressive ne sont probablement pas un facteur.

Cela ne veut pas dire que vous devriez devenir fou dans vos implémentations. C’est plutôt de dire qu’une conception simple, propre et simple aura des ordres de grandeur plus précieux pour votre futur mainteneur hypothétique que la méthode de consistance de plaque de chaudière ridicule par méthode. Cela nous amène au vrai point ...

Les API ne sont pas jetables.

Il s’agit de tous les API, au niveau du code, des services Web, des kits de développement (SDK), etc. Ceux-ci doivent obligatoirement être cohérents. Les gains de productivité de cette variété de cohérence sont énormes pour plusieurs raisons:

Tests d'intégration:

Si vous maintenez la cohérence de vos API, vous pouvez créer des suites de tests d'intégration. Ceux-ci permettent aux développeurs d'échanger librement les détails de la mise en œuvre et d'obtenir une validation immédiate. Tu veux échanger tes conneries avec LINQ? Les tests d'intégration sont-ils exécutés? Il fournit également une validation lors de la préparation de la production. Parce que les ordinateurs sont rapides, un seul ordinateur portable peut effectuer le travail de milliers de testeurs exécutant des tâches banales. Cela revient à augmenter considérablement les effectifs de votre organisation.

Productivité

Lorsque les API sont cohérentes, vous pouvez deviner comment utiliser une API en suivant ce que vous avez appris sur l’utilisation d’autres parties de l’API. En effet, l’API offre un "aspect et une convivialité" naturels et cohérents. Cela signifie que vos clients passent moins de temps à parcourir la documentation. L'intégration est plus facile et moins chère. Moins de questions sont posées aux personnes qui ont développé l'API. La cohérence fait de chacun un gagnant

Pourquoi la cohérence est-elle importante dans ce scénario? Parce que les API ont le problème exactement opposé des implémentations. Le nombre de personnes qui les utilisent est généralement beaucoup plus important que le nombre de personnes contribuant à leurs implémentations. Des gains peu élevés résultant d’une uniformité faible sont multipliés et les coûts de maintien de cette cohérence sont amortis.

Conclusion

La cohérence est chère. À première vue, il réduit la productivité. Cela contraint les développeurs et rend leur vie plus difficile. Cela impose des limites à la manière dont ils peuvent résoudre un problème, ce qui les force parfois à le résoudre de manière non optimale. C’est souvent pour des raisons qu’ils ne comprennent pas, qui sont mal conçus ou qui ne leur sont pas familiers (contrats, politiques plus larges d’organisation ou entre organisations).

Dans son exposé sur Pycon 2015, Raymond Hettinger a formulé d'excellents arguments concernant l'utilisation du guide de rédaction PEP8 pour les équipes de programmeurs python. Il a montré que l'obsession pour la cohérence stylistique d'un élément de code faisait que les réviseurs manquaient de graves problèmes de logique et de conception. Son hypothèse peut être résumée comme il est facile de trouver des incohérences stylistiques; déterminer la qualité réelle d'un morceau de code est difficile

Le point ici est d'être critique. Identifiez où la cohérence est importante et protégez-la de manière agressive. Où ce n'est pas important, ne perdez pas votre temps. Si vous ne pouvez pas fournir un moyen objectif de mesurer la valeur de la cohérence (dans les cas susmentionnés, "effectif effectif", coût en fonction de la productivité) et que vous ne pouvez pas démontrer que les rendements sont substantiels, alors vous ne faites probablement pas du bien à ton organisation.


4

Vous ne connaissez pas LINQ? Si tel est le cas, mon code ne serait-il pas plus facile à gérer pour mes collègues développeurs si je ne l'utilisais pas?

Le langage C # évolue toujours. Si les gens n’apprenaient pas les changements du C 1, ils manqueraient:

  • Génériques
  • Partials
  • Méthodes anonymes
  • Itérateurs
  • Types nullables
  • Auto-propriétés
  • Types anonymes
  • Méthodes d'extension
  • Lingue
  • Lambdas
  • Méthodes asynchrones

Ceci est juste une petite sélection de fonctionnalités communes trouvées dans l'article de Wikipedia. Ce que je veux dire, c'est que si les développeurs n'apprennent pas, la base de code restera dans le vide. On peut espérer que vos développeurs s'améliorent continuellement et que la base de code évolue, supportée par une suite de tests complète. Vous souvenez-vous de la difficulté avec .NET 1 à implémenter manuellement les propriétés.

Linq rend la vie plus facile. Utilisez-le là où vous le pouvez. Vous pourriez motiver les membres de votre équipe.

Dans quelle mesure les motifs font-ils partie du style de code et où devrions-nous établir une distinction entre rester cohérent et apporter des améliorations?

Les améliorations sont progressives. Pour moi, il n’a aucun sens de conserver l’ancien code de style moins lisible et potentiellement moins gérable. Les membres de votre équipe doivent au moins être capables de comprendre ce qui se passe, même s'ils ne peuvent pas l'écrire.


2
Je suis tout à fait d’accord avec ce que vous dites, mais ma question porte moins sur les nouvelles fonctionnalités linguistiques et sur la responsabilité des développeurs de les apprendre, mais plutôt sur la question plus générale de la résolution de problèmes similaires de différentes manières dans un domaine relativement restreint d’une base de code. J'ai mentionné LINQ parce que c'est un bon exemple d'utilisation d'une manière différente de résoudre un problème. Mon collègue est heureux d'utiliser de nouvelles fonctionnalités linguistiques, mais uniquement si elles ne vont pas à l'encontre du code sur lequel il travaille.
Robert Johnson

@ RobertJohnson Je ferais remarquer à votre collègue que la maintenabilité prime sur la cohérence, donc même si quelque chose "va à contre-sens" du code existant, si c'est plus maintenable, vous devriez le faire. Je doute que l’utilisation de l’ancien séjour DAO soit plus facile à maintenir que Linq.
Andy

3

Vous devez être cohérent, mais pas nécessairement avec l'ancien code. En d’autres termes, votre équipe doit convenir de la bonne façon de faire quelque chose et l’utiliser chaque fois que du nouveau code est écrit ou que des modifications importantes sont apportées.

De cette façon, vous tirez le meilleur parti des avantages de la cohérence (en particulier, peu importe qui écrit le code), mais vous pouvez toujours vous améliorer si l'équipe voit un avantage clair en procédant différemment.

Dans un monde idéal, nous réécririons tout l'ancien code pour le rendre conforme à la nouvelle méthode. Bien que cela ne soit pas économiquement viable, cela devrait avoir un sens technique (sinon, la nouvelle méthode n’est pas une meilleure solution) et votre plan à long terme devrait consister à l’améliorer. Si cela ne vaut pas la peine, ne vous embêtez pas avec la nouvelle méthode. Autrement dit, la nouvelle façon de considérer la déclaration comme la bonne doit présenter un avantage évident.


1

Je pense qu'il est important de suivre un style de code dans un projet, par exemple. conventions de dénomination, indentations, etc.

Je ne suis pas d'accord pour dire que vous devriez être limité par l'utilisation de nouvelles constructions de langage ou de nouveaux modèles de conception simplement parce que vos collègues ne les comprennent pas, ou bien ils n'ont pas déjà été utilisés dans le projet.

Bien sûr, ces choses devraient avoir de bonnes raisons de les utiliser, par exemple. performance ou brièveté, le cas échéant.


Quel était le moins pour?
Ozz

0

Je ferais extrêmement attention en suivant aveuglément les modèles de conception actuels. Bien sûr, quand il n'y a pas d'inconvénient notable, il faut toujours essayer de suivre des modèles similaires dans la base de code.

Cependant, il est beaucoup trop facile de se retrouver dans des situations où la majorité des développeurs ont le sentiment que la "meilleure pratique" consiste à suivre les mauvais schémas existants, ce qui conduit à de bonnes situations pour lesquelles de bons développeurs écrivent du code incorrect et non maintenable.

D'autre part, la cohérence est importante. Lorsque vous travaillez avec des bases de code énormes, il est extrêmement utile d'essayer de suivre des schémas similaires afin que, même si les développeurs ne lisent pas chaque centimètre de la base de code, ils savent à quoi s'attendre.

Par conséquent, j'estime qu'il est préférable d'établir et de mettre à jour des directives sur les modèles que les développeurs devraient suivre s'ils le peuvent. De cette façon, tout nouveau code est cohérent avec un autre nouveau code.


-1

Nous organisons régulièrement des réunions techniques assez informelles que chacun de nous peut organiser. Si nous trouvons une nouvelle technique, nous la présentons à la réunion. Vous avez généralement une bonne idée de la mesure dans laquelle l’idée est acceptée et comprise par vos collègues. Cela vous aide à décider s'il est sage de l'inclure dans votre code, aide les autres à le déchiffrer si vous le faites et établit également la personne à qui s'adresser si d'autres ont besoin d'aide avec ce style. Si personne ne réinventait la roue, nous traînerions toujours des objets sur des rondins.


A quoi servait le vote négatif?
Ant

Je n'étais pas le votant inférieur, mais cela ne semble pas vraiment cibler la question. C'est un processus d'équipe qui pourrait être appliqué à n'importe quoi plutôt que de discuter de problèmes de style de codage. Aussi, ne voulez-vous pas dire "inventé la roue" plutôt que "réinventé la roue"?

Je suppose qu’il est sémantique de savoir si une grume est un type de roue mais elle tourne, réduit le frottement, a une surface qui est en contact successif avec le sol et est ronde. Je suis sûr qu'il existe de meilleurs exemples de ce que je veux dire - je laisserai cela comme un exercice pour le lecteur.
Ant
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.