O que Rich Hickey quis dizer quando disse: "Toda essa especificidade [de interfaces / classes / tipos] mata sua reutilização!"


41

Na palestra instigadora de Rich Hickey, Goto Conference " The Value of Values ", aos 29 minutos, ele está falando sobre a sobrecarga de uma linguagem como Java e faz uma declaração como "Todas essas interfaces matam sua reutilização". O que ele quer dizer? Isso é verdade?

Na minha busca por respostas, encontrei:

  • O PRINCÍPIO DO MENOR CONHECIMENTO AKA A Lei de Demeter, que incentiva interfaces de API herméticas. A Wikipedia também lista algumas desvantagens.

  • A crise de roupas imperiais de Kevlin Henney, que argumenta que usar, não reutilizar, é o objetivo apropriado.

  • " Stop Writing Classes ", de Jack Diederich, que argumenta contra o excesso de engenharia em geral.

Claramente, qualquer coisa escrita mal o suficiente será inútil. Mas como a interface de uma API bem escrita impediria que esse código fosse usado? Ao longo da história, existem exemplos de algo feito para uma finalidade sendo usado mais para outra coisa . Mas no mundo do software, se você usa algo para um propósito a que não se destina, geralmente ele quebra.

Estou procurando um bom exemplo de uma boa interface que impede o uso legítimo, mas não intencional, de algum código. Isso existe? Não consigo imaginar.


1
Não assisti / li o material (adicionei "Stop Writing Classes" à minha lista de observação :)), mas talvez eles estejam discutindo sob um ângulo de digitação dinâmico versus estático? ...novamente?
Andrés F.

oO Application Programming Interfaces de interface
Thomas Eding

Obrigado pelos links! Não achei a palestra de Jack Diederich particularmente esclarecedora (observe como ele falha em responder às perguntas genuínas da platéia de forma convincente .. "uh, sim, talvez nesse caso ...". Gostei de que ele parece estar argumentando por Programação Funcional sem mesmo percebendo;)), mas a "Crise Imperial do Vestuário" é muito boa e perspicaz.
Andrés F.

1
O MPO é que as pessoas que não acreditam em reutilização não dividem as coisas em unidades pequenas o suficiente. Uma grande coisa criada para uma finalidade específica não pode ser reutilizada. No entanto, pequenas coisas geralmente têm um objetivo pequeno o suficiente para que o pequeno seja útil em mais de um contexto.
Amy Blankenship

1
@AmyBlankenship Achei a "Crise imperial de roupas" vinculada acima como um insight. O autor considera "reutilizar" um ídolo falso (algo que não se provou útil na prática, e também a maioria das pessoas nem o entende mesmo que use a palavra). Ele também não considera as bibliotecas "reutilizadas"; você usa uma biblioteca, não a reutiliza . Ele também considera projetar algo para reutilizar "uma faca de dois gumes"; algo que as pessoas costumam considerar uma situação win-win, mas que realmente não é: quando você projetar algo para reutilização, é sempre um compromisso (por exemplo, você pode perder na simplicidade)
Andres F.

Respostas:


32

Não assisti a apresentação completa de Rich Hickey, mas se eu o entendi corretamente, e a julgar pelo que ele diz sobre a marca de 29 minutos, ele parece estar discutindo sobre os tipos que matam a reutilização. Ele está usando o termo "interface" como um sinônimo de "tipo nomeado", o que faz sentido.

Se você possui duas entidades { "name":"John" }do tipo Persone { "name": "Rover" }do tipo Dogno Java-land, elas provavelmente não poderão interoperar, a menos que compartilhem uma interface ou ancestral comum (como Mammal, o que significa escrever mais código). Assim, as interfaces / tipos aqui são "matar sua reutilização": embora Persone Dogtêm a mesma aparência, não pode ser usado de forma intercambiável com o outro, a menos que você escrever código adicional para suportar isso. Nota Hickey também brinca sobre projetos em Java que precisam de muitas classes ("Quem aqui escreveu um aplicativo Java usando apenas 20 classes?"), O que parece uma consequência do exposto acima.

Em linguagens "orientadas a valores", no entanto, você não atribui tipos a essas estruturas; são apenas valores que compartilham a mesma estrutura (no meu exemplo, ambos têm um namecampo com um valor String) e, portanto, podem interoperar facilmente, por exemplo, podem ser adicionados à mesma coleção, passados ​​para os mesmos métodos, etc.

Em resumo, tudo isso parece ter algo a ver com igualdade estrutural versus tipo explícito / igualdade de interface . A menos que eu tenha perdido algo das partes do vídeo que ainda não assisti :)


