Qu'est-ce que Rich Hickey voulait dire quand il a dit: "Toute cette spécificité [des interfaces / classes / types] tue votre réutilisation!"

41

Dans 29 minutes, dans son discours « La valeur des valeurs » de Rich Hickey, qui suscite la réflexion, il parle de la surcharge d’un langage tel que Java et fait une déclaration du type «Toutes ces interfaces tuent la réutilisation». Que veut-il dire? Est-ce vrai?

Dans ma recherche de réponses, j'ai croisé:

  • Le principe de moindre connaissance AKA La loi de Demeter qui encourage les interfaces API hermétiques. Wikipedia répertorie également certains inconvénients.

  • La crise vestimentaire impériale de Kevlin Henney affirme que l’objectif approprié est de ne pas réutiliser.

  • Discuter de Jack Diederich dans " Stop Writing Classes " qui va à l'encontre de la sur-ingénierie en général.

Clairement, tout ce qui est écrit assez mal sera inutile. Mais comment l'interface d'une API bien écrite empêcherait-elle l'utilisation de ce code? Tout au long de l’histoire, il existe des exemples de produits fabriqués dans un but particulier et utilisés pour autre chose . Mais dans le monde du logiciel, si vous utilisez quelque chose dans un but pour lequel il n'a pas été conçu, cela se brise généralement.

Je cherche un bon exemple d'une bonne interface empêchant une utilisation légitime mais involontaire de certains codes. Est-ce que ça existe? Je ne peux pas l'imaginer.

GlenPeterson
la source
1
Je n'ai pas regardé / lu le contenu (j'ai ajouté "Arrêtez d'écrire des classes" à ma liste à surveiller :)), mais peut-être qu'ils discutent sous un angle de frappe dynamique ou statique? ...encore?
Andres F.
oO Interfaces d'interface de programmation d'applications
Thomas Eding
Merci pour les liens! Je n'ai pas trouvé le discours de Jack Diederich particulièrement éclairant (voyez comment il ne répond pas de manière convaincante aux véritables questions du public. "Euh, oui, peut-être dans ce cas ...". même le remarquant;)), mais la "crise du vêtement impérial" est très bonne et perspicace.
Andres F.
1
MPO est que les personnes qui ne croient pas en la réutilisation ne décomposent pas les choses en unités suffisamment petites. Une grande chose qui est construite pour un but spécifique ne peut pas être réutilisée. Cependant, les petites choses ont généralement un objectif suffisamment petit pour être utilisé dans plusieurs contextes.
Amy Blankenship
1
@AmyBlankenship J'ai trouvé la «crise de l'habillement impérial» liée ci-dessus très perspicace. L'auteur considère que la "réutilisation" est une fausse idole (une chose qui n'a pas été prouvée utile dans la pratique, et que la plupart des gens ne comprennent même pas, même s'ils utilisent le mot). Il ne considère pas non plus les bibliothèques comme "réutilisables"; vous utilisez une bibliothèque, vous ne la réutilisez pas. Il envisage également de concevoir quelque chose à réutiliser "une épée à double tranchant"; Quelque chose que les gens considèrent généralement comme une situation gagnant-gagnant mais qui ne l’est vraiment pas: quand vous concevez quelque chose pour le réutiliser, c’est toujours un compromis (par exemple, vous risquez de perdre en simplicité)
Andres F.

Réponses:

32

Je n'ai pas visionné l'intégralité de la présentation de Rich Hickey, mais si je le comprends bien, et d'après ce qu'il dit à propos de la barre des 29 minutes, il semble se disputer au sujet des types qui tuent la réutilisation. Il utilise vaguement le terme "interface" comme synonyme de "type nommé", ce qui a du sens.

