A volta do Paradigma Funcional para criação de Softwares comerciais

De acordo com o Wikipedia (link), a Programação Funcional (ou FP, de Functional Programming ) é um paradigma de programação que trata a computação como uma avaliação de funções matemáticas , e que evita estados ou dados mutáveis, enfatizando a aplicação de funções, ao contrário da programação imperativa comumente encontrada em linguagens como Java e C# , que enfatizam mudanças no estado dos programas. Este paradigma nasceu de um modelo de computação criado por Alonzo Church na década de 30, e posteriormente, com a Linguagem de Programação Lisp, desenvolvida por John McCarthy no final da década de 50, ambos no século passado. Desde então, diversas novas Linguagens Funcionais foram criadas e aprimoradas, contudo, este paradigma têm obtido maior popularidade no meio acadêmico, enquanto que no meio comercial/industrial, têm pouco espaço se comparado com a programação imperativa, com suas linguagens estruturadas e orientadas a objetos. Por muitos anos, a indústria têm considerado as linguagens funcionais como ineficientes, sendo adequadas apenas para resolver exercícios acadêmicos, e como sua sintaxe e semântica são diferentes do que os programadores comerciais estão acostumados a usar, pouco foi feito para que estas ganhassem maior popularidade.

Contudo, de alguns anos pra cá, o que se tem visto no meio comercial/industrial é uma espécie de “resgate” ao paradigma funcional, com diversas linguagens implementando recursos clássicos deste paradigma, como cálculos lambda, closures, imutabilidade, entre outros. Novas linguagens como F#, Scala e Clojure foram criadas com foco no paradigma funcional para uso comercial, e até algumas das mais populares linguagens imperativas como Java e C# , têm incorporado em sua sintaxe diversos dos conceitos encontrados no Paradigma Funcional. Em 2009, Steve Vinoski publicou um artigo chamado “Welcome to the Functional Web” (link), alertando sobre a retomada da popularidade do uso de linguagens funcionais na Web, causada principalmente pela facilidade de se trabalhar com concorrência e expressividade, resultando em performance e eficiência. O objetivo deste resumo é enfatizar com exemplos práticos, os principais fatores que levaram este paradigma a retomar seu merecido espaço, principalmente no uso comercial.

1) Expressividade

Este talvez seja um dos itens mais conhecidos dos programadores comerciais, já que é do conhecimento de muitos que, caso sejam usados corretamente, recursos do Paradigma Funcional permitem fazer “mais com menos”, ou seja, menos linhas de código para se resolver o mesmo problema. Linguagens imperativas são conhecidas por serem “verbosas”, ou seja, é necessário escrever uma considerável porção de código para resolver determinado problema, enquanto que estes podem ser muito simplificados na Programação Funcional.

Considere o exemplo abaixo, escrito na Linguagem Java, versão 7.

ex1

Este código faz um loop em um vetor de itens, e verifica para cada item, se o usuário que é enviado por parâmetro o possui. Caso sim, adiciona este no vetor, devolvendo todos os itens que o usuário possui. Considere agora o código abaixo, que resolve o mesmo problema descrito acima, contudo escrito na Linguagem Java, versão 8.

ex2

Observe que, o código acima faz uso de operadores lambda (->) e closures, se tornando muito mais expressivo que o código anterior, ou seja, faz o mesmo com menos linhas de código. Isto soa fantástico levando em consideração que está sendo utilizada uma linguagem que desde o começo foi projetada para ser imperativa, e que devido ao seu compromisso em garantir compatibilidade com versões anteriores, está limitada no que diz respeito a inovação e evolução.

Ao considerarmos uma linguagem como Scala, que não tem tantas restrições quanto a linguagem Java, além de ter sido projetada como linguagem funcional, o mesmo problema pode ser resolvido de forma ainda mais expressiva. Segue exemplo abaixo:

def possui(user: User) = items.filter(user possui _)

2) Imutabilidade

A Imutabilidade é um recurso constantemente adotado em Linguagens Funcionais, e que de alguns anos pra cá, tem sido adotado em alguns recursos das Linguagens Imperativas. Está relacionada com o fato dos objetos e variáveis não poderem ter os seus valores alterados, obrigando o compilador a sempre devolver uma nova instância com a alteração requisitada do objeto, ao invés de alterar a instância original.

Por exemplo, considere o exemplo abaixo, escrito em Java:

ex3

A variável dataCompra recebeu uma data e foi enviada como parâmetro para se calcular a data de vencimento. Antes da execução do método, foi invocado um “print” na tela para garantir que o valor mostrado é exatamente o valor que foi instanciado, ou seja, 15/08/2014. Após executar o método, é possível garantir que o valor da variável dataCompra permaneça o mesmo? Segue abaixo o resultado:

ex4

