Existe-t-il des cas exceptionnels où nous pouvons accepter un code en double?

57

Je travaille sur un projet logiciel dans lequel nous devons construire trois API. Un pour le canal de banque à domicile , un pour le canal d' agence et un troisième pour le canal de téléphonie mobile .

L'API de l'agence est la plus complète, car elle possède toutes les fonctionnalités. Ensuite, une API Home un peu plus petite, puis une API mobile.

Les architectes ont créé ici une couche commune (services EJB multicanaux partagés par toutes les API). Mais alors les API sont différentes.

Il n'y a pas de grande différence pour le moment entre les API. La grande équipe a commencé avec le canal de l'agence, et nous l'adaptons maintenant pour le canal domestique. Nous enrichissons simplement les objets de notre application personnelle. Sinon, le code est similaire à 95% entre les API. Les API sont construites sur Spring MVC , et elles ont (contrôleurs, modèles et certains utilitaires).

Fondamentalement, les contrôleurs font le mappage de BO vers ChannelObject (il me semble que ce n'est pas le bon endroit pour le faire), ainsi que certains utilitaires et sérialiseurs supplémentaires. Tout est en double pour l'instant. Ils disent que la raison de la duplication est qu'ils veulent que les API soient indépendantes. "Si demain nous voulons un comportement différent pour le domicile que pour l'agence ou le mobile, nous ne lutterons pas!"

Y at-il un cas où nous devrions accepter le code en double?

Mohamed Amine Mrad
la source
22
Et si, dans trois ans, ils décident de vouloir un accès et une représentation cohérents des données entre toutes les API ... eh bien ... "Lutte!"
Becuzz
26
Du code en double n'est pas nécessairement une mauvaise chose. On ne saurait trop insister sur le dicton "DRY est l'ennemi du découplage". Il a déclaré que concevoir pour l'avenir plutôt que pour le moment est vraiment une très mauvaise chose. Cet avenir ne se réalise presque jamais. Au lieu de cela, concevez une solution hautement découplée, couverte par de bons tests automatisés pour déterminer ce dont vous avez besoin maintenant. Ensuite, à l'avenir, si quelque chose de différent est nécessaire, il sera plus facile de changer.
David Arno
2
Je pense que les deux cas où je n'ai jamais regretté la duplication de code sont les suivants: (a) le code dupliqué est une partie très petite et peu importante du total et (b) je copie le code d'un système déjà en train de mourir dans un nouveau système conçu pour la longévité. Il y a beaucoup d'autres cas où j'ai pleuré des larmes amères après avoir falsifié du code.
Michael Kay
14
Là où j'ai travaillé, il a souvent été noté qu'il faut (souvent) dupliquer une fois et faire abstraction des points communs la troisième fois. Cela supprime le Zeitgeist pour une abstraction précoce, peut-être inappropriée, qui augmente le couplage au lieu de la cohésion. Lorsque les besoins futurs sont bien compris, des exceptions peuvent bien entendu être faites.
Pieter Geerkens
3
Un cas
simple

Réponses:

70

La duplication peut être la bonne chose à faire, mais pas pour cette raison.

Dire "nous pourrions vouloir que ces trois emplacements dans la base de code se comportent de manière différente même si, à l'heure actuelle, ils sont identiques" n'est pas une bonne raison pour une duplication à grande échelle. Cette notion pourrait s’appliquer à tous les systèmes et servir à justifier toute duplication, ce qui n’est évidemment pas raisonnable.

Les doubles emplois ne devraient être tolérés que lorsque les supprimer serait globalement plus coûteux maintenant pour une autre raison loi).

Pour ce que vous faites, la bonne solution pourrait être, par exemple, d’extraire le comportement dupliqué à l’heure actuelle dans une stratégie ou un autre modèle modélisant le comportement sous forme de classes, puis d’utiliser trois instances de la même classe. De cette façon, lorsque vous ne voulez changer le comportement dans l' un des trois endroits, il suffit de créer une nouvelle stratégie et instancier que dans un seul endroit. De cette façon, il vous suffit d'ajouter quelques classes et de laisser le reste de la base de code presque complètement vierge.