Si vous avez deux entités { "name":"John" }de type Personet { "name": "Rover" }de type Dog, elles ne peuvent probablement pas interopérer en Java-land à moins qu'elles ne partagent une interface ou un ancêtre commun (comme Mammal, ce qui signifie écrire plus de code). Donc, les interfaces / types ici "tuent ta réutilisation": même si, Personet qu’ils se Dogressemblent, l’un ne peut pas être utilisé de façon interchangeable, à moins d’écrire du code supplémentaire pour supporter cela. Remarque Hickey plaisante également sur les projets en Java nécessitant beaucoup de classes ("Qui ici a écrit une application Java utilisant seulement 20 classes?"), Ce qui semble être une conséquence de ce qui précède.

Dans les langages "axés sur les valeurs", toutefois, vous n'affecterez pas de types à ces structures; ce sont juste des valeurs qui partagent la même structure (dans mon exemple, elles ont toutes deux un namechamp avec une valeur String) et peuvent donc facilement interopérer, par exemple, elles peuvent être ajoutées à la même collection, transmises aux mêmes méthodes, etc.

En résumé, tout cela semble être quelque chose sur l' égalité structurelle vs type explicite / l' égalité d'interface . Sauf si j'ai oublié quelque chose dans les extraits de la vidéo que je n'ai pas encore visionnés :)

Andres F.
la source
2
BTW, le discours de Jack Diederich "Arrêtez d'écrire des classes" ne semble pas avoir de lien avec ce sujet, mais plutôt sur YAGNI et "n'écrivez pas de code tant que vous n'en avez pas besoin, et n'écrivez que du code simple".
Andres F.
9
ERROR: Object doesn't have a property called "name"est souvent le résultat de value-orientedlangues, et l'autre problème est lorsque vous ne souhaitez plus appeler cette propriété name. Bonne refactoring chance parce qu'il ya probablement des centaines d'objets avec une propriété , namemais tous ne sont pas Personou Dog.
Reactgular
2
@MathewFoscarini Ouais, je ne suis pas nécessairement d'accord avec ça, c'est juste mon interprétation de ce que je pense que Hickey disait :) J'aime les types et le typage statique; Je commence juste à ne pas aimer Java. Et mon aversion n’est pas liée à interfaces mais au gâchis qui est le projet Java typique.
Andres F.
1
Java est le langage de programmation pour ceux qui préfèrent trop réfléchir. C'est l'un des rares langages qui permet à un développeur de cacher facilement ses tentatives de sur-ingénierie d'un projet.
Reactgular
"Dans les langages" orientés valeurs ", vous n'attribuerez pas de types à ces structures" - je pense que vous devez dire "en dynamique" orientés valeurs "..." Haskell et Scala sont orientés valeurs, mais leur système de types statique leur donne le problème exact que vous décrivez. Je pense que la solution à ce problème n'est pas tant la valeur que l'utilisation de cartes pour transmettre des paramètres à des fonctions. L'utilisation de cartes immuables (valeurs) est simplement plus sûre.
GlenPeterson
28

Il fait probablement référence au fait fondamental qu'une interface ne peut pas être instanciée. Vous ne pouvez pas reuseune interface. Vous ne pouvez implémenter que du code qui le prend en charge, et lorsque vous écrivez du code pour une interface, il n'y a pas de réutilisation.

Java a l'habitude de fournir des frameworks de nombreuses API prenant une interface en argument, mais l'équipe qui a développé l'API n'implémente jamais un large éventail de classes que vous pouvez réutiliser avec ces interfaces.

C'est un peu comme un framework d'interface graphique qui a une IWindowinterface pour une boîte de dialogue et vous pouvez ensuite ajouter des IButtoninterfaces pour les contrôles. Sauf qu'ils ne vous ont jamais donné une bonne Buttonclasse qui implémente IButton. Donc, il ne vous reste plus qu'à créer les vôtres.

Les frameworks abstraits qui ont un large éventail de classes de base fournissant des fonctionnalités de base sont plus réutilisables et fonctionnent mieux lorsque ces classes abstraites sont accessibles à ceux qui utilisent le framework.

