3 pontos por GN⁺ 2024-01-05 | 1 comentários | Compartilhar no WhatsApp
  • O Go evoluiu ao longo de 14 anos desde que foi lançado como open source em 10 de novembro de 2009, com o objetivo não de criar apenas uma nova linguagem, mas de facilitar a construção de software de produção
  • Uma especificação formal, várias implementações de compilador, compilação cruzada fácil, garantia de compatibilidade após o Go 1.0, a biblioteca padrão e o gofmt sustentaram sua adoção
  • A concorrência, que foi um ponto forte para estruturar software de servidor, também gerou confusão porque no início não se explicou bem a diferença para paralelismo nem onde ela era adequada
  • Interfaces se tornaram a base de bibliotecas, testes, gerenciamento de dependências e design centrado em composição, enquanto a ausência de genéricos dificultou por mais de uma década o design de polimorfismo
  • Houve muitos tropeços em gerenciamento de pacotes, documentação e colaboração com a comunidade, mas o Go buscou um ambiente em que o código continue parecido e siga compilando mesmo com autores e épocas diferentes

O objetivo do Go: mais do que uma linguagem, uma forma de desenvolver software

  • 10 de novembro de 2023 marcou o 14º aniversário da abertura do Go como projeto open source
  • Quando foi apresentado em 2009, Ken Thompson, Robert Griesemer, Russ Cox, Ian Taylor, Adam Langley, Jini Kim e outros acompanharam o lançamento do projeto
  • O objetivo original do Go não era a nova linguagem em si, mas escrever software de alta qualidade de uma forma melhor
  • Na época, o gargalo não estava tanto nos recursos da linguagem, mas na complexidade de criar software moderno de servidor no Google
    • controle de dependências
    • equipes grandes e estruturas de pessoal em mudança
    • facilidade de manutenção
    • testes eficientes
    • aproveitamento de CPUs multicore e redes
  • Até hoje, o Go se define como um projeto para tornar a construção de software de produção mais fácil e mais produtiva

A identidade comunitária criada pelo mascote Gopher

  • O gopher do Go foi um dos fatores iniciais do sucesso da linguagem
  • Criado por Renee French, o gopher virou um símbolo compartilhado pelos programadores Go e uma espécie de bandeira da comunidade
  • Em conferências como a GopherCon, o gopher ajudou a criar uma atmosfera de projeto que combinava excelência técnica com diversão
  • A escolha de publicá-lo sob licença Creative Commons Attribution teve prós e contras
    • incentivou remixes e variações, fortalecendo o espírito comunitário
    • mas a exigência de atribuição também gerou debates e casos de crédito incorreto em trabalhos que Renee French não criou
  • Continuar administrando o mascote de modo a preservar seu espírito original ainda é um desafio

As escolhas técnicas que o Go acertou

  • A equipe escreveu primeiro uma especificação formal, fixando o comportamento das implementações de compilador e permitindo que várias implementações concordassem sobre o mesmo comportamento
    • havia a convicção de que um único compilador não podia servir sozinho como especificação
    • o primeiro rascunho da especificação foi escrito no 18º andar de um prédio em Darling Harbour, Sydney
  • Várias implementações de compilador ajudaram a refinar a linguagem e a especificação
    • em 7 de junho de 2008, Ian Taylor enviou um e-mail dizendo que leu o rascunho da especificação do Go e criou um frontend para gcc
    • depois disso, outras implementações compatíveis também surgiram
  • Ao tornar a compilação cruzada simples, o Go permitiu que desenvolvedores trabalhassem na plataforma que quisessem e implantassem na plataforma necessária
  • Depois de organizar a linguagem no Go 1.0, a decisão de introduzir garantia de compatibilidade teve grande impacto na adoção do Go
    • manter compatibilidade forte tem custo, mas reduz a preocupação de que uma nova versão do Go quebre projetos existentes
  • A biblioteca padrão ofereceu a maior parte do que era necessário para escrever código de servidor no século 21 e fez a comunidade trabalhar sobre a mesma caixa de ferramentas
    • no início, ela também cresceu porque não havia outro lugar para instalar código Go
    • isso ajudou a reduzir a proliferação de bibliotecas variantes e a unificar a comunidade

Ferramentas e a experiência de desenvolvimento moldada pelo gofmt

  • O Go foi desenhado para ser fácil de fazer parsing, o que facilitou a criação de ferramentas
  • No começo achava-se necessário depender de IDEs, mas como a instrumentação era simples, com o tempo as IDEs passaram a oferecer suporte a Go e surgiu o gopls
  • Junto com o compilador, vieram ferramentas auxiliares como testes automáticos, cobertura e vetting de código
  • O comando go integrou todo o processo de build, e muitos projetos puderam resolver quase tudo o que era necessário para construir e manter código Go com esse comando
  • O gofmt se firmou como uma ferramenta que impactou não só o Go, mas a comunidade de programação como um todo
    • Robert Griesemer defendeu desde o início que o gofmt fosse criado
    • antes do gofmt, formatadores automáticos quase não eram usados porque sua qualidade não era boa
    • ele reduziu o tempo gasto em discussões sobre espaços e quebras de linha
    • ao se tornar uma biblioteca internamente, o gofmt passou a permitir fazer parsing e modificação de AST e regenerar saída legível por humanos
    • isso também abriu caminho para outras ferramentas, como simplifier, analyzer e ferramentas de cobertura de código

