Avatar enviado por xavdid

Uma reflexão sobre o #12in23 de quem completou o desafio

@xavdid
Mais de 2 anos atrás

Este post foi publicado originalmente no site do David e é republicado aqui com permissão

Em janeiro do ano passado, o Exercism anunciou um novo programa chamado 12in23, no qual desafiou os participantes a experimentar 12 linguagens de programação novas em 2023. Cada mês teria um tema (como "Analytical April" ou "Object Oriented October") e destacaria linguagens específicas para experimentar. Eu adoro aprender coisas novas e me tornei meio nerd de linguagens (de programação), então decidi tentar. 12 linguagens, 12 meses!

Agora que o ano está quase acabando, estou incrivelmente satisfeito com o rumo do projeto. Consegui experimentar 12 linguagens novas, conheci pessoas ótimas na comunidade do Exercism e ainda publiquei algumas contribuições open source legais no caminho! Neste post, eu passo por todas elas e falo sobre o que tirei de cada uma.

Escolhendo as linguagens

Defini algumas diretrizes para o ano para aproveitar ao máximo a experiência:

  1. As linguagens deveriam ser totalmente novas para mim ou pelo menos desconhecidas o suficiente para que eu sentisse que estava aprendendo muito.
  2. As linguagens escolhidas deveriam ser (potencialmente) práticas para eu aprender mais no futuro. Este projeto era só por diversão, mas quero passar meu tempo aprendendo coisas (ao menos parcialmente) úteis.
  3. Eu instalaria todas as ferramentas locais e o plugin do VSCode para qualquer linguagem que estivesse usando. Queria comparar as linguagens em pé de igualdade, com o máximo de dicas de tipo e intellisense possível. Na faculdade, fazia toda a minha lição de programação no Sublime Text, sem nenhum linting nem autocomplete. Eu temia que, se aprendesse a programar usando todas essas ferramentas, dependeria demais delas e não seria um bom programador. Aconteceu o contrário. Quanto mais cognição eu puder transferir para as minhas ferramentas, mais vou poder pensar no problema em questão. Não memorize as coisas, memorize como encontrá-las.

Vamos nessa!

Janeiro (sem tema)

Quando janeiro começou, a equipe do Exercism ainda estava escolhendo os temas mensais, então a linguagem daquele mês ficou a meu critério. Sem uma direção definida, abri o ano com Go. Eu tinha feito um curso intensivo da linguagem em meados de 2022, mas não a tinha usado muito desde então e não me sentia nem um pouco proficiente.

Go é uma linguagem interessante. Seu compilador rígido significa que Seu Programa Vai Estar Correto e você não avança um centímetro até que ele ache que é seguro fazer isso.1 Sua abordagem verbosa para o tratamento de erros faz com que você nunca seja pego de surpresa (ao custo de escrever if err != nil { return err } tantas tantas vezes). Ela é boa em tornar fáceis as coisas difíceis (como paralelismo com canais), mas também torna difíceis algumas coisas fáceis (manipulação de string). Ela tem uma biblioteca padrão robusta, o que significa que você dá conta da maioria das tarefas sem módulos de terceiros. Gosto de como boa parte do ecossistema (formatação, instalação, build etc.) é nativa e faz parte do próprio comando go. A linguagem tem seus detratores, mas acho que ela em grande parte alcança seus objetivos de correção e manutenibilidade.

Não gostei tanto de usá-la a ponto de recorrer a ela como primeira escolha, mas é uma ótima ferramenta para ter à mão em programas sensíveis a desempenho, como mostrar o caminho aninhado no meu prompt do shell.

Functional February

Em fevereiro, mergulhamos de cabeça nas linguagens funcionais, um ramo meio matemático das linguagens de programação imperativas mais comuns. As linguagens funcionais são conhecidas por suas funções "puras" (sem efeitos colaterais). Escolhi Elixir, principalmente porque meu amigo Caleb a usa no Advent of Code e fala muito bem dela.

Gostei bastante do tempo que passei com Elixir. Ela foi inspirada em Ruby (o que faz sentido; seu criador, José Valim, era um dos principais contribuidores do Rails). Achei simples expressar conceitos funcionais, como o encadeamento de métodos. Adorei todo o açúcar sintático que facilitava isso, como o operador de pipe (|>):

