Une défense pour passe-partout?

14

Pour moi, le code passe-partout est évidemment mauvais. Cependant, j'ai rencontré un développeur qui affiche une résistance dans toute tentative de réduction du passe-partout. J'ai réalisé que je n'avais pas d'argument facilement formé et bien pensé après l'horreur que j'ai développée pour lui au fil du temps.

Pour que je puisse former un argument convaincant en faveur de moins de passe-partout, quels sont les contre-arguments? En d'autres termes, quels sont les arguments (le cas échéant) en faveur du passe-partout?

(Je veux dire ce que je pense être généralement entendu par passe-partout, mais un bon exemple est celui des getters et setters en Java.)

distrait
la source
7
Arguments contre le code en double (en supposant que le passe-partout est copié / collé): stackoverflow.com/a/2490897/1583
Odé
1
@Oded: C'est vrai. Mais vous avez mal lu la question. :) Il essaie de voir s'il y a quelque chose à dire pour le code passe-partout. Je suppose qu'il est très bien informé des inconvénients.
Steven Jeuris
3
@StevenJeuris - J'ai parfaitement lu la question. C'est pourquoi je n'ai pas posté de réponse. J'ajoute seulement à l'autre côté de l'argument. Juste pour que le PO ait "un argument facilement formé et bien pensé après l'horreur que j'ai développé pour lui au fil du temps" pour la prochaine fois;)
Odé
2
La chaudière peut être esthétiquement agréable: en.wikipedia.org/wiki/This_Is_the_House_That_Jack_Built
SK-logic
Plusieurs bonnes réponses et commentaires qui se complètent ... difficile de choisir lequel accepter.
résumé

Réponses:

15

Une chose importante à retenir est que le code est généralement réduit en supprimant le contexte inutile. Si le compilateur peut comprendre quelque chose, l'argument va, il n'est pas nécessaire de l'écrire explicitement.

Et ce serait formidable si seul le compilateur était destiné à le lire. Mais rappelez-vous que "les programmes doivent être écrits pour que les gens puissent les lire, et accessoirement pour que les machines s'exécutent". (Ironiquement, cette citation provient d'un manuel consacré à l'une des langues les plus difficiles à lire pour les êtres humains ordinaires, en grande partie à cause de sa lourdeur excessive.)

Ce qui peut vous sembler ennuyeux et répétitif pendant que vous écrivez peut être un contexte précieux pour quelqu'un d'autre qui vient un an (ou cinq) plus tard et doit maintenir votre code.

WRT l'exemple Java en particulier, je conviens que c'est un bon exemple de mauvais passe-partout, car il peut être remplacé par quelque chose qui est à la fois plus court et plus facile à lire, et aussi plus flexible: Propriétés. Mais cela ne signifie pas que tous les éléments syntaxiques passe-partout de tous les langages sont aussi inutiles que les getters et setters de Java et C ++.

Mason Wheeler
la source
7
Bien sûr, cet argument fonctionne dans les deux sens. Une quantité considérable de code passe-partout est juste là pour apaiser le compilateur et n'aide pas les humains à comprendre - pour rester avec les getters / setters, ces dizaines de lignes doivent être lues entièrement pour être sûrs que "ce ne sont que des getters et setters à ne rien faire" , plutôt que de lire une seule ligne courte par propriété qui indique simplement qu'il s'agit d'une propriété et de son type.
6
Je pense que le passe-partout est également dangereux pour le lecteur humain. En étant forcé d'écrire du texte répétitif et sans signification, nous masquons les parties pertinentes du code à d'autres personnes. Si quelque chose est utile, par définition, ce n'est pas un passe-partout.
Andres F.
1
@Giorgio: Au contraire, c'est bien plus que mon opinion; c'est l'opinion de la grande majorité des gens qui ont déjà essayé de l'étudier. Et lorsque "difficile à lire" est intrinsèquement une question d'opinion en premier lieu, le fait que cette opinion soit si largement partagée en fait un fait.
Mason Wheeler
1
@Mason Wheeler: La façon dont les gens perçoivent les langages de programmation est souvent influencée par leur expérience passée. Les personnes qui ont appris à programmer dans Scheme trouvent C ou Pascal maladroit et difficile à lire. D'un autre côté, la grande majorité des gens ont appris à programmer dans une langue traditionnelle.
Giorgio
2
Je suis d'avis que lorsque plus de contexte est caché au programmeur en supprimant le passe-partout, cela signifie seulement que l'humain doit garder une plus grande carte mentale de tout ce qui se passe invisible dans les coulisses et c'est un plus grand détriment en ce qui concerne débogage que d'économiser un peu d'espace visuel lors de la création.
Patrick Hughes
7