Concorrência: poderosa, mas explicada tarde demais

  • Em 2002, o software do Google quase evitava threads, num ambiente que citava a posição de John Ousterhout de que “threads were bad” para desencorajar seu uso
  • O Go partiu da experiência de que era possível usar concorrência de forma melhor do que com pacotes de baixo nível como pthread
  • O Go teve papel importante para que o mundo da programação aceitasse a concorrência como uma ferramenta poderosa
    • especialmente em ambientes multicore e de rede
    • hoje, a maioria das linguagens mainstream oferece suporte a concorrência
  • Em vez de usar nomes como coroutine, task ou thread, o Go criou o novo termo goroutine
  • async/await é uma grande melhoria sobre pthread, mas comparado a goroutine, channel e select, pode ser mais fácil e menor para quem implementa, ao custo de devolver parte da complexidade ao programador
    • o problema de Bob Nystrom em “What Color is Your Function?” é usado como exemplo
    • o modelo CSP do Go combina bem com linguagens procedurais, mas exige complexidade de runtime para ser implementado corretamente
    • como múltiplas implementações de concorrência no mesmo ambiente podem causar problemas, o Go colocou isso na linguagem, não em uma biblioteca

Dois erros na forma de tratar concorrência

  • A equipe do Go não orientou suficientemente, no começo, sobre onde a concorrência deveria ser usada
    • o principal uso era simplificar software de servidor em bibliotecas centrais como net/http
    • não era um recurso para ser usado em todo lugar de todo programa
  • Também foi um problema explicar tarde demais a diferença entre paralelismo e concorrência
    • muitos desenvolvedores tentaram paralelizar código com goroutines para deixá-lo mais rápido, e acabaram se surpreendendo ao vê-lo ficar mais lento
    • código concorrente só pode ganhar velocidade com paralelização quando o próprio problema é paralelizável, como no processamento de requisições HTTP
  • Para compensar isso, em 2012 foi apresentada na Waza a palestra “Concurrency is not Parallelism
  • Essa explicação deveria ter acontecido antes
  • Ainda assim, o Go ajudou a popularizar a concorrência como forma de estruturar software de servidor

Interfaces e design centrado em composição

  • Interfaces são, junto com concorrência, uma das ideias centrais que distinguem o Go
  • As interfaces do Go são próximas da resposta da linguagem ao design orientado a objetos original, focado em comportamento
  • A forma dinâmica, em que não é preciso declarar antecipadamente que tipo implementa qual interface, recebeu críticas no começo, mas foi importante para o estilo de programação em Go
  • A biblioteca padrão, os testes e o gerenciamento de dependências dependem muito da natureza aberta das interfaces
  • O sort do Go é implementado como uma função que opera sobre interfaces
    • para muita gente isso era diferente do estilo orientado a objetos ao qual estava acostumada, mas era uma ideia poderosa
  • Interfaces pequenas como Reader, Writer e a empty interface se tornaram base das bibliotecas Go
    • essas três interfaces famosas têm, em média, respectivamente 2 e 3 métodos
    • conjuntos pequenos de métodos se tornaram um idiomatismo típico de Go

O longo desvio em torno dos genéricos

  • A equipe do Go via a programação genérica como algo que tendia a fazer as pessoas pensarem primeiro nos tipos e só depois nos algoritmos
    • preferia design orgânico a abstrações prematuras
    • valorizava mais funções do que containers
  • O Go incluiu na linguagem containers genéricos como map, slice, array e channel, mas não expôs essa genericidade diretamente ao usuário
  • Considerava-se que a maior parte das tarefas simples de programação era coberta por esses tipos, mas nem sempre, e esse limite incomodou parte dos usuários
  • Como interfaces eram a base da programação em Go, o novo modelo de polimorfismo precisava necessariamente se encaixar bem nelas
    • houve várias tentativas e implementações abandonadas
    • após muita discussão, houve também ajuda de teóricos de tipos liderados por Phil Wadler
  • No fim, o Go projetou genéricos generalizando interfaces de “conjunto de métodos” para “conjunto de tipos”
  • O termo “generics” vem do polimorfismo centrado em estruturas de dados e não descreve com precisão o polimorfismo paramétrico que o Go oferece, mas na prática o nome usado acabou sendo mesmo generics