Les développeurs Java ont commencé à faire cette chose où leurs couches d'API exposées uniquement interfaces. Vous pouvez implémenter ces interfaces, mais vous ne pouvez jamais réutiliser les classes du développeur qui a implémenté ces interfaces. C'est un peu comme un style de développement d'API avec une cape et une dague.

Réactionnel
la source
4
Merci pour cette réponse. J'ai maintenant l'impression de comprendre la question et la réponse :)
MetaFight
2
+1 J'apprécie vraiment votre réponse et cela ajoute une couche fascinante d'informations intéressantes à cette question. Mais je pense que la réponse d'Andreas F. est probablement plus proche du cœur de ce que M. Hickey voulait dire, alors j'ai accepté la sienne.
GlenPeterson
@GlenPeterson pas de problème, je pense qu'il pourrait être sur la marque aussi.
Reactgular
1
Eh bien, ceci et la réponse acceptée mettent en évidence deux interprétations légèrement différentes, mais tout aussi intéressantes. Je suis curieux de savoir à quoi M. Hickey avait pensé lorsqu'il en parlait ..
David Cowden
Vous ne pouvez pas réutiliser une interface, mais vous pouvez l'étendre (et donner un numéro de version précieux) sans changer les anciennes classes. Vous pouvez également hériter de nombreuses interfaces pour ajouter un nouveau travail pour de nouvelles classes ou ajouter un nouvel héritage dans les anciennes classes recompilées. Vous pouvez également étendre la classe qui implémente cette interface pour un nouveau travail.
Cl-r
14

Je pense que la diapositive 13 de sa présentation ( La valeur des valeurs ) aide à comprendre ceci:

http://i.stack.imgur.com/LVMne.png


Valeurs

  • Pas besoin de méthodes
    • Je peux vous envoyer des valeurs sans code
      et tout va bien

D'après ma compréhension, Hickey suggère que si je dois, par exemple, doubler la valeur que vous m'avez envoyée, j'écris simplement du code ressemblant à

    MyValue = Double(YourValue)

Vous voyez, le code ci-dessus est le même, peu importe la valeur que vous avez envoyée - une sorte de réutilisation parfaite .

Maintenant, à quoi cela ressemblerait-il dans le langage ayant des objets et des interfaces?

    Doublable MyValue = YourValue.Double()

