Ferramentas do usuário

Ferramentas do site


linguagens_para_2017

Linguagens para 2017: Go e Elixir

(postado em 13/fev/2017; republicado aqui com pequenas atualizações em 30/mar/2021)

Um dos focos da ThoughtWorks é ajudar nossos clientes a criar plataformas digitais de inovação. Na visão técnica, isso implica em APIs, micro-serviços, nuvem, arquiteturas orientadas a eventos, e outros temas que acadêmicos estudam como sistemas distribuídos.

Duas empresas que dependem de sistemas distribuídos em larga escala—Ericsson e Google—criaram linguagens especialmente para enfrentar esses desafios: Erlang e Go. Elas tem pouco em comum, mas suportam sistemas que lidam com alta concorrência — por exemplo, 2 milhões de conexões em um único servidor no WhatsApp, com Erlang em 2012.

Este post dá uma visão de alto nível e dicas para saber mais sobre Go, Erlang e Elixir—uma linguagem mais moderna implementada sobre a máquina virtual de Erlang.

NOTA: Estas são opiniões pessoais. No Technology Radar da ThoughtWorks, Go está no círculo adote, Elixir em experimente, e Erlang foi citada nos temas de linguagens funcionais, linguagens concorrentes, e abstrações e padrões para concorrência. Os serviços de uma plataforma digital podem ser construídos com qualquer linguagem que permita a programação de sistemas conectados em rede. O próprio conceito de uma plataforma implica em liberdade para implementar os serviços e seus clientes nas linguagens que fazem mais sentido em cada contexto, e para cada equipe.

Alta concorrência em Go, Erlang e Elixir

Para suportar alta concorrência, tanto Erlang quanto Go oferecem — com nomes diferentes — algo como green threads, que são mais leves do que as threads gerenciadas pelo sistema operacional, como temos em Java, Python, Ruby etc. Um único programa pode executar, de modo concorrente, centenas de milhares ou até milhões de “processos” em Erlang ou “gorrotinas” em Go, aproveitando ao máximo todos os núcleos da CPU da máquina. Outra semelhança é que Erlang e Go oferecem mecanismos para troca de mensagens entre processos/gorrotinas, evitando os problemas da comunicação através de memória compartilhada que assombram a programação com threads e locks.

De resto, as linguagens são muito diferentes. Go é estaticamente tipada e compila para código de máquina, enquanto Erlang é dinamicamente tipada e compila para bytecodes que rodam em uma VM chamada BEAM.

Go é uma linguagem imperativa que propõe uma forma de programação orientada a objetos sem herança mas com “duck typing estático”—as interfaces não são declaradas nos tipos que as implementam; basta implementar os métodos certos para satisfazer uma interface, mas a aderência à interface é verificada em tempo de compilação.

Erlang é uma linguagem funcional que implementa pattern matching, uma ideia poderosa que muda as regras usuais de passagem de parâmetros e a vinculação de valores a variáveis. A explicação fica para outro dia. Por hora, saiba que pattern matching vai te fazer pensar diferente.

Há alguns anos dei uma olhada em Erlang, mas fui desestimulado por sua sintaxe pouco amigável. A sintaxe é a interface de usuário de uma linguagem. Boas interfaces de usuário aumentam a produtividade e reduzem erros. Daí surgiu Elixir, uma nova linguagem implementada sobre a VM de Erlang. Na PythonBrasil 2014 tivemos o keynote do José Valim—criador de Elixir—e assim ela entrou na minha lista de prioridades logo após Go.

Aprendendo Go

Estudei Go antes de mergulhar em Elixir por dois motivos: apostei que seria mais fácil e vi mais oportunidades de aplicação. Já temos projetos em Go na ThoughtWorks (alguns abertos no Github). Além disso, estão chegando até nós demandas envolvendo Go em vários países, incluindo no Brasil.

O primeiro contato com Go é suave, graças ao tutorial interativo online Um tour por Go. Para ir além daquele passeio, em 2015 fizemos um grupo de estudos sobre Go no Garoa Hacker Clube. Em 2016 retomei o principal exemplo daquele grupo de estudos e transformei em um tutorial sobre TDD com Go.

A referência mais importante foi lançada no final de 2015: The Go Programming Language (GOPL) de Alan A. A. Donovan e Brian W. Kernighan—o mesmo co-autor do clássico sobre C conhecido como Kernighan & Ritchie. Além de explicar com precisão, Donovan e Kernighan mostram como programar Go em estilo idiomático—sem sotaques de outras linguagens. Mas o melhor de GOPL são os exemplos variados, incluindo um gerador de gráficos logo no primeiro capítulo.

