Aplicando os princípios do Código Limpo a linguagens funcionais

16

Atualmente, estou lendo o Código Limpo de Robert Martin . Eu acho ótimo e, ao escrever o código OO, levo suas lições a sério. Em particular, acho que o conselho dele de usar pequenas funções com nomes significativos faz meu código fluir muito mais suavemente. É melhor resumido por esta citação:

[Nós] queremos poder ler o programa como se fosse um conjunto de parágrafos TO, cada um dos quais descrevendo o nível atual de abstração e referenciando parágrafos TO subsequentes no próximo nível abaixo.

( Código Limpo , página 37: um "parágrafo TO" é um parágrafo que começa com uma frase expressa no infinitivo. "Para executar X, executamos as etapas Y e Z." "Para executar Y, nós ..." etc. ) Por exemplo:

PARA RenderPageWithSetupsAndTeardowns, verificamos se a página é uma página de teste e, se for o caso, incluímos as configurações e os teardowns. Nos dois casos, renderizamos a página em HTML

Também escrevo código funcional para o meu trabalho. Os exemplos de Martin no livro definitivamente são lidos como se fossem um conjunto de parágrafos e são muito claros - mas não tenho tanta certeza de que "leia como um conjunto de parágrafos" seja uma qualidade desejável para o código funcional. .

Tomando um exemplo da biblioteca padrão Haskell :

maximumBy               :: (a -> a -> Ordering) -> [a] -> a
maximumBy _ []          =  error "List.maximumBy: empty list"
maximumBy cmp xs        =  foldl1 maxBy xs
                        where
                           maxBy x y = case cmp x y of
                                       GT -> x
                                       _  -> y

Isso é o mais longe que você pode obter dos conselhos de Martin, mas é conciso e idiomático Haskell. Ao contrário dos exemplos de Java em seu livro, não consigo imaginar como refatorá-lo para algo que tenha o tipo de cadência que ele pede. Suspeito que Haskell, escrito de acordo com o padrão do Código Limpo , sairia por muito tempo e antinatural.

Estou errado ao considerar (pelo menos alguns) o Código Limpo em desacordo com as práticas recomendadas de programação funcional? Existe uma maneira sensata de reinterpretar o que ele diz em um paradigma diferente?

Patrick Collins
fonte
1
Programadores funcionais tendem a escrever código excessivamente conciso, é verdade. Eu não consideraria remotamente essa prática recomendada, mesmo nesse ambiente.
Telastyn 27/08/14
Perdoe a ignorância, mas o que é um parágrafo do TO?
Shashank Gupta
4
Como foi mencionado em outra pergunta recentemente, Dijkstra escreveu sobre a tolice da "programação de linguagem natural" e eu tendem a concordar com ele que o código que parece prosa é um sonho. Eu acho que isso é especialmente verdadeiro em Haskell que, sendo puro, simbolicamente expressa igualdades entre valores, em vez de sequências de etapas para produzir efeitos. Eu acho que o importante é que o código citado seja idiomático. Por exemplo, xsé um nome ruim, mas é tão comum em linguagens funcionais quanto iem variáveis ​​de loop.
Doval 28/08
@ShashankGupta Editei a pergunta com um link para a página específica do livro, bem como meu próprio entendimento do que o tio Bob escreveu.
@ShashankGupta Ele dá alguns exemplos, mas a idéia é que ela deva ler como prosa. "Para encontrar o máximo da lista, verifique todos os elementos ..."
Patrick Collins

Respostas:

11

O Código Limpo é, antes de tudo, um manual de estilo. Strunk e branco não se aplicam quando você está escrevendo em Klingon. A idéia é que você queira deixar claro para os programadores que provavelmente lerão seu código. Você deseja ter um código modularizado e fácil de reestruturar. Existem maneiras de fazer isso em Haskell, assim como existem em qualquer outro idioma, mas os detalhes precisos variam.

Dito isto, existem várias diretrizes de estilo para Haskell. O Stack Overflow também possui um guia bastante abrangente . Manter a lógica de codificação direta e breve parece ser bastante constante. A generalização de funções também é enfatizada, pois leva à modularidade. O código DRY também é enfatizado, o mesmo que com o Código Limpo.

No final, as diretrizes de código da Clean Code e Haskell lutam pela mesma coisa, mas acabam seguindo seus próprios caminhos para chegar lá.

Engenheiro Mundial
fonte
1
Eu sinto que esta resposta desconta os princípios que o Código Limpo ensina, que são muito aplicáveis ​​em todos os idiomas, e que é essencial para a pergunta. Eu posso ver por que as pessoas pensam no Código Limpo como um manual de estilo, e acho que é parcialmente verdade, mas não é verdade o suficiente para descartar o livro inteiro como um.
Allan
Não penso no livro de código limpo da Martin como manual de estilo. Sinto que os ensinamentos do livro realmente se encaixam em algum lugar entre um guia de estilo e padrões de design.
Michael R
15

Não sei se sigo o que você quer dizer com seu exemplo. Os parágrafos, como ele os descreve, não exigem muito esforço. Ele não quer dizer que o código deva ler como o inglês. A parte importante é o agrupamento de funcionalidades no mesmo nível de abstração, em uma progressão lógica. Esse é um conceito estrutural teórico que transcende os paradigmas de programação.

Expressado no formato "parágrafo" de Bob Martin, li seu exemplo como:

  • Para calcular maximumBy, você precisa de uma função de pedido e de uma lista, e o resultado é um elemento dessa lista.
  • Para calcular a maximumBylista vazia e qualquer função de pedido, é um erro.
  • Para calcular o maximumByde uma lista xs, você dobra essa lista usando a maxByfunção
  • Para calcular os maxBydois elementos da lista, compare-os usando a função de pedido fornecida. Se o primeiro elemento for maior, escolha-o. Caso contrário, escolha o segundo.

Você está começando com os conceitos mais gerais e progredindo para mais detalhes, assim como nos exemplos imperativos. A idéia dos "parágrafos TO" é que você pode parar de ler em um determinado momento quando obtiver detalhes suficientes, sem precisar pular a página para cima e para baixo. Esse é certamente o caso aqui.

Talvez alguns nomes possam ser melhores, mas são convenções comuns da linguagem, especialmente ao escrever funções genéricas de ordem superior. Nomes de funções de ordem superior também não se traduzem bem em frases verbais imperativas, como nos exemplos do livro, porque descrevem mais as relações entre os verbos.

Existem maneiras de implementar isso que não seguem as diretrizes "parágrafo TO". Deixar a assinatura de tipo explícita omitiria a sentença "visão geral" de nível superior. Você pode usar uma expressão if para o tratamento de erros em vez da correspondência de padrões, o que atrapalha isso de maneira inadequada com outro nível de abstração. Você pode incorporar maxByuma função anônima em vez de atribuir um nome que possa ser descrito posteriormente com mais detalhes.

Na verdade, acho que construções como wherena verdade se encaixam melhor no formato do parágrafo, porque você pode usá-las para dar um nome a um detalhe mais profundo de uma maneira próxima à maneira como a expressamos em inglês e limitar o escopo de maneira semelhante em um caminho claro para o contexto do "parágrafo".

Karl Bielefeldt
fonte