Oh, attendez! Et si YourValuene met pas en œuvre Doublable? non pas que cela ne puisse pas être doublé, ce pourrait être parfaitement mais ... et s'il n'y avait pas de méthode Double ? (et s'il y a une méthode appelée say TwiceAsMuch?)

Euh oh on a un problème. YourValue.Doublene fonctionnera pas, il ne peut plus être réutilisé . D'après ma lecture de la diapositive ci-dessus, c'est à propos de ce que Hickey voulait dire quand il disait: "Toutes ces interfaces tuent la réutilisation!"

Vous voyez, les interfaces supposent que les objets sont transmis "avec leurs méthodes", ainsi que le code qui les exploite. Pour utiliser des objets, il faut comprendre comment appeler ce code, quelle méthode appeler.

Lorsque la méthode attendue est manquante, il y a un problème, même si sémantiquement , l'opération souhaitée est parfaitement logique pour un objet. Comme indiqué dans la présentation, les valeurs n'ont pas besoin de méthodes ("je peux vous envoyer des valeurs sans code et tout va bien"), ce qui permet d'écrire du code les traitant de manière générique.


Note latérale: la notion de transmission de valeurs sans code me rappelle en quelque sorte un motif de poids mouche dans la POO.

un objet qui minimise l'utilisation de la mémoire en partageant autant de données que possible avec d'autres objets similaires; c'est une façon d'utiliser des objets en grand nombre lorsqu'une représentation répétée utiliserait une quantité de mémoire inacceptable ... Les objets Flyweight sont par définition des objets de valeur . L’identité de l’instance d’objet n’ayant pas d’importance, deux instances Flyweight de même valeur sont considérées comme égales ...

Les utilisations Flyweight que j'ai observées suivaient généralement la même approche consistant à supprimer le code (méthodes, interfaces) des objets et à leur transmettre des informations, ainsi que des valeurs sans code , en s'attendant à ce que le code reçu dispose des moyens nécessaires pour les utiliser.

Cela ressemble beaucoup à la diapositive: "Les valeurs n'ont pas besoin de méthodes. Je peux vous envoyer des valeurs sans code et tout va bien".

moucheron
la source
5
Les génériques s’occuperaient à peu près de ce problème. Doubler est logique sur certains objets, mais pas sur d'autres. Dans le langage Go, il existe une implémentation d'interface implicite (une forme de typage de canard), vous n'avez donc pas à vous soucier de toutes ces interfaces. D'autre part, vous devez savoir quel objet va être touché par votre signature de méthode; sinon, vous pourriez obtenir des résultats inattendus. Il y a toujours des compromis.
Robert Harvey
1
Une prise intéressante. Bonne réponse!
maple_shaft
2
Le modèle de poids mouche n’est pas ce dont parle Rich. Comme l'indique la deuxième phrase de l'article, l'objectif du motif poids mouche est de conserver la mémoire. L'approche de Rich ne cherche pas à faire cela.
5
MyValue = Double(YourValue)n'a pas de sens si YourValue est une chaîne, une adresse, un utilisateur, une fonction ou une base de données. Sinon, votre argument de méthode manquante est fort. OTOH, méthodes d’accessoires vous permettent d’appliquer diverses contraintes afin que vos valeurs soient valides et que seules des opérations sensibles soient utilisées pour produire de nouvelles valeurs. Si vous décidez ultérieurement de séparer l'adresse de votre utilisateur et de votre société, les méthodes d'accès vous éviteront de casser tous les clients de votre code. Ils peuvent donc contribuer à la réutilisation à long terme même s’ils la gênent parfois à court terme.
GlenPeterson
4
(En revanche, je suis d’accord sur le fait qu’en Java-land, l’explosion de classes, d’interfaces et de frameworks est un cauchemar. La solution "entreprise" la plus simple en Java est un gâchis de code. Je tire donc une leçon précieuse de cette question / réponse, sans pour autant être d'accord avec les méthodes de dactylographie dynamiques)
Andres F.
2

Dans un monde idéal (c’est-à-dire), les classes et les interfaces décrivent toujours le comportement, mais le fait est que trop souvent, elles ne décrivent que des données. Pas BankAccountplus tard qu'hier, j'ai regardé la vidéo de quelqu'un qui a construit une classe dite qui n'était rien de plus qu'une glorifiée int(en fait, elle était beaucoup moins utile qu'un int, "tuant" ainsi la réutilisation que j'aurais eue si elle avait été laissée comme telle int), tout cela au nom du «bon» design. La quantité de code, de sueur et de larmes gaspillée pour réinventer continuellement les représentations alambiquées des données est stupéfiante; si vous n'utilisez pas les données de manière significative, laissez-les simplement.

C'est à ce stade que Rich Hickey se contente de jeter le bébé avec l'eau du bain et de dire que nous devrions tous aller vivre au pays des valeurs (un voisin du royaume des noms). Je pense, par contre, que la POO peut et doit promouvoir la réutilisation (et surtout la découvrabilité, que je trouve insuffisante en programmation fonctionnelle) si elle est utilisée judicieusement. Si vous recherchez un principe de POO qui capture le mieux cette tension, je pense que cela pourrait être http://c2.com/cgi/wiki?TellDontAsk (qui est bien sûr un proche cousin de Demeter)

CurtainDog
la source
Qu'entendez-vous par découvrabilité? Est-ce semblable à ceci ?
1
Oui, je pense que cela touche beaucoup de points principaux. C'est un point subtil, mais la découvrabilité est un acte d'équilibre. Rendre les choses trop transparentes est également indésirable, car vous obtiendrez un mauvais rapport signal / bruit.
CurtainDog