1 pontos por GN⁺ 3 시간 전 | 1 comentários | Compartilhar no WhatsApp
  • Chesterton’s fence é um conselho para não mudar levianamente um código cujo motivo você desconhece, mas código sem motivo registrado e histórico de commits sem explicação empurram o mesmo peso para o próximo desenvolvedor
  • O corpo dos commits dos últimos 13 anos nesse repositório soma apenas 295 linhas; removendo os corpos relacionados a dependabot, revert e typo, cai para 167 linhas
  • Os títulos dos commits, mesmo em mudanças grandes, não dão contexto, como em “fix page A”, e quase não há documentação separada nem comentários no código, o que torna difícil rastrear o motivo das mudanças
  • No código restam refatorações inacabadas, vestígios de funcionalidades removidas, recursos adicionados mas não conectados nem usados, e funcionalidades que aparentemente ninguém usa
  • Mensagens de commit e documentação deveriam ao menos registrar “o que mudou, por que mudou e por que essa é uma boa solução”; quando não se deixa nada, o custo para quem vem depois aumenta

O peso deixado por código sem motivo

  • Chesterton’s fence é a metáfora de que, se você não entende por que algo está daquele jeito, não deve sair mudando sem cuidado
    • Em programação, também pode acontecer de alguém “corrigir” um código que parecia estranho e só depois descobrir que havia uma razão para aquela estranheza
  • Neste caso, aparece o problema do lado oposto
    • Há muito código e muitas decisões estranhas, mas não existe registro que permita saber por que ficaram assim
    • Os desenvolvedores anteriores já saíram todos, então nem há a quem perguntar
  • O histórico de commits do repositório praticamente não oferece contexto útil
    • O corpo dos commits dos últimos 13 anos totaliza 295 linhas
    • Excluindo manualmente os corpos de commits de dependabot, “revert commit” e “fix typo”, restam 167 linhas
    • Dá algo como uma linha por mês
  • Os títulos dos commits também costumam ser insuficientes para explicar mudanças grandes, como “fix page A”
  • Não há documentação separada e quase não existem comentários no código
  • Uma situação assim se aproxima mais do dedo do meio de Chesterton: “fizemos um monte de coisas estranhas, mas não vamos dizer por quê”

O mínimo de registro que um desenvolvedor deve deixar

  • A base de código contém vários tipos de código incompleto ou residual
    • Refatorações que nunca terminaram
    • Vestígios de funcionalidades removidas
    • Funcionalidades adicionadas, mas não conectadas nem usadas
    • Funcionalidades que aparentemente ninguém usa
  • No geral, também parece haver um forte problema de Chesterton’s gap
    • Algo como “ainda não existe uma cerca, então vamos construir uma”, sem perguntar se a cerca realmente é necessária
  • Escrever bem é difícil, mas deixar uma explicação aceitável não é
  • Um registro de mudanças deveria responder basicamente a três perguntas
    • O que está sendo mudado
    • Por que está sendo mudado
    • Por que esta solução é boa
  • Em alguns casos, “Implement new feature X” pode bastar, mas na maioria das vezes há algo a dizer sobre por que ou como a funcionalidade foi adicionada daquele jeito
  • Em correções de bugs, refatorações e mudanças substanciais, normalmente dá para registrar ao menos um ou dois parágrafos explicando a mudança e seu motivo
  • Esse tipo de registro não é opcional; faz parte do trabalho de desenvolvimento de software
    • Não precisa ser elegante
    • Não precisa ser um inglês perfeito
    • Não precisa ser um ensaio grandioso
    • Mesmo que falte alguma coisa, ainda é muito melhor do que não deixar nada
  • Quando não se deixa nada, o problema é empurrado para todas as pessoas que vierem depois