Un argument en faveur du code passe-partout est que si vous le changez en un seul endroit, cela n'affecte qu'un seul flux du code. Cela doit être mis en balance avec le fait que le plus souvent, vous voulez en fait qu'un changement affecte chaque morceau de code qui l'utilise. Mais j'ai vu de rares exemples qui soutiennent l'argument.

Disons que vous avez un morceau de code qui dit

public ForTheBar(Foo foo)
{
    Bar bar = foo.bar();
    return bar.BeFooed();
}

Ceci est utilisé à environ 2 endroits dans votre code.

Un jour, quelqu'un arrive et dit "ok, dans ce chemin seulement, nous voulons que vous grommitiez le bar avant de le faire."

Et vous pensez "bien c'est simple".

public ForTheBar(Foo foo, bool shouldIGrommit)
{
    Bar bar = foo.bar();

    if (shouldIGrommit)
    {
        bar.BeGrommitted();
    }

    return bar.BeFooed();
}

Ensuite, votre utilisateur ajoute de nouvelles fonctionnalités et vous estimez qu'il s'intègre bien avec FooTheBar. Et vous leur demandez consciencieusement si vous devez Grommit ce bar avant de vous Foo et ils disent "non, pas cette fois".

Il vous suffit donc d'appeler la méthode ci-dessus.

Mais alors votre utilisateur dit "ok, attendez, dans le troisième cas, nous voulons que vous griffonniez la barre avant d'appeler BeFooed."

Pas de problème, vous pensez, je peux le faire.

public ForTheBar(Foo foo, bool shouldIGrommit, bool shouldIDoodle)
{
    Bar bar = foo.bar();

    if (shouldIGrommit)
    {
        bar.BeGrommitted();
    }

    if (shouldIDoodle)
    {
        bar.BeDoodled();
    }

    return bar.BeFooed();
}

Soudain, votre code devient de moins en moins standard. Vous auriez peut-être dû accepter les deux lignes de code répétées. À présent, vous auriez trois morceaux de code, chacun de 2 à 3 lignes de long et ne semblant plus très répétés.

Tout cela étant dit, je contrerais cela avec "ce n'est pas un cas courant, et quand cela se produit, vous pouvez refactoriser".

Un autre argument que j'ai récemment entendu est que le code standard peut parfois vous aider à naviguer dans le code. L'exemple dont nous parlions était où nous avions supprimé des tonnes de code de mappage passe-partout et l'avons remplacé par AutoMapper. Maintenant, a-t-on soutenu, parce que tout est basé sur des conventions, vous ne pouvez pas dire "Où est cette propriété définie" à l'IDE et vous attendre à ce qu'il sache.

J'ai vu des gens discuter de choses similaires à propos des conteneurs IoC.

Je ne dis pas que je suis d'accord avec eux, mais c'est quand même un argument valable.

pdr
la source
2
J'ai préféré la deuxième partie de votre réponse. ; p +1
Steven Jeuris
réalisez juste que mon exemple est assez similaire au vôtre ... devinez même si ce n'est pas du bon sens, cela semble se produire un peu :)
kritzikratzi
6

L'évolution de l'efficacité

Vous commencez par ceci:

<p>
    <label for="field">My field</label>
    <input type="text" id="field">
</p>

alors vous vous débarrassez de tout ce passe-partout ennuyeux et le mettez dans une fonction:

  1. createFieldHtml( id, label )

    c'est bien, je me sauve tellement de lignes!

  2. createFieldHtml( id, label, defaultValue )

    oui, j'ai aussi besoin d'une valeur par défaut, facile à ajouter.

  3. createFieldHtml( id, label, defaultValue, type )

    cool, je peux aussi l'utiliser pour les cases à cocher

  4. createFieldHtml( id, label, defaultValue, type, labelFirst )

    Le concepteur UX a déclaré que l'étiquette doit être après la case à cocher.

  5. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate )

    il rend maintenant un sélecteur de date en cas de besoin. Hm .. les params deviennent un peu incontrôlables

  6. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate, containerCssClasses )

    il y avait ce seul cas où je dois ajouter des classes CSS

  7. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate, containerCssClasses, fieldCssClasses, disabled, clearAfter, helpText, uploadPath )

    aaaaaaaaaaaaaaaaaaaaa

