Existem pequenas quantidades de programação funcional compreensíveis por pessoas que não são FP? [fechadas]

43

Caso : estou trabalhando em uma empresa, escrevendo um aplicativo em Python que está manipulando muitos dados em matrizes. Eu sou o único desenvolvedor deste programa no momento, mas provavelmente será usado / modificado / estendido no futuro (1-3 anos) por algum outro programador, neste momento desconhecido para mim. Eu provavelmente não estarei lá diretamente para ajudar, mas talvez dê algum suporte via e-mail se eu tiver tempo para isso.

Então, como um desenvolvedor que aprendeu programação funcional (Haskell), eu costumo resolver, por exemplo, a filtragem como esta:

filtered = filter(lambda item: included(item.time, dur), measures)

O resto do código é OO, são apenas alguns pequenos casos onde eu quero resolvê-lo assim, porque é muito mais simples e bonito de acordo comigo.

Pergunta : está tudo bem hoje escrever código como esse?

  • Como um desenvolvedor que não escreveu / aprendeu FP reage ao código assim?
  • É legível?
  • Modificável?
  • Devo escrever documentação como explicar a uma criança o que a linha faz?

     # Filter out the items from measures for which included(item.time, dur) != True
    

Eu perguntei ao meu chefe, e ele apenas diz "FP é magia negra, mas se funciona e é a solução mais eficiente, então não há problema em usá-lo."

Qual é a sua opinião sobre isso? Como programador não-FP, como você reage ao código? O código é "googable", então você pode entender o que ele faz? Eu adoraria feedback sobre isso.

    
por kd35a 30.07.2012 / 11:54
fonte

7 respostas

50

Is it readable?

Para mim: Sim, mas cheguei a entender que a comunidade Python muitas vezes parece considerar a compreensão de listas uma solução mais limpa do que usar map() / filter() .

Na verdade, o GvR até mesmo considerou eliminar completamente essas funções.

Considere isso:

filtered = [item for item in measures if included(item.time, dur)]

Além disso, isso tem o benefício de que uma compreensão de lista sempre retornará uma lista. map() e filter() , por outro lado, retornarão um iterador no Python 3.

Observação: se você quiser ter um iterador, é tão simples quanto substituir [] por () :

filtered = (item for item in measures if included(item.time, dur))

Para ser honesto, vejo pouco ou nenhum motivo para usar map() ou filter() no Python.

Is it Modifiable?

Sim, certamente, no entanto, há uma coisa para tornar isso mais fácil: Faça disso uma função, não um lambda.

def is_included(item):
    return included(item.time, dur)
filtered = filter(is_included, measures)
filtered = [item for item in measures if is_included(item)]

Se a sua condição se tornar mais complexa, isso será muito mais fácil, além de permitir que você reutilize seu cheque. (Note que você pode criar funções dentro de outras funções, isso pode mantê-lo mais próximo do local onde é usado).

How does a developer that hasn't written/learned FP react on code like this?

Ele faz o google na documentação do Python e sabe como funciona cinco minutos depois. Caso contrário, ele não deveria estar programando em Python.

map() e filter() são extremamente simples. Não é como se você estivesse pedindo para eles entenderem as mônadas. É por isso que não acho que você precise escrever esses comentários. Use bons nomes de variáveis e funções, então o código é quase auto-explicativo. Você não pode prever quais recursos de idioma um desenvolvedor não conhece. Por tudo que você sabe, o próximo desenvolvedor pode não saber o que é um dicionário.

O que não entendemos geralmente não é legível para nós. Assim, você poderia argumentar que não é menos legível do que uma compreensão de lista, se você nunca viu nenhum deles antes. Mas como Joshua mencionou em seu comentário, eu também acredito que é importante ser coerente com o que outros desenvolvedores usam - pelo menos se a alternativa não fornecer nenhuma vantagem substancial.

    
por 30.07.2012 / 12:46
fonte
24