foo(bar(baz(new_function(other_function()))))
# becomes
other_function() |> new_function() |> baz() |> bar() |> foo()

Foi também a minha primeira vez trabalhando com macros, ou seja, código que escreve código. Como os programas em Elixir podem ser expressos em uma AST que é, ela mesma, código Elixir válido, é fácil escrever código que produz outro código válido. É um conceito muito legal que Elixir tornou fácil. Também curti o jeito como as funções podiam fazer pattern matching com o formato dos seus argumentos, de modo que as chamadas de função podiam ser encaminhadas para a implementação apropriada:

defmodule TuplePrinter do
  def print({a}) do
	IO.puts("single")
	IO.puts(a)
  end

  def print({a, b}) do
	IO.puts("double")
	IO.puts(a)
	IO.puts(b)
  end
end

TuplePrinter.print({1})
TuplePrinter.print({2, 2})

# single
# 1
# double
# 2
# 2

Parece o tipo de recurso que ou é ótimo, ou transforma seu código num espaguete completo. De qualquer forma, foi um conceito legal!

Elixir também se beneficia de rodar dentro da máquina virtual BEAM do Erlang, o que lhe dá um grande ecossistema com o qual se comunicar. Ela é ótima em concorrência e é o núcleo do adorado framework web Phoenix.

Embora eu não tenha necessidade imediata de usar Elixir, achei muito divertido trabalhar com ela e com certeza algo que eu estaria aberto a revisitar. Além disso, foi um desafio interessante resolver problemas familiares de formas desconhecidas (a saber, de forma recursiva).

Mechanical March

O mês de março focou nas linguagens "de sistema", que compilam para código de máquina.

Das opções, Go era a única linguagem que me interessava.2 Agora, leitores atentos vão notar que eu já tinha feito um mês de Go, então repeti-la não contaria para as minhas 12. Bem, quando escolhi Go para janeiro, eles ainda não tinham anunciado os temas, então eu não percebi que estava me colocando numa enrascada.

Se eu soubesse que o Bun estava chegando, provavelmente teria experimentado Zig, mas infelizmente eu não conseguia (ainda) prever o futuro. Então, sem uma escolha mais atraente, fui de mais um mês de Go, ciente de que precisaria repetir alguma linguagem em algum momento no restante do ano.

Analytical April

O mês de abril foi todo sobre linguagens populares para ciência de dados. Eu já conhecia Python demais e fiz R numa aula de estatística na faculdade (e não gostei), então lá fui eu de Julia!

Gostei do tempo que passei com ela, mas principalmente porque parecia muito com Python. Foi um pouco perturbador, como ser americano no Canadá. Tudo parece muito familiar, mas está só um pouco fora do lugar de um jeito difícil de identificar. De repente, alguém te oferece uma moeda de 2 dólares (ou uma função que é muito bem feita para fazer contas com matrizes) e você percebe que não está mais no Kansas.

O que mais me chamou a atenção foi o sistema de tipos de Julia. Ele era anotado (opcionalmente) como o sistema de tipos de Python, mas tinha verificações em tempo de execução para garantir que os argumentos correspondessem aos tipos declarados. Acho que o sistema de Python encontra o equilíbrio certo entre se integrar às ferramentas e não atrapalhar, mas admito que os erros em tempo de execução de Julia para funções com tipos errados também foram úteis.

No fim das contas, Julia era legal, mas não é algo que eu espere precisar no futuro.

Mindshifting May

O mês de maio apostou ainda mais no "tente algo novo", destacando linguagens que fazem coisas muito incomuns. Aproveitei a oportunidade para experimentar a sempre popular Rust. Preciso dizer: eu entendo o hype.

Embora o famoso borrow checker certamente exija um tempo para se acostumar, gostei do jeito que ele me fazia pensar nos meus programas com mais cuidado. O compilador era certamente rígido, mas as mensagens de erro iam muito além para me ajudar a corrigir os problemas. Não vou dizer que fui especialmente produtivo na primeira semana, mas sinto que pelo menos consigo ver o topo da curva de aprendizado.