2
Aliás, a palestra de Jack Diederich "Stop Writing Classes" parece não ter relação com esse tópico, e é mais sobre YAGNI e "não escreva código até que você precise, e depois escreva apenas código simples".
Andrés F.

9
ERROR: Object doesn't have a property called "name"geralmente é o resultado de value-orientedidiomas e o outro problema é quando você não deseja mais chamar essa propriedade name. Boa sorte na refatoração, porque provavelmente há centenas de objetos com uma propriedade, namemas nem todos são Personou Dog.
Reactgular

2
@MathewFoscarini Sim, eu não necessariamente concordo com isso, é apenas a minha interpretação do que eu acho que Hickey estava dizendo :) Eu gosto de tipos e tipagem estática; Estou apenas começando a não gostar do Java. E minha antipatia não está relacionada a interfaces, mas à bagunça que é o projeto Java típico.
Andrés F.

1
Java é a linguagem de programação para quem prefere pensar demais. É uma das poucas linguagens que permite que um desenvolvedor esconda facilmente suas tentativas de projetar demais um projeto.
Reactgular

"Em linguagens 'orientadas a valores', você não atribui tipos a essas estruturas" - acho que você precisa dizer "Em dinâmicas 'orientadas a valores' ..." Haskell e Scala são orientadas a valores, mas seu sistema de tipos estáticos dá a eles o problema exato que você está descrevendo. Eu acho que a solução para esse problema não é tanto valor quanto usar mapas para passar parâmetros para funções. Usar mapas imutáveis ​​(valores) é apenas mais seguro.
GlenPeterson

28

Ele provavelmente está se referindo ao fato básico de que uma interface não pode ser instanciada. Você não pode reuseuma interface. Você só pode implementar código que o suporte e, quando você escreve código para uma interface, não há reutilização.

O Java tem um histórico de fornecer estruturas de muitas APIs que usam uma interface como argumentos, mas a equipe que desenvolveu a API nunca implementa uma ampla variedade de classes para você reutilizar com essas interfaces.

É como uma estrutura de GUI que possui uma IWindowinterface para uma caixa de diálogo e, em seguida, você pode adicionar IButtoninterfaces para controles. Exceto, eles nunca lhe deram uma boa Buttonaula que implementa IButton. Então você fica criando o seu próprio.

Estruturas abstratas que possuem uma ampla variedade de classes base, fornecendo funcionalidades principais, são mais reutilizáveis ​​e funcionam melhor quando essas classes abstratas são acessíveis àqueles que usam a estrutura.

Os desenvolvedores de Java começaram a fazer isso onde suas camadas de API eram expostas apenas interfaces. Você poderia implementar essas interfaces, mas nunca poderia reutilizar classes do desenvolvedor que implementou essas interfaces. É como um estilo de capa e punhal de desenvolvimento de API.


4
Obrigado por esta resposta. Agora me sinto como se eu entendi a pergunta e a resposta :)
MetaFight

2
Eu realmente aprecio sua resposta e adiciona uma camada fascinante de informações interessantes a esta pergunta. Mas acho que a resposta de Andreas F. provavelmente está mais próxima do que o Sr. Hickey quis dizer, então aceitei a dele.
GlenPeterson

@GlenPeterson não tem problema, acho que ele também pode estar em risco.
Reactgular

1
Bem, isso e a resposta aceita destacam duas interpretações ligeiramente diferentes, mas igualmente interessantes. Estou curioso para saber qual o Sr. Hickey tinha em mente ao falar sobre isso ..
David Cowden

Você não pode reutilizar uma interface, mas pode estendê-la (e fornecer um número de versão valioso) sem alterar as classes antigas. Você também pode herdar de várias interfaces para adicionar novo trabalho a novas classes ou adicionar nova herança em classes recompiladas antigas. Você também pode estender a classe que implementa essa interface para um novo trabalho.
precisa

14

Acho que o slide 13 de sua apresentação ( O Valor dos Valores ) ajuda a entender isso:

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


Valores

  • Não precisa de métodos
    • Posso enviar valores sem código
      e você está bem

Meu entendimento é que Hickey sugere que, se eu precisar, digamos, dobrar o valor que você enviou para mim, eu simplesmente escrevo um código parecido com

    MyValue = Double(YourValue)

Veja, o código acima é o mesmo, independentemente do valor que você enviou - uma reutilização perfeita .

Agora, como isso seria na linguagem com objetos e interfaces?

    Doublable MyValue = YourValue.Double()

Oh espere! e se YourValuenão implementar Doublable? não que não possa ser duplicado, pode perfeitamente ser, mas ... e se simplesmente não houver método Double ? (e se houver um método chamado digamos TwiceAsMuch?)

