Por que Go é ruim para programadores mudos

O artigo foi escrito como uma resposta a um artigo antipode publicado anteriormente.


imagem


Nos últimos dois anos, tenho usado o Go para implementar um servidor RADIUS especializado com um sistema de cobrança desenvolvido. No processo, eu aprendo as sutilezas da própria linguagem. Os programas em si são muito simples e não têm a finalidade de escrever um artigo, mas a experiência de usar o Go merece merecer algumas palavras em sua defesa. O Go está se tornando um idioma cada vez mais popular para códigos sérios e escaláveis. O idioma é criado no Google, no qual é usado ativamente. Para resumir, acredito sinceramente que o design da linguagem Go é ruim para os programadores do Dumb.


Projetado para programadores fracos?


Conversa fraca sobre problemas. Forte conversa sobre idéias e sonhos ...

O Go é muito simples de aprender, tão simples que você pode ler o código com pouca ou nenhuma preparação. Esse recurso do idioma é usado em muitas empresas mundiais quando o código é lido em conjunto com especialistas não essenciais (gerentes, clientes etc.). Isso é muito conveniente para metodologias como o Design Driven Development.


Até os programadores iniciantes começam a produzir código bastante decente após uma ou duas semanas. O livro que estudei Go é chamado “Go Programming” (escrito por Mark Summerfield). O livro é muito bom, aborda muitas das nuances da linguagem. Após linguagens desnecessariamente complicadas, como Java, PHP, a falta de mágica é refrescante. Porém, mais cedo ou mais tarde, muitos programadores limitados desejam usar métodos antigos em um novo campo. Isso é realmente necessário?


Rob Pike (o principal ideólogo da linguagem) criou o Go como uma linguagem industrial fácil de ler e eficaz de usar. O idioma foi projetado para máxima produtividade em grandes equipes e não há dúvida sobre isso. Muitos programadores iniciantes reclamam que existem muitos recursos que eles não possuem. Esse desejo de simplicidade foi uma decisão consciente dos desenvolvedores de linguagem e, para entender completamente o que era, precisamos entender a motivação dos desenvolvedores e o que eles alcançaram no Go.


Então, por que foi tão simples? Aqui estão algumas citações de Rob Pike:


O ponto chave aqui é que nossos programadores não são pesquisadores. Eles geralmente são muito jovens, vêm até nós depois da escola, talvez tenham estudado Java, C / C ++ ou Python. Eles não conseguem entender uma linguagem excelente, mas, ao mesmo tempo, queremos que eles criem um bom software. É por isso que a linguagem deve ser fácil de entender e aprender.

Ele deveria estar familiarizado, grosso modo como C. Os programadores do Google iniciam suas carreiras mais cedo e estão familiarizados com linguagens processuais, em particular a família C. A exigência de produtividade rápida em uma nova linguagem de programação significa que a linguagem não deve ser muito radical.

Palavras sábias, certo?


Artefatos de Simplicidade


A simplicidade é uma condição necessária para o belo. Leo Tolstoi.

Ser simples é uma das aspirações mais importantes em qualquer design. Como você sabe, um projeto perfeito não é um projeto onde não há nada a acrescentar, mas um - do qual não há nada a remover. Muitos acreditam que, para resolver (ou mesmo expressar) tarefas complexas, é necessária uma ferramenta complexa. No entanto, isso não é verdade. Tomemos, por exemplo, a linguagem PERL. Os ideólogos da linguagem acreditavam que um programador deveria ter pelo menos três maneiras diferentes de resolver um problema. Os ideólogos da língua Go seguiram um caminho diferente, decidiram que, para atingir o objetivo, um caminho é suficiente, mas realmente bom. Essa abordagem tem uma base séria: a única maneira é mais fácil de aprender e mais difícil de esquecer.