O cargo, o gerenciador de pacotes do Rust, também merece menção especial. Embora eu não tenha instalado nenhum pacote de terceiros, suas funcionalidades de build, teste e formatação eram ótimas. O mesmo vale para sua extensão de VSCode, que tinha todas as comodidades que eu esperaria de uma linguagem de tipagem estática como Rust. Uma boa experiência de desenvolvedor realmente faz toda a diferença.

Embora sejam muito diferentes no nível de implementação, Rust me pareceu semelhante a Go quanto ao que eu usaria cada uma para fazer: programas rodarem muito rápido. Muitas ferramentas em linguagens que uso regularmente estão começando a recorrer a Rust por suas características de desempenho, então prevejo vê-lo mais no futuro (mesmo que eu não esteja escrevendo Rust).

Summer of Sexps (June)

O mês de junho foi dedicado às S-expressions, uma forma sintática comum em lisps. Escolhi Clojure, uma linguagem funcional que roda na JVM.

Eu tinha escrito um pouco de Clojure muitos anos atrás. Eu tinha acabado de sair da faculdade e me tornei o único mantenedor de um script diário crítico para o negócio no meu primeiro emprego. Escusado será dizer que foi uma época complicada. Eu estava curioso para ver se, agora que estava mais velho e mais sábio, ela era mais acessível.

Fico feliz em relatar que era! A experiência funcional de fevereiro me ajudou a pensar de forma recursiva, e a sintaxe não era tão ruim assim quando você se aprofundava. Sua interoperabilidade com a JVM também seria útil se eu a estivesse usando num projeto maior.

Não me vejo usando Clojure para nada quando há alternativas disponíveis, mas não foi uma experiência de todo desagradável.

Missão paralela: o Universal Test Runner!

Por anos, usei uma pequena função bash para rodar os testes de unidade no meu diretório atual. Enquanto eu trabalhava com todas essas linguagens novas, me peguei adicionando linhas a ela por conveniência; lembrar de rodar t era muito mais fácil do que reaprender o comando de teste específico de cada linguagem toda hora.

À medida que a lógica necessária ultrapassou meu nível de conforto com bash, tirei um tempo em junho e transformei o projeto em algo próprio: o Universal Test Runner.

Eu o compartilhei no fórum do Exercism e tive uma boa recepção. Eles gostaram tanto que decidimos construir uma funcionalidade parecida na própria CLI do Exercism (que é escrita em Go, um assunto que, por sorte, eu tinha acabado de revisar). Então, na segunda metade do ano, eu podia rodar exercism test para rodar a suíte de testes da linguagem daquele mês (um comando que é suportado nativamente no Universal Test Runner).

Se você quiser saber mais sobre o processo, escrevi sobre ele em muito mais detalhes quando foi lançado.

Enfim, seguindo em frente!

Jurassic July

O mês de julho destacou linguagens antigas. A oferta era bem escassa este mês em termos de praticidade. Comecei com o venerável COBOL, já que ouvi dizer que ele ainda roda muita infraestrutura crítica. Mas, com um casamento no início de agosto se aproximando, eu não tinha tempo nem energia para sentar e aprender uma linguagem tão diferente para mim. Então, em vez disso, troquei para Visual Basic, a opção que parecia menos ruim.

Não há muito a dizer aqui. A linguagem parecia um pouco verbosa, mas fácil o suficiente de usar. Pelo que entendo, ela foi projetada mesmo para o desenvolvimento de UI no Windows, então fazer exercícios pequenos torna difícil ter uma boa noção dela como um todo.

Appy August

O mês de agosto foi tomado pelas linguagens que constroem aplicativos. Como era de se esperar, havia muitas opções este mês. Fui de Swift. Como alguém que usa muitos produtos da Apple, a linguagem feita sob medida por eles é bem relevante para mim. Eu não era totalmente novato nela: publiquei um único app para iOS em 2016, escrito inteiramente em Swift. Mas eu não tinha tocado na linguagem desde então e ela evoluiu muito, então imaginei que ainda contava.

Fiquei agradavelmente surpreso com a facilidade de trabalhar com ela. Em contraste com muitas das outras linguagens aqui, Swift é bem nova. Foi lançada em 2014 e claramente se beneficiou das lições do design moderno de linguagens. Ela tem um gerenciador de pacotes nativo, optional chaining, funções de primeira classe e uma interpolação de string sensata. Era ergonômica de ler e escrever, mesmo sem usar o Xcode.