Kilian Foth
la source
1
Si deux choses se comportent de la même manière, il s’agit d’un double emploi. Bien qu'ils ne se comportent pas de la même manière pour une raison quelconque, ils ne devraient pas être fusionnés. Peut-on extraire une partie commune des implémentations? Parfois, il y a des blocs de construction non encore abstraits, qui sait.
Déduplicateur
32
Par exemple, trois parties de notre application ont été utilisées dans une partie du code, qui était assez terriblement écrit avec beaucoup de petites branches conditionnelles partout pour couvrir les exceptions de chacune de ces trois. Mais , et c’était là le facteur le plus important, il avait été très utilisé pendant deux ans sans aucun rapport de bogue significatif. Ainsi, lorsqu'une quatrième partie de l'application devait faire quelque chose avec cela, mais là encore, elle était légèrement différente, il a été décidé de ne pas toucher au code imparfait qui fonctionnait parfaitement, et de simplement le copier et créer une base mieux écrite et flexible pour l'avenir.
KRyan
2
La duplication est la bonne chose à faire lorsque les coûts de lisibilité augmentent trop par rapport aux coûts de maintenance qui sont finalement liés. Je ne pense pas que cela s'applique du tout dans ce scénario et est souvent vu à plus petite échelle dans un projet, pas quelque chose comme ça. Même dans ce cas, il est très rare que vous vous retrouviez dans une situation où c'est le cas, cela se produira si vous avez une duplication de niche imbriquée qui vous obligerait à utiliser un modèle de méthode de modèle ou similaire, mais dans des endroits restreints. Cela finira généralement par rendre le code obscurcissant.
opa
Un exemple où la duplication est utile (et "le supprimer vous coûtera globalement plus cher maintenant ") est la validation d'entrée dans les applications Web: nous utilisons une première validation (éventuellement simplifiée) chez le client afin que l'utilisateur reçoive un retour immédiat des problèmes; et ensuite, nous effectuons la même validation (ou une validation plus approfondie) sur le serveur car les clients ne peuvent pas faire confiance.
Hagen von Eitzen
3
@HagenvonEitzen Mais cela n’a pas besoin de duplication, cela dépend de la pile technologique. Par exemple, vous pouvez avoir l'entrée de vérification JavaScript dans le navigateur, puis la vérification Java sur le serveur, de sorte que vous avez une fonctionnalité dupliquée. Mais si vous deviez exécuter Node.js sur le serveur, vous pourriez utiliser la même validation JavaScript dans le navigateur et sur le serveur, en éliminant la duplication. Vous souhaitez toujours que le code s'exécute à plusieurs endroits (un environnement de confiance et un environnement non sécurisé), mais le code ne doit pas nécessairement être dupliqué.
Joshua Taylor
87

Sandi Metz, un ingénieur logiciel de renom et auteur dans l'écosystème Ruby, a un grand billet de blog et un discours où elle parle aussi de la relation entre la duplication et l' abstraction. Elle arrive à la conclusion suivante

la duplication est bien moins chère que la mauvaise abstraction

Et je suis complètement d'accord avec elle. Permettez-moi de vous donner plus de contexte à cette citation. Il est parfois très difficile de trouver la bonne abstraction. Dans de tels cas, il est tentant de choisir n'importe quelle abstraction pour réduire les doubles emplois. Mais plus tard, vous découvrirez peut-être que votre abstraction ne tient pas dans tous les cas. Cependant, il est coûteux de tout changer à nouveau et d’emprunter un autre chemin (pour une explication bien meilleure, regardez-la parler!).

Alors oui, pour moi, il y a des cas exceptionnels, où accepter le double emploi est la bonne décision, en particulier lorsque vous n'êtes pas sûr de ce qui va arriver et que les exigences vont probablement changer. D'après votre message, je déduis qu'il y a beaucoup de doublons à présent, mais vos collègues suggèrent que cela pourrait changer et que les deux applications ne soient pas couplées l'une à l'autre. À mon avis, cet argument est valable et ne peut être négligé en général.

Larsbe
la source
23
Ah oui, si vous ne pouvez pas déduire les règles généralisées, essayer de les abstraire ne peut qu'échouer. Et si la correspondance est une coïncidence, elle pourrait être de courte durée.
Déduplicateur
5
Il peut être coûteux de changer une abstraction une fois qu'elle est en place, mais éliminer le double emploi une fois qu'elle est en place peut poser encore plus de problèmes. Bien sûr, cela dépend beaucoup de la langue, etc. - les systèmes de type statiques forts modernes peuvent vous aider à obtenir des modifications, même à grande échelle, de certains droits d'abstraction. Garder les fonctionnalités dupliquées synchronisées n'est cependant pas quelque chose qu'un système de types peut vous aider beaucoup (car les doublons sont, pour le système de types , simplement différents). Mais je suppose que dans les langages dynamiques, typés «canard», c'est plutôt l'inverse; donc cela pourrait avoir un sens pour Ruby.
leftaroundabout
34

