Aplicando os princípios do Clean Code para linguagens funcionais

15

Atualmente, estou lendo código limpo de Robert Martin . Eu acho ótimo, e quando escrevo código OO, eu estou levando suas lições para o coração. Em particular, acho que o seu conselho para usar pequenas funções com nomes significativos faz o meu código fluir muito mais suavemente. É melhor resumido por esta citação:

[W]e want to be able to read the program as though it were a set of TO paragraphs, each of which is describing the current level of abstraction and referencing subsequent TO paragraphs at the next level down.

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

TO RenderPageWithSetupsAndTeardowns, we check to see whether the page is a test page and if so, we include the setups and teardowns. In either case we render the page in HTML

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

Tirando um exemplo da biblioteca padrão do 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 do conselho de Martin, mas é Haskell, idiota e conciso. Ao contrário dos exemplos de Java em seu livro, não consigo imaginar uma maneira de refatorar isso em algo que tenha o tipo de cadência que ele pede. Eu suspeito que Haskell escreveu para o padrão de Código Limpo seria tão longo e antinatural.

Estou errado em considerar (pelo menos alguns) 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?

    
por Patrick Collins 28.08.2014 / 00:14
fonte

2 respostas

11

O Clean Code é, antes de tudo, um manual de estilo. Strunk e White não se aplicam quando você está escrevendo em Klingon. A ideia é que você queira ser claro para os programadores que provavelmente lerão seu código. Você deseja ter um código modular e fácil de reestruturar. Existem maneiras de fazer isso em Haskell, assim como há maneiras de fazer isso em qualquer outro idioma, mas os detalhes precisos irão variar.

Assim sendo, há várias diretrizes para Haskell. O Stack Overflow também possui um guia bastante abrangente. Manter a lógica de codificação simples 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, da mesma forma que com o Código Limpo.

No final, o Código Limpo e as diretrizes de codificação de Haskell lutam pela mesma coisa, mas acabam tomando seus próprios caminhos para chegar lá.

    
por 28.08.2014 / 00:41
fonte
13

Não sei se entendi o que você quer dizer com seu exemplo. Parágrafos, como ele os descreve, não requerem prolhmanidade. Ele não significa que o código deve ser lido 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.

Expressa no formato "TO paragraph" de Bob Martin, li seu exemplo como:

  • Para calcular o maximumBy , você precisa de uma função de ordenação e uma lista, e o resultado é um elemento dessa lista.
  • Para calcular o maximumBy de uma lista vazia e qualquer função de pedido é um erro.
  • Para calcular o maximumBy de uma lista xs , você passa o cursor sobre essa lista usando a função maxBy .
  • Para calcular o maxBy de dois elementos da lista, você os compara usando a função de ordenação 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 de TO" é que você pode parar de ler em um certo ponto quando tiver obtido detalhes suficientes, sem precisar pular a página para cima e para baixo. Esse é certamente o caso aqui.

Alguns nomes talvez sejam melhores, mas são convenções comuns da linguagem, especialmente ao escrever funções genéricas de ordem superior. Os nomes de funções de ordem superior também não se traduzem bem em frases verbo-imperativas, como os exemplos do livro, porque descrevem mais as relações entre os verbos.

Existem maneiras de implementar isso que não seguem as diretrizes do "parágrafo". Deixar a assinatura de tipo explícita omitiria a sentença de "visão geral" de nível mais alto. Você poderia usar uma expressão if para o tratamento de erros em vez da correspondência de padrões, o que poderia atrapalhar isso de forma inadequada com outro nível de abstração. Você poderia inserir maxBy como uma função anônima em vez de fornecer um nome que possa ser descrito mais adiante com mais detalhes.

Na verdade, acho que construções como where na verdade são um ajuste melhor para o formato de parágrafo, porque você pode usá-las para dar um nome a um detalhe mais profundo de uma forma próxima nós o expressamos em inglês e, da mesma forma, limitamos seu escopo de maneira clara ao contexto do "parágrafo".

    
por 28.08.2014 / 03:05
fonte