- Várias decisões de design da linguagem Go foram tomadas de forma desnecessária ou ignorando experiências já consolidadas
- O problema de gerenciamento do escopo das variáveis de erro dificulta a legibilidade do código e a identificação de bugs
- Em vários pontos, como a dualidade do
nil, uso de memória e portabilidade do código, aparecem designs pouco intuitivos e desalinhados com a realidade
- As limitações da instrução
defer e a forma como a biblioteca padrão lida com exceções dificultam garantir segurança contra exceções
- Problemas acumulados, como gestão de memória e tratamento deficiente de UTF-8, estão afetando negativamente a qualidade de codebases em Go no longo prazo
Crítica de longo prazo à linguagem Go
A falta de intuição no escopo das variáveis de erro
- A sintaxe do Go amplia desnecessariamente o escopo da variável de erro (
err), aumentando a possibilidade de falhas
- No código de exemplo, a variável
err permanece viva por toda a função e é reutilizada, o que prejudica a legibilidade e a manutenibilidade do código
- Desenvolvedores experientes acabam enfrentando mal-entendidos e perda de tempo ao investigar bugs por causa desse problema de escopo
- A sintaxe não permite limitar adequadamente essas variáveis a um escopo mais local
Duas formas de nil
- Em Go, existe a confusão de que
nil se comporta de forma diferente em tipos interface e tipos ponteiro
- Como no exemplo abaixo, mesmo que
s (ponteiro) e i (interface) recebam nil, s==i pode ser avaliado de forma diferente, mostrando um comportamento inconsistente
- Isso reproduz um problema que normalmente se quer evitar ao lidar com
null, deixando traços de um design feito sem reflexão suficiente
Limites na portabilidade do código
- O uso de comentários para compilação condicional é claramente ineficiente em termos de manutenção e portabilidade
- Quem já teve experiência real construindo software portável sabe que essa abordagem é trabalhosa e propensa a erros
- Experiências históricas acumuladas (portabilidade de código, casos práticos) estão sendo ignoradas
- Para mais detalhes, veja Go programs are not portable
A falta de clareza sobre a propriedade de append
- A relação de propriedade entre a função
append e slices não é clara, o que dificulta prever o comportamento do código
- Pelo exemplo, quando uma slice recebe
append dentro da função foo, é difícil saber de antemão qual será o impacto real sobre o valor original
- Os “quirks” da linguagem que é preciso decorar só aumentam, favorecendo erros
Falhas no design da instrução defer
- Ela não oferece suporte claro à liberação de recursos como no princípio RAII (Resource Acquisition Is Initialization)
- Em comparação com estruturas de gerenciamento de recursos em Java e Python, em Go não fica claro quais recursos devem ser liberados com
defer
- Como no exemplo com arquivos, até o problema de double-close precisa ser tratado manualmente, e a ordem e a forma corretas de liberação não ficam claras
Tratamento de exceções na biblioteca padrão
- Go não adota uma estrutura com exceções explícitas (
exception), mas situações excepcionais como panic ainda assim acontecem
- Em alguns casos,
panic nem encerra completamente o programa e acaba sendo engolido
- Existem padrões na biblioteca padrão (
fmt.Print, servidor HTTP etc.) que ignoram exceções, o que torna impossível garantir segurança real contra exceções
- No fim, escrever código seguro contra exceções continua sendo necessário, mas não é possível usar exceções diretamente
Tratamento de UTF-8 e strings
- Mesmo que se coloque dados binários arbitrários no tipo
string, Go continua funcionando sem validação especial
- É possível enfrentar casos em que nomes de arquivo criados antes da codificação UTF-8 simplesmente desaparecem silenciosamente
- Isso pode causar perda de dados importantes em backups e reflete uma abordagem simplificada que não considera situações reais de trabalho
Limites da gestão de memória
- É difícil ter controle direto sobre o uso de RAM, e a confiabilidade do GC (garbage collector) também tem limites
- O consumo de memória em Go aumenta e, no longo prazo, isso se transforma em custos e problemas de desempenho
- Em ambientes com múltiplas instâncias e contêineres, problemas reais de custo e escalabilidade acabam surgindo
Conclusão: havia caminhos melhores
- Mesmo já existindo designs de linguagem comprovadamente eficazes, Go optou por ignorá-los em muitos aspectos
- Diferentemente dos problemas das primeiras propostas de Java, quando Go foi lançado já existiam abordagens melhores
Materiais de referência
Ainda não há comentários.