5 pontos por GN⁺ 2026-04-25 | 1 comentários | Compartilhar no WhatsApp
  • Projetos tendem a se dividir entre o fluxo de simplesmente fazer e terminar logo e o fluxo em que pesquisa e design crescem até fazer você perder o problema original; na prática, muitas vezes simplesmente tentar fazer avança mais
  • Mesmo ao criar uma busca fuzzy de caminhos para Emacs, recursos extras de uma boa biblioteca geraram novas exigências e inflaram o design; no fim, ao descartar todo o código de ancoragem que não era necessário, a lição de YAGNI voltou a se confirmar
  • Em diffs de código, a comparação por linha não captura bem estruturas de nível superior como funções ou tipos, e mesmo ferramentas baseadas em treesitter podem ficar difíceis de ler se o pareamento entre entidades falhar entre versões, exibindo longos blocos como exclusões e adições
  • A direção necessária é primeiro criar uma ferramenta de escopo mínimo voltada para revisão por turno da saída de LLM, começando com extração de entidades em Rust e pareamento simples para ver rapidamente um resumo de mudanças em alto nível

Excesso de reflexão e expansão de escopo

  • Projetos tendem a se dividir entre o fluxo de simplesmente fazer e terminar logo e o fluxo em que, ao mergulhar em casos anteriores, o escopo cresce e no fim o problema original deixa de ser resolvido
  • Uma prateleira de cozinha feita no fim de semana foi planejada tomando café, teve um suporte impresso em 3D ajustado algumas vezes e ficou pronta dentro do próprio fim de semana com materiais e tinta que já sobravam
    • O CAD do suporte para o bin da Ikea está publicado em OnShape CAD
    • Os materiais reaproveitaram sobras da bancada de trabalho, e os cantos foram lixados no olho com uma palm sander
  • Nessa prateleira, o principal critério de sucesso não era fazer algo perfeitamente ajustado à cozinha, mas curtir marcenaria com um amigo, o que reduziu a necessidade de pensar demais em critérios detalhados
  • Em contraste, na busca por uma ferramenta de diff estrutural, o resultado de difftastic deixou a desejar, então houve 4 horas de pesquisa sobre ferramentas e workflows relacionados, até voltar ao critério original: um workflow de diff melhor para usar no Emacs
  • Interesses antigos como interfaces para prototipagem de hardware, uma linguagem misturando Clojure e Rust, e uma linguagem para CAD consumiram centenas de horas em pesquisa de base e pequenos protótipos, mas ainda não viraram algo que resolva diretamente a motivação inicial
  • Nos projetos de linguagem e CAD, os critérios de sucesso são nebulosos: substituir Rust ou Clojure, atacar só parte do problema, bastar como playground de aprendizado, trocar um CAD comercial, ou ainda precisar ser útil para outras pessoas
  • Examinar essas perguntas tem valor, mas a visão aqui é que fazer muita coisa de verdade costuma ser melhor do que apenas analisar muita coisa
  • Mesmo que, olhando depois, o resultado claramente não seja bom, simplesmente tentar fazer acaba levando mais longe no geral