Como a comunidade de desenvolvedores está recuperando o interesse na programação funcional, não é incomum ver alguma programação funcional em linguagens que eram originalmente totalmente orientadas a objetos. Um bom exemplo é o C #, onde tipos anônimos e expressões lambda permitem ser muito mais curtos e expressivos por meio de programação funcional.

Dito isto, a programação funcional é estranha para iniciantes. Por exemplo, quando durante um curso de treinamento, eu expliquei aos iniciantes como eles podem aprimorar seu código através da programação funcional em C #, alguns deles não estavam convencidos, e alguns disseram que o código original era mais fácil de entender para eles. O exemplo que dei a eles foi o seguinte:

Código antes de refatorar:

var categorizedProducts = new Dictionary<string, List<Product>>();

// Get only enabled products, filtering the disabled ones, and group them by categories.
foreach (var product in this.Data.Products)
{
    if (product.IsEnabled)
    {
        if (!categorizedProducts.ContainsKey(product.Category))
        {
            // The category is missing. Create one.
            categorizedProducts.Add(product.Category, new List<Product>());
        }

        categorizedProducts[product.Category].Add(product);
    }
}

// Walk through the categories.
foreach (var productsInCategory in categorizedProducts)
{
    var minimumPrice = double.MaxValue;
    var maximumPrice = double.MinValue;

    // Walk through the products in a category to search for the maximum and minimum prices.
    foreach (var product in productsInCategory.Value)
    {
        if (product.Price < minimumPrice)
        {
            minimumPrice = product.Price;
        }

        if (product.Price > maximumPrice)
        {
            maximumPrice = product.Price;
        }
    }

    yield return new PricesPerCategory(category: productsInCategory.Key, minimum: minimumPrice, maximum: maximumPrice);
}

Mesmo código após a refatoração usando FP:

return this.Data.Products
    .Where(product => product.IsEnabled)
    .GroupBy(product => product.Category)
    .Select(productsInCategory => new PricesPerCategory(
              category: productsInCategory.Key, 
              minimum:  productsInCategory.Value.Min(product => product.Price), 
              maximum:  productsInCategory.Value.Max(product => product.Price))
    );

Isso me faz pensar que:

  • você não deve se preocupar se souber que o próximo desenvolvedor que manterá seu código terá experiência geral suficiente e algum conhecimento de programação funcional, mas:

  • caso contrário, evite programação funcional, ou coloque um comentário detalhado explicando ao mesmo tempo a sintaxe, as vantagens e as possíveis advertências de sua abordagem versus uma programação não funcional.

por 30.07.2012 / 12:24
fonte
20

Eu sou um programador não FP e recentemente modifiquei o código do meu colega em JavaScript. Houve um pedido Http com um retorno de chamada que se parecia muito com a declaração incluída por você. Devo dizer que levei algum tempo (como meia hora) para descobrir tudo (o código não era muito grande).

Não houve comentários e acho que não houve necessidade de nenhum. Eu nem sequer pedi ao meu colega para me ajudar a entender o código dele.

Tendo em conta que estou a trabalhar há cerca de 1,5 anos, penso que a maioria dos programadores será capaz de compreender e modificar esse código, uma vez que o fiz.

Além disso, como Joachim Sauer disse em seu comentário, muitas vezes há pedaços de FP em muitas linguagens, como C # (indexOf, por exemplo). Muitos programadores não-FP lidam com isso com bastante frequência, e o trecho de código que você incluiu não é algo terrível ou incompreensível.

    
por 30.07.2012 / 12:26
fonte
3

Eu diria definitivamente sim!

Existem muitos aspectos da programação funcional, e usar funções de ordem superior, como no seu exemplo, é apenas uma delas.

Por exemplo, considero escrever funções puras como extremamente importante para qualquer software escrito em qualquer idioma (onde por " puro "quero dizer sem efeitos colaterais), porque:

  • eles são mais fáceis de testar na unidade
  • eles são muito mais compostos do que funções de efeitos colaterais
  • eles são mais fáceis de depurar