Muitos migrantes reclamam que o idioma não contém abstrações elegantes. Sim, é, mas essa é uma das principais vantagens do idioma. O idioma contém um mínimo de mágica - portanto, não é necessário conhecimento profundo para ler o programa. Quanto à verbosidade do código, isso não é um problema. Um programa Golang bem escrito é lido verticalmente com pouca ou nenhuma estrutura. Além disso, a velocidade de leitura de um programa é pelo menos uma ordem de magnitude mais rápida que a sua escrita. Se você considerar que todo o código possui formatação uniforme (executada usando o comando gofmt interno), a leitura de algumas linhas extras não é um problema.


Não é muito expressivo


A arte não tolera quando restringe sua liberdade. A precisão não é de sua responsabilidade.

Devido ao desejo de simplicidade, Go não possui construções que em outras línguas sejam percebidas como algo natural para as pessoas acostumadas a elas. No início, isso pode ser um pouco inconveniente, mas você percebe que o programa é lido muitas vezes mais fácil e mais definido.


Por exemplo, um utilitário de console que lê stdin ou um arquivo a partir dos argumentos da linha de comando terá a seguinte aparência:


package main import ( "bufio" "flag" "fmt" "log" "os" ) func main() { flag.Parse() scanner := newScanner(flag.Args()) var text string for scanner.Scan() { text += scanner.Text() } if err := scanner.Err(); err != nil { log.Fatal(err) } fmt.Println(text) } func newScanner(flags []string) *bufio.Scanner { if len(flags) == 0 { return bufio.NewScanner(os.Stdin) } file, err := os.Open(flags[0]) if err != nil { log.Fatal(err) } return bufio.NewScanner(file) } 

Embora a solução para o mesmo problema na linguagem D pareça um pouco mais curta, no entanto, não é mais fácil ler


 import std.stdio, std.array, std.conv; void main(string[] args) { try { auto source = args.length > 1 ? File(args[1], "r") : stdin; auto text = source.byLine.join.to!(string); writeln(text); } catch (Exception ex) { writeln(ex.msg); } } 

Copie o inferno


O homem carrega o inferno em si mesmo. Martin Luther.

Os iniciantes reclamam constantemente do Go em termos de falta de genéricos. Para resolver esse problema, a maioria deles usa cópia direta de código. Por exemplo, esses profissionais infelizes acreditam que a função de resumir a lista de números inteiros não pode ser implementada de outra maneira senão por simples copiar e colar para cada tipo de dados.


 package main import "fmt" func int64Sum(list []int64) (uint64) { var result int64 = 0 for x := 0; x < len(list); x++ { result += list[x] } return uint64(result) } func int32Sum(list []int32) (uint64) { var result int32 = 0 for x := 0; x < len(list); x++ { result += list[x] } return uint64(result) } func main() { list32 := []int32{1, 2, 3, 4, 5} list64 := []int64{1, 2, 3, 4, 5} fmt.Println(int32Sum(list32)) fmt.Println(int64Sum(list64)) } 

A linguagem possui meios suficientes para implementar essas construções. Por exemplo, a programação generalizada é boa.


 package main import "fmt" func Eval32(list []int32, fn func(a, b int32)int32) int32 { var res int32 for _, val := range list { res = fn(res, val) } return res } func int32Add(a, b int32) int32 { return a + b } func int32Sub(a, b int32) int32 { return a - b } func Eval64(list []int64, fn func(a, b int64)int64) int64 { var res int64 for _, val := range list { res = fn(res, val) } return res } func int64Add(a, b int64) int64 { return a + b } func int64Sub(a, b int64) int64 { return a - b } func main() { list32 := []int32{1, 2, 3, 4, 5} list64 := []int64{1, 2, 3, 4, 5} fmt.Println(Eval32(list32, int32Add)) fmt.Println(Eval64(list64, int64Add)) fmt.Println(Eval64(list64, int64Sub)) } 

E, embora nosso código tenha sido um pouco mais longo que o caso anterior, ele se generalizou. Portanto, não será difícil para nós implementar todas as operações aritméticas.