Dito tudo isso, Swift é útil principalmente no contexto de apps para plataformas Apple, que eu não desenvolvo atualmente. Embora tenha funcionado bem para os exercícios, não pretendo voltar a ela tão cedo. Mas eu adoro poder escrever nela no meu iPad, isso sim!

Slimline September

O mês de setembro explorou linguagens muito concisas ou pequenas. Fui de jq, uma ferramenta que uso e adoro há anos.

No entanto, sempre a considerei apenas uma ferramenta para trabalhar com JSON, não uma linguagem de programação de propósito geral. Fiquei agradavelmente surpreso ao ver que ela tem todos os recursos habituais, funções, variáveis, laços etc., então consegui escrever programas bem complexos:

# input: { "series": "1", "sliceLength": 1 }
. as {series: $series, sliceLength: $sliceLength} |
if
  $series == "" then
	"series cannot be empty" | halt_error
  elif $sliceLength > ($series | length) then
	"slice length cannot be greater than series length" | halt_error
  elif $sliceLength == 0 then
	"slice length cannot be zero" | halt_error
  elif $sliceLength < 0 then
	"slice length cannot be negative" | halt_error
  else
	.
end
| [range(0; $series | length)]
| map($series[. : . + $sliceLength])
| map(select(. | length == $sliceLength))

Foi divertido experimentar todos os recursos do jq que eu nunca precisei para transformações simples de dados. Embora as ferramentas aqui fossem um pouco deficientes (sem integração com editor etc.), uma compreensão mais profunda da amplitude da funcionalidade do jq valeu a pena.

edição: DJ Adams no Mastodon me chamou a atenção para o projeto jq-lsp e seu plugin de VSCode correspondente. Perdi o barco dessa vez, mas vou conferir no futuro.

Object Oriented October

O mês de outubro mergulhou nas linguagens orientadas a objetos. Tenho um carinho especial por designs orientados a objetos, que refletem de perto como eu visualizo programas na minha cabeça. Fui de Ruby, o que pode parecer uma escolha estranha.

Trabalho na Stripe, casa da maior base de código Ruby do mundo. Certamente não contaria como uma linguagem "desconhecida", não é? Embora tudo isso seja verdade, nosso monólito Ruby parece muito distante do Ruby "padrão": tudo é verificado com o Sorbet, há muita geração de código, e fazemos muita mágica para que tudo funcione junto e escale. Embora o Ruby dentro e fora da Stripe seja, no fim das contas, a mesma linguagem, trabalhar em escalas tão diferentes proporciona experiências muito distintas; eu queria saber como era a vida lá fora (nos anos desde que eu tinha usado Ruby intensamente).

Em grande parte, foi bom! O Ruby em si é ótimo e cita a "felicidade do programador" como um objetivo principal, o que ressoou comigo. Gosto de como muitas vezes consigo adivinhar o nome de funções da biblioteca padrão que nunca usei. Gosto de como é fácil construir código funcional e de como a sintaxe é ergonômica e expressiva.

Dito isso, fiquei surpreso com o quanto as ferramentas de desenvolvimento ficavam atrás das de Python. Talvez eu esteja mal-acostumado, mas ter dicas de tipo no editor e ter linting e formatação extremamente rápidos é mais importante para mim do que eu imaginava. Para uma linguagem tão popular quanto Ruby foi no seu auge, fiquei surpreso com o quanto ela parecia atrasada nesse aspecto.3 Também nunca me acostumei de todo com os parênteses opcionais nas chamadas de função, o que tornava passar funções como argumentos menos direto.

Ruby continua sendo uma ótima linguagem e vou continuar usando no trabalho, mas ela não faz nada por mim que Python já não faça, pelo menos no momento.

Nibbly November

O mês de novembro foi o mais difícil até agora: linguagens de montagem. Embora já não seja comum escrevê-las à mão, é um assunto útil e interessante de conhecer. Escolhi WebAssembly por sua importância para a web moderna e futura. Embora seja tipicamente usada como alvo de compilação (e não algo que você escreve à mão), existem ferramentas para os malucos por aí.

