English version is available here.
Elm é uma linguagem de programação criada por Evan Czaplicki e uma definição recorrente usada para descrevê-la é:
"Uma linguagem de programação agradável para desenvolvimento de aplicações web confiáveis" - página inicial do site do Elm.
Adoro essa descrição pois mostra bem a filosofia da linguagem e de sua comunidade. Uma definição mais formal poderia ser algo como: Elm é uma linguagem de programação funcional pura com estrutura de dados imutáveis, soundness type system, currying, e blá blá blá. Mas ao invés disso, o autor preferiu destacar em sua definição a sua real intenção: criar uma linguagem segura e que as pessoas desenvolvedoras web sintam prazer em usar. O resto é consequência disso!
Mas como você deve saber, existem várias outras alternativas ao JavaScript para desenvolvimento de webapps. A maior parte delas (incluindo Elm) é formada por linguagens que são transpiladas para JavaScript. Uma lista de algumas alternativas famosas (e outras não tão famosas assim), incluem: CoffeScript, TypeScript, Reason, ReScript, PureScript, Blazor, ClojureScript, ...
Com tantas opções, quais seriam as principais característica de Elm que a faz ser tão "deliciosa" e única?
As principais diferenças de Elm
Funções puras
São vários fatores que fazem com que eu goste muito desta linguagem, mas se tivesse que destacar apenas uma característica técnica que a torna tão diferente das demais soluções, seria: Elm é uma linguagem pura.
Isso significa que todas as funções que escrevemos em Elm são obrigatóriamente puras, ou seja, não podem ocasionar efeitos colaterais. Já expliquei de forma detalhada o que são função puras nesse artigo e neste vídeo.
Esta característica força uma maneira diferente de se desenvolver software. De certa forma, ela te priva de uma série de possibilidades mas que, em conjunto de uma arquitetura pensada para isso, consegue tornar o desenvolvimento muito mais previsível, seguro, fácil de testar e de manter.
Ao descobrir que Elm era uma linguagem pura, a primeira pergunta que me fiz foi:
🤔 Mas como é possível desenvolver uma página dinâmica sem fazer uma chamada REST?? Afinal, isso é uma forma de efeito colateral!
E se você também ficou curioso ou curiosa, saiba que é possível sim. Mesmo que todas as funções que você implementa sejam puras, existe uma runtime capaz de realizar (de forma muuuuito controlada) alguns tipos de efeitos colaterais, incluindo o acionamento de serviços REST. Mas para entender como isso é possível, você terá que dar seus primeiros passo no mundo do Elm e ler o guia para iniciantes. Ele é bem curtinho e muito fácil de seguir. Mesmo que nunca desenvolva um projeto real em Elm, é provável que encontre ali ideias que vai conseguir reaproveitar em outras linguagens e frameworks. Foi só depois de ler este guia e entender como a arquitetura do Elm funciona que finalmente consegui entender, por exemplo, como funcionam o React, Flutter, Redux, MobX e similares! 😉
Mas essa não é a principal característica que me faz gostar tanto de Elm.
Mensagens de erro amigáveis
Outra particularidade exaltada dentro da comunidade Elm, é a capacidade do seu compilador de gerar mensagens de erro extramemente amigáveis. Essa é uma preocupação constante e em cada nova versão as mensagens ficam mais claras. Segundo este post, o objetivo é que as mensagens de erro não só apontem as falhas mas consigam também ensinar a sintaxe da linguagem. Isso ajuda principalmente o pessoal mais iniciante a entender o paradigma funcional.
Mas esta não é a principal característica que me faz gostar tanto de Elm.
Imutabilidade
Um fator bem interessante desta linguagem é que todas as estruturas de dados são imutáveis. Uma vez atribuido um valor a uma variável, ela não pode ser alterada dentro do mesmo escopo. Ou seja, o seguinte código é inválido em Elm:
x = x + 1
Se você entrar no REPL (executando o comando elm repl
) e tentar executar o código acima, receberá a seguinte mensagem de erro:
> x = x + 1
-- CYCLIC DEFINITION ------------------------------------------------------ REPL
The `x` value is defined directly in terms of itself, causing an infinite loop.
2| x = x + 1
^
Are you are trying to mutate a variable? Elm does not have mutation, so when I
see x defined in terms of x, I treat it as a recursive definition. Try giving
the new value a new name!
Maybe you DO want a recursive value? To define x we need to know what x is, so
let’s expand it. Wait, but now we need to know what x is, so let’s expand it...
This will keep going infinitely!
Hint: The root problem is often a typo in some variable name, but I recommend
reading <https://elm-lang.org/0.19.1/bad-recursion> for more detailed advice,
especially if you actually do need a recursive value.
A primeira vez que vi esta mensagem quase caí da cadeira. Como assim não posso incrementar o valor de x??? Foi a primeira linguagem que conheci em que isso era proibido! Mas no fundo sempre achei que incrementar uma variável não fazia o menor sentido. Na matemática, o seguinte sistema de equações é considerado inválido:
Olhando desta forma, não parece óbvio que se x tem o valor 1, ele (neste escopo) nunca poderia ser igual a ele mesmo mais um? Então por que isso foi normalizado no mundo da programação?
Conto um pouco mais sobre este tema e como foram meus primeiros passos no mundo da programação funcional neste artigo.
Talvez você esteja se perguntando como seria possível desenvolver um sistema inteiro sem poder alterar (reatribuir) valores de variáveis. E este foi um dos motivos de me aventurar nesta linguagem. Eu tinha que entender como isso seria possível! Com o tempo fui percebendo como a imutabilidade me ajuda a criar códigos mais simples e evita uma série de bugs.
Mas essa ainda não é a principal característica que me faz gostar tanto de Elm.
Ausência de referência nula
Todo mundo que programa em JavaScript já se deparou com o famoso undefined is not a function
!
Já falei sobre como as mensagens de erro em Elm são pensadas com muito carinho e, por isso, uma mensagem tão vaga e genérica como essa nunca iria aparecer em um código feito em Elm.
Mas o compilador do Elm vai muito além disso. Como já descrevi neste artigo, a possibilidade de atribuir uma refência nula a uma variável traz uma série de problemas e ficou conhecido como "o erro de um bilhão de dólares". E Elm tomou a atitude mais direta e sensata para resolver este problema: eliminou completamente a possibilidade de criar referências nulas! Utilizando artifícios como Maybe, o compilador do Elm consegue tratar todos os cenários onde um valor ausente precisa ser representado.
Elm ainda traz outros conceitos similares, mas com outros propósitos, como o uso do Result ao invés das infames exceptions.
Mas essa ainda não é a principal característica que me faz gostar tanto de Elm.
Ausência de erros em tempo de execução (runtime)
Outra característica que chama muita atenção e tem bastante destaque dentro da comunidade Elm é a ausência de erros em tempo de execução.
É praticamente impossível de se gerar falhas inesperadas durante a execução de aplicações escritas em Elm. Existem relatos de sistemas com mais de 600.000 linhas de código Elm que não apresentam erros inesperados (aquelas exceções sem tratamento) durante sua execução.
Quem programa em JavaScript sabe que, por mais que se tome cuidado, erros vão escapar em situações inusitadas. Em Elm isso não acontece. Se há a possibilidade de ocorrer um problema, o compilador vai te mostrar onde e como ele pode ocorrer e irá te obrigar a tratar todas as possíveis situações. É como programar com alguém te ajudando o tempo todo a não fazer besteiras!
Discuto este tema mais em detalhes neste artigo.
Mas essa ainda não é a principal característica que me faz gostar tanto de Elm.
Um incrível sistema de gerenciamento de pacotes
Toda pessoa desenvolvedora JavaScript já xingou o NPM pelo menos algumas vezes na vida. Quem nunca ficou horas tentando encontrar um erro obscuro para depois apagar o node_modules
, baixar as dependências novamente e tudo passar a funcionar como em um passe de mágica, sem nunca encontrar a fonte real do problema? Pelo menos comigo, isso já aconteceu inúmeras vezes.
E quando tenho que atualizar as dependências do projeto JavaScript? Sempre vem aquele frio na barriga! Aquelas mensagens estranhas de erro na console e horas tentando encontrar o motivo de uma função não ser mais encontrada. Um simples minor update de uma biblioteca pode trazer o caos e me fazer ganhar muitos novos fios de cabelo branco.
Já o gerenciador de pacotes do Elm não costuma me deixar na mão. Primeiro porque ele obriga o uso de versionamento semântico. Por exemplo: se uma pessoa que mantêm um pacote tentar subir uma nova versão modificando a assinatura de uma função pública e ela alterar apenas o último número (minor) da versão do pacote, o envio da nova versão será recusado! Graças às funções puras e um excelente sistema de tipos, o servidor é capaz de perceber esta situação e invalidar o envio.
E ainda ganhamos algumas funcionalidades muito legais de brinde. É possível, por exemplo, comparar o que foi alterado de uma versão para outra de um pacote, utilizando o comando elm diff
seguido do nome e as versões que quer comparar:
elm diff Microsoft/elm-json-tree-view 1.0.0 2.0.0
This is a MAJOR change.
---- JsonTree - MAJOR ----
Changed:
- parseString : String -> Result String Node
+ parseString : String -> Result Error Node
- parseValue : Value -> Result String Node
+ parseValue : Value -> Result Error Node
O exemplo acima mostra que da versão 1.0.0 para a 2.0.0 do pacote elm-json-tree-view
, o retorno da função parseString
, que antes era Result String Node
, passou a ser do tipo Result Error Node
.
Desconheço outra linguagem que tenha um gerenciado de pacotes que consiga fazer isso. 😃
Outra grande vantagem em relação ao NPM é que todas as funções de terceiros, importadas através de pacotes Elm, também são puras. Ou seja, são incapazes de realizar quaisquer tipos de efeitos colaterais sem o seu consentimento. Isso traz uma garantia forte em termos de segurança. Enquanto ao importar uma dependência através do NPM, ela vai ter permissão para fazer tudo que quiser, sem qualquer tipo de controle.
Mas essa ainda não é a principal característica que me faz gostar tanto de Elm.
Equilíbrio
Minha carreira sempre girou em torno de linguagens orientadas a objetos, em especial, Java. Mas por volta de 2017 comecei a me aventurar no mundo da Programação Funcional. Neste artigo conto um pouco dos motivos que me levaram para este paradigma.
Quando comecei a ler sobre este universo, uma linguagem que aparecia de forma recorrente era Haskell. Era uma espécie de lugar sagrado onde as pessoas que realmente entendiam do assunto iam parar. Deslumbrado pela possibilidade de encontrar meu cálice sagrado, comecei a me aventurar nesta linguagem. Logo no início percebi que o caminho seria mais tortuoso do que imaginava. Entre idas e vindas, li alguns livros e fiz alguns cursos. Mas a curva de aprendizado era mais íngrime do que eu esperava!
Experimentei diversas abordagens diferentes, desde tentar aprender um framework mais pragmático como o IHP (uma espécie de "Ruby on Rails" do mundo Haskell), até livros e cursos bem téoricos sobre Teoria das Categorias e Cálculo Lambda. Gostaria de dizer que encontrei uma forma de diminuir significativamente a curva de aprendizado e me tornei fluente nesta linguagem, mas estaria mentindo descaradamente.
Mesmo não conseguindo adentrar muito afundo nesta linguagem, consegui ver uma luz no fim do tunel. Um mundo mais colorido e feliz! Mas sem muita ajuda, não consegui chegar lá. Foi frustrante, mas resolvi adiar esta jornada. Outra questão era que, mesmo que chegasse ao outro lado daquele longo caminho, dificilmente conseguiria trazer muitas pessoas comigo. Seria como convecer meus amigos a fazer uma trilha de vários dias e super difícil, prometendo que no final iriam ver uma linda cachoeira. Encontrei poucas pessoas dispostas a encarar esta jornada comigo.
Além disso tudo, Haskell foi criada dentro do mundo acadêmico e, embora hoje seja utilizada nas mais diversas áreas, ainda é bastante comum encontrar discussões dentro desta comunidade que, embora sejam interessantes, são difíceis de compreender. Existem exceções, como é o caso da iniciativa Simple Haskell. Mas acho que posso dizer que em geral é uma comunidade difícil de adentrar.
E no meio deste caminho me deparei com Clojure. Uma linguagem funcional da família LISP, muito mais simples e fácil de aprender! Em pouco tempo fui capaz de entender sua filosofia e estava já utilizando-a na prática em um sistema real no trabalho. Cheguei inclusive a criar um curso de Introdução à Programação Funcional usando esta linguagem como base. Mas, embora goste muito dela e queira ainda me aprofundar mais, sinto falta de alguns artifícios que só uma linguagem fortemente tipada e pura conseguiria prover.
E foi ao longo desta jornada que me deparei com Elm. Até então, não me interessava muito por front-end. Minha carreira foi bastante voltada ao back-end. Mas vi ali uma oportunidade de diminuir aquela curva de aprendizado. Como Elm é uma linguagem de domínio específico (desenvolvimento de webapps), ela é muito mais simples que Haskell! Decidi dar uma chance a ela como forma de me preparar para encarar Haskell depois.
E conforme fui conhecendo a comunidade Elm, fui percebendo que esta foi uma escolha muito acertada. O criador da linguagem tem uma base muito sólida em Haskell (inclusive o compilador do Elm é escrito em Haskell) e deixa claro que seu objetivo é justamente trazer os benefícios que encontrou nessa linguagem para mais pessoas. Mas isso não seria possível se trouxesse junto toda a bagagem e complexidade de Haskell.
E quando digo complexidade, não estou me referindo apenas às partes mais técnicas da linguagem, mas também todo o linguajar do seu entorno. Você não vai encontrar pessoas da comunidade Elm falando que para entender Elm é preciso antes estudar sobre Monads, Functors, Type Classes e outros tantos temas que são discutidos com frequência na comunidade Haskell. E não porque a comunidade não vê valor nisso, mas sim por que entende que é possível encontrar uma outra abordagem onde, através de um linguajar mais simples, sejamos capazes de transmitir as ideias por trás destes conceitos para mais pessoas. Posteriormente, se desejarem, podem se aprofundar nestes temas e encontrar por elas mesmas o que isso tudo significa. Mas para desenvolver uma boa webapp, não é necessário entender os detalhes de um Monad.
Por isso me identifiquei tanto com Elm. Este equilibrio entre trazer do Haskell o que realmente proporciona valor, evitando aquelas partes que são muito complexas e que agregariam poucos benefícios (pelo menos dentro do contexto de desenvolvimento de webapps), faz com que tenhamos uma linguagem muito limpa, bem desenhada e com uma curva de aprendizado muito menos íngrime.
Encontrar este equilíbrio é uma tarefa bem difícil. As pessoas desenvolvedoras mais avançadas, que conhecem artifícios mais complexos e buscam um nível de abstração maior, podem se frustrar e considerar Elm uma linguagem simples demais. Já as pessoas mais iniciantes no mundo da programação funcional, que ainda não estão acostumadas com uma linguagem de programação orientada a expressões, podem sofer ao descobrir, por exemplo, que todo if precisa de um else.
Enfim chegamos ao motivo que eu acredito ser o principal que faz com que Elm seja uma linguagem de programação tão deliciosa: conseguir encontrar (pelo menos para os meus critérios) um ótimo equilíbrio nisso tudo.
E se você der uma chance e ler o guia de introdução ao Elm, talvez também se apaioxe por este paradigma e nunca mais volte a ver programação com o mesmo olhar de antes!
Bônus - Elm Fullstack?
Eu não sei se um dia vou ser conseguir compreender Haskell a fundo e ser capaz de chegar finalmente naquela cachoeira que me foi prometida. Mas quem sabe eu nem precise seguir este caminho? O Evan deu sinais de que está trabalhando para trazer o Elm também para o backend! Dia 22 de maio de 2023 irá fazer a primeira apresentação pública de seu trabalho.
Então este talvez seja o melhor momento da história para se aprender Elm! Se ficou tão empolgada quanto eu, recomendo (mais uma vez) começar pelo guia para iniciantes. Depois pode continuar pelo livro Elm in Action ou, se preferir um curso on-line, tem a sua disposição este curso na Udemy do Carlos Saltos ou este curso do Richard Feldman.
Gostou deste texto? Conheça meus outros artigos, podcasts e vídeos acessando: https://segunda.tech.
Top comments (2)
Artigo incrivel.
Me deixou com muita vontade de apreder esse linguagem.
Vou iniciar meus estudos em ELM!
Obrigado pelo comentário Victor! Fico feliz que tenha curtido! 😄