Existe uma boa razão para tornar públicas as funções puras?

25

Eu tive um pequeno debate com um colega de trabalho. Simplificando, existe um bom motivo para ocultar / encapsular funções que são puras?

Por "puro", quero dizer a definição da Wikipedia :

  • Sempre retorna os mesmos resultados da mesma entrada. (Para fins desta discussão, Foo Create(){ return new Foo(); }é considerado impuro se Foonão tiver semântica de valor.)
  • Não usa estado mutável (exceto variáveis ​​locais) ou E / S.
  • Não produz efeitos colaterais.
Telastyn
fonte
26
Poderia haver um argumento para não tornar um membro dessa função de uma classe.
Pieter B
6
@ PieterB - de fato, embora nem todos os idiomas suportem isso, e alguns idiomas permitem o módulo interno, mesmo para funções gratuitas.
Telastyn 26/09/14
3
Qual a sua opinião? Não acho que a pureza da função esteja relacionada à sua pertença à API pública.
Andres F.
@andresF. - o debate foi realmente sobre se uma regra de validação ilimitada deveria ser tornada pública. Argumentei que, como era uma função pura, havia pouco dano. Nesse caso em particular, ajudou na testabilidade e provavelmente foi reutilizado. Esta questão é mais sobre a amplitude que esse argumento poderia / deveria aplicar.
Telastyn 26/09/14
2
@Telastyn Se é reutilizável, mas não faz parte da responsabilidade da classe atual, provavelmente deve estar em uma classe / módulo / qualquer que seja seu idioma. Sendo parte da responsabilidade da nova classe / módulo, ela seria necessariamente tornada pública. Como você mencionou o teste, observarei que você não precisa necessariamente zombar do método ao fazer isso. Como um "detalhe de implementação", zombar dele durante os testes oferece pouco benefício.
precisa saber é o seguinte

Respostas:

76

Uma função pura ainda pode ser um detalhe de implementação. Embora a função possa não causar danos (do ponto de vista de não quebrar invariantes / contratos importantes), expondo-a tanto o autor quanto os usuários dessa classe / módulo / pacote perdem. O autor perde porque agora ele não pode removê-lo, mesmo que a implementação mude e a função não seja mais útil para ele. Os usuários perdem porque precisam peneirar e ignorar funções extras que não são relevantes para o uso da API para entendê-la.

Doval
fonte
33
+1. Os membros públicos da sua classe são sua API. Não se trata de "Pode me machucar se for público?", Mas sim "Deve fazer parte da API?"
Ordous
1
A única coisa que gostaria de acrescentar é que, se você começar a ver funções semelhantes aparecendo em outros locais, refatorá-lo em outra classe para que várias classes possam fazer uso dela. Ou, se for uma preocupação, para começar, defina-a em uma classe separada.
precisa saber é o seguinte
1
Eu selaria as classes públicas que não devem ser estendidas também.
Den
+1 por apontar que ocultar ou mostrar uma função (ou classe) são principalmente questões de proteção e manutenção de uma API e não estão relacionadas ao tipo de código que é.
Marco
42

A questão está ao contrário.

Você não procura um motivo para tornar uma função não pública. É uma mentalidade incorreta para começar (na minha opinião). O raciocínio deve seguir o contrário.

Em outras palavras - não pergunte "por que eu o tornaria privado?". Pergunte: "por que eu a tornaria pública?"

Em caso de dúvida, não exponha. É como a navalha de Ockham - não multiplique entidades além da necessidade.

EDIT: Abordando contra-argumentos apresentados por @Telastyn nos comentários (para evitar discussões prolongadas):

Eu ouvi isso ao longo do tempo, e até o defendi por algum tempo, mas, na minha experiência, as coisas tendem a ser muito particulares.

Sim, às vezes é difícil se uma classe é aberta para herança, mas você não pode substituir alguns métodos privados (cujo comportamento você gostaria de alterar).

Mas protectedseria suficiente - e ainda não é público.

Isso leva a muita duplicação de código e sobrecarga para acessar "coisas que não deveriam ser públicas", mas que são acessadas indiretamente de qualquer maneira.

Se isso se tornar problemático, simplesmente torne-o público! Existe a necessidade de que eu estava falando :)

Meu argumento é que você não deve fazê-lo por precaução (YAGNI e tudo).