Muitos dirão que o programa D parece significativamente mais curto e terá razão.


 import std.stdio; import std.algorithm; void main(string[] args) { [1, 2, 3, 4, 5].reduce!((a, b) => a + b).writeln; } 

No entanto, é apenas mais curto, mas não mais correto, pois o problema de manipulação de erros é completamente ignorado na implementação D.


Na vida real, quando a complexidade da lógica aumenta, a diferença está diminuindo rapidamente. Ainda mais rapidamente, a lacuna diminui quando é necessária uma ação que não pode ser executada usando operadores de idioma padrão.


Em termos de capacidade de suporte, extensibilidade, legibilidade, na minha opinião, a linguagem Go vence, embora perca em verbosidade.


A programação generalizada em alguns casos nos oferece benefícios inegáveis. Isso ilustra claramente o pacote de classificação. Portanto, para classificar qualquer lista, basta implementar a interface sort.Interface.


 import "sort" type Names []string func (ns Names) Len() int { return len(ns) } func (ns Names) Less(i, j int) bool { return ns[i] < ns[j] } func (ns Names) Swap(i, j int) { ns[i], ns[j] = ns[j], ns[i] } func main() { names := Names{"London", "Berlin", "Rim"} sort.Sort(names) } 

Se você pegar um projeto de código aberto e executar o comando grep "interface {}" -R, verá com que frequência as interfaces confusas são usadas. Os camaradas de mente estreita dirão imediatamente que tudo isso se deve à falta de genéricos. No entanto, isso está longe de ser sempre o caso. Tomemos, por exemplo, o idioma DELPHI. Apesar de ter esses mesmos genéricos, ele contém um tipo especial VARIANT para operações com tipos de dados arbitrários. Vá faz a mesma coisa.


De uma arma em pardais


E uma camisa de força deve se encaixar no tamanho da loucura. Stanislav Vamos.

Muitos fãs de esportes radicais podem dizer que o Go tem outro mecanismo para criar genéricos - a reflexão. E eles terão razão ... mas apenas em casos raros.


Rob Pike nos adverte:


Esta é uma ferramenta poderosa que deve ser usada com cuidado. Deve ser evitado até que seja estritamente necessário.

A Wikipedia nos diz o seguinte:


Reflexão significa um processo durante o qual um programa pode rastrear e modificar sua própria estrutura e comportamento em tempo de execução. O paradigma de programação subjacente à reflexão é chamado de programação reflexiva. Este é um tipo de metaprogramação.

No entanto, como você sabe, você tem que pagar por tudo. Nesse caso, é:


  • dificuldade em escrever programas
  • velocidade de execução do programa

Portanto, a reflexão deve ser usada com cautela, como uma arma de grande calibre. O uso impensado da reflexão leva a programas ilegíveis, erros constantes e baixa velocidade. Exatamente o fato é que o programador esnobe pode exibir seu código na frente de outros colegas mais pragmáticos e modestos.


Bagagem cultural de C? Não, de vários idiomas!


Junto com o estado, os herdeiros ficam com dívidas.

Apesar do fato de muitos acreditarem que o idioma é completamente baseado no legado de C, isso não é verdade. A linguagem incorporou muitos aspectos das melhores linguagens de programação.


Sintaxe


Primeiro de tudo, a sintaxe das construções gramaticais é baseada na sintaxe da linguagem C. No entanto, a linguagem DELPHI também teve um impacto significativo. Portanto, vemos que o excesso de colchetes é completamente removido, reduzindo muito a legibilidade do programa. Além disso, o idioma contém o operador :: =, que é inerente ao idioma DELPHI. O conceito de pacotes é emprestado de idiomas como o ADA. A declaração de entidades não utilizadas é emprestada do idioma PROLOG.


Semântica