En défense du passe-partout

J'ai du mal à mettre cela en mots parce que c'est vraiment quelque chose que j'ai remarqué récemment, alors je vais faire une liste:

  1. Il me semble qu'il y a une certaine peur d'avoir des lignes en double qui s'étirent un peu. S'il ne s'agit que de quelques lignes, cela pourrait ne poser aucun problème. certaines choses sont intrinsèquement "presque répétitives" (comme l'exemple ci-dessus). Je vois peu de chance de l'optimiser à long terme.
  2. Les gens aiment encapsuler les fonctionnalités quelque part; si vous regardez objectivement et il semble que c'est juste "cacher le gâchis" - soyez méfiant! il serait peut-être temps pour un bon vieux passe-partout
  3. Lorsque vous avez une fonction qui devient de plus en plus puissante; cela prend de nombreux chemins d'exécution différents en fonction de l'entrée et en fin de compte très peu - cela peut être du temps passe-partout!
  4. Lorsque vous ajoutez une couche d'abstraction au-dessus d'une autre couche d'abstraction, mais juste pour raccourcir votre code (la couche sous-jacente n'est pas destinée à être modifiée) - temps passe-partout!
  5. Lorsque vous avez une fonction qui prend tellement de paramètres que vous avez vraiment besoin d'avoir des paramètres nommés - c'est peut-être le temps passe-partout.

Récemment, je me suis toujours demandé ceci:
puis-je copier et coller dans un autre projet sans rien changer? si oui, c'est bien d'encapsuler ou de mettre dans une bibliothèque, si non: c'est l'heure du passe-partout.

Ceci est très opposé à la perception générale selon laquelle le passe-partout est du code copier-coller. Pour moi, le passe-partout concerne le copier-coller, mais il faut toujours le modifier un tout petit peu.


Mise à jour : je viens de tomber sur un article donnant à mon exemple ci-dessus un vrai nom: "anti-pattern trop SEC".

La fonction obtient plus de paramètres et possède une logique interne de plus en plus complexe pour contrôler son comportement dans différents cas. Les fonctions trop SÈCHES sont faciles à repérer. Ils ont beaucoup de logique si-alors complexe qui essaie de répondre à une grande diversité d'utilisation. [...] De plus, répéter du code n'est pas toujours une mauvaise chose si le code est petit et remplit une fonction discrète.

C'est une lecture courte et intéressante, vous pouvez trouver l'article ici: Anti-Pattern Too Dry

kritzikratzi
la source
1
"Lorsque vous ajoutez une couche d'abstraction au-dessus d'une autre couche d'abstraction, mais juste pour raccourcir votre code" Vrai, vous ne devez ajouter des couches d'abstraction qu'en cas de possibilité de réutilisation.
Steven Jeuris
4
+1. Ne vous répétez pas, mais n'allez pas trop loin pour éviter de vous répéter presque .
Julia Hayward
4

Je méprise le code passe-partout, mais pouvoir supprimer le code passe-partout ne signifie pas toujours que c'est la meilleure façon de procéder.

Le cadre WPF a des propriétés de dépendance , ce qui implique une quantité insensée de code passe-partout. Pendant mon temps libre, j'ai étudié une solution qui réduit considérablement la quantité de code à écrire. Plus d'un an plus tard, je continue d'améliorer cette solution et j'ai encore besoin d'étendre ses fonctionnalités ou de corriger des bugs.

Quel est le problème? C'est formidable pour apprendre de nouvelles choses et explorer des solutions alternatives, mais ce n'est probablement pas la meilleure décision commerciale .

Le cadre WPF est bien documenté. Il documente correctement comment écrire votre code passe-partout. Tenter de supprimer ce code passe-partout est un bon exercice, et quelque chose qui vaut vraiment la peine d'être exploré, mais atteindre le même niveau de `` polissage '' que celui proposé par msdn prend beaucoup de temps, ce que nous n'avons pas toujours.