A editora Novatec lançou a edição brasileira de GOPL—A Linguagem de Programação Go—no 1º trimestre de 2017. Fiz a revisão técnica da excelente tradução de Lúcia Kinoshita—a mesma que traduziu meu livro Python Fluente com muita competência. GOPL é muito superior a todos os demais livros sobre Go que já folheei. Mas não é fácil, os autores esperam que você conheça outras linguagens. Por exemplo, saber um pouco de C ajuda a entender a sintaxe e o uso de ponteiros em Go. O livros Introdução à Linguagem Go, de Caleb Doxsey, e Go em Ação de Kennedy & Cia. são bem mais suaves, especialmente o primeiro.

Aprendendo Elixir

Assim como Erlang, Elixir é uma linguagem funcional de tipagem dinâmica que implementa pattern matching e oferece somente estruturas de dados imutáveis. Para quem nunca praticou programação funcional, aprender Elixir é aprender um novo paradigma. Inspirada em Ruby, a sintaxe de Elixir é mais familiar que a de Erlang, e é extensível através de macros sintáticas—que são usadas para criar DSLs como nos pacotes Phoenix e Ecto. Elixir traz uma biblioteca padrão mais conveniente, e ferramentas e frameworks inspirados pelas melhores práticas da engenharia de software moderna.

O mais importante é que Elixir compila para o mesmo bytecode da máquina virtual BEAM de Erlang, e assim aproveita toda a infra-estrutura reforçada por quase 20 anos de uso intensivo em produção, incluindo OTP que é provavelmente o framework mais avançado para sistemas distribuídos que qualquer pessoa pode usar em produção (talvez existam frameworks melhores em mega-empresas como Google ou NetFlix, mas se existem eles não estão compartilhando).

Estes dias estou estudando Elixir em dois livros. Depois de folhear vários, escolhi Programming Elixir, de Dave Thomas, e The Little Elixir & OTP Guidebook, de Benjamin Tan Wei Hao. O primeiro é uma indicação óbvia: Dave Thomas publicou seu livro sobre Elixir antes de todos, depois de ter apresentado Ruby para o mundo e co-criado o clássico The Pragmatic Programmer. Mas The Little Elixir & OTP Guidebook é ainda melhor: em 296 páginas apresenta o essencial da linguagem e do framework OTP, sem se perder em detalhes que podem ser pesquisados na documentação oficial. Benjamin Tan Wei Hao é uma inspiração que quero seguir em meu próximo livro (depois do Fluent Python, Second Edition).

Assim que terminar as leituras iniciais de Elixir, vou estudar o suficiente de Erlang para ler Designing for Scalability with Erlang/OTP de Francesco Cesarini e Steve Vinoski. Mais do que um livro sobre a linguagem e o framework, Cesarini e Vinoski apresentam padrões de projeto para sistemas distribuídos altamente escaláveis e tolerantes a falhas. Assisti Cesarini apresentando os capítulos 13 a 16 de seu livro na OSCON 2016 e foi um dos melhores tutoriais que já vi. Ele sabe como Erlang/OTP foi usada para criar o WhatsApp (artigo na Wired).

Estou convencido de que estudar a arquitetura do OTP pode ajudar no projeto de sistemas distribuídos confiáveis em qualquer linguagem.

Encerrando por hoje

É muito estimulante conhecer duas linguagens que atacam o mesmo domínio—sistemas distribuídos—de formas tão diferentes, mas também com semelhanças importantes.

Em sistemas distribuídos é preciso suportar alta concorrência. Green threads consomem muito menos recursos que threads gerenciadas pelo SO, e são mais fáceis de depurar do que callbacks (mesmo embrulhados em Promises ou Futures). O que Erlang/Elixir chama de “processo” e para Go é uma “gorrotina”, são variantes de green threads—com a diferença que em Erlang o escalonamento é preemptivo mas em Go é cooperativo. É uma escolha: o escalonamento preemptivo consome mais ciclos de CPU trocando contextos de execução, porém torna o sistema mais resiliente.

A outra característica comum é oferecer um mecanismo para troca de dados entre processos/gorrotinas que não envolve memória compartilhada, e portanto não depende da aplicação de travas para funcionar corretamente.

Em quase tudo mais, Elixir e Go são bem diferentes, o que sugere possíveis usos complementares. Por exemplo, em um serviço de processamento de imagens na nuvem, Elixir pode ser usada para implementar a lógica de negócio e a API pública, delegando para servidores Go os processos mais intensivos em CPU.

Espero encontrar você nos próximos eventos sobre Go e Elixir por aí!

linguagens_para_2017.txt · Última modificação: 2021-03-31 08:38 por luciano