Eu também evito frequentemente a alteração de valores e variáveis - outro conceito emprestado do FP.

Ambas as técnicas funcionam bem em Python e em outras linguagens que não são comumente classificadas como funcionais. Eles geralmente são suportados pela própria linguagem (por exemplo, final variables em Java). Assim, futuros programadores de manutenção não enfrentarão uma enorme barreira para entender o código.

    
por 30.07.2012 / 18:48
fonte
2

Tivemos essa mesma discussão em uma empresa para a qual trabalhei no ano passado.

A discussão envolveu "código mágico" e se deveria ser encorajado ou não. Ao olhar para ele um pouco mais, parecia que as pessoas tinham opiniões muito diferentes sobre o que realmente era "código mágico". Os que levantaram a discussão pareciam significar principalmente que expressões (em PHP) que usavam estilo funcional eram "código mágico", enquanto desenvolvedores que se originavam de outras linguagens que usavam mais estilo FP em seus códigos pareciam pensar que o código mágico era quando você fez inclusão dinâmica de arquivos através de nomes de arquivos e assim por diante.

Nós nunca chegamos a uma boa conclusão sobre isso, mais do que as pessoas pensam que o código que parece estranho é "mágico" ou difícil de ler. Então, é uma boa ideia evitar código que pareça estranho para outros usuários? Eu acho que isso depende de onde é usado. Eu evitaria usar expressões no estilo fp (inclusão dinâmica de arquivos e assim por diante) em um método principal (ou partes centrais importantes de aplicativos) onde os dados deveriam ser encapsulados de forma clara e fácil de ler, intuitiva. Por outro lado, eu não acho que se deva ter medo de empurrar o envelope, os outros desenvolvedores provavelmente aprenderão FP rapidamente se eles forem confrontados com o código FP e talvez tenham algum bom recurso interno para consultar sobre os problemas.

TL; DR: Evite na parte central de alto nível dos aplicativos (que precisam ser lidos para uma visão geral da funcionalidade do aplicativo). Caso contrário, use-o.

    
por 30.07.2012 / 12:47
fonte
2

A comunidade de C ++ também recebeu lambda, e acredito que eles tenham aproximadamente a mesma pergunta. A resposta pode não ser a mesma, no entanto. O equivalente em C ++ seria:

std::copy_if(measures.begin(), measures.end(), inserter(filter),
  [dur](Item i) { return included(i, dur) } );

Agora, std::copy não é novo e as variantes _if também não são novas, mas o lambda é. No entanto, ele é definido claramente no contexto: dur é capturado e, portanto, constante, Item i varia no loop e a única instrução return faz todo o trabalho.

Isso parece aceitável para muitos desenvolvedores de C ++. Eu ainda não experimentei opiniões sobre lambda de ordem superior, e esperaria muito menos aceitação.

    
por 30.07.2012 / 15:19
fonte
0

Poste um snippet de código para um desenvolvedor que não seja tão fluente em python, e pergunte se ele pode passar 5 minutos verificando o código para ver se ele entende.

Se sim, você provavelmente está pronto para ir. Se não, você deve olhar para torná-lo mais claro.

Poderia seu colega ser tolo e não entender algo que deveria ser óbvio? Sim, mas você deve sempre programar de acordo com o KISS.

Talvez seu código seja mais eficiente / bonito / elegante do que uma abordagem mais simples e à prova de idiotas? Então você precisa se perguntar: eu preciso fazer isso? Novamente, se a resposta for não, então não faça isso!

Se depois de tudo isso, você ainda acha que precisa e quer fazer o caminho do FP, então faça de tudo. Confie em seus instintos, eles são mais adequados às suas necessidades do que a maioria das pessoas em qualquer fórum:)

    
por 21.08.2012 / 12:01
fonte