A lei da conservação da expansão de escopo

  • O tempo de sair construindo sem pensar também tem limites e exige equilíbrio, e a experiência de fazer um LLM agent escrever muito código para depois jogar tudo fora trouxe YAGNI de volta à cabeça
  • A ideia era criar uma busca fuzzy de caminhos em todo o filesystem no estilo do Finda para usar no Emacs; como essa mesma função já havia sido implementada à mão antes, parecia plausível terminar tudo em poucas horas supervisionando um LLM
  • No começo, numa conversa de planejamento, veio a recomendação de Nucleo, que parecia bem projetado e bem documentado, então foi adotado para obter smart case e Unicode normalization
    • Por exemplo, a query foo casa tanto com Foo quanto com foo, mas Foo não casa com foo
    • O tratamento de cafe e café entra no mesmo contexto
  • O problema não era a boa biblioteca em si, mas o fato de o Nucleo também suportar ancoragem
  • Como, num corpus só de caminhos de arquivo, uma âncora de início de linha parecia inútil, surgiu a tentativa de reinterpretá-la como âncora por segmento de caminho
    • Por exemplo, a ideia era que ^foo casasse com /root/foobar/, mas não com /root/barfoo/
  • Para tratar isso de forma eficiente, o índice precisaria armazenar limites de segmento e permitir verificar a query rapidamente em cada segmento
  • Além disso, seria preciso lidar com queries ancoradas contendo barra, como ^foo/bar, e só a checagem por segmento já não bastaria para casar corretamente caminhos como /root/foo/bar/baz/
  • Mais algumas horas foram gastas nesse design, trocando ideias com o LLM e escrevendo código que encapsulava os tipos do Nucleo, até que o código ficou grande demais e desagradou, levando à reescrita manual de um wrapper menor
  • Depois de uma pausa, veio a constatação de que não havia lembrança de realmente precisar de ancoragem no Finda, e que num corpus de caminhos muitas vezes basta colocar / no início ou no fim da query para cobrir a maior parte desse papel
    • A única exceção restante é a âncora para fim de nome de arquivo
  • No fim, todo o código de ancoragem foi descartado, e é difícil ter certeza se ainda assim houve ganho em relação a ter escrito tudo diretamente desde o começo, sem LLM nem discussões com outras pessoas
  • Parece existir uma espécie de lei da conservação segundo a qual, quanto mais a velocidade de programação aumenta, mais também aumentam funcionalidades desnecessárias, rabbit holes e desvios

Diff estrutural

  • Em código, diff normalmente significa um resumo de mudanças por linha entre duas versões de um arquivo, e na visualização unified adições e remoções aparecem com + e -
  • O mesmo diff também pode ser renderizado em comparação lado a lado, e quanto mais complexa a mudança, mais fácil esse formato pode ficar de ler
  • O problema do diff por linha é que ele não reconhece estruturas de nível superior como funções ou tipos; se as chaves por acaso “fecham”, a exibição pode omitir que as linhas pertencem a funções diferentes
  • difftastic tenta reduzir esse problema usando a concrete syntax tree fornecida pelo treesitter, mas o pareamento de entidades entre versões nem sempre funciona bem
  • No diff que motivou tudo isso, struct PendingClick não foi reconhecida como correspondente entre os dois lados, aparecendo como removida à esquerda e adicionada à direita
  • Sem investigar a fundo por que o pareamento falhou, a conclusão foi que seria melhor ver PendingClickRequest e PendingClick correspondendo entre os dois lados, mesmo que isso tornasse o diff total mais longo