Compilador: primeiro em C, depois em Go

  • O fato de o compilador inicial do Go ter sido escrito em C incomodou parte da comunidade da linguagem
    • havia quem defendesse usar toolkits como LLVM ou tornar o compilador self-hosting em Go desde o início
  • A razão de começar o compilador em C foi prática
    • para fazer bootstrap de uma nova linguagem, é preciso uma linguagem existente
    • Ken Thompson já havia escrito um compilador em C, e sua estrutura interna podia servir de base ao compilador do Go
    • se a equipe desenhasse a linguagem ao mesmo tempo em que escrevesse o compilador nela própria, a linguagem poderia acabar enviesada para escrever compiladores
  • O compilador inicial produzia código comum e tinha um interior nada limpo, mas era pequeno, familiar e fácil de modificar rapidamente
  • A adição de segmented stack com crescimento automático mostrou a vantagem dessa escolha
    • se tivessem usado um toolkit como LLVM, a integração seria difícil porque incluiria mudanças em ABI e até suporte ao coletor de lixo
  • A estrutura originalmente herdada da família de compiladores do Plan 9 também combinava bem com compilação cruzada
  • No Go 1.5, Russ Cox escreveu uma ferramenta para traduzir de forma semiautomática o compilador de C para Go
    • nessa altura a linguagem já estava madura, então a preocupação de moldá-la em torno do compilador havia desaparecido
    • depois da migração para Go, foi possível aplicar ao desenvolvimento do compilador vantagens do próprio Go, como testes, ferramentas, reescrita automática e análise de desempenho
  • Hoje também existem um compilador Go baseado em LLVM e vários outros compiladores

Operação do projeto open source e comunidade

  • Desde o começo, entendeu-se que o Go precisava ser um projeto open source para ter sucesso
  • Ainda assim, julgou-se mais produtivo desenvolvê-lo em privado até organizar a ideia central e a implementação do comportamento
    • os dois primeiros anos antes da abertura foram importantes para deixar os objetivos claros
  • Depois da abertura como open source, a contribuição da comunidade foi enorme, e Ian Taylor em especial gastou muito tempo respondendo perguntas
  • A porta para Windows foi feita inteiramente pela comunidade sob orientação de Alex Brainman
  • A equipe do Go demorou a entender a melhor forma de colaborar com a comunidade
    • achava que estava se comunicando bem, mas mal-entendidos e expectativas desalinhadas desperdiçaram tempo
  • Em vez de aceitar código rapidamente e ajeitar depois, o projeto Go escolheu garantir alta qualidade de código antes do merge
    • revisão de código obrigatória
    • atenção minuciosa aos detalhes
  • Como esse método coloca mais peso sobre a comunidade, participantes que não entendem seu valor podem sentir que não são bem-vindos
  • O histórico do repositório do projeto Go passou por SVN, Perforce, Mercurial e Git, mas Russ Cox preservou a história, e por isso o repositório Git atual ainda contém registros das mudanças iniciais em SVN
  • O Google apoia o Go, mas não define a agenda da equipe Go
    • a grande base interna de código Go no Google é usada para testar e validar releases
    • o fluxo vai do repositório público para o Google, e não o contrário
    • a equipe central do Go é paga pelo Google, mas atua de forma independente

Tentativas e erros no gerenciamento de pacotes

  • O design de packages da linguagem Go em si foi excelente, mas o desenvolvimento do gerenciamento de pacotes não correu bem
  • Especificar caminhos no import como strings comuns foi uma escolha importante e flexível
  • O problema foi que a transição de um mundo só com biblioteca padrão para um modelo de obtenção de código pela web foi turbulenta
  • A equipe inicial do Go estava acostumada ao monorepo do Google e ao hábito de fazer build sempre no head
    • não tinha experiência suficiente com gerenciadores de pacotes que lidam com múltiplas versões
    • não enfrentou desde o começo a complexidade técnica de resolver grafos de dependência
  • O trabalho em deps.dev é tratado quase como uma forma de compensação por isso
  • As tentativas de resolver o problema de gerenciamento de dependências junto com a comunidade foram bem-intencionadas, mas quando o design final apareceu, muitos membros da comunidade se sentiram excluídos
  • A experiência virou uma lição sobre como a participação comunitária realmente precisa funcionar, e desde então houve muita melhora
  • Hoje o design parece estável, tecnicamente excelente e funciona bem para a maioria dos usuários

Documentação e exemplos executáveis

  • Muita documentação foi escrita no começo, mas ela não estava no nível que a comunidade queria
  • O ponto mais ausente era a necessidade de exemplos de uso até mesmo para as funções mais simples
    • mais valioso do que dizer o que algo faz era mostrar como usar
  • Hoje a documentação inclui muitos exemplos, a maioria fornecida por contribuidores open source
  • O Go cedo passou a permitir executar exemplos diretamente na web
    • na apresentação do Google I/O de 2012, foi possível rodar no navegador trechos de código mostrando concorrência
    • Andrew Gerrand escreveu a tecnologia web que tornou isso possível
    • depois ela foi levada também ao blog e à documentação online de packages
  • The Go playground é oferecido como um sandbox público para que qualquer pessoa teste e desenvolva código livremente

Onde o Go chegou após 14 anos

  • Graças às decisões tomadas no design da linguagem e no processo de desenvolvimento, o Go se estabeleceu como mais do que uma linguagem de programação: uma forma de escrever software
  • Os seguintes fatores contribuíram para onde o Go chegou
    • uma biblioteca padrão forte que implementa a maior parte das funções básicas necessárias para código de servidor
    • concorrência como componente de primeira classe da linguagem
    • uma abordagem baseada em composição em vez de herança
    • um modelo de empacotamento que deixa claro o gerenciamento de dependências
    • ferramentas integradas e rápidas de build e teste
    • formatação rígida e consistente
    • uma postura que valoriza legibilidade acima de esperteza
    • garantia de compatibilidade
  • A comunidade Go é formada por Gophers diversos e ativos, e tem papel central no sucesso do projeto
  • Como resultado, o código Go tende a se parecer e funcionar de forma semelhante independentemente de quem o escreveu, há relativamente poucas facções usando subconjuntos diferentes da linguagem, e existe a garantia de que ele continuará compilando e rodando com o passar do tempo
  • Essas características podem ser vistas como um resultado raro entre grandes linguagens de programação