Si les gens commencent à raisonner sur le design avec les mots "si demain" , c'est souvent un grand signe d'avertissement pour moi, en particulier lorsque cet argument est utilisé pour justifier une décision qui implique du travail et des efforts supplémentaires, pour lesquels personne ne sait vraiment si rentable et qu’il est plus difficile de changer ou de revenir que la décision opposée.

La duplication de code ne réduit l'effort que pour un court terme, mais accroît les efforts de maintenance presque immédiatement, proportionnellement au nombre de lignes de code dupliquées. Notez également qu’une fois le code dupliqué, il sera difficile de supprimer cette duplication s’il s’avère que la décision est mauvaise. Tandis que si vous ne dupliquez pas le code maintenant, il est toujours facile d’introduire la duplication plus tard si cela reste conforme à DRY. était la mauvaise décision.

A déclaré que, dans les grandes organisations, il est parfois avantageux de privilégier l'indépendance de différentes équipes par rapport au principe DRY. Si la suppression de la duplication en extrayant les 95% de parties communes des API deux, un nouveau composant conduit à un couplage de deux équipes par ailleurs indépendantes, cela pourrait ne pas être la décision la plus sage. Par contre, si vos ressources sont limitées et qu’une seule équipe gère les deux API, je suis sûr que leur propre intérêt est de ne pas créer un double effort et d’éviter toute duplication inutile de code.

Notez en outre que cela fait une différence si les API "Home" et "Agency" sont utilisées exclusivement par des applications totalement différentes, ou si on peut essayer d'écrire un composant construit au-dessus de ces API pouvant également être utilisé dans un contexte "Home" comme dans un contexte "d'agence". Dans cette situation, avoir les parties communes des API parfaitement identiques (ce que vous ne pouvez garantir que si les parties communes ne sont pas dupliquées) facilitera probablement le développement d'un tel composant.

Donc, s'il s'avère qu'il y aura vraiment des sous-équipes différentes, chacune responsable de chacune des API, chacune avec un calendrier et des ressources différentes, alors il est temps de dupliquer le code, mais pas "au cas où".

Doc Brown
la source
3
Même plus grand signe d'avertissement que "si demain" pour moi est "Cela ne changera jamais".
Abuzittin gillifirca
@abuzittingillifirca: et qu'est-ce que cela a à voir avec la question ou ma réponse?
Doc Brown
1
Je conteste votre premier paragraphe.
abuzittin gillifirca
2
@abuzittingillifirca: Eh bien, relisez la question: il s'agit de raisonner avec un argument du type "si demain" pour justifier une décision de duplication difficile à inverser , rendant ainsi le logiciel plus difficile à modifier dans certains cas. Cela peut sembler un peu paradoxal, mais le meilleur moyen de garder les logiciels changeables pour l’avenir n’est pas de faire des hypothèses (probablement fausses) sur l’avenir, mais de garder les logiciels aussi petits et aussi solides que possible.
Doc Brown
13

Duplication pour éviter le couplage . Disons que vous avez deux gros systèmes et que vous les forcez à utiliser la même bibliothèque. Vous pouvez coupler le cycle de libération des deux systèmes. Ce n'est peut-être pas si grave, mais disons qu'un système doit introduire un changement. L'autre doit analyser le changement et peut être affecté. Parfois, cela peut casser des choses. Même si les deux parties sont capables de coordonner les changements, cela pourrait prendre beaucoup de réunions, passer par les gestionnaires, les tests, les dépendances et la fin de la petite équipe autonome.

Donc, vous payez le prix du code dupliqué pour gagner en autonomie et en indépendance.

Borjab
la source
Il s'agit donc d'une duplication inter-composants pour éviter le couplage. Mais vous voudriez toujours éviter la duplication intra-composant, non?
TemplateRex
Eh bien, oui, vous souhaitez minimiser le code en double car cela rendra votre code plus facile à comprendre et à modifier. Mais rappelez-vous qu'il existe de bonnes réponses avec des exceptions viables. Il peut être difficile de trouver la bonne abstraction pour éviter les doubles emplois.
Borjab