JavaScript Gom Jabbar
(frantic.im)- Usando a cena de um desenvolvedor JavaScript com 10 anos de experiência lendo um
package.jsoncomo uma prova de dor, o texto mostra quanta complexidade acumulada do ecossistema cabe em um único arquivo de configuração - Campos como
main,browseretype: moduleevocam velhas cicatrizes de migração de JavaScript isomórfico, bundles para navegador e da transição entre CommonJS e ESM - Em
scripts,dependenciesedevDependencies, se misturam variações de lint,watchman, gulp,left-pad, moment.js e problemas antigos de gerenciamento de pacotes comoresolutions eslint,postcss,jeste ferramentas de build e teste aumentam o custo de manter o ambiente de desenvolvimento por meio de regras rígidas, erros de instalação específicos de plataforma e da dificuldade de configurar ESM e TypeScript- Mesmo olhando para
enginesdo Node, a razão para não migrar para Bun ou Deno é a certeza de que a dor não desapareceria, só ficaria maior, e o desenvolvedor fecha o arquivo e sobrevive por enquanto
A provação de ler package.json
- A história começa com um desenvolvedor que usa JavaScript há 10 anos diante da situação de abrir um arquivo
package.jsonno computador e precisar lê-lo até o fim - Esse arquivo não é apenas um arquivo de configuração simples, mas algo que faz voltar de uma vez só as memórias e dores vividas no ecossistema JavaScript
versionainda não chegou a1.0, e o SemVer permanece como uma lembrança desagradável de algo que ele aprendeu a ignorar há muito temponamemostra a situação de não poder usar o nome desejado porque alguém já o ocupou há 7 anos e nunca mais atualizou o pacote
Velhas cicatrizes de módulos e bundling
- A presença conjunta dos campos
mainebrowserrevela vestígios do JavaScript isomórfico - A lembrança de tentar usar
requireno módulofsdentro de um bundle para navegador, e dos hacks usados para fazer isso funcionar, ficou como uma experiência desagradável type: moduleestá ligado à migração derequireparaimport- A experiência de tentar importar módulos CommonJS e ESM uns nos outros permaneceu como uma grande dor
A confusão de scripts e dependências
scriptsé o centro de uma confusão quente e dolorosa- Existem variações como
lint,lintall,lintfastelintdiff - Aparecem execução em paralelo, argumentos pouco claros e escape duplo de argumentos em formato JSON
- Mesmo depois da migração para yarn e pnpm, alguns subcomandos ainda chamam npm
- Existem variações como
- Alguns scripts ainda usam
watchman- É preciso lembrar que ele não deve ser usado porque não oferece suporte a symlink
- A issue relacionada está aberta desde 2015
- Scripts baseados em gulp também continuam lá, e embora exista vontade de trocá-los por algo mais moderno, ninguém tem coragem de fazer a substituição
O trauma evocado pela lista de pacotes
- Em
dependencieshá muitos pacotes, e cada um deles faz ressurgir sua própria memória traumática left-padé um pacote pequeno, mas ficou marcado como o lendário pacote que “quebrou a internet inteira”- Sempre que a lista de dependências é alterada, alguns pacotes despejam no console longos pedidos de doação ou avisos de breaking changes
- O desenvolvedor chega ao ponto de apenas torcer para que nenhum pacote malicioso roube segredos ou destrua o computador
- moment.js é lembrado como uma biblioteca com boa API, mas a internet decidiu que ela é mutável demais, grande demais e não suporta treeshaking, e agora a situação é de precisar migrar para date-fns
- As versões dos pacotes estão muito atrasadas em relação ao presente e precisam de upgrade, mas a experiência passada com upgrades faz prever muita dor
resolutionspermanece como mais uma dor escolhida para evitar upgrades de pacotes
Outra complexidade criada pelas ferramentas de desenvolvimento
- Ao olhar para
devDependencies, fica difícil até lembrar da época em que só eram necessárias dependências não-dev - A configuração do
eslintficou rígida demais, a ponto de qualquer pequeno erro gerar um sublinhado vermelho, e a CI trata problemas de lint como se fossem o fim do mundo- Isso dá uma falsa sensação de segurança aos engenheiros juniores do time
- Já houve várias discussões sobre quais regras ativar
- A dor cresce na mesma medida que a quantidade de
eslint-ignoreespalhados pelo codebase
postcssnão é usado diretamente, mas existe como um pacote exigido pela dependência de alguma dependência- Toda vez que se tenta rodar
npm installem uma nova plataforma, ele provoca erros obscuros de compilação em C++
- Toda vez que se tenta rodar
jestcomeçou como um test runner rápido, mas agora ficou grande e pesado, dependendo de alguns pacotes do Babel- O restante da aplicação é transpilado com a combinação de esbuild e swc
- Configurá-lo direito para ESM e TypeScript é tão difícil quanto um “projeto científico de PhD”
- No codebase, muitas ferramentas e parsers estão envolvidos: TypeScript, esbuild, swc, babel, eslint, prettier, jest, webpack, rollup, terser e outros
- Em
engines,nodeestá especificado, e mesmo que se migrasse para Bun ou Deno, a dor não pararia, apenas pioraria - Depois de ler até a última chave de fechamento, ele fecha a aba, retoma o fôlego e sobrevive por enquanto com as mãos e o cérebro ainda intactos
1 comentários
Comentários no Hacker News
Bem engraçado. Escrevi JavaScript por uns 18 anos e parei há uns 3 anos, e a maioria das preocupações desta lista é coisa dos últimos 10 anos
Chama especialmente a atenção a ausência dos polyfills que com certeza estariam lá se isso tivesse sido escrito em 2013. Que outros pesadelos de JavaScript de 2013 praticamente sumiram hoje? Claro, foram substituídos por esta lista engraçada
Minha parte favorita foi a de ficar contando ferramentas e parsers que funcionam no codebase e lembrar de TypeScript, esbuild, swc, babel, eslint, prettier, jest, webpack, rollup, terser, e a dor ser tão grande que você já nem quer saber se esqueceu mais algum
undefinedsobrescrito,with, simulação de campos privados com closures, protótipos modificados, globais padrão,thismudando conforme o local da chamada, coerção automática de tipos em comparações…É, foi assim por mais de 10 anos de JavaScript
SomeFunction.prototypeAí você embrulhava isso numa função anônima autoexecutável e retornava como objeto, para poder chamar
new SomeFunction()ouSomeFunction.actualFunction()como seSomeFunctionfosse uma classe. Também era horrível não ter arrow functions, então a gente alterava o próprioFunction.prototypepara amarrar eventos ao escopo usando.apply(), ou caía no inferno interminável de.bind(this)em cada callback de eventoAinda hoje tive o azar de escrever um teste técnico para uma empresa que ainda usa JavaScript puro, sem Promise nem arquivos de declaração, e foi como voltar à primeira vez que conheci Node em 2012. A exigência de usar JavaScript eu consegui contornar com JSDoc, mas foi muito pior do que eu lembrava
Sempre passo pelo mesmo processo toda vez que começo um projeto novo em JavaScript, ou melhor, um projeto em TypeScript
Geralmente é frontend, então escolho React, embora também tenha vontade de usar Svelte. Antigamente o bundler era create-react-app ou algum wrapper de Webpack, mas hoje Vite é a melhor opção porque exige pouca configuração e suporta os principais frameworks
Aí instalo e configuro o compilador TypeScript, normalmente copiando e colando de um template. Defino como alvo o JavaScript estável mais recente e módulos ESM, configuro eslint e prettier para funcionarem juntos e adiciono plugins de TypeScript e React, por exemplo. Também coloco hooks para rodar Prettier e eslint antes do commit
Instalo extensões da IDE e preparo um
.devcontainerou uma lista de extensões recomendadas. Não me importo muito com estilo em si; o importante é consistência no código e detectar erros, então no geral uso configurações prontas de eslintDepois configuro testes unitários com jest ou vitest, e junto vêm mais configurações de TypeScript e regras de eslint. Gosto de tailwind como framework CSS, então ainda instalo styled-components e twin.macro para encaixar bem com React, além de plugin do Google Fonts ou alguma biblioteca de fontes
Só depois de mais ou menos um dia disso tudo é que dá para começar a programar. Por que isso dá tanto trabalho? Tem tanta gente usando a combinação Vite + TypeScript + React/Vue/Svelte + eslint/prettier + tailwind/bootstrap + jest/vitest, então por que não existe uma biblioteca sem configuração que já atenda de cara 90% dos casos de uso?
Mesmo quando eu conseguia fazer a cadeia de ferramentas subir de algum jeito, eu não tinha sensação nenhuma de controle, parecia algo que desabaria com a menor tremida e que eu não conseguiria consertar
Ultimamente resolvi ver a maior parte dessa stack de JavaScript como um obstáculo ao que eu quero fazer e voltei a montar apps com renderização no servidor no estilo antigo, com Flask e Jinja2. Não é moderno nem brilhante e ainda está sem CSS, então hoje ficou bem feio, mas me aconselharam a tentar com CSS moderno puro. Ainda assim, é surpreendente a velocidade com que dá para entregar funcionalidades nessa stack
package.json. Claro, eu faço mais backend, mas talvez no frontend também dê para criar um template pessoal assim, não?npm createnão resolve isso?Se você rodar
npm create vue, sai uma configuração de Vue bem decente e funcional, com a maior parte disso já pronta. Concordo que existe muito boilerplate e um monte de firula, mas os apps que fazemos na web hoje também ficaram muito maiores do que antes. Dá para usar JavaScript só com ESModules, sem ferramentas, mas em geral isso não acontece porque essas ferramentas realmente fazem alguma coisa útil. Não é o jeito mais limpo, mas funcionaQuando for começar um projeto novo, é só clonar e trocar alguns nomes, e pronto
Este é mais um daqueles casos em que as pessoas dizem JavaScript, mas na verdade querem dizer “a tralha do ecossistema Node”
Desde o começo já dizem que é preciso abrir e ler o arquivo
package.json, e depois a coisa segue nessa linha. Quase nada do que foi mencionado tem relação com JavaScript em siÉ verdade que JavaScript e NodeJS não são a mesma coisa, mas a maioria provavelmente entendeu o que o autor quis dizer. Seria melhor escrever de forma mais precisa, mas também não dá para dizer que esteja totalmente errado
package.json. Até a ECMA colocar um gerenciador de pacotes ou bundler na especificação oficial,package.jsoné de fato parte do JavaScriptGosto do tom brincalhão. Depois que sua pele e suas terminações nervosas já queimaram em várias camadas, é útil revisitar esses pontos de dor
Dito de outro modo, você pode dar um MacBook novo para um desenvolvedor júnior motivado e jogá-lo na água funda, e ele ainda vai conseguir ser produtivo em um dia. Não precisa conhecer containers, .NET, nginx nem 100 ferramentas de linha de comando usadas com frequência; se der problema, é só pesquisar
Mesmo sabendo que conseguiria construir o navio inteiro em poucos dias se pudesse simplesmente mexer com as próprias mãos, ele acaba lutando contra camadas de complexidade desnecessária enquanto tenta consertar um navio dentro de uma garrafa usando as ferramentas toscas fornecidas. É exatamente essa a sensação de avançar rápido num projeto pessoal usando só JavaScript, HTML e CSS e depois ser colocado para trabalhar com frontend moderno
Eles ingenuamente não percebem que isso leva meses para ser feito, que parte do problema é justamente o excesso de frameworks, e que no dia seguinte ele já estará ultrapassado
“Segui as instruções e apareceu que o grunt não estava instalado. Como agora sou uma pessoa velha, eu não sabia muito bem o que era grunt, e meu arquivo grunt também não parecia bater com nada. Então pesquisei um pouco e descobri o que era grunt. Grunt é… na verdade eu ainda não sei bem o que é.”
--Joe Armstrong, https://www.youtube.com/watch?v=lKXe3HUG2l4
Há alguns dias executei
gem install wayback_machine_downloader. Nunca gostei da linguagem Ruby o suficiente para entrar de vez no ecossistema dela, mas de fora ele parece ter se mantido surpreendentemente estável. gem ainda é uma ferramenta usada, e Rails ainda existeEstou esperando um projeto novo que realmente precise de um frontend complexo, o bastante para passar de 0 a 30 linhas de JavaScript. Quando isso acontecer, acho que ficarei mais feliz com HTMX do que com o framework gigante mais popular do momento
Isto não é sobre JavaScript, é sobre npm
Eu odeio npm por causa desse tipo de tralha e evito ao máximo. Pessoalmente uso Deno, e no trabalho usamos algo baseado em monorepo, parecido com bazel, que faz com que npm não seja necessário
Mas acho JavaScript/TypeScript linguagens muito boas de programar, e são minha primeira escolha para qualquer coisa que eu vá criar. Fico triste quando as pessoas dizem “JavaScript é ruim”, mas o que elas querem dizer na verdade é que é ruim construir app React com npm. Programar em JavaScript/TypeScript moderno é realmente prazeroso
Parece que JavaScript e seu ecossistema deixaram PTSD em todos nós a ponto de não conseguirmos aproveitar a comédia deste texto
Há discussão “séria” demais em torno de um texto engraçado. Podem dissecar à vontade, mas seria bom lembrar que a intenção real é humor
Sinceramente, o primeiro ecossistema em que comecei foi Node, e depois percebi que as outras coisas que aprendi também tinham seus próprios problemas malucos
Haskell era muito difícil de usar em várias máquinas, instalá-lo no MacOS em 2019 também era doloroso, e gerenciar o ecossistema era complicado. Macros e extensões são bastante confusas, e a compatibilidade retroativa da linguagem também não é boa. Já o JavaScript de 2010 geralmente ainda funciona em 2023 como se espera
Até montar direito uma imagem Docker ou um ambiente como codespace/gitpod é difícil, e a imagem padrão fornecida pelo GitHub também não é grande coisa e tem problemas
C é razoável na maioria das plataformas, mas a própria linguagem, sinceramente, é complexa e exige um conhecimento enorme do sistema como um todo. O resultado é que é fácil acabar com código pouco portátil, inadequado para a maior parte dos usos de programação geral
Eu poderia continuar, mas quem já usou várias linguagens sabe que todos os ecossistemas têm vários defeitos e que todos nós continuamos sofrendo. Com PHP, nunca consegui terminar a configuração de um projeto em menos de alguns dias; Elm dói menos, mas tem seus próprios problemas com o estado de ditador benevolente e o ritmo de desenvolvimento
Sou um desenvolvedor poliglota que acha confortável trabalhar com vários paradigmas e linguagens de programação, tanto no frontend quanto no backend
Quase sempre tenho exatamente essa reação toda vez que vejo um
package.jsonpassar de 20 linhaspackage.jsoncom mais de 200 linhasFalando em voz alta como se estivesse tentando afastar o demônio. “Não devo temer. O medo é o assassino da mente. O medo é a pequena morte que traz a aniquilação total. Enfrentarei meu medo. Permitirei que ele passe por mim. E quando ele tiver passado, voltarei o olho da mente para ver seu caminho. Onde o medo tiver passado, não haverá nada. Apenas eu permanecerei.”
Chorando
Um desenvolvedor JavaScript das antigas lendo o texto e sofrendo com PTSD e flashbacks
Não devo temer. O medo é o assassino da mente. O medo é a pequena morte que traz a aniquilação total
Enfrentarei meu medo. Permitirei que ele passe por mim. E quando ele tiver passado, voltarei o olho da mente para ver seu caminho
Onde o medo tiver passado, não haverá nada. Apenas eu permanecerei
Termina de ler o texto e percebe que sobreviveu, mas já está encharcado de suor