Steven Jeuris
la source
Cependant, je suis toujours très satisfait du résultat que j'ai en ce moment et je l'utilise volontiers dans mes projets de temps libre. :)
Steven Jeuris
3
chaque fois que je touche WPF et ces propriétés de dépendance, je souhaite toujours que C # ait quelque chose d'aussi simple que les macros de C ++. Bien sûr, les macros sont mal utilisées entre de mauvaises mains, mais elles pourraient éliminer tellement de répétitions ici. Je devrai jeter un œil à votre framework AOP la prochaine fois que je commencerai à souhaiter ces macros :)
DXM
@DXM Si vous le faites, et que cela se bloque lamentablement, n'oubliez pas de me blâmer et de publier les erreurs. ; p
Steven Jeuris
L'extrait de code a très bien fonctionné pour moi pour les propriétés de dépendance.
Codisme
@Codism: Eh bien, ils sont une solution, mais je méprise ceux aussi . :)
Steven Jeuris
1

Le problème avec le passe-partout est qu'il viole SEC. En substance, lorsque vous écrivez un passe-partout, vous répétez le même code (ou un code très similaire) dans un certain nombre de classes. Lorsque ce code doit être modifié, il n'est pas du tout certain que le développeur se souvienne de tous les endroits où le code a été répété. Cela conduit à des bogues où d'anciennes API ou d'anciennes méthodes sont utilisées.

Si vous refactorisez le passe-partout dans une bibliothèque commune ou une classe parente, il vous suffit de modifier le code au même endroit lorsque votre API change. Plus important encore, lorsque des changements inattendus se produisent, le code se casse en un seul endroit et vous permet de savoir exactement ce que vous devez corriger pour que tout fonctionne à nouveau. C'est de loin préférable à un scénario où un changement entraîne des échecs dans des dizaines, voire des centaines de classes.

quantique
la source
2
Comment est-ce un argument en faveur du passe-partout ?
Chris Wesseling du
0

Je vais prendre un tact différent. La cohérence dans le développement est l'une des caractéristiques les plus importantes de la conception de logiciels, c'est un outil essentiel pour rendre les applications extensibles et maintenables, mais peut être difficile à réaliser lors de la gestion d'une équipe sur plusieurs sites, langues et fuseaux horaires.

Si elle est atteinte, la cohérence rend le code beaucoup plus accessible "une fois que vous en avez vu un, vous les avez tous vus", beaucoup moins cher à maintenir et à refactoriser, mais surtout, beaucoup plus facile à étendre. Lorsque vous écrivez une bibliothèque qui nécessite un passe-partout, ainsi que la puissance de votre bibliothèque, vous avez également donné au développeur:

  • Un point de départ comprend le préambule (passe-partout) dans votre fonctionnalité, la plupart des classes clés et des points d'accès figureront généralement dans le passe-partout. Cela donne aux développeurs un point de départ dans la documentation
  • Les attentes que vous placez sur les développeurs deviendront apparentes, par exemple si vous configurez un objet de traçage dans le cadre du préambule, les développeurs sauront où consigner les exceptions et les informations
  • Compréhension implicite lorsque vous forcez le développeur à passer par votre processus d'instanciation de classes, ils peuvent déduire les techniques dont ils auront besoin pour accéder au reste de votre bibliothèque et avoir la possibilité de les présenter aux conventions que vous avez utilisées dans votre bibliothèque
  • Validation facile lorsque votre code passe-partout est nécessaire, il peut généralement très facilement se valider lui-même avec des exceptions et des clauses de garde, empêchant les consommateurs de rester bien plus loin sur la ligne lorsque vous êtes déjà engagé dans un processus défectueux
  • La configuration d'une bibliothèque qui nécessite du code passe-partout est facile car il existe déjà un point d'implémentation évident pour personnaliser la fonctionnalité pour un seul chemin d'exécution. Ceci est particulièrement utile si le code de votre passe-partout requis est amélioré avec le modèle Factory ou Command

Lorsque les consommateurs de votre bibliothèque maîtrisent l'instanciation, ils peuvent facilement créer des méthodes privées / d'extension, des classes parentes ou même des modèles pour implémenter le code passe-partout.

Dead.Rabit
la source
-3

Le seul vrai problème avec le code passe-partout est que lorsque vous y trouvez un bogue, vous devez le réparer partout où vous l'utilisez plutôt qu'au seul endroit que vous avez réutilisé .

Edward Strange
la source