Me senti inesperadamente bem preparado para este mês. A sintaxe parecia com a de Clojure e a estrutura da linguagem parecia com a do TIS-100 do Zachtronics. Por incrível que pareça, gostei de ter que começar do zero para cada operação; tinha um charme antiquado. Eu odiaria se tivesse que realmente fazer algo de útil desse jeito, mas, por enquanto, foi uma curiosidade divertida. Com comentários generosos, consegui escrever algo quase legível:

(module
  (func (export "eggCount") (param $number i32) (result i32)
	(local $res i32) ;; result
	(local $remainder i32) ;; loop counter

	(loop $loop

  	;; $res =
  	(local.set $res
    	;; $res +
    	(i32.add
      	(local.get $res)
      	;; $number % 2
      	(i32.rem_u
        	(local.get $number)
        	(i32.const 2)
      	)
    	)
  	)

  	;; $number //= 2
  	;; (keep on stack)
  	(local.tee $number
    	(i32.div_u
      	(local.get $number)
      	(i32.const 2)
    	)
  	)

  	;; this will keep looping until remainder is 0
  	br_if $loop
	)

	local.get $res
  )
)

O maior obstáculo foi a falta de documentação e recursos. Era difícil até saber quais funções globais estavam disponíveis. Mas, como eu não vou realmente usar isso, depois que peguei o jeito, não me incomodou muito.

Em dezembro, o ano foi encerrado com linguagens que não se encaixavam em outras categorias. Por causa da repetição em março, eu precisava completar duas linguagens neste mês.

Comecei com Wren. Criada por Bob Nystrom, famoso, entre outras coisas, por Crafting Interpreters. Fiquei encantado com sua atenção aos detalhes, seu tamanho reduzido e seu design de cima para baixo; tudo parece muito bem pensado. Esse nível de cuidado fica evidente nos detalhes das regras de escopo de variáveis e de privacidade. Seu compilador é pequeno e cheio de comentários, então é um ótimo recurso de aprendizado se você curte implementação de linguagens.

Wren é um pouco crua e parece estar quase abandonada, mas acho que isso é normal para uma linguagem de brinquedo. Ninguém entra nisso esperando que esteja pronta para produção. Há certamente espaço no mundo para linguagens que não são de produção.

Também: Lua

Minha segunda escolha deste mês foi Lua. Em contraste com Wren, ela é incrivelmente prática. Sua fácil capacidade de ser embutida faz com que apareça em muitos lugares, como scripts no Redis e mods de Factorio. O modelo de objetos exigiu um pouco de tempo para se acostumar, mas consigo ver como eu seria produtivo rapidamente. Logo me apeguei às tabelas como uma estrutura que faz tudo. As ferramentas eram boas: o gerenciador de pacotes funcionava de imediato e a extensão de VSCode suportava anotações de tipo baseadas em comentários sem complicação.

Embora eu não tenha nada para que precise de Lua imediatamente, é outra ótima ferramenta para ter à mão por causa do seu uso generalizado.

Para terminar

Gostei dessa turnê pelas linguagens mais do que esperava. Não só aprendi algumas habilidades práticas novas, como sinto que meus horizontes se ampliaram bastante.

Quanto ao que vem a seguir, acho que é aprender muito mais Rust. Sua importância no cenário das ferramentas de desenvolvimento é evidente a essa altura, e quero garantir que consiga ler e contribuir com as coisas nas quais confio.

Não tenho um resultado concreto em mente, mas tenho o livro do Rust inteiro para ler, um curso de Rust para devs de JS que eu reembolsei um ano, e uma trilha inteira do Exercism para concluir. Gostaria de contribuir com pelo menos um projeto open source (provavelmente o Just, um dos meus programas favoritos recentes), mas vamos ver onde o ano me leva.

Até lá, boas festas e um ótimo restante de 2023 para você!

  1. Variáveis não utilizadas são um erro de compilação?? Ah, faça-me o favor ↩

  2. Na verdade, tentei C++ primeiro (que eu não escrevia desde a faculdade). Simplesmente não era divertido, então desisti ↩

  3. Essa é outra forma pela qual o Ruby "real" difere da minha experiência na Stripe, então fico feliz por ter experimentado das duas maneiras ↩

05 de janeiro de 2024 · Achou útil?