Oh, nós temos um problema. YourValue.Doublenão funcionará, não poderá mais ser reutilizado . Pela minha leitura do slide acima, é sobre o que Hickey quis dizer quando disse: "Todas essas interfaces matam sua reutilização!"

Veja bem, as interfaces assumem que os objetos são passados ​​"junto com seus métodos", juntamente com o código que opera neles. Para usar objetos, é preciso entender como chamar esse código, qual método chamar.

Quando o método esperado está ausente, há um problema, mesmo que semanticamente , a operação desejada faça todo o sentido para um objeto. Conforme declarado na apresentação, os valores não precisam de métodos ("Posso enviar valores sem código e você está bem"), permitindo escrever código lidando com eles de maneira genérica.


Nota lateral: a noção de passar valores sem código de alguma forma me lembra um padrão Flyweight no OOP.

um objeto que minimiza o uso da memória compartilhando o máximo de dados possível com outros objetos semelhantes; é uma maneira de usar objetos em grandes números quando uma representação repetida simples usaria uma quantidade inaceitável de memória ... Objetos Flyweight são, por definição, objetos de valor . A identidade da instância do objeto não tem importância, portanto, duas instâncias Flyweight do mesmo valor são consideradas iguais ...

Os usos do flyweight que eu vi normalmente seguiram a mesma abordagem de remover o código (métodos, interfaces) dos objetos e distribuir coisas ao redor, bem como valores sem código , esperando que o código de recebimento tenha os meios necessários para operar com eles.

Isso parece muito com o slide "valores não precisam de métodos. Posso enviar valores sem código e você está bem".


5
Os genéricos praticamente resolveriam esse problema. Dobrar faz sentido em alguns objetos, mas não em outros. Na linguagem Go, há implementação implícita de interface (uma forma de digitação de pato), portanto você não precisa se preocupar com todas essas interfaces. Por outro lado, você precisa saber qual objeto será atingido pela assinatura do seu método; caso contrário, você poderá obter resultados inesperados. Sempre há trocas.
Robert Harvey

1
Uma tomada interessante. Boa resposta!
maple_shaft

2
O padrão de peso mosca não é o que Rich está falando. Como afirma a segunda frase do artigo, o objetivo do padrão de peso de mosca é conservar a memória. A abordagem de Rich não procura fazer isso.

5
MyValue = Double(YourValue)não faz sentido se YourValue for uma String, um Endereço, um Usuário, uma Função ou um Banco de Dados. Caso contrário, seu argumento do método ausente é forte. OTOH, os métodos de acesso permitem impor várias restrições para que seus Valores sejam válidos e que apenas operações sensíveis sejam usadas para produzir novos Valores. Se, posteriormente, você decidir separar o endereço do usuário e da empresa, os métodos de acesso significam que você não quebra todos os clientes do seu código. Portanto, eles podem ajudar a reutilizar a longo prazo, mesmo que às vezes o impeçam no curto prazo.
GlenPeterson

4
(Por outro lado, concordo que em Java-land, a explosão de classes, interfaces e estruturas é um pesadelo. A solução mais simples de "empreendedor" em Java é uma bagunça de código. Portanto, aproveito uma lição valiosa pergunta e resposta, sem necessariamente concordar com as coisas tipagem dinâmica)
Andres F.

2

Em um (ie) meu, classes e interfaces ideais do mundo sempre descreveriam o comportamento, mas o fato é que, com muita freqüência, eles acabam descrevendo dados. Ontem, vi o vídeo de alguém criar uma BankAccountclasse chamada que nada mais era do que um glorificado int(na verdade, era muito menos útil do que um int, portanto, 'matando' a reutilização que eu teria, se simplesmente fosse deixada como uma int), tudo em nome de "bom" design. A quantidade de código, suor e lágrimas desperdiçados na reinvenção contínua de representações complicadas de dados é impressionante; se você não estiver usando os dados de maneira significativa, deixe estar.

Agora, este é o estágio em que Rich Hickey se contenta em jogar o bebê fora com a água do banho e dizer que todos devemos viver na terra dos valores (um vizinho do reino dos substantivos). Penso, por um lado, que o POO pode e promove a reutilização (e, principalmente, a descoberta, que acho que falta na programação funcional) quando empregado criteriosamente. Se você está procurando um princípio de POO que capte melhor essa tensão, acho que pode ser http://c2.com/cgi/wiki?TellDontAsk (que, obviamente, é um primo próximo de Demeter)


O que você quer dizer com descoberta? É semelhante a isso ?

1
Sim, acho que isso toca em muitos dos pontos principais. É um ponto sutil, mas a descoberta é um ato de equilíbrio, tornar as coisas muito transparentes também é indesejável, porque você terá uma má relação sinal / ruído.
CurtainDog
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.