3 pontos por GN⁺ 2023-07-03 | 1 comentários | Compartilhar no WhatsApp
  • Usando a cena de um desenvolvedor JavaScript com 10 anos de experiência lendo um package.json como uma prova de dor, o texto mostra quanta complexidade acumulada do ecossistema cabe em um único arquivo de configuração
  • Campos como main, browser e type: module evocam velhas cicatrizes de migração de JavaScript isomórfico, bundles para navegador e da transição entre CommonJS e ESM
  • Em scripts, dependencies e devDependencies, se misturam variações de lint, watchman, gulp, left-pad, moment.js e problemas antigos de gerenciamento de pacotes como resolutions
  • eslint, postcss, jest e 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 engines do 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.json no 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
  • version ainda não chegou a 1.0, e o SemVer permanece como uma lembrança desagradável de algo que ele aprendeu a ignorar há muito tempo
  • name mostra 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 main e browser revela vestígios do JavaScript isomórfico
  • A lembrança de tentar usar require no módulo fs dentro de um bundle para navegador, e dos hacks usados para fazer isso funcionar, ficou como uma experiência desagradável
  • type: module está ligado à migração de require para import
  • 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, lintfast e lintdiff
    • 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
  • 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 dependencies há 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
  • resolutions permanece 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 eslint ficou 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-ignore espalhados pelo codebase
  • postcss não é usado diretamente, mas existe como um pacote exigido pela dependência de alguma dependência
    • Toda vez que se tenta rodar npm install em uma nova plataforma, ele provoca erros obscuros de compilação em C++
  • jest começ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, node está 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

 
GN⁺ 2023-07-03
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

    • Grunt, Gulp, CoffeeScript, IIFE, undefined sobrescrito, with, simulação de campos privados com closures, protótipos modificados, globais padrão, this mudando conforme o local da chamada, coerção automática de tipos em comparações…
      É, foi assim por mais de 10 anos de JavaScript
    • Concordo com a parte sobre callbacks. Mas, olhando meu JavaScript de 10 anos atrás, a maior dor eram todas as classes falsas feitas mexendo em SomeFunction.prototype
      Aí você embrulhava isso numa função anônima autoexecutável e retornava como objeto, para poder chamar new SomeFunction() ou SomeFunction.actualFunction() como se SomeFunction fosse uma classe. Também era horrível não ter arrow functions, então a gente alterava o próprio Function.prototype para amarrar eventos ao escopo usando .apply(), ou caía no inferno interminável de .bind(this) em cada callback de evento
    • Eu desenvolvia no Firefox para usar o Firebug, tendo que dar suporte separadamente a ie6, ie7, ie8
    • Também houve uma época em que trocávamos os cabeçalhos por pequenos applets em Flash para usar a fonte que quiséssemos sem ficar limitados às fontes instaladas pelo usuário
    • Inferno de callbacks e a ausência geral de tipos eram grandes problemas
      Ainda 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 .devcontainer ou 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 eslint
    Depois 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 quem já sabe tudo isso leva um dia. Como desenvolvedor mais voltado a backend e operações, tentei entrar nessa pilha algumas vezes, mas honestamente em muitos casos simplesmente fracassei
      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
    • São dois linters. Só isso já é insano. O resto é ainda pior, mas até o menor pedaço da escolha de ferramentas no ecossistema JavaScript está cheio de dor
    • Eu copio meu diretório inicial de TypeScript e só mudo o nome no package.json. Claro, eu faço mais backend, mas talvez no frontend também dê para criar um template pessoal assim, não?
    • O npm create nã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 funciona
    • Talvez baste criar um projeto stub com toda a configuração que você gosta, subir no GitHub
      Quando 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

    • Qual será a proporção de desenvolvedores JavaScript que não usam NodeJS?
      É 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
    • Certo, então o ecossistema não é um alvo válido para criticar uma linguagem
    • Tente realmente escrever JavaScript uma vez sem bundler usando package.json. Até a ECMA colocar um gerenciador de pacotes ou bundler na especificação oficial, package.json é de fato parte do JavaScript
    • Se isso te incomoda tanto, então toda vez que alguém disser JavaScript, é só pensar que na verdade quer dizer ECMAscript
    • Sim. Isso é uma crítica ao ecossistema JavaScript
  • Gosto 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

    • Sim. A ironia é que, por causa desse compromisso, você pode jogar um desenvolvedor sênior que passou 20 anos fazendo coisas que rodam no navegador e mesmo assim ele não estará pronto em um dia
      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
    • Aí você passa de um a três dias montando alguma gambiarra, se arrepende pelos próximos 10 anos e acaba escrevendo um texto desses. O ciclo continua
    • Os juniores que eu conheço dizem: “vamos criar um framework para lidar com essa complexidade”
      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
    • Agora, em vez de pesquisar, perguntam ao ChatGPT
  • “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 existe
    Estou 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

    • Concordo. Estou fazendo um videogame e decidi não usar dependência nenhuma, e isso tornou programar realmente divertido
  • 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

    • Ser humor não significa que não seja sério
  • 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

    • É por isso que tento usar Go para quase tudo. Mesmo quando não é a melhor escolha, é a que dá menos trabalho
    • C é complexo? É praticamente a única linguagem que consigo manter inteira na cabeça independentemente de com que frequência eu a use. Parte da sintaxe do JavaScript moderno eu uso todo dia e mesmo assim evapora facilmente da memória
  • 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.json passar de 20 linhas

    • Estou encarando o novo frontend em Angular que estamos desenvolvendo agora, e há quatro componentes de frontend, cada um com um package.json com mais de 200 linhas
      Falando 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
    • Eu também. Mas, falando de algo fora do assunto, o link no perfil é bloqueado pelo uBlock Origin e leva a uma toca de coelho de sites estranhos. Nunca usei hackernewsers, então não sei se esse é o funcionamento normal
  • 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