1 comentários

 
GN⁺ 3 시간 전
Comentários do Lobste.rs
  • Às vezes, não é claro no momento o que vai se tornar importante depois. Ajuda muito quando todo o processo que levou até um commit fica registrado publicamente, mas como todos os envolvidos já têm muito contexto, algumas coisas acabam ficando de fora por serem consideradas “óbvias demais”.
    Quando a discussão não é registrada, fica muito mais difícil escavar o processo de tomada de decisão como uma arqueologia digital. No fim, às vezes é preciso lidar com um estado em que não se sabe por que aquela cerca está ali, e avaliar com base no contexto atual e no conhecimento do sistema que as pessoas de agora têm.
    Ajuda muito quando há alguém que permaneceu no projeto por bastante tempo e adquiriu compreensão e intuição sobre o sistema como um todo. Organizações que veem desenvolvedores como engrenagens substituíveis acabam sem ninguém ficando tempo suficiente, repetindo os mesmos erros e reinventando a roda.

    • O maior benefício que tiro de code review é que outra pessoa lê o código e acaba deixando comentários em todo lugar onde o motivo não está claro. O que não está claro para mim eu já comento, então agora fica comentário em todo ponto onde pelo menos uma das duas pessoas achou que precisava de explicação.
      Quando a próxima pessoa olhar o código, a chance de ela entender por que aquilo está daquele jeito deixa de ser zero.
    • É parecido com receitas antigas que não anotavam ingredientes que “todo mundo sabia onde encontrar”, ou com música medieval cuja rítmica e compasso partiam do pressuposto de que “todo mundo sabe”. Hoje já não sabemos mais o que havia ali.
  • Nunca entendi desenvolvedores que colocam só “fix” ou “WIP commit” na mensagem de commit. Provavelmente nunca fizeram uma arqueologia de código séria, ou nem chegaram a pensar que isso fosse algo possível.
    Eu sempre tento errar pelo lado de informação demais. Assim, meu eu do futuro, meu sucessor ou o pobre coitado chamado quando der pane pelo menos têm alguma chance de descobrir por que algo acabou quebrando.

    • Isso talvez seja um caso de tamanho errado da unidade de trabalho. Para alguns desenvolvedores, um commit pode ser apenas um entre centenas de pequenos passos para criar uma única funcionalidade “vendável”.
      Nesses casos, fica difícil acompanhar mentalmente o que mudou após cada checkpoint ou escrever uma explicação significativa, e o commit passa a ser tratado menos como um meio de dividir o trabalho em unidades bem definidas e mais como o botão de “salvar” de um videogame.
      Por outro lado, se você gerar um grande commit como resultado de uma grande refatoração de API, provavelmente qualquer coisa menos que uma explicação no nível de um documento de design será insuficiente, e se você não vai fazer isso, o valor de uma mensagem longa também fica ambíguo. Ainda assim, algumas pessoas tratam isso como se fosse um distintivo de honra e começam a colocar nos anúncios de release frases como “correções de bugs e melhorias de funcionalidades”, o que é claramente a conclusão errada.
  • Muitos desenvolvedores frequentemente esquecem que a “outra pessoa” que vai precisar ler e entender o contexto de uma mudança pode ser eles mesmos no futuro. Todo mundo já passou pela situação de coçar a cabeça olhando para um bloco de código, rodar git blame e ver o próprio nome encarando de volta.
    Boas mensagens de commit já me pouparam incontáveis vezes de gastar horas, às vezes dias, cavando em issues, e-mails e logs de chat atrás do porquê. Isso aconteceu até em casos em que eu supostamente deveria conseguir responder de imediato.
    É preciso ser gentil com seu eu do futuro. Vale a pena despejar no log do git tudo o que você sabia, pensava e foi discutido. Nunca é claro o que ainda continuará óbvio daqui a 5 anos.

    • Claro, parte desse conhecimento talvez faça mais sentido em comentários ou em documentos de design, e não no log de commits.
    • A parte de me assustar ao ver meu nome no git blame pelo menos não acontece muito quando houve um motivo para aquilo. Coisas aleatórias, como o comportamento estranho de outra pessoa, são difíceis de explicar de forma útil se você não consegue ver o processo dela, mas se foi algo que um dia fez sentido para mim, ao reler eu normalmente consigo entender de novo.
      Meu jeito de aprender parece ser mais como camadas de lava se acumulando. Desde o ensino médio, em vez de mudar muito, fui só acrescentando o que sei e as formas como consigo usar esse conhecimento.
  • Recentemente alguém afirmou que, se uma mensagem de commit passa de uma frase, em geral é perda de tempo; eu queria rebater com força, mas fui pior do que esperava em provar o contrário
    Uma das questões é que tipo de informação deve entrar na mensagem de commit e que tipo deve ir para comentários inline, ADRs ou outros documentos mais longos
    Ainda tento escrever boas mensagens de commit, mas no trabalho isso já parece sem esperança, e nem nos meus projetos pessoais de brincadeira eu consigo manter consistência

    • Para mim, mensagens de commit são para o revisor. Elas dizem por que essa mudança é necessária, o que ela corrige ou por que queremos uma nova funcionalidade, e oferecem uma estrutura para entender a mudança
      Mas o código final deve ser compreensível sem precisar ler a mensagem de commit. Se houver algo no código novo que precise de justificativa, isso deve entrar em comentário
      Em outras palavras, a mensagem de commit explica por que fizemos essa mudança agora, enquanto os comentários explicam por que o código, no estado final da mudança, está daquele jeito
      Mudanças maiores, especialmente novas funcionalidades, deveriam ter algum documento de design em algum lugar. Se precisar de revisão, pode ser um documento real dentro do repositório, ou pode estar no rastreador de issues
      A mensagem de commit deve apontar para esse documento e talvez também precise explicar detalhes que surgiram quando o design foi traduzido para o código. Se possível, também é bom incluir um breve resumo do documento de design. Isso é especialmente importante quando há vários possíveis revisores: sinaliza quem deveria se interessar mais e ajuda a detectar casos em que ficou de fora alguém que deveria ter dado feedback na fase de design
    • Meu critério para decidir o que colocar numa mensagem de commit é que, em geral, eu não a vejo por git log ou jj log, mas quase sempre por meio da exibição de comentários por linha
      A linha de título costuma ser muito útil, de forma geral, para decidir se vale a pena investigar mais. Quando o corpo traz informação sobre por que a mudança foi feita, isso ajuda quando o motivo não é intuitivo
      Por exemplo, mesmo que entre bastante código, muitas vezes só “admin: add impersonation” já basta. Mas se for “auth: shorten JWT timeouts”, eu gostaria de ver uma ou duas frases explicando por que os timeouts precisavam ser reduzidos
      Mensagens de commit realmente longas me parecem, na prática, pouco úteis. Em grande parte pelos mesmos motivos apontados no texto. Esse formato parece vir de fluxos de trabalho em que a mensagem de commit também é a descrição do PR, como fluxos baseados em e-mail ou o Gerrit. Nesses casos não chega a ser prejudicial, mas também é difícil dizer que agrega valor necessariamente
    • Já escrevi um texto tentando responder exatamente a essa pergunta. Organizei vários lugares de documentação em uma hierarquia e reuni regras práticas para decidir onde colocar cada tipo de informação
      Estou numa situação parecida. No grupo mais amplo do meu trabalho, só eu e mais uma pessoa escrevemos mensagens de commit detalhadas
  • Mesmo que você saiba por que uma cerca foi construída, pode não saber por que ela está ali agora. Mesmo sendo a própria pessoa que construiu a cerca de Chesterton, talvez você não saiba se pode derrubá-la
    A árvore de interdependências pretendida quando o sistema foi criado é apenas um subconjunto da árvore de interdependências real em algum momento posterior. Então, mesmo que um desenvolvedor perfeito explique completamente por que a cerca foi construída, a utilidade disso é limitada
    O que essa pessoa sabe é por que ela foi construída, não a resposta para “o que quebra se eu remover esta cerca?”. Basta ver https://xkcd.com/1172/. Entre os casos de uso engraçados, alguns podem parecer irrelevantes, mas sempre existem usos legítimos que nem o desenvolvedor original conseguiria prever
    Saber o que o desenvolvedor original pensava, ou o que ele fumou, é legal, mas essa informação fica em algum ponto entre incompleta e irrelevante
    Como exemplo inventado, imagine que a cerca de Chesterton tenha sido erguida originalmente para manter as crianças longe de uma poça d’água, numa época em que havia fazendas dos dois lados. Agora existe uma rodovia, e essa cerca pode ter se tornado por acaso a única barreira que impede colisões entre carros e veados, evitando mortes em massa de animais e pessoas
    Ninguém sabe disso. A combinação entre rodovia e ausência da cerca nunca foi testada, e na verdade nunca existiu; além disso, quem construiu a rodovia e o departamento de recursos naturais não sabem por que há tão poucos atropelamentos de animais naquela estrada. Alguns anos depois, todas as fazendas podem virar conjuntos habitacionais e deixar de ser uma rota importante de migração animal; nesse ponto, a cerca pode se tornar inútil — ou não
    Se isso lhe parece forçado ou algo que não se aplica ao seu caso, eu tenho inveja. Pela minha experiência, tirando empresas com algum porte e que não sejam muito antigas, no geral é assim que as coisas funcionam
    A verdade é que tudo o que fazemos faz parte de um ecossistema, depende de coisas com as quais nunca concordamos explicitamente em interagir, e também é algo de que outras coisas passam a depender. Dá para reduzir a superfície da API e evitar que todos os detalhes de implementação virem problema do vizinho, mas o acoplamento não intencional é quase uma lei do universo tão inevitável quanto o aumento da entropia
    Para algumas pessoas, isso soa niilista e derrotista. Dá para dizer que não deveríamos lutar contra a entropia? Mas eu acho que o melhor uso do tempo e o maior retorno sobre o investimento vêm de reconhecer que isso, no fundo, não é algo para combater, e sim para gerenciar
    Se você finge que sempre pode conhecer o estado do mundo, está basicamente agendando fracasso e autopunição. É como 100% de uptime: não existe, e para a maioria dos casos é uma meta errada
    Se você admite que está gerenciando um processo com certo grau de incerteza heisenberguiana, consegue escolher maneiras de usar melhor o tempo limitado do dia para produzir resultados melhores. Em especial, isso permite fazer um equilíbrio inteligente entre resposta preventiva e resposta reativa, além de entender que não dá para reduzir a resposta reativa a zero, e que às vezes não faz sentido gastar um ano de prevenção para evitar um dia de reação
    Então, quanta documentação deve ir em um commit? Quantos documentos de design ou planos de teste deveriam existir? Eu também não sei. Mas, se for para sugerir uma linha de pensamento: toda documentação é escrita para o leitor
    Se você altera a base de código, as pessoas do time atual — incluindo quem entrar depois — devem conseguir, por meio de investigação, entender o que a mudança fez e por que foi feita; e também deveria haver alguns alertas sobre armadilhas perigosas ou bugs que sustentam carga
    Em geral, isso funciona melhor na forma de ponteiros para contexto adicional que montem o cenário, não como prosa longa. Por exemplo: “Esta etapa exige autenticação como parte da política que requer aprovação multipartes para toda alteração. see: go/multiparty”

    • O fato de a entropia aumentar e de continuarem surgindo acoplamentos não intencionais pode até ser visto não como defeito, mas como uma característica útil que impede que sistemas fiquem presos para sempre em um estado permanente
      Sistemas que buscam perfeição ao lidar com seres humanos são realmente desconfortáveis. Coisas como DRM, trusted computing, remote attestation, Faro Plague e smart contracts
      Sistemas que podem ser reiniciados em modo de serviço para serem corrigidos são muito melhores. Porque não dá para prever em que direção o software deve evoluir para realmente ajudar as pessoas no futuro. Melhor torná-lo fácil de modificar do que travá-lo 100%
  • Quase não escrevemos corpo de commit, mas escrevemos títulos razoavelmente bons. Se esse for o critério de medição, não sei bem do que ele é critério
    Em codebases grandes, código claro e cobertura de testes suficiente muitas vezes são bem mais úteis do que documentação

    • Não concordo. Às vezes tanto a mudança em si quanto o motivo dela são sutis. Quando você está tentando entender por que um código estranho está daquele jeito, olhar os testes alterados naquele commit é uma etapa extra e não necessariamente diz por que a mudança foi feita
      Pode acontecer de uma mudança totalmente válida ser feita, os testes serem atualizados de acordo, mas depois continuar completamente obscuro por que aquela mudança era necessária. Isso é ainda mais verdadeiro quando as linhas modificadas causam comportamento inesperado ou comportamento adicional em produção
      Um simples revert pode não ser desejável, e nessas horas ter o histórico completo de por que a mudança foi feita ajuda de verdade
      Já vi muitos casos em que a ideia estava certa, mas surgiram consequências inesperadas. Se você conhece a intenção, consegue chegar a uma mudança realmente correta que também resolva o novo problema e preserve o motivo original da alteração
      Se você insiste em commits de uma linha só, então pelo menos coloque o número do ticket para que o histórico possa ser lido por lá
  • Ganhei um dinheiro bem decente durante cinco anos viajando por regiões exóticas para recuperar codebases desse tipo. @arp242, sempre cobre mais caro e durma com https://archive.org/details/working-effectively-with-legacy-code debaixo do travesseiro

  • Felizmente, os geradores de tranqueira de IA escrevem mensagens de commit gigantes. Muitas vezes elas até têm alguma relação com a mudança real, então pelo menos essa parte estaria resolvida

    • Será mesmo? Talvez sejam boas para resumir o que mudou, mas acho difícil que consigam escrever bem por que mudou