A semântica da linguagem DELPHI foi tomada como base dos pacotes. Cada pacote contém dados e códigos e contém entidades públicas e privadas. Isso permite reduzir a interface do pacote ao mínimo.


A operação de implementação pelo método de delegação foi emprestada da DELPHI.


Compilação


Não é de admirar que haja uma piada: o Go foi desenvolvido enquanto o programa C foi compilado. Um dos pontos fortes da linguagem é a compilação ultrarrápida. A ideia foi emprestada da DELPHI. Além disso, cada pacote Go corresponde ao módulo DELPHI. Esses pacotes são recompilados apenas quando necessário. Portanto, após a próxima edição, não é necessário compilar o programa inteiro, mas basta recompilar apenas os pacotes e pacotes alterados, dependendo desses pacotes alterados (e somente se as interfaces do pacote tiverem sido alteradas).


Projetos de alto nível


O idioma contém muitas construções diferentes de alto nível que não estão de forma alguma associadas a idiomas de baixo nível, como C.


  • Linhas
  • Hash da tabela
  • Fatias
  • A digitação de patos é emprestada de idiomas como o RUBY (que, infelizmente, muitos não entendem e não utilizam todo o seu potencial).

Gerenciamento de memória


O gerenciamento de memória geralmente merece um artigo separado. Se em linguagens como C ++, o controle é completamente deixado para o desenvolvedor, em linguagens posteriores como DELPHI, um modelo de contagem de referência foi usado. Com essa abordagem, os links cíclicos não eram permitidos, uma vez que os clusters perdidos foram formados, a detecção desses clusters (como em C #) é incorporada ao Go. Além disso, o coletor de lixo é mais eficaz do que a maioria das implementações conhecidas atualmente e já pode ser usado para muitas tarefas em tempo real. O próprio idioma reconhece situações em que um valor para armazenar uma variável pode ser alocado na pilha. Isso reduz a carga no gerenciador de memória e aumenta a velocidade do programa.


Concorrência e Concorrência


O paralelismo e a competitividade da língua estão além dos elogios. Nenhum idioma de baixo nível pode competir remotamente com o idioma Go. Para ser justo, vale a pena notar que o modelo não foi inventado pelos autores da linguagem, mas simplesmente emprestado da boa e antiga linguagem da ADA. A linguagem é capaz de processar milhões de conexões paralelas usando todas as CPUs, tendo na ordem de magnitude menos comum para problemas complexos de códigos multithread com deadlocks e condições de corrida.


Benefícios adicionais


Se isso for benéfico, todos se tornarão altruístas.

O idioma também nos fornece uma série de benefícios indiscutíveis:


  • O único arquivo executável após a criação do projeto simplifica bastante a implantação de aplicativos.
  • A digitação estática e a inferência de tipo podem reduzir significativamente o número de erros no código, mesmo sem a realização de testes. Conheço alguns programadores que ficam sem escrever testes e, ao mesmo tempo, a qualidade do seu código não sofre significativamente.
  • Compilação cruzada muito simples e excelente portabilidade da biblioteca padrão, o que simplifica bastante o desenvolvimento de aplicativos de plataforma cruzada.
  • As expressões regulares do RE2 são seguras para threads e têm tempos de execução previsíveis.
  • Uma poderosa biblioteca padrão, que permite que a maioria dos projetos fique sem estruturas de terceiros.
  • A linguagem é poderosa o suficiente para se concentrar no problema, e não nos métodos para resolvê-lo, e ao mesmo tempo baixa o suficiente para que o problema possa ser resolvido com eficiência.
  • O sistema eco Go já contém ferramentas prontas para uso em todas as ocasiões: testes, documentação, gerenciamento de pacotes, linters poderosos, geração de código, um detector de condições de corrida, etc.
  • A versão 1.11 do Go agora possui gerenciamento de dependência semântica interno, construído sobre hosts VCS populares. Todas as ferramentas que compõem o ecossistema Go usam esses serviços para baixar, compilar e instalar código deles de uma só vez. E isso é ótimo. Com o advento da versão 1.11, o problema com a versão do pacote também foi completamente resolvido.
  • Como a idéia principal do idioma é reduzir a mágica, o idioma incentiva os desenvolvedores a lidar explicitamente com o tratamento de erros. E isso está correto, porque, caso contrário, ele simplesmente esquecerá completamente o tratamento de erros. Outra coisa é que a maioria dos desenvolvedores ignora deliberadamente o tratamento de erros, preferindo simplesmente encaminhar o erro em vez de processá-lo.
  • A linguagem não implementa a metodologia clássica de POO, pois não existe virtualidade em sua forma pura no Go. No entanto, isso não é um problema ao usar interfaces. A ausência de POO reduz significativamente a barreira de entrada para iniciantes.

Facilidade para obter benefícios da comunidade


Complicar é simples, simplificar é difícil.

O Go foi projetado para ser simples e se destacou por isso. Foi escrito para programadores inteligentes que entendem todas as virtudes do trabalho em equipe e estão cansados ​​da variabilidade infinita das linguagens de nível corporativo. Tendo um conjunto relativamente pequeno de construções sintáticas em seu arsenal, ele praticamente não está sujeito a alterações ao longo do tempo, então os desenvolvedores liberaram muito tempo especificamente para o desenvolvimento, e não para um estudo interminável de inovações de linguagem.


As empresas também obtêm várias vantagens: um baixo limite de entrada permite que você encontre rapidamente um especialista, e a imutabilidade do idioma permite que você use o mesmo código após 10 anos.


Conclusão


O grande tamanho do cérebro ainda não transformou um único elefante em ganhador do Prêmio Nobel.

Para os programadores cujo ego pessoal prevalece sobre o espírito de equipe, bem como para os teóricos que amam tarefas acadêmicas e o "auto-aperfeiçoamento" interminável, a linguagem é realmente ruim, porque é uma linguagem artesanal de uso geral que não permite receber prazer estético do resultado de seu trabalho e se mostrar. um profissional na frente dos colegas (desde que medamos a mente precisamente com esses critérios, e não com o coeficiente de QI). Como tudo na vida, é uma questão de prioridades pessoais. Como todas as inovações que valem a pena, a linguagem já percorreu um longo caminho, da negação universal ao reconhecimento de massa. A linguagem é engenhosa em sua simplicidade, mas, como você sabe, tudo engenhoso é simples!


Sumário


Entre todas as críticas severas dirigidas a Go, destacam-se as seguintes declarações:


  • Sem genéricos. Se olharmos para as estatísticas dos idiomas mais populares, notamos que metade dos dez principais idiomas não possui genéricos. Principalmente, os genéricos são necessários apenas em contêineres. Portanto, o ganho deles não é muito grande.
  • Outros idiomas, como o Rust, são muito melhores (pelo menos nas categorias de sites XXX). Novamente, se olharmos para as estatísticas dos idiomas mais populares, não encontraremos Rust na lista, ou estará em algum lugar abaixo da classificação. Pessoalmente, gosto de Rust, mas escolhi Go.
  • XXX tem um bolo. Este é o outro lado da moeda da simplicidade. Se é uma desvantagem ou não, é para todos decidirem. No entanto, os desenvolvedores do projeto deram sua preferência em favor da simplicidade.
  • Eles vão lançar o Go 2.0, então veremos. Essa posição é adotada por observadores, não por praticantes.
  • Não é expressivo o suficiente. Concordo que, em algumas áreas, a expressividade é esfarrapada, mas, em geral, é uma linguagem simples e consistente. Além disso, devido à pobreza do idioma, somos forçados a prestar mais atenção à arquitetura do aplicativo desenvolvido, o que afeta positivamente sua flexibilidade.

Na verdade, o artigo não pensou nas vantagens sintáticas da linguagem Go, mas como uma breve visão geral de suas vantagens para o trabalho em equipe e a efetiva evolução do projeto que está sendo desenvolvido. Entendeu-se que o artigo teria continuado, em relação a problemas mais específicos. No entanto, devido à falta de interesse no tópico, provavelmente não haverá continuação.


Um experimento


Não acredite nas palavras - nem nas suas nem nos estranhos, mas acredite nas ações - tanto nas suas como nos estranhos.

A parte final é destinada exclusivamente àquela categoria de pessoas que se consideram otimistas de mente construtiva e que podem confirmar isso com seus próprios assuntos. O restante da platéia, pule esta parte.


Esse experimento foi inspirado por amigos que afirmavam que todos os otimistas construtivos haviam deixado (pelo menos virtualmente) as extensões de nosso país e se estabeleceram, por exemplo, no Stack Overflow, e aqui a maioria dos snobs permaneceu. Durante muito tempo eu não acreditei neles, então decidi realizar esse experimento.
Vários artigos foram publicados no hub, resultado da análise dos comentários nos quais cito.


  • De fato, a hipótese de meus amigos foi confirmada, no entanto, ainda são encontradas pessoas adequadas entre os vendedores ambulantes, embora sua porcentagem esteja caindo rapidamente. Yuri Bykov chama essas pessoas de " tolos " em quem repousa todo o país. Segundo ele, o percentual é pequeno (cerca de 2%). Não sou tão pessimista e acho que há muito mais deles.
  • A lei da mídia. Informações destrutivas têm muito mais interesse do que informações construtivas.
  • A psicologia da multidão. Isso é uma coisa terrível, até transforma uma ovelha abusiva em uma pessoa adequada. Um homem na multidão não é mais um homem. Não se pode falar em objetividade. Sem argumentos lógicos, sem fontes autorizadas ou precedentes não o afetam mais.
  • Responsabilidade e impunidade. As pessoas estão dispostas a humilhar outras pessoas a fim de se exaltarem (pelo menos aos seus próprios olhos). Especialmente se você não precisar responder (o que poderia ser mais fácil - clique no sinal de menos e você nem precisa escrever um comentário). Há tanto em comum entre palavras e ações quanto entre um canal e um esgoto.
  • Vaidade. A maioria dos esnobes está pronta para se destacar de qualquer maneira. Eles não têm medo de nenhuma barreira moral.
  • Pessimismo Ao contrário dos países ocidentais (e especialmente da América), sentimentos pessimistas prevalecem no país. Como você sabe, um otimista está procurando oportunidades em meio a dificuldades, e um pessimista está procurando dificuldades entre oportunidades. Em nosso país, quase ninguém presta atenção às qualidades positivas de qualquer coisa.
  • Profissionalismo e visão de mundo. Muitas pessoas escolhem as ferramentas como um fim em si mesmas, e não como um meio para um fim. As pessoas se esqueceram de como trabalhar com informações. As pessoas não vêem florestas atrás das árvores. De uma série de informações, eles não são capazes de extrair os pensamentos principais. Ninguém quer olhar de um ponto de vista diferente, não padrão para si. A dissidência é suprimida. Não é aceito aqui.
  • Simpatia e respeito. Grupos amigos louvados existem apenas em palavras. Os valores de desenvolvimento ágil estão apenas no papel.
  • Hipocrisia. Você pode escrever um artigo separado sobre isso em geral.
  • Princípio. Há pessoas que fazem a pergunta certa: “ Que diabos estou fazendo? ”No entanto, nem todo mundo entende que, devido à falta de princípio, para nós, o interesse egoísta momentâneo é mais importante do que todos os nossos princípios combinados. É mais fácil culpar tudo pelas circunstâncias e dizer que nada depende de nós.

Com profundo respeito e simpatia por todos os otimistas construtivos.


Adverax

Source: https://habr.com/ru/post/pt448932/


All Articles