Ferramentas e referências de diff estrutural

  • A ferramenta de semantic diff mais acabada e cuidadosamente polida, na avaliação do autor, é semanticdiff.com
    • Ela é oferecida por uma pequena empresa alemã, com plugin gratuito para VSCode e um web app que mostra diff de PRs no GitHub
    • Porém, não oferece uma biblioteca de código que possa servir de base para o workflow desejado
    • O texto semanticdiff vs. difftastic tem muitos detalhes úteis, incluindo o problema de o difftastic não mostrar nem mesmo mudanças significativas de indentação em Python
    • Em um comentário no HN, um dos autores disse que abandonou o uso de treesitter para tratar semântica, relatando que parsing podia falhar por causa de palavras-chave dependentes de contexto e comportamento do lexer, a ponto de a ferramenta travar quando nomes como async eram usados como parâmetro
  • diffsitter é baseado em treesitter e inclui um servidor MCP
    • Tem bastante estrela no GitHub, mas a documentação não pareceu especialmente boa, e foi difícil encontrar materiais explicando como funciona
    • A wiki do difftastic diz que ele executa longest-common-subsequence sobre as folhas da árvore
  • gumtree é uma ferramenta surgida de pesquisa acadêmica em 2014
    • Como exige Java, não combina com o uso pessoal de algo rápido para acionar dentro do Emacs
  • mergiraf é um merge-driver em Rust baseado em treesitter
    • A architecture overview é bem organizada, e internamente ele usa o algoritmo Gumtree
    • Pela documentação e pelos diagramas, passa a impressão de um projeto escrito com bastante cuidado
    • O autor do semanticdiff.com escreveu num comentário no HN que o GumTree entrega resultados rapidamente, mas mesmo com melhorias propostas em artigos posteriores ainda retornava pareamentos ruins com frequência considerável, o que acabou levando a uma abordagem baseada em Dijkstra para minimizar o custo do mapeamento
  • weave é outro merge-driver em Rust baseado em treesitter
    • O conjunto da obra — landing page chamativa, muitas estrelas no GitHub, servidor MCP — pareceu um tanto exagerado
    • Houve uma olhada também no crate de extração de entidades sem
    • O código central de diff parece razoável, mas um pouco verboso, e o pareamento de entidades usa um algoritmo guloso
    • O modelo de dados não detecta movimentações dentro do arquivo, embora esse tipo de mudança possa ser importante
    • Há também muita análise de impacto baseada em heurísticas que parece exigir integrações de linguagem mais fortes para inspirar confiança
      • Ao executar sem diff --verbose HEAD~4, apareceu inclusive uma saída com bug marcando como alteradas linhas que na prática não tinham mudado
    • Havia funções potencialmente úteis demais, num estado que parecia 80% pronto, então não serviu como base; ainda assim, fazer tudo isso em 3 meses foi considerado impressionante
  • diffast calcula a tree edit-distance de ASTs com base em um algoritmo descrito num artigo acadêmico de 2008
    • Suporta Python, Java, Verilog, Fortran e C/C++ por meio de parsers dedicados
    • A galeria de exemplos de diferenças em AST é bem organizada
    • Exporta informações em forma de tuplas, úteis para uso com datalog
  • autochrome é uma ferramenta de diff específica de Clojure e usa programação dinâmica
    • A explicação visual e o walkthrough com exemplos são muito bons
  • O texto de Tristan Hume, Designing a Tree Diff Algorithm Using Dynamic Programming and A*, é uma referência valiosa sobre projeto de algoritmos de tree diff

O workflow desejado e um plano de escopo mínimo

  • O principal caso de uso é a revisão por turno da saída de LLM, e não se deixa um agent gerar de uma vez mais de 10 mil linhas de código sem controle
  • A ideia é delegar ao agent tarefas com escopo definido, voltar alguns minutos depois para ver uma visão geral das mudanças e então editar manualmente no Emacs, jogar tudo fora e tentar de novo, ou até reescrever tudo por conta própria
  • O workflow desejado começa vendo primeiro um resumo em alto nível de quais tipos, funções e métodos foram adicionados, removidos ou modificados
  • Em seguida, deve ser possível expandir rapidamente o diff textual de cada entidade, fazendo a transição natural do resumo para o detalhe
  • Também é importante poder corrigir a mudança ali mesmo, sem saltar para outro lugar, com edição inline em vez de trocar da tela de diff para a tela do arquivo
  • A inspiração é transportar o workflow de revisão e staging de mudanças do Magit do nível de arquivo e linha para o nível de entidade
  • Em sintonia com a lição reaprendida de escopo mínimo, o plano agora é primeiro montar às pressas um framework de extração de entidades baseado em treesitter voltado só para Rust
  • O pareamento começará de forma simples, com uma estratégia gulosa, e o diff será renderizado na linha de comando
  • Se isso já produzir resultados melhores que o difftastic naquele commit específico, a próxima etapa será ligar a ideia a um workflow mais interativo no Emacs, como o do Magit
    • Se possível, fica aberta até a chance de reaproveitar o próprio Magit
    • Suporte a novas linguagens será adicionado apenas quando necessário
    • Mais adiante, em vez do guloso simples, pode haver exploração de pareamento global baseado em pontuação
  • Se o resultado ficar satisfatório, talvez seja publicado, mas juntar estrelas no GitHub ou karma no HN não é o objetivo; também pode continuar só como uma ferramenta silenciosa de uso pessoal
  • Às vezes, tudo o que se quer é apenas uma prateleira, frase que amarra novamente a ideia de fazer apenas o necessário em vez de expandir demais

