Go: uma visão arquitetural
Do ponto de vista arquitetural, quais as vantagens e desvantagens de se adotar a linguagem Go na visão da itexto Consultoria
Temos adotado a linguagem Go e parte do seu ecossistema em alguns projetos com muito sucesso. No entanto nem tudo é lindo, há questões e riscos que devem ser levantados, e o fato de adotarmos uma ampla quantidade de tecnologias no nosso dia a dia nos permite ter uma visão mais crítica que considero um dos maiores diferenciais da itexto.
O que temos gostado
A Curva de aprendizado
Fazia um bom tempo que não encontrávamos uma linguagem tão fácil de aprender. Ao aplicarmos membros do nosso time ao aprendizado temos observado o período de uma a duas semanas para que se tornem produtivos na linguagem.
É importante ter claro o que chamamos de "produtivo":
- Ser capaz de entender código escrito na linguagem, ou seja, conhecer os construtores básicos da mesma.
- Saber integrações mínimas necessárias para o dia a dia, tais como usar um banco de dados relacional e realizar requisições contra serviços que usam o protocolo HTTP.
- Conseguir implementar endpoints HTTP usando o framework.
- Entender o ferramental básico e o processo de compilação/construção oferecido pela linguagem.
É mais comum do que você imagina: pense em usuários que estão acostumados a apenas executar os testes e a aplicação pela IDE, por exemplo, mas que delegam a implantação para um time totalmente a parte (nem que o "time" seja algum mecanismo de integração contínua)
Algo que também ajuda muito na curva de aprendizado é o ferramental. Hoje você consegue fazer essencialmente tudo usando ferramentas gratuitas, como o VS Code e seus plugins que já vão te prover tudo o que é necessário tanto para quem está dando seus primeiros passos quanto para aqueles que já tenham mais experiência com a linguagem.
Cross compilação
A cada dia que se passa a plataforma ARM se mostra mais presente: especialmente por que o custo em cloud pode ser significativamente menor (Oracle Cloud é um excelente exemplo).
Não só por causa da cloud, mas também motivado pela Apple que, ao lançar o M1, acidentalmente nos criou uma grande dor de cabeça, que se reflete na cloud: imagens Docker que não executavam nos novos (na época) Macs e que hoje temos dificuldade em executar em alguns ambientes cloud também.
Ter a possibilidade de no Linux gerar binários que serão executados em outras plataformas e sistemas operacionais é algo que tem se mostrado bastante interessante para nós no dia a dia.
Mas vai além da cloud, do ARM e do Mac: Go também pode ser usado no desenvolvimento de sistemas embarcados. Projetos como TinyGo (https://tinygo.org/) tem um valor ENORME para nós, pois nos abre oportunidades muito interessantes de negócio, conforme entramos no mercado de engenharia.
Acreditamos que a facilidade de aprendizado de Go se bem explorada pode ser uma verdadeira revolução no mercado de software embarcado, pois o torna este mercado muito mais acessível para os iniciantes.
Cold start e tempo de compilação
As aplicações Go que escrevemos costumam ter tempo de inicialização quase instantâneo. E isto para nós é muito importante, especialmente quando executadas em lambda functions.
Go é hoje para nós uma das melhores linguagens (pra mim, a melhor) quando o assunto é a escrita de lambda functions, onde o cold start pode ser um problemão se não for levado em consideração.
Não só pra lambda functions, também para aplicações que vão ser gerenciadas em ambientes como Elastic Beanstalk. Poder iniciar rápidamente uma instância em caso de falhas, especialmente no caso de aplicações que recebam tráfego intenso.
O tempo de compilação surpreende, especialmente se comparado com Rust, e consideramos importante também por tornar mais dinâmico o fluxo de desenvolvimento.
No caso do Rust também temos a inicialização instantânea do código, possibilidades interessantes de cross compilação, mas a curva de aprendizado o coloca em desvantagem em relação ao Go neste ponto.
Redução de custos na cloud devido ao baixo consumo de memória
Dinheiro não fala: dinheiro grita. E a facilidade de aprendizado de Go, somado ao baixíssimo consumo de memória que estamos experimentando (consumo de 20 a 30 mb de RAM em aplicações que recebem centenas de requisições por segundo) consegue nos reduzir custos em duas frentes importantes: desenvolvimento e infraestrutura.
Está se tornando normal poder usar as instâncias menores dos provedores cloud.
Está se popularizando o uso da GraalVM e técnicas de redução de pacotes mas ainda não é mainstream: a compilação ainda é bastante lenta e ainda não está presente no dia a dia da maior parte das equipes.
Rust aqui também se mostra como uma alternativa muito interessante para a redução de custos, porém em relação ao Go ainda perde no que diz respeito a... adivinha! Ela mesmo: a Curva de aprendizado.
Pontos de atenção
Há pontos em Go que precisam ser levados em consideração. O principal risco é: você tem altíssima produtividade na linguagem que fácilmente vira improdutividade no médio caso se não tiver cuidado.
É muito comum encontrar programas, por exemplo, compostos por um único arquivo: algo muito similar era comum no início do Node.js, por exemplo, antes da emergência de frameworks (especialmente o Express.js). Aliás, vejo muitas similaridades no Go de hoje com o Node.js de 2009.
Outro problema são estruturas de diretórios completamente aleatórias que dificultam muito a manutenção.
Falta padronização nos projetos
Você ainda encontra muitas dúvidas relativas ao modo como o código fonte deve ser organizado nos projetos apesar de oficialmente já haver uma sugestão. Uma busca rápida na Internet e você vai encontrar dúvidas como esta, relativamente recente (final de 2021).
Este comportamento é comum, especialmente em casos muito especializados, como a aplicação em lambda functions. É muito importante ao iniciar um novo projeto definir quais padrões devem ser seguidos no médio e longo prazo do projeto.
Vimos algo similar no Java antes da popularização do Maven, que foi quem realmente padronizou a estrutura de diretórios que é adotada até hoje.
Faltam frameworks
A maior parte dos frameworks que você encontra hoje em Go são para o desenvolvimento de aplicações web, mas em sua maioria são extremamente parecidos: essencialmente roteadores de requisições HTTP com algum mecanismo de interceptação de requisições.
A maior parte são o que chamamos de micro frameworks, muito similares ao que vemos no Flask (Python) ou Express.js (Node.js). Resolvem um problema específico, mas não nos ajudam a organizar os projetos com convenções que possibilitem uma melhor manutenibilidade no médio e longo prazo.
Observamos nisto a volta dos frameworks caseiros, o que se não for bem conduzido pode gerar problemas no médio e longo prazo.
Há sinais de mudança no entanto, com iniciativas como Bud, Revel (mais focado em controladores e views) que nos oferece um framework fullstack para desenvolvimento web com Go.
Você encontra hoje até mesmo alguns ORMs para Go, como GORM (não confundir com o projeto de mesmo nome para o Grails que tem a mesma função, só que para Groovy), mas ainda não tem o nível de maturidade que encontramos no Hibernate (Java) ou Entity Framework (.net).
O que digo relativo a frameworks se aplica portanto ao ecossistema Go, que ainda não é tão rico quanto o que temos em Java, .NET, Python ou Node.js.
A outra vê como uma dificuldade na adoção da linguagem (e seu ecossistema) no ambiente corporativo.
Concluindo
Go tem sido uma das ferramentas que mais me encantou nos últimos dois anos. A curva de aprendizado, desempenho e baixíssimo consumo de memória tem apresentado este ecossistema para nós como uma alternativa interessantíssima para se reduzir o custo com infraestrutura (o que é vital no caso de startups, por exemplo).
Ao mesmo tempo, é importante ter cuidado para não se apaixonar demais pela ferramenta: há limitações. A liberdade na organização do código fonte pode levar ao caos muito fácil.
Naturalmente não caberia aqui tudo o que vemos de positivo em Go. Faltou falar sobre o ferramental que acho excelente, assim como da presença de uma excelente documentação que tem nos ajudado bastante, por isto foquei apenas no que justificou, no nosso caso, a adoção de Go como, quem diria, uma alternativa ao próprio Java.
(uma alternativa, não um substituto (ainda))