Observe que é sempre mais fácil tornar pública uma função privada do que recolocá-la na privacidade. O último provavelmente quebra o código existente.

Konrad Morawski
fonte
Eu ouvi isso ao longo do tempo, e até o defendi por algum tempo, mas, na minha experiência, as coisas tendem a ser muito particulares. Isso leva a muita duplicação de código e sobrecarga para acessar "coisas que não deveriam ser públicas", mas que são acessadas indiretamente de qualquer maneira.
Telastyn 26/09/14
3
@Telastyn IMHO, parece que o aplicativo sofre de alguns erros de design; se você estiver disposto a expor um método porque precisa invocá-lo por caminhos de código distintos, é provavelmente um sinal de que esse método deve ser dividido em seu próprio módulo que pode ser injetado ou incluído quando apropriado, especialmente se for uma função pura .
Leo
@leo - desculpe, eu não sigo. Considere uma função como número inteiro menor que. Essa é uma função pura e agradável que é exposta especificamente porque pode ser injetada e incluída (ou simplesmente usada) quando apropriado.
Telastyn 26/09/14
5
@Telastyn Na minha opinião, isso é um sintoma da filosofia "tudo é um objeto / classe" combinada com o fato de que algumas linguagens OOP não têm tipos de dados compostos além de classes. Assim que alguém precisa passar dois valores ao mesmo tempo, acaba escrevendo uma classe e todos os colegas de trabalho e softwares de verificação de estilo dirão para você tornar esses campos privados.
Doval
@Telastyn Right. O que quero dizer é que, se o método 'integerLessThan' for iniciado como um detalhe de implementação encapsulado de um método público, mas você achar que precisa invocar o método privado em outros lugares, isso provavelmente é um sinal de que o método privado pertence a um método diferente. módulo / pacote / classe para que possa ser importado independentemente da lógica que o chama. A simples divulgação do método como está significa que o método está localizado arbitrariamente no primeiro módulo em que você o achou útil.
Leo
6

Não acho que a decisão de ocultar / encapsular uma função dependa de sua pureza. Só porque uma função é pura, não significa que os externos precisam saber sobre ela. É interessante notar que, se a função é pura e pretende ser pública, talvez nem precise ser um membro da instância da interface; talvez seja mais adequada como estática. Mas, novamente, tudo isso depende da intenção do contrato e, nesse caso, do agrupamento lógico da funcionalidade, não da pureza da função.

reclamar
fonte
5

As aulas devem seguir o Princípio da Responsabilidade Única . Embora uma classe precise recorrer a outras funcionalidades para atingir seus objetivos, ela só deve expor funções que fazem parte de sua única responsabilidade.

Aqui está apenas um exemplo de caso em que a visibilidade pode causar um problema.

Considere uma classe que frobica os widgets. Talvez como parte de seu código de frobificação, ele precise de alguma função utilitária que analise uma string: talvez precise transformar o nome do widget de uma maneira que as funções de string padrão não suportem.

Como essa é uma função pura (a string entra, a transforma de alguma forma, retorna uma nova string), ela pode ser pública ou privada sem conseqüências. Ou poderia?

Se você o tornar público, agora a sua classe tem duas responsabilidades: fazer widgets em alta velocidade e transformar strings. Isso viola o SRP e pode causar problemas se outras classes dependerem da função. Como isso é algo que você acha que é usado apenas internamente na classe, talvez você altere sua interface ou visibilidade. Agora as aulas em outras partes do sistema estão interrompidas.

Mantendo a função privada, ninguém nunca tem a oportunidade de confiar em códigos que não fazem parte da responsabilidade única da classe.


fonte
2
Eu argumentaria que ele deveria conter apenas funções que fazem parte de sua única responsabilidade, e não apenas expor.
Telastyn 26/09/14
1
Eu acho que há uma área cinzenta. Você realmente precisa de uma StringTransformerclasse separada para encapsular duas ou três linhas de código que são usadas apenas em um só lugar? Concordo que, uma vez que o código é usado em vários locais, é melhor separá-lo em uma nova classe com uma responsabilidade, mas há uma troca.
Certamente. Diretrizes são diretrizes, não regras.
Telastyn 26/09/14
@ snowman em não java, você acabou de criar uma biblioteca de funções.
Pieter B
@ PieterB não é sobre Java v. Para torná-lo verdadeiramente OO você precisaria de uma fábrica, algumas classes abstratas, etc.