1 comentários

 
GN⁺ 2026-04-25
Comentários do Hacker News
  • Acho que isso mostra muito bem a maior dificuldade de uma pesquisa de PhD
    Quando você pega um tema interessante e lê o máximo possível da bibliografia relacionada, é fácil perceber quantas coisas parecidas com o que você queria fazer já foram feitas, e aí o scope creep tende a piorar bastante
    Depois de gastar toda a energia e empolgação do começo, você precisa empurrar à força os 20~30% finais para levar aquilo até um estado publicável

    • No dia 1, você começa querendo aplicar um catalisador industrial existente a um novo uso para reduzir o custo de produção de um precursor de medicamento essencial
      No dia 400, depois de praticamente explicar a teoria de tudo, você está tentando construir um dispositivo experimental em órbita no ponto de Lagrange para detectar uma partícula universal que media todas as forças do universo conhecido
    • Essa sensação me pareceu absurdamente real
      Fico me perguntando como dá para aliviar isso
    • Acho que a razão de a maioria dos doutorados passar por isso é que o objetivo do PhD, no fim das contas, é provar que você consegue fazer normal science
      Na prática, é um trabalho do tipo aumentar a observabilidade de um sistema de 1% para 1,001%, e acaba sendo mais uma porta de entrada para uma carreira acadêmica
      Por isso, quase nunca vejo teses que sejam realmente interessantes, muito novas ou diretamente aplicáveis à ciência
    • E, além disso, você precisa aguentar tudo isso enquanto o arrependimento por ter começado o PhD vai ficando cada vez mais pesado
    • Começar tentando ler toda a bibliografia possível é claramente uma abordagem errada
      Na prática, quase nunca vi alguém pesquisar assim; normalmente o certo é ler dois ou três artigos e ir construindo a partir dali
      Mergulhar fundo na literatura faz mais sentido depois que já houver algum resultado e você começar a organizar isso por escrito
  • Continuo pensando na ideia de que melhor já basta
    Pequenas melhorias se acumulam com o tempo, e como nada nasce perfeitamente novo desde o início, ficar sentado tentando desenhar a solução perfeita tende a ser contraproducente
    A ideia de que o obstáculo é o caminho também se encaixa bem aqui

    • A frase de não deixar que o perfeito seja inimigo do suficientemente bom cai como uma luva
      Um colega com quem eu trabalhava, ao criticar mudanças de código, quando sentia que estava pegando detalhe demais, dizia: "está melhor do que antes"
      Isso permitia apontar o que podia melhorar, mas ao mesmo tempo dava permissão para seguir em frente mesmo com pequenas imperfeições, e eu apoio muito essa postura
    • No fim, isso é perfeccionismo
      Eu costumava pensar em perfeccionismo só como a busca exagerada por realizações muito altas, mas também pode ser a incapacidade de aceitar algo que não seja perfeito, a ponto de desistir sem avançar
      A procrastinação em grandes tarefas muitas vezes tem a mesma raiz
  • Gostei de algo que o CEO da Rec Room disse
    As equipes sempre dizem que gostariam que o projeto tivesse sido mais curto; quase nunca dizem que gostariam de ter adiado mais o lançamento, deixado mais complexo e refinado mais
    Isso não se aplica 100% a todas as situações, claro, mas se for para errar, acho melhor fazer menor e lançar cedo do que abrir demais a escala e desperdiçar tempo

  • Acho que os seres humanos, por natureza, têm facilidade para chegar a ideias parecidas, então se você conclui um projeto sem saber o que já existe, ele tende a acabar sendo uma reinvenção em algum grau
    Por outro lado, se você pesquisar antes, pode perceber que aquilo já existia parcialmente e perder o entusiasmo
    Mesmo assim, talvez o mais importante seja terminar de construir pelo próprio aprendizado
    Claro, isso é mais difícil quando você precisa produzir resultado acadêmico novo ou lucrar com um projeto realmente único, mas até esses campos são surpreendentemente tolerantes a pequenas torções sobre o que já existe

  • Estou passando exatamente por isso agora em um side project
    A área é Information Retrieval, então tenho pouca experiência e naturalmente existe muito prior art que posso aprender ou integrar
    Depois de ler este texto, fiquei mais inclinado a primeiro construir a minha própria versão e só olhar referências anteriores quando travar ou precisar de ideias
    Por outro lado, vendo o documentário recente sobre Clojure, o Rich Hickey parece ter feito justamente o oposto: passou muito tempo mergulhando em bibliografia, artigos e outras linguagens antes de começar
    Mas ele também já tinha feito outras linguagens antes, então, no quadro geral, o aprendizado dele também começou construindo coisas por conta própria
    Talvez a questão seja não passar tempo demais só pensando: fazer logo, aprender com a prática, bater em paredes e só então sentir necessidade de investigar mais a fundo

  • Definir um prazo resolveu a maior parte dos meus problemas com scope creep
    Pela minha experiência, projetos com deadline rígido, como game jams ou competições de programação, são fáceis de terminar, enquanto projetos com final em aberto são muito mais difíceis de concluir
    Vejo isso numa linha parecida com o motivo de o padrão C++ sair a cada 3 anos, em vez de esperar até que todos os recursos desejados estejam prontos
    https://news.ycombinator.com/item?id=20428703

  • O texto foi interessante, mas achei que as ideias do autor estavam um pouco espalhadas demais

    • O ponto central aqui, no fim, é scope creep
    • Isto não é exatamente um post de blog focado e afiado em um tema específico, mas algo mais próximo de uma atualização de newsletter para quem já acompanha essa pessoa
  • Para alguém que diz estar sendo esmagado por scope creep, ele parece ser do tipo que faz coisa demais, a ponto de terminar o texto com uma pilha de links sobre assuntos variados
    No fundo, parece alguém que realmente gosta de aprender e experimentar várias coisas, e o processo de cair em rabbit holes em si parece estimular a cabeça dele de um jeito prazeroso

  • Houve uma percepção que me ajudou muito como alguém que constrói coisas sozinho
    A maior parte do que parecia uma abstração essencial era, na verdade, scope creep com outro nome
    Eu estava adicionando flags a cada nova funcionalidade, até começar a ver um padrão no meu código e definir uma regra
    Uma funcionalidade não seria lançada se não houvesse testes para o comportamento com a flag desligada
    Isso me fez enxergar a flag não como rota de fuga, mas como parte do produto, e três itens do backlog simplesmente desapareceram quando passei a pensar assim

  • É verdade que planejamento excessivo e scope creep são problemas, mas, por outro lado, também é preciso evitar balançar demais para o lado do desenvolvimento improvisado
    Alguns dos meus projetos mais bem-sucedidos foram casos em que eu modelei os dados e planejei/revisei grande parte das funcionalidades antes de produzir software de fato funcionando
    Nessa etapa, muitas vezes é difícil saber o que é exagero, e se eu remover funcionalidades que eu ou o usuário provavelmente vamos querer, mais tarde acabo gastando muito tempo redesenhando o núcleo do código
    Se eu errar para o outro lado, o projeto cresce demais e aí passo a chamar isso de scope creep
    No fim, esse julgamento depende de quão bem você conhece o domínio
    Se você conhece menos do que imagina, vai ter muito retrabalho; se conhece mais do que imagina, talvez pudesse ter ido mais longe e acabou desperdiçando tempo com baby steps
    Em qualquer direção sobra arrependimento, então no fim isso parece uma grande questão de julgamento

    • O ideal me parece ser gastar tempo suficiente na fase de análise para preencher a cabeça com o contexto correto, mas, na hora de construir, estar pronto para abandonar a solução superprojetada e implementar logo o caminho que fizer sentido
      Não dá para cair na falácia do custo afundado, e só porque você pesquisou um tema em nível de doutorado por algumas horas não significa que precisa colocar isso no projeto
      Se não se encaixa exatamente no problema atual, o melhor é descartar sem dó
    • Não se preocupe tanto em estar errado; faça primeiro e ajuste se for preciso