O post que você citou exagera um pouco sua afirmação. O FP não elimina a necessidade de padrões de design. O termo "padrões de design" simplesmente não é amplamente usado para descrever a mesma coisa nas linguagens FP. Mas eles existem. As linguagens funcionais possuem muitas regras de boas práticas no formato "quando você encontrar o problema X, use um código parecido com Y", que é basicamente o que é um padrão de design.
No entanto, é correto que a maioria dos padrões de design específicos de OOP sejam praticamente irrelevantes nas linguagens funcionais.
Não acho que deva ser particularmente controverso dizer que os padrões de design em geral só existem para corrigir as deficiências da linguagem. E se outro idioma puder resolver o mesmo problema trivialmente, ele não precisará de um padrão de design para ele. Os usuários desse idioma podem nem estar cientes de que o problema existe , porque, bem, não é um problema nesse idioma.
Aqui está o que a Gangue dos Quatro tem a dizer sobre esse problema:
A escolha da linguagem de programação é importante porque influencia o ponto de vista de alguém. Nossos padrões assumem os recursos de linguagem no nível Smalltalk / C ++, e essa escolha determina o que pode e não pode ser implementado facilmente. Se assumirmos linguagens procedurais, poderíamos ter incluído padrões de design chamados "Herança", "Encapsulamento" e "Polimorfismo". Da mesma forma, alguns de nossos padrões são suportados diretamente pelas linguagens orientadas a objetos menos comuns. O CLOS possui vários métodos, por exemplo, que diminuem a necessidade de um padrão como o Visitor. De fato, existem diferenças suficientes entre o Smalltalk e o C ++ para significar que alguns padrões podem ser expressos mais facilmente em um idioma que no outro. (Veja Iterator, por exemplo.)
(O texto acima é uma citação do livro Introdução aos padrões de design, página 4, parágrafo 3)
Os principais recursos da programação funcional incluem funções como valores de primeira classe, curry, valores imutáveis etc. Não me parece óbvio que os padrões de design do OO estejam se aproximando de qualquer um desses recursos.
Qual é o padrão de comando, se não uma aproximação das funções de primeira classe? :) Em uma linguagem FP, você simplesmente passaria uma função como argumento para outra função. Em uma linguagem OOP, é necessário agrupar a função em uma classe, a qual você pode instanciar e depois passar esse objeto para a outra função. O efeito é o mesmo, mas no OOP é chamado de padrão de design, e é necessário muito mais código. E qual é o padrão abstrato de fábrica, se não curry? Passe parâmetros para uma função um pouco de cada vez, para configurar que tipo de valor ele gera quando você finalmente o chama.
Portanto, sim, vários padrões de design do GoF são redundantes nas linguagens FP, porque existem alternativas mais poderosas e fáceis de usar.
Mas é claro que ainda existem padrões de design que não são resolvidos pelas linguagens FP. Qual é o equivalente FP de um singleton? (Ignorando por um momento que singletons geralmente são um padrão terrível de se usar.)
E funciona nos dois sentidos também. Como eu disse, o FP também tem seus padrões de design; as pessoas simplesmente não pensam nelas como tal.
Mas você pode ter passado por mônadas. Quais são eles, senão um padrão de design para "lidar com o estado global"? Esse é um problema tão simples nas linguagens OOP que não existe um padrão de design equivalente lá.
Não precisamos de um padrão de design para "incrementar uma variável estática" ou "ler a partir desse soquete", porque é exatamente isso que você faz .
Dizer que uma mônada é um padrão de design é tão absurdo quanto dizer que Inteiros com suas operações usuais e elemento zero é um padrão de design. Não, uma mônada é um padrão matemático , não um padrão de design.
Em linguagens funcionais (puras), efeitos colaterais e estado mutável são impossíveis, a menos que você trabalhe com o "padrão de design" da mônada ou com qualquer outro método para permitir a mesma coisa.
Além disso, em linguagens funcionais que suportam OOP (como F # e OCaml), parece-me óbvio que os programadores que usam essas linguagens usariam os mesmos padrões de design encontrados disponíveis para qualquer outra linguagem OOP. De fato, agora eu uso F # e OCaml todos os dias, e não há diferenças marcantes entre os padrões que uso nessas linguagens e os padrões que uso quando escrevo em Java.
Talvez porque você ainda esteja pensando imperativamente? Muitas pessoas, depois de lidar com linguagens imperativas a vida toda, têm dificuldade em abandonar esse hábito quando tentam uma linguagem funcional. (Eu já vi algumas tentativas engraçadas de F #, onde literalmente todas as funções eram apenas uma sequência de instruções 'let', basicamente como se você tivesse tomado um programa em C e substituído todos os pontos e vírgulas por 'let'. :))
Mas outra possibilidade pode ser que você simplesmente não tenha percebido que está resolvendo problemas trivialmente, o que exigiria padrões de design em uma linguagem OOP.
Quando você usa currying ou passa uma função como argumento para outro, pare e pense em como faria isso em uma linguagem OOP.
Existe alguma verdade na alegação de que a programação funcional elimina a necessidade de padrões de design de OOP?
Sim. :) Quando você trabalha em uma linguagem FP, não precisa mais dos padrões de design específicos de OOP. Mas você ainda precisa de alguns padrões gerais de design, como MVC ou outros itens não específicos de OOP, e precisa de alguns "novos padrões de design" específicos de FP. Todos os idiomas têm suas deficiências, e os padrões de design geralmente são como trabalhamos com eles.
De qualquer forma, você pode achar interessante tentar usar linguagens FP "mais limpas", como ML (meu favorito pessoal, pelo menos para fins de aprendizado) ou Haskell , onde você não tem a muleta OOP para recorrer quando você é confrontado com algo novo.
Como esperado, algumas pessoas se opuseram à minha definição de padrões de design como "corrigindo deficiências em uma linguagem", então aqui está minha justificativa:
Como já foi dito, a maioria dos padrões de design é específica para um paradigma de programação, ou às vezes até para uma linguagem específica. Freqüentemente, eles resolvem problemas que existem apenas nesse paradigma (consulte mônadas para PF ou fábricas abstratas para OOP).
Por que o padrão abstrato de fábrica não existe no FP? Porque o problema que ele tenta resolver não existe lá.
Portanto, se existe um problema nos idiomas OOP, o que não existe nos idiomas FP, isso claramente é uma falha nos idiomas OOP. O problema pode ser resolvido, mas seu idioma não o faz, mas requer um monte de código padrão para você contornar. Idealmente, gostaríamos que nossa linguagem de programação magicamente resolvesse todos os problemas. Qualquer problema que ainda exista existe, em princípio, uma falha na linguagem. ;)