Porquê Elm: chega de dor de cabeça com front-end, chega de JavaScript
Baseado na palestra que ofereci no encontro do Grupy-SP, em 17 de setembro de 2016. O código dessa atividade está disponível no GitHub.
O problema que o Elm resolve
Para entender o porquê eu gosto do Elm precisamos falar sobre duas coisas: JavaScript e DOM.
Precisamos falar sobre JavaScript
Alguém aqui gosta de JavaScript? Eu confesso que dou risada com algumas coisas do JavaScript:
Mas deixemos os memes de canto. Arrisco dizer que quem gosta de Python não gosta de JavaScript por três motivos:
- Existem muitas formas de fazer a mesma coisa, nem todas são óbvias e nem todas funcionam em todos os navegadores. Por exemplo, aqui temos uma lista de 535 formas de recarregar uma página. Bateu aquela saudades do there should be one – and preferably only one – obvious way to do it, né?
- Debugar JavaScript é difícil pois as mensagens de erro padrão são péssimas. Por exemplo, tentar pegar o primeiro elemento de uma lista vazia, no JavaScript, vai te retornar apenas undefined. Bateu saudades do IndexError: list index out of range, né?
- O código é verboso demais no JavaScript — mas reconheço que isso é muito subjetivo. De qualquer forma, quem está acostuamdo com as list comprehensions do Python acha um absurdo usar for (var i = 0; i < myList.length; i++) { … }.
“Maybe this new JavaScript framework will compensate for the fact I haven’t actually learned JavaScript properly” - every front-end dev.
— I Am Devloper (@iamdevloper) September 22, 2015
Mas não podemos nos livrar do JavaScript – pelo menos não tão cedo. Ele roda em todos os navegadores, assim é a linguagem padrão disponível para UI e UX na web, seja em computadores, tablets ou celulares.
E, por sorte, existem coisas boas no JavaScript!
Esse livro da foto, e essa palestra do mesmo autor, desmisitificam uma crítica muito comum: JavaScript é lento. Não é. O que é lento é o DOM, ou, mais precisamente, alterar o DOM. Então vamos falar sobre o DOM.
Precisamos falar sobre DOM
O problema com o DOM é que a cada alteração mínima na página, o JavaScript tem que processar a nova entrada, pedir permissão ao navegador para alterar o DOM, destruir o nó que vai ser substituído no DOM, criar o novo nó, recalcular como renderizar a página atualizada (incluindo processar todos os estilos CSS), avisar o navegador que a mudança foi feita e atualizar as referências ao DOM no JavaScript. Tudo isso, digamos, a cada mudança que ocorre na tela (sem que a página toda seja recarregada).
Imagine você no Gmail ou Facebook: uma mensagem nova chega no chat, tem uma notificação com o número de mensagens que aparece, a janela de chat aparece e pisca, o nome da pessoa fica diferente na lista de amigos. E ao mesmo tempo a página segue mudando com mais um email, mais um comentário, etc. Cada coisinha dessa requereria uma sequência como a do parárafo anterior. É muita alteração no DOM e isso tende a ser custoso.
Para resolver esse problema a ideia foi criar um DOM virtual. A cada mensagem nova no chat, ao invés do JavaScript sair alterando cada coisinha no DOM, primeiro ele processa todas as alterações em um DOM virtual. Depois ele compara o DOM virtual com o DOM real e altera-o uma única vez. Essa é a estratégia de vários frameworks como o React e o Vue, ou mesmo a estratégia de front-end do AngularJS ou do Ember.js.
“The Top 100 JavaScript Frameworks of 2015″
— I Am Devloper (@iamdevloper) November 2, 2015
ಠ_ಠ this is an issue.
Isso resolveu o problema do custo da alteração do DOM. Mas não resolveu a nossa dependência do JavaScript para isso. Até que chegou o Elm.
Bem vindo, Elm
O Elm chegou com várias promessas ótimas. Ele promete ser mais rápido que as alternativas mencionadas anteriormente:
E, entre outras coisas, promete no runtime exceptions, ou seja, sem erros na hora do usuário executar a aplicação. A NoRedInk, pioneira na adoção do Elm, tem uma aplicação em Elm de mais ou menos 36 mil linhas, rodando há 1 ano. Zero erros reportados.
Mas… como o Elm consegue? Esse é o foco da palestra.
Primeiros passos
O primeiro passo para entender como o Elm consegue resolver esse problema é entender que ele não é só uma linguagem que compila para JavaScript. Ele oferece um ambiente de desenvolvimento único, sem paralelos com JavaScript. No final, por acaso, ele vira um .js para você integrar na aplicação. Por acaso pois ele não depende do JavaScript e, se um dia os navegadores suportarem outra linguagem, ou mesmo Elm, o JavaScript some de cena sem deixar vestígios no ambiente de desenvolvimento Elm.
Elm é uma outra linguagem, com outra lógica, e com compilador próprio. Ela é uma linguagem funcional, trabalha com constantes e expressões — sempre.
Conhecendo a sintaxe e as mensagens de erro
Depois de instalar o Elm, vamos brincar um pouco para sentir como ele é. Faremos isso abrindo o console, o read–eval–print loop, com $ elm-repl:
No Elm os tipos importam muito. E ele usa isso para verificar várias possibilidades de erro no código — e não compila enquanto você não resolver esses problemas em potencial. Vamos a alguns exemplos:
Que tal tentar juntar um número inteiro com uma string?
Reparem como a mensagem de erro é clara: TYPE MISMATCH te diz qual o tipo do erro (o tipo de um valor não é o que o compilador espera), tem um ^^^^^^ sublinhando, na devida linha, qual valor é esse. Ainda tem uma dica: para concatenar texto, use ++ ao invés de +. E, por fim, um exclarecimento: ele diz que é o texto, e não o número, que ele acredita ser o problema pois ele começa avaliando o valor da esquerda, sempre. Se a gente tivesse colocado "Ahoy" ++ 42, ele reclamaria que o 42 não é texto.
Outro exemplo: o Maybe. Imagine uma cenário onde, por algum motivo, você precisa do primeiro elemento de uma lista. Mas imagine que por algum motivo (talvez ainda desconhecido) aquela lista chegou ali vazia. No Python temos um IndexError, como já vimos. E no Elm?
Faríamos assim com uma lista contendo três elementos. Mas repare no detalhe do tipo que essa função retornou, Just 1, e no tipo que essa mesma função retorna quando passamos uma lista vazia, o Nothing:
O Elm sabe que uma lista pode ser vazia. E não te deixa esquecer disso. Quando você for usar um valor que vem de uma lista, você tem que prever esse cenário. Por isso ele não retorna um número, no nosso caso, logo de cara. Ele retorna Just 1 ou Nothing — sendo que 1 é o primeiro item da nossa lista.
Se quisermos somente o número, sem o tipo Just <número>, podemos dizer qual é o valor padrão:
É com estruturas e lógicas como essa que o Elm consegue prometer – e cumprir — a promessa de não deixar passar erros.
Compilando e colocando a mão na massa
Mas e como desenvolvemos algo de verdade? Bom, vamos por partes.
Comecemos com um arquivo simples, Main.elm:
Todo arquivo Elm que vai ser compilado espera uma função main. E essa função main tem que retornar um Html — afinal, o Elm é pensando para produzir interfaces para navegadores.
Então importamos uma função, text, que retorna um Html. Depois definimos que a função main: ela retorna seja lá o que for que aquela função Html.text produzir quando passarmos a ela um texto "Ahoy".
A primeira linha é padrão em todo arquivo Elm: você dá um nome ao módulo que está criando ali naquele arquivo (e esse nome tem que bater com o nome do arquivo). O (..) define o que desse módulo é acessível externamente — algo com o que não precisamos nos preocupar agora (.. define que tudo é acessível externamente).
Feito isso, é só compilar: $ elm-make Main.elm. Inspecionando o diretório, vamos ver quatro arquivos:
Main.elm é o nosso código fonte. index.html é o nosso código compilado em HTML, com o JavaScript embutido, pronto para rodar no navedagor — não tenha medo, abra para ver como ficou! elm-package.json e elm-stuff são criados pelo próprio Elm para controlar teu projeto.
Se quisermos compilar somente o JavaScript, para incluí-lo no HTML separadamente, podemos: $ elm-make M


Discussion in the ATmosphere