1 comentários

 
GN⁺ 2024-01-05
Opiniões no Hacker News
  • É realmente ótimo que pessoas centrais reservem tempo para deixar retrospectivas, e isso ajuda muito quem quer realmente promover mudanças hoje
    Ainda assim, acho que Rob Pike não deixou suficientemente claro o que Go fez bem. Go administrou bem não só a linguagem em si, mas também as forças atuando sobre o projeto: limitou o uso-alvo à programação de sistemas, definiu claramente a linguagem e seus princípios, manteve uma postura de priorizar a qualidade corrigindo problemas antes da distribuição e, embora controlasse rigorosamente a linguagem, os releases e a mensagem central, deu espaço para a comunidade liderar em áreas mais periféricas
    Um ponto subestimado é que o próprio Google não interferiu muito. Pode ser porque Go de fato contribuía para os objetivos do Google e era importante. Fica a dúvida se isso ainda seria possível em novos projetos hoje
    Dart quase não foi adotado fora do Flutter, o que é interessante quando comparado à realidade de que há muito mais código de aplicação do que código de sistemas. Go foi uma tecnologia central para mover software do lado do servidor do ambiente inchado do Java para contêineres nativos, e se tornou a base de grande parte da infraestrutura de aplicações web da última década. Mesmo com esse crescimento, a equipe permaneceu pequena e as figuras centrais continuaram lá, mas não sei se isso continuará assim

    • Go tem coleta de lixo e, por causa de um runtime pesado que inclui green threads, a interoperabilidade com C fica trabalhosa e lenta
      Por isso, por design, ela não é adequada como linguagem de programação de sistemas. Como no início eles próprios a chamavam assim, surgiu um mito estranho que persistiu por muito tempo, mas essa frase parece ter sido removida há alguns anos
      Go está mais para concorrente da família Java do que de C ou Rust, e isso fica claro ao ver onde ela é usada na prática. Ainda assim, por causa do sistema de tipos limitado e do excelente suporte a concorrência, ela frequentemente ocupa uma camada um pouco mais baixa na stack
    • Tenho dificuldade em concordar com a parte de que a comunidade lidera. Ainda parece muito que o Google decide
      Isso foi especialmente verdadeiro no versionamento. No começo, Go nem reconhecia o problema; quando o consenso da comunidade cresceu, esqueceram as discussões anteriores e decidiram que agora seria com modules
      Também me lembro de que eles não queriam tornar monotonic time uma API pública até a Cloudflare sofrer uma falha por causa do horário de verão
    • Eu era desenvolvedor Java e hoje gosto de Go, mas não tenho certeza se meus antigos colegas de Java gostariam de Go. Mesmo quando era uma linguagem nova, Go era meio sem graça
      No mundo Java, há a diversão de refatorar uma base de código usando recursos novos, por exemplo ótimos streams. Em Go, a diversão vem de encontrar a abstração mais simples e comum possível
    • Trabalho com Dart. Não vejo como tão fatal a crítica de que Dart não é adotado fora do Flutter
      Toda linguagem precisa de bibliotecas e frameworks adequados a um domínio específico. Flutter é um framework para escrever apps cliente em Dart; sem Flutter, por mais que você goste da linguagem Dart, teria de gastar um tempo enorme só para descobrir como desenhar pixels na tela no Android e no iOS
      Qualquer pessoa que escreve aplicações constrói sobre uma pilha de bibliotecas e frameworks. A diferença entre Go e Dart junto com Flutter é basicamente que, em Go, bibliotecas de domínio necessárias para servidores — como networking, serialização e criptografia — estão na biblioteca padrão
      Dart tem elementos básicos como coleções e assíncrono em bibliotecas embutidas, mas depende de pacotes externos como Flutter para funcionalidades específicas de domínio. Isso se deve em grande parte ao fato de Dart ter, desde muito cedo, um sistema sólido de gerenciamento de pacotes. Muitas bibliotecas centrais escritas e mantidas pela equipe do Dart também são distribuídas pelo gerenciador de pacotes em vez de embutidas, porque assim é muito mais fácil evoluí-las
      Frameworks de UI tendem a ter vida útil mais curta que linguagens, então acho melhor que Flutter não esteja cravado na biblioteca padrão do Dart. Flutter é excelente, mas eu não ficaria surpreso se algo melhor surgisse daqui a 20 anos; se, nessa época, Flutter não estiver embutido, usuários de Dart poderão migrar com mais facilidade
    • Nos layoffs, cortaram equipes centrais de FOSS, e a liderança detesta FOSS de verdade. É porque isso não fica bonito na planilha da Ruth
      FOSS de mentira como Android é tolerado estrategicamente, mas fora isso a sensação é que, se não levar a cliques em anúncios, é considerado inútil
  • Em 2012, como desenvolvedor Python, comecei a usar Go porque precisava fazer manipulação de bits para Modbus. Nunca distribuí aquele código, mas fiquei chocado com como mexer em bits e bytes simplesmente funcionava com tanta facilidade
    Dez anos depois, e após alguns trabalhos quase em tempo integral com Go, ainda me surpreende que a maior parte das coisas simplesmente funcione
    Gosto da linguagem Go e da comunidade Go. Agradeço pelo trabalho de pessoas como Rob, Ian e Russ, que criam Go, e também aprecio que esta palestra/texto trate com franqueza dos “trechos difíceis” com a comunidade
    Ainda assim, tendo passado por aquele período, é muito difícil acreditar que eles realmente não sabiam exatamente como estavam agindo, especialmente na confusão do gerenciamento de pacotes. Mesmo assim, a avaliação do texto de que agora chegaram a uma boa solução também está correta
    Espero que Go nos próximos 10 anos, e linguagens semelhantes inspiradas por ela, como Zig e Deno, continuem crescendo com comunidades saudáveis

    • O que mais gosto na equipe central de Go é que ela soube dizer “não” a todo tipo de pedido e, quanto a generics, dizer “vamos esperar pela implementação correta”
      Sou mais biólogo computacional do que programador, então meu uso de Go é irregular, mas, quando volto para Go, meu código antigo compila e a linguagem se comporta como eu espero
      Ao mesmo tempo, acho positivo que Rob Pike tenha reconhecido erros no processo de aprender a interagir com a comunidade, sem aceitar todos os recursos brilhantes que apareciam
    • Venho de Python. Hoje em dia, com ferramentas de IA como Bard e GPT-4, estou convertendo utilitários antigos em Python diretamente para Go
      Alguns funcionaram de imediato, e outros precisei ajustar um pouco porque o modelo de IA tinha informações de API um pouco desatualizadas
      Mesmo assim, o fato de copiar o programa para o servidor com scp e ele simplesmente funcionar é surpreendente em comparação com a dança que eu fazia em Python toda vez pensando “qual é o sistema venv da moda agora?”
    • Acho que Zig e Deno não são objetos de comparação tão bons com Golang. Elixir e ReasonML parecem mais parecidas; e, olhando para dentro do Google, também há Dart
  • É um ótimo texto, mas também parece bastante autocelebratório. Achei que haveria algum reconhecimento dos problemas mais profundos da linguagem, mas talvez o ponto central seja que, para eles, a linguagem é perfeita e eu é que sou o problema
    Por isso é difícil recomendar Go. Há problemas com o sistema de tipos, tratamento de erros, concorrência insegura, sintaxe simples demais, nil, valores zero padrão e muitos pacotes populares abandonados
    Hoje uso Rust como linguagem principal. O ecossistema é ativo e tem uma visão em vários aspectos em que Go não tem
    Falando de forma mais incisiva, acho que Go teve sua época quando competia com PHP como linguagem de backend

    • Acho que isso não contribui muito para a discussão. Sem pontos concretos, soa como defesa do Rust
      O primeiro parágrafo parece “não gosto”, o segundo é sarcasmo, o terceiro também é “não gosto”, o quarto é “Rust é melhor” e o quinto parece mais sarcasmo
    • Os cientistas da linhagem Plan 9 gostam demais da própria marca. Comecei a usar Go em 2012, mas desisti depois que acabaram com o deps.dev
      Alguns anos depois, no trabalho, tentei introduzir Go na equipe para concluir um projeto, mas outro engenheiro dedicou tempo a analisar a linguagem e listou os motivos pelos quais ela não era boa, e ele estava certo
      O ponto central era que ela é simples, mas pequenas coisas como tratamento de erros e imports não usados tornam o uso sofrido. Pessoalmente, eu gostava do tratamento de erros, mas não gostava do sistema de tipos
    • Usei Go antes de aprender Rust, e ver a diferença entre as duas mudou bastante minha visão
      Como eu já tinha usado OCaml, sabia o valor dos tipos Option e Result em vez de try/catch ou nil, mas usava Go por ser fácil. Só que essa facilidade traz um custo de manutenção de longo prazo. É melhor acertar as coisas desde o começo e não encarar dificuldades depois
      Não quero ser leviano, mas ouvi muitas vezes a descrição de que Go é uma linguagem que pegou os avanços dos últimos 50 anos em linguagens de programação e os jogou fora
    • Concordo com a avaliação sobre linguagens de programação, mas, em defesa de Go, ela é mais uma linguagem feita por e para pessoas que não se interessam por linguagens de programação em si
      Não digo isso em mau sentido. Rob Pike não se importa com o fato de a concorrência ser insegura ou de nil ser o erro de um bilhão de dólares, e a maioria dos usuários de Go também não
      Isso faz de Go uma boa linguagem? Não. Mas esse não é o ponto. Go é uma linguagem conveniente e boa o suficiente, combinada com ferramentas convincentes que a tornam fácil de usar. É como o Crocs das linguagens de programação
    • Aprendi Rust, mas a comunidade de usuários de Rust torna impossível gostar da linguagem. Anos se passaram e isso não mudou; se é que não piorou em vez de melhorar
      Se eu precisar de alta integridade e segurança, usaria Ada ou Ada/SPARK com verificação formal. Fora isso, Go oferece produtividade muito maior que Rust
      Pessoalmente, vejo Rust como um exemplo clássico de engenharia excessiva, assim como C++
  • Pode soar ressentido, mas há 10 anos fui ridicularizado no go-nuts e também recebi uma resposta desdenhosa de Rob Pike. Tudo porque ousei dizer que a forma como go get e os imports de módulos pela rede funcionavam, eram promovidos em toda a documentação para iniciantes e usados por toda a comunidade acabaria sendo prejudicial e míope

    • O sistema de pacotes do Go, especialmente antes dos modules, parecia uma gambiarra que anexava um comportamento externo a um sistema mais limitado, projetado para ser usado apenas dentro do monorepo do Google
      A estranha árvore de namespace global faz sentido lá dentro, e a ênfase em artefatos gerados por código versionados também é compreensível considerando que o Google inclui até artefatos de build no monorepo
    • Ainda assim, é interessante que o resultado produzido pelo Go seja melhor que o de outras linguagens
      Claro, há o problema do v2 e o eterno problema do v0. Mesmo assim, é melhor do que usar npm ou lidar com alguma coisa do Python que faz a gente fazer o sinal da cruz
    • Rob Pike acabou expondo ao mundo o quanto é ignorante em relação à teoria de linguagens de programação descoberta depois de 2000
  • Este texto parece uma versão mais pessoal do artigo publicado na ACM [1]. Ambos reconhecem que não criaram uma grande nova linguagem de programação do ponto de vista da especificação da linguagem, mas construíram muito bem as coisas ao redor dela, e isso pode ser ainda mais importante
    No texto enviado, ele diz que inventaram a abordagem de uso de interfaces e a abordagem de concorrência. Mas goroutines são como threads de Haskell, e interfaces, quando dão suporte a parâmetros genéricos como agora, ficam muito parecidas com typeclasses de Haskell. Considerando que Haskell veio antes de Go, é interessante ver programadores imperativos descobrindo de forma independente o poder de ideias da programação funcional
    Uma inovação de linguagem em Go é que uma implementação de interface não precisa declarar a interface que implementa. Do ponto de vista de segurança, isso é terrível, mas na prática quase não causa problemas e elimina os horríveis problemas de dependência circular que se encontram em Haskell e Rust
    [1] https://cacm.acm.org/magazines/2022/5/260357-the-go-programm...

    • Acho que você subestima o quanto o fato de interfaces serem tipos estruturais foi importante para o efeito geral desse recurso sobre a linguagem e, além disso, sobre os idiomas de uso e o ecossistema
      Se um tipo tivesse que declarar antecipadamente quais interfaces implementa, Go teria sido uma linguagem completamente diferente. Esse foi um dos principais diferenciais de Go. Pelo menos até TypeScript aparecer com interfaces de tipos estruturais por outros motivos
    • Tipos estruturais já são um conceito com mais de 25 anos e já eram usados em linguagens como OCaml e Scala
    • Não sei como isso é uma inovação. Todas as linguagens mainstream anteriores a Go que me vêm à cabeça funcionam desse jeito
      Dá para citar ao menos uma linguagem de programação que valha nossa atenção e que obrigue a fornecer explicitamente a implementação de uma interface quando ela é definida?
  • Parece que os problemas relacionados a criptografia do Go ainda não foram muito comentados. Depois que o OpenSSH abandonou o SHA1, a equipe do Go levou um ano para adicionar suporte a SHA2 em x/crypto/ssh [1]. O Gitea foi uma vítima conhecida [2]
    Além disso, ver um mantenedor de criptografia atacando o GnuPG [3] e tentando minar a confiança em Dan Bernstein [4] não inspira confiança
    [1]: https://github.com/golang/go/issues/49269
    [2]: https://github.com/go-gitea/gitea/issues/17798
    [3]: https://twitter.com/FiloSottile/status/1127643698676797441
    [4]: https://twitter.com/FiloSottile/status/1555669786826244096

    • O problema é que os pacotes x/ costumam ficar bastante abandonados e seguem um modelo de desenvolvimento que dificulta para novos contribuidores enviar patches com sucesso
      Por outro lado, vejo o pacote crypto da biblioteca padrão como um dos grandes sucessos do Go. O OpenSSL foi um desastre por muito tempo, e o Go, especialmente agl, criou e distribuiu uma implementação alternativa muito usada, com qualidade média alta. Isso vale em especial do ponto de vista de haver muito menos armadilhas na API pública
  • O texto menciona gofmt como algo “bem-feito”, e isso merece destaque
    Para muitos designers e defensores de linguagens, pode parecer algo trivial, mas ele tem um valor enorme porque elimina completamente, desde o primeiro dia do projeto Go, uma daquelas discussões comuns de bikeshedding
    Vi várias linguagens mais novas copiarem isso de propósito, ou adotarem a ideia pensando que, se o Go tem, elas também deveriam ter
    Já vi regras de formatação bem estranhas, mas quase nenhuma à qual fosse impossível se acostumar. Por outro lado, em bases de código sem regras de formatação obrigatórias, muitas vezes o resultado foi um código mais difícil de entender

    • Tenho uma tendência a ficar mexendo na formatação do código, e gosto que go fmt torne isso praticamente irrelevante
  • Concordo com a afirmação de que “a existência de uma biblioteca sólida e bem-feita, com a maior parte do que é necessário para escrever código de servidor no século XXI, foi um grande trunfo”
    Go foi financiada pelo Google porque o Google tinha um problema. Era preciso escrever muito código de aplicações do lado do servidor, Python era lento demais e C++ era frágil demais. Go se encaixou muito bem nessa lacuna
    Um grande bônus era que as pessoas do Google escreveram as bibliotecas necessárias para esse tipo de trabalho e também as usavam internamente. Por isso, ao usar as bibliotecas, tratava-se de código que já havia sido bastante exercitado na prática, até nos caminhos de erro
    Tenho discordâncias técnicas em relação à linguagem. Especialmente, no começo, a ênfase em usar filas para tudo, até mesmo criar mutexes com filas. Mas eles acertaram nas green threads adequadas ao caso de uso. O problema da cor das funções é um problema real, e os truques obscuros que fazem Rust usar async e threads juntos são exagerados demais. Go abre mão de um pouco de desempenho e ganha muita simplicidade
    A antiga aversão a threads também é interessante. Comecei em mainframes UNIVAC, que tinham threads desde 1967, chamadas na época de “activities”. Em 1972, não só havia threads em espaço de usuário, como elas rodavam em multiprocessadores simétricos. Também havia E/S assíncrona e funções de conclusão em espaço de usuário, instruções embutidas para locks e um sistema operacional internamente baseado em threads
    Threads e multiprocessadores eram considerados normais, e ao migrar para UNIX parecia que tínhamos perdido essas coisas. UNIX/Linux levou décadas para alcançar esse campo, e várias gerações de programadores não sabiam como usar multiprocessadores com memória compartilhada
    A teoria inicial de concorrência de Dijkstra foi reinventada com outros termos e, muitas vezes, com designs piores. O pessoal de Go entendeu o bounded buffer de Dijkstra e por que bounded buffers de comprimento 0 e 1 são úteis. Foi bom ver isso novamente. Com as primitivas corretas, concorrência não é tão difícil. Se você tenta resolver espalhando locks por todo lado, como no pensamento clássico de pthreads, não funciona direito. Também não ajudou o fato de, no início do UNIX/Linux, o escalonador de CPU ser realmente péssimo, fazendo o desbloqueio de threads funcionar de forma horrível

    • Críticos aleatórios do HN dizem com frequência coisas como “Go foi financiada porque o Google tinha um problema”, mas isso acontece porque eles não entendem bem como o Google funciona nem o tamanho da empresa
      Go foi criada porque Rob Pike tinha um problema. Ele não gostava de C++, Java nem Python, e, por ser Rob Pike, o Google permitiu que ele passasse alguns anos trabalhando em uma nova linguagem. Não foi Larry, Sergey, Sundar ou Eric que foram até Rob pedir para ele fazer alguma coisa
      Em linhas gerais, Go foi financiada porque Rob Pike pediu apoio, o Google queria manter Rob Pike na empresa e acreditava que ele quase certamente faria algo interessante. Na Engenharia do Google, dinheiro da empresa significa, na prática, algo próximo de permitir que pessoas trabalhem em algo
      Como Rob Pike era um engenheiro brilhante, Go acabou saindo bastante boa em alguns aspectos e se encaixava bem no problema inicial dele de ter de usar C++, Python ou Java para escrever aplicações operacionais no Google. Algumas pessoas dentro do Google também concordaram e começaram a usar Go, e algumas delas, influentes, “incentivaram” outras pessoas a usar Go em vez de Python
    • Go não é simplesmente um projeto do Google; na prática, é a filosofia de compiladores do Plan 9 para Unix/Linux, mais CSP
    • Isso não bate com minha lembrança de trabalhar no Google naquela época. Assim como o meme de que “Go era para programação de sistemas”, quando você examina, parece mais uma crença que não faz muito sentido
      Em 2009, no Google, Python quase não era usado em servidores além de algumas utilidades internas, exceto pelo caso da aquisição do YouTube, então dá para descartar essa ideia de imediato. O maior servidor em Python feito pelo próprio Google era o Mondrian, ferramenta de code review escrita por Guido van Rossum, que depois foi substituída pelo Critique, escrito em Java
      Na época, o Google tinha uma política de três linguagens bastante rígida para eliminar guerras de linguagens de programação. Era permitido usar C++, Java e Python; Python era usado para scripts, C++ para infraestrutura e Java para servidores web
      Havia também áreas de sobreposição. Java foi introduzido depois de C++, e alguns servidores web permaneceram em C++ porque eram difíceis de reescrever. Também houve tentativas de migração gradual para Java, mas elas não ganharam muita tração. Alguns servidores de infraestrutura, como o Megastore, foram escritos em Java, e as bibliotecas centrais em geral eram em C++ com JNI e bindings para Python
      Também havia brechas na política, então algumas equipes criaram suas próprias linguagens para infraestrutura interna, e a base de código real usava linguagens de configuração customizadas e também Sawzall, criada por Rob Pike. A sintaxe era um pouco parecida com a de Go
      No geral, as pessoas tinham bastante liberdade de escolha, e novos servidores web eram escritos principalmente em Java, enquanto coisas como novos motores de banco de dados eram escritas principalmente em C++
      Escrever código assíncrono era, sem dúvida, difícil, e é verdade que Go resolveu bem essa parte. Mas Go não foi um projeto iniciado pela alta liderança para resolver um problema do Google. Não porque a liderança tivesse medo desse tipo de projeto, mas porque havia uma enorme quantidade de projetos internos de infraestrutura criados e com pessoas alocadas por equipes relevantes para resolver diretamente dores dos desenvolvedores. Grandes upgrades de rede impulsionados naquela época são exemplos disso. Esses projetos eram anunciados com antecedência
      Não me lembro de haver grande insatisfação com aquela situação. Tempos de build eram um problema até Bazel/Blaze passar a funcionar junto com clusters de build remotos; depois disso, como tudo era armazenado em cache remoto, mesmo bases de código enormes podiam ser compiladas em poucos segundos. A velocidade do compilador local passou a importar muito pouco, e javac também era muito rápido
      O anúncio de Go foi uma grande surpresa. Se ela realmente tivesse sido desenvolvida para resolver um problema do Google, o jeito típico do Google teria sido lançá-la primeiro internamente, evoluí-la por alguns anos com usuários internos e só então torná-la pública. Mas Go foi pública primeiro. As pessoas ao meu redor se perguntavam para que aquilo servia, uma reação difícil de esperar se tivesse sido realmente impulsionada por demanda interna
  • É interessante a parte sobre a decisão de usar o compilador C de Ken Thompson em vez do LLVM. As pessoas reclamaram, e especialmente nas primeiras versões isso também resultou em código gerado menos otimizado
    Como contrapartida, foi possível criar rapidamente stacks segmentadas. Se tivessem que implementar isso no LLVM e adequar à ABI do LLVM, talvez nem tivessem conseguido fazer
    No texto, isso é apresentado não como o único benefício dessa decisão, mas como um exemplo de benefício

    • O conteúdo da entrevista relacionado ao LLVM não é preciso. Implementaram stacks segmentadas no LLVM para Rust, e na prática foi bem fácil
      O X86FrameLowering já tinha suporte, e ele já existia na época em que Go foi lançado. Ao ativar a divisão de stack, o LLVM emite uma verificação no prólogo da função e, se necessário, chama __morestack para alocar mais stack. A ABI do Windows MSVC também precisa de um código muito parecido para dar suporte a _chkstk, então isso se encaixa naturalmente com o suporte a __morestack
      Na verdade, fazer o GDB entender stacks segmentadas foi mais difícil do que qualquer parte da implementação no compilador. Isso independe do backend
      Provavelmente o autor confundiu isso com stacks relocáveis. Na época, era necessário garbage collection preciso, o que tornava a implementação difícil, mas hoje a Azul já implementou isso no LLVM. Naquele momento, a forma mais fácil de implementar garbage collection preciso era fazer spill de todos os registradores através das chamadas de função; isso exigia mais esforço de implementação, mas não era nada excessivo. Como o compilador do Plan 9 aparentemente já fazia isso de qualquer forma, também não teria sido uma regressão de desempenho em relação ao 6g/8g. De todo modo, o suporte a garbage collection da Azul agora tem uma implementação adequada, capaz de armazenar raízes em registradores
    • No fim, Go não acabou abandonando as stacks segmentadas? Foi no Go 1.3, lançado em 2014. Por causa do problema de “hot spot” [1]
      Portanto, é verdade que a capacidade de experimentar teve valor, mas esse exemplo específico não é um caso perfeito
      [1]: https://go.dev/doc/go1.3#:~:text=Go%201.3%20has%20changed%20...
  • Estou concebendo uma linguagem estática de hobby e tentando algo que lide ao mesmo tempo com interfaces e genéricos, e senti na pele que Rob está certo. Fazer os dois se encaixarem bem é realmente difícil
    Ainda assim, acho que vale a pena. Pessoalmente, não me parece muito gratificante usar uma linguagem estaticamente tipada em que o usuário não pode definir seus próprios tipos genéricos
    No passado, programei em um ambiente BASIC que tinha GOSUB para sub-rotinas, mas não oferecia uma forma de escrever sub-rotinas que recebessem argumentos. Não quero repetir essa experiência no nível do sistema de tipos
    Por isso entendo que a equipe de Go tenha levado tempo para encontrar um bom design. Projetar uma boa linguagem é difícil; projetar uma boa linguagem com sistema de tipos é 10 vezes mais difícil; e projetar um sistema de tipos com genéricos é mais 10 vezes mais difícil

    • Não concordo. A parte mais difícil da implementação de genéricos aparece quando há suporte a herança de implementação, e Go não oferece isso
      Go assumiu a parte mais fácil da implementação de genéricos. O motivo de não terem feito antes não foi técnico. Foi ideológico, baseado puramente em ignorância, porque a maioria dos designers de Go deixou de acompanhar a área de teoria de linguagens de programação depois do fim dos anos 1990
    • As linguagens da família ML e as linguagens funcionais não parecem ter esse problema, e muitas delas têm sistemas de tipos muito mais sofisticados e poderosos que o de Go
    • Scala foi lançada antes de Golang e, quando Golang surgiu, já estava ganhando popularidade. E nem tinha recursos em escala GOOG por trás