Observe que a variável sofreu um efeito colateral, ou seja, o método conseguiu modificar o valor da variável, refletindo na execução externa do método. Neste caso, a data não é um objeto Imutável, mas sim Mutável. A grande questão da Imutabilidade é que objetos imutáveis são muito mais simples de manipular do que os mutáveis, tendo um comportamento bem mais previsível. Objetos imutáveis não sofrem efeitos colaterais, pois têm comportamento previsível em relação ao seu estado, evitando um imenso desperdício de tempo para descobrir e corrigir erros por causa de efeitos colaterais em objetos mutáveis.

Claro que é possível implementar Imutabilidade em Linguagens Imperativas, criando cópias defensivas de objetos, ou seja, os atributos podem ser encapsulados em uma classe, e toda vez que forem retornados, um novo objeto clone é retornado, ao invés do objeto original. Contudo, o que está sendo feito é um mero “Work Around” para resolver tal problema. O ideal é que a Imutabilidade seja nativa, como acontece por exemplo, na classe String da Linguagem Java.

Uma consequência interessante da Imutabilidade está no fato das variáveis não mudarem, ou seja, nascem e morrem com o mesmo estado. Programando no Paradigma Funcional, praticamente se extingue a necessidade do uso de variáveis globais, que podem interferir no retorno das funções. Na programação imperativa,a saída da função depende o argumento de entrada e o estado atual do programa. Na programação funcional, funções apenas dependem de seus argumentos de entrada. Em outras palavras, quando uma função for chamada mais de uma vez com o mesmo valor de entrada, esta sempre obterá o mesmo valor de saída, semelhante ao que acontece na matématica, uma vez que, por exemplo, sempre que a função na figura abaixo for chamada com entrada “5”, o valor retornado sempre será 27. Essa abordagem facilita bastante os testes dos sistemas, possibilitando automações, eliminando erros e redundâncias, deixando o código-fonte mais modular.

f(x)2

Caso tenha interesse em ler mais sobre Imutabilidade, o livro “Introdução à Arquitetura e Design de Software” aborda sobre o tema. Segue link

3) Concorrência

Dean Wampler escreveu em seu livro “Programação Funcional para Desenvolvedores Java” (link) que aprender a escrever software com concorrência
robusta não é mais algo opcional. Isso faz todo o sentido, quando olhamos para os processadores atuais, que possuem praticamente a mesma frequência dos processadores de 4 ou 5 anos atrás, contudo com mais núcleos, cache e otimizações. As fabricantes de processadores (AMD e Intel) tiveram que tomar este rumo com os processadores por um simples motivo: os antigos processadores estavam atingindo velocidades (ou frequências) muito altas e logo não haveria sistema de refrigeração eficiente o suficiente para que eles não chegassem a temperaturas tão altas. Com isso, os processadores multicore ganharam espaço, e a tendência é que cada vez mais núcleos sejam adicionados nos processadores.

Contudo, para usufruir de um processador multinúcleo, os Softwares devem ser projetados para executarem tarefas em paralelo, ou seja, multithread. Processadores com mais de um núcleo podem executar mais de uma thread simultaneamente, contudo, para se aproveitar deste benefício, deve-se ter o mínimo de travas (ou locks) possível, ou seja, quanto mais travas em threads originadas por áreas de regiões críticas, mais tempo as threads dos demais núcleos estarão paradas esperando que a execução dentro da região crítica termine. E regiões críticas são definidas porque é a solução a ser utilizada quando se manipula memória compartilhada.

Linguagens Funcionais oferecem nativamente uma alta escalabilidade com sincronização e concorrência multithreads, em virtude principalmente das variáveis imutáveis. Com a tendência de cada vez mais núcleos nos processadores, as linguagens serão obrigadas a oferecer a máxima escalabilidade possível para execuções multithreads.

Conclusão

Com novas linguagens funcionais para uso comercial, recursos de Programação Funcional sendo adotados em Linguagens Imperativas, e com esta série de vantagens, como por exemplo a concorrência, é inevitável que ao menos os princípios de Programação Funcional retomem o seu merecido espaço na criação de Softwares comerciais. IDEs como a versão 8.0 do NetBeans já estão utilizando Sistemas de Recomendação para sugerir ao Programador que modifique o código escrito para os princípios do Paradigma Funcional, seja sugerindo que um loop simples seja modificado para uma instrução Lambda, ou que atributos se tornem imutáveis utilizando o modificador final, como mostra a figura abaixo.

ex5

ex1

About CarlosEduardoXP

Especialista em desenvolvimento de Sistemas Distribuídos, sempre aplicando boas práticas e padrões difundidos na comunidade. Auto didata, fanático por refatoração e performance, sempre buscando reutilização e testes automatizados cada vez mais eficazes.
This entry was posted in Software Development. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s