Outro dia resolvi dar uma olhada no Java 8 e, de cara, me deparei com “Java 8 In Action“, publicado por Manning. A primeira coisa que me surpreendeu é como uma das proposições de venda exclusivas do Java 8 é a programação funcional; as funções são, agora, variáveis de primeira classe, você pode passá-las pelo seu código como se fosse um int ou uma String. Essa é uma grande mudança.
Parece que as linguagens funcionais se tornaram mais populares nos últimos anos e há inúmeras para se escolher. Exemplos de linguagens de programação modernas incluem Clojure, JavaScript, Scala, e até mesmo Erlang, inventada na década de 1980, dando um ar retrô na nossa lista.
Então, por que existe essa mudança de direção? Você pode até achar várias razões, mas vamos começar com a premissa de que a indústria de melhores práticas muda ao longo do tempo e até mesmo as linguagens mais populares um dia vão cair em desuso. Imagino que se você ainda é jovem o suficiente, um dia vai olhar para trás e falar: “Lembra quando costumávamos usar o Java?” Antes de verificar o porquê da existência dessa mudança, vamos refletir sobre como chegamos aqui dando uma volta na década de 1980…
Segundo a Wikipedia, o PC da IBM foi lançado em 12 de agosto de 1981. Os primeiros PCs foram entregues com BASIC (1), apesar de os “caras legais” logo terem se cansado disso e mudaram para Turbo Pascal da Borland. A novidade do Turbo Pascal não durou muito tempo, porque a Microsoft comprou a Microsoft C (ou MSC), que logo se tornou, de fato, o padrão. Foi legal porque se você fosse inteligente poderia acessar o hardware diretamente, usando int 21H, int 10H e int 14h e outros, e se me lembro qual interrupção fez o quê, então você é velho como eu (2)…
Existiram outros computadores antes do PC da IBM, incluindo Apple II, Commodore Pet etc., mas o PC da IBM era um PC “adulto” para aplicações voltadas para negócios. Eu me lembro de tentar comprar um para um projeto que fiz em 1985, que custou milhares de libras e você não conseguia um nem por amor nem por dinheiro, todo mundo queria um; no entanto, eu discordo.
No final de 1980, veio o Microsoft Windows SDK, baseado em C, que está por aí desde Windows 1 foi construído (aparentemente a Microsoft não usou janelas sobrepostas no Windows 1, porque copiou a Macintosh da Apple e provavelmente violou suas patentes – mesmo que a Apple tenha, supostamente, roubado a ideia para o Mac da Xerox Parc; se isso é verdade, eu não eu não tenho como confirmar). O SDK realmente decolou no Windows 2, apresentando ao mundo o callback, programação baseada em mensagens; uma ideia que eles supostamente roubaram do X-Windows e Motif no Unix.
Lá pelos meados dos anos 90, linguagens se tornaram orientadas a objeto; classes foram inventadas para unir métodos e dados, introduzindo os conceitos de ocultação de dados e encapsulamento. ‘C’ se tornou ‘C++’ e se você usava o Windows SDK nessa época, então você migrou para Microsoft Foundation Classes; um wrapper OO ao redor do SDK. Essa mudança foi vista como uma coisa boa. Um grande problema com as antigas funções baseadas em linguagens era que você poderia alocar variáveis globais em qualquer lugar em sua base de código e alterá-las usando qualquer função a qualquer momento. Isso, obviamente, causou grandes estragos em vários sistemas, já que você não podia ter certeza de que mudando o estado de uma variável global não introduziria um bug num cantinho escondidinho do seu aplicativo. O outro grande problema com a linguagem C era que você era responsável pela alocação e desalocação de memória e se os ponteiros de memória eram globais, então, quando você os acessava, poderia não ter 100% de certeza que o ponteiro ainda era válido e, se não fosse, você estava perdido.
Junto com as linguagens orientadas a objeto surgiram as metodologias orientadas a objeto, culminando no final de 1990 com o UML. Isso foi uma fusão do Método Booch, OMT de James Rumbaugh e OOSE de Ivor Jacobsen, e eram rigorosas quando se tratava de projetar o software. Todos os tipos de ferramentas estavam disponíveis para o trabalho de documentar e comunicar os seus projetos e, por experiência própria, alguns deles eram de qualidade bem duvidosa, o que acaba levantando a questão: os desenvolvedores realmente estavam usando UML para escrever seus programas UML? Se sim, então esses produtos não eram realmente uma boa propaganda para UML.
Atualmente, você não vê muitas organizações por aí usando UML, embora eu ainda o faça quando preciso de um design direto na minha cabeça. Minha primeira escolha da ferramenta UML é, e sempre será, lápis e papel. É simples e funciona.
Finalmente, em minha breve história da programação, temos o Java. Inicialmente lançado em 1995 e se tornando popular alguns anos depois, o Java foi baseado na ideia de melhoria do C++. Isso, principalmente, porque ele é executado em sua própria máquina virtual, que cuida da alocação e desalocação de memória para você. Tornou-se um verdadeiro padrão das linguagens orientada a objeto.
O detalhe desse cronograma amplamente constituído é o conceito sob pinning de programação imperativa. Em resumo, a linguagem Assembly deu origem a C, C para C++ e OO, e C++ e OO levando para Java – todas as imperativas. A Wikipedia oferece uma boa visão geral de programação imperativa, então eu não vou entrar em detalhes, mas vou resumir a programação imperativa aquela com funções e estado mutável, o que significa que você pode ter variáveis globais e de instância.
Como a programação funcional difere de programação imperativa? A ideia principal é que as funções são dados, assim como inteiros e strings; algoritmos são implementados em termos de chamadas de função (loops while e for não existem, você usa recursão) e as variáveis são sempre locais.
Você poderia ser forçado, de forma enganosa, a pensar que, por ter o conceito de uma função e não de classes, linguagens como C e Turbo Pascal são linguagens de programação funcional. Elas não são. São linguagens de programação imperativas, porque têm os dados de estado.
Então, o que mudou? A resposta que foi dada pelos desenvolvedores Erlang, e que você vai encontrar no livro de Manning Java 8, é que foi o hardware que mudou. “Computadores”, pelo menos os que que você encontrará em uma sala de servidor, são agora multiprocessadores sofisticados, coisas multi-core com terabytes de memória. Tomemos, por exemplo, o servidor HP Proliant DL580 G8; ele tem até quatro processadores, e cada um pode ter até 15 núcleos de 64 bits. Isso é muita coisa, especialmente quando comparado com o Intel 8086 16bit, o PC original da IBM. Supondo que você esteja rodando Unix e que executou o comando top, então o uso máximo do processador seria dado como 6000%. Dado esse aumento considerável no poder das máquinas, os desenvolvedores de software precisam de linguagens que as suportem, permitindo que eles usem com facilidade todo esse poder de processamento, e é aí que entra a programação funcional.
Na programação imperativa, você pode ter variáveis de instância, variáveis globais e estado mutável. Eles podem ser compartilhados entre threads, embora compartilhar esses recursos seja dispendioso e ineficiente em termos de sincronização e bloqueio. É também bem lento e difícil de fazer, pois você precisa evitar conflitos e outros problemas parecidos. A programação funcional elimina todos esses problemas, porque acaba com toda a tediosa perda de tempo com variáveis de instância e estado. Isso significa que você não tem que se preocupar com, bloqueio, sincronização, thread ou processos (chame-os como quiser) pois eles podem ser independentes uns dos outros.
Essa é a teoria, mas isso aguenta exames mais aprofundados? Não nos esqueçamos de que é possível escrever bons programas multi-threaded que usam de forma eficaz os vários núcleos de um multi-core e multi-processador de uma máquina com Java 6 ou 7 imperativo. Assim como linguagens de programação funcional, você tem que pensar sobre o que você está fazendo, planejar um projeto apropriado e executá-lo usando as “melhores práticas” de negócios. Só porque o Java 6 ou 7 é uma linguagem imperativa, você não tem que compartilhar dados entre threads/processos e utilizar sincronização e bloqueio. Isso é só uma questão de design. A conclusão lógica é que você pode fazer issosem programação funcional, que leva, possivelmente, à verdadeira razão por trás da popularidade de linguagens de programação funcional: as pessoas gostam de usá-las!
Você poderia dizer, portanto, que as linguagens funcionais são a “última moda”, mania, tendência moda. Eu tenho que enfatizar que “moda” no desenvolvimento de software não é necessariamente uma coisa ruim e não é nada novo. Se você voltar para a minha história acima, verá que a linha do tempo está cheia de tendências e manias: a adoção de C sobre Turbo Pascal e BASIC, a mudança de paradigma de Orientação a Objeto e até mesmo a mudança para Java com suas promessas de compile once e run anywhere.
É imprescindível que você aprenda programação funcional com Java 8? Pergunte-me daqui a alguns anos…
1 – Todos os Fatos históricos neste artigo são garantidos pela minha memória falha e imprecisa.
2 – Me corrija se eu estiver errado, mas int 21H = Funções MSDOS, int 10H = acesso direto à tela, int 14H = serial I/O.
——-
Artigo de Roger Hughes, publicado originalmente no iMasters.