1 pontos por GN⁺ 5 시간 전 | 1 comentários | Compartilhar no WhatsApp
  • Conventional Commits tenta dar significado às mensagens de commit com o formato <type>[optional scope]: <description>, mas coloca o tipo de mudança na frente e deixa o escopo como opcional, empurrando para trás a informação realmente necessária para navegação
  • Colaboradores, debuggers e equipes de resposta a incidentes procuram no log de commits a área do código afetada pela mudança, e como bugs podem surgir em qualquer tipo de alteração, o escopo (scope) é mais importante que o tipo
  • Em fix(compiler): prevent namespaced SVG <style> elements from being stripped, só a descrição já indica que se trata de uma correção de bug, e em refactor(core): Update webmcp support to use document.modelContext, um único commit pode abranger correção, refatoração e adição de funcionalidade, então o type é redundante e limitado
  • A geração automática de CHANGELOG e a decisão de incremento de versão semântica têm leitores diferentes para log de commits e changelog, e os resultados podem divergir por causa de reversões, quebras acidentais de compatibilidade e correções posteriores dessas quebras
  • Mensagens de commit com prefixo de escopo mostram primeiro o alvo da mudança, e condições de build e deploy também funcionam melhor quando se baseiam nos arquivos alterados via git diff, e não no tipo do título

Prioridades erradas

  • Conventional Commits tem como objetivo dar significado às mensagens de commit para ajudar desenvolvedores e usuários finais a entender as mudanças
<type>[optional scope]: <description>

[optional body]

[optional footer(s)]
  • A linha de título é composta por um <type> como fix, feat, chore, docs, refactor, um scope opcional e uma descrição
  • O defeito central é a estrutura priorizar o type, isto é, a natureza da mudança, em vez do scope, que é o alvo da mudança
  • Uma estrutura em que o scope é opcional permite que a informação mais importante do commit fique ausente, e colocar o type no começo do título inverte a prioridade

Por que scope é mais importante que type

  • Colaboradores leem o log de commits para encontrar mudanças desde a última contribuição, o fluxo geral do projeto e commits que podem entrar em conflito com o trabalho em andamento durante um pull ou rebase
  • Quem está fazendo debug procura mudanças que mexeram na área relacionada ao componente onde o bug apareceu, e como bugs podem surgir em alterações de qualquer type, essa informação não ajuda
  • Equipes de resposta a incidentes vasculham o log de commits perto do momento da falha para encontrar a área que causou o problema; se houver um commit com scope auth no ponto em que erros na API de entrada aumentaram, ele vira um forte candidato à causa
  • Para quem lê o log de commits, o importante não é que tipo de mudança foi feita, mas em que área ela mexeu

A redundância e os limites do type

  • fix(compiler): prevent namespaced SVG <style> elements from being stripped já deixa claro só pela descrição que é uma correção de bug, então o type fix é redundante
  • O espaço na linha de título do commit é limitado, então gastar caracteres com um type que já pode ser inferido da descrição não ajuda
  • refactor(core): Update webmcp support to use document.modelContext atualiza a funcionalidade webmcp do componente core para dar suporte tanto a document.modelContext quanto a navigator.modelContext
  • Essa mudança pode ser vista ao mesmo tempo como correção de bug, refatoração e nova funcionalidade, mas a informação realmente importante é que ela altera o componente core/webmcp

Os limites da promessa de automação

  • A ideia de gerar automaticamente um CHANGELOG a partir dos commits com ferramentas como git-cliff ou conventional-changelog esbarra no fato de que o log de commits e o changelog têm leitores diferentes
  • O CHANGELOG é voltado para usuários e foca em entender diferenças funcionais e de negócio entre versões
  • O log de commits é voltado para desenvolvedores e foca em entender como a base de código mudou ao longo do tempo e em acompanhar esse fluxo pela ótica do scope
  • Em projetos com complexidade moderada ou maior, uma funcionalidade relevante costuma entrar por vários commits; para desenvolvedores, o processo de implementação é útil, mas para usuários finais importa apenas a funcionalidade pronta
  • Commits de reversão (revert) são importantes para desenvolvedores no fluxo do log, mas para o usuário final uma mudança revertida equivale a uma mudança que nunca foi feita
  • Incrementar versão semântica com base no type do commit pode gerar problemas como subir major mesmo quando a quebra de compatibilidade foi revertida, subir minor/patch por engano porque a quebra só foi percebida depois, ou marcar como quebra algo que desapareceu ao ser combinado com commits posteriores
  • Nessas situações, até dá para corrigir o histórico com rebase, mas o workflow pode impedir isso ou torná-lo frágil, além de reduzir a confiabilidade do fluxo transmitido pelo log de commits
  • Se o processo de build ou deploy for disparado pelo type no título do commit, uma mensagem como docs: fix typos pode driblar a automação mesmo inserindo uma vulnerabilidade no subsistema de autenticação
  • É melhor definir condições de build e deploy identificando os arquivos alterados com git diff do que usando o título do commit

Problemas de adoção e alternativas

  • Conventional Commits incentiva cada projeto a definir seu próprio conjunto de types, mas muitos projetos simplesmente adotam os types padrão do commitlint, que podem não combinar bem com as características específicas de cada projeto
  • A especificação de Conventional Commits tecnicamente define apenas fix e feat; os demais types ficam a cargo de cada projeto
  • Em ambientes corporativos, exigências de gestão de mudanças e auditoria às vezes obrigam a incluir o número do ticket em toda mensagem de commit; se o <scope> for usado para isso, perde-se um metadado realmente útil
  • Linux, FreeBSD, Git, Go, NixOS e Node.js usam mensagens de commit com prefixo de scope adaptado ao projeto
  • No kernel Linux, o subsystem é um scope natural; no projeto Go, é o caminho do pacote; em arquiteturas de microsserviços, tende a ser o nome do microsserviço
  • scopedcommits.com propõe voltar a um formato de mensagem de commit centrado em scope e separar a geração de CHANGELOG da gestão do log de commits
  • As vantagens de Conventional Commits não se converteram em benefícios reais, e sua popularidade em projetos open source, somada à tendência de AIs de adotá-lo como padrão, está espalhando mensagens de commit com antipadrões misturados

1 comentários

 
GN⁺ 5 시간 전
Opiniões no Lobste.rs
  • Fico feliz de ver um texto que organiza de forma lógica uma crítica aos conventional commits, e não só como uma rejeição instintiva
    Eu não tinha pensado muito a fundo sobre por que não gosto disso, e achei que talvez fosse por eu ter passado a associar com código gerado por LLM. Especialmente chore: é o que eu mais detesto; espero que não reinventem a notação húngara. Isso nem deveria ter sido criado em primeiro lugar

    • Em especial, chore: nem existe mais no guia de estilo de commits do Angular e, talvez por terem percebido o quão vago era, acabou sendo absorvido por build:
      Mesmo na época em que existia no estilo do Angular, a descrição de chore: sugeria usos bem específicos, mas em alguns projetos open source parece que colocam isso no clima, literalmente para tarefas que soam como coisas que deu preguiça de fazer
  • Eu não gosto de conventional commits, mas acho que a alternativa proposta deixa passar o motivo de o scope ser opcional
    Em projetos pequenos, sem muitos módulos bem definidos, o conceito de “scope” não é muito útil. Uma prática útil que ambos deixam de fora é colocar números de issue ou ticket no título do commit, porque isso facilita entender o contexto adicional da mudança e ajuda especialmente na revisão de código. Dito isso, eu não gosto da ideia de tornar número de ticket obrigatório, porque isso só faz surgir tickets inúteis para mudanças triviais; mas, se a mudança trata de um bug ou tarefa específica, ela deveria estar ligada a esse bug ou tarefa

    • Se você não precisa de scope, é só omitir
      Ainda é melhor do que um “type” de commit redundante, que deveria ficar evidente só de olhar a linha de título
    • Idealmente, eu acho que não deveria haver nenhum estilo de commit prescrito; basta usar a formulação que fizer sentido para aquele commit
      Se a mudança corresponde claramente a um ticket, use um commit com “número de ticket”; se não, use outro formato. Algumas mudanças se encaixam melhor no type do que no scope, e outras no contrário, então também dá para misturar scoped commits com conventional commits
  • Dá vontade de dizer: “não usem fonte monoespaçada em texto corrido”
    Ainda assim, em geral concordo com a premissa do texto

  • Mesmo que as mensagens de commit não sejam grandes coisas, para ter noção do escopo das mudanças eu recomendo usar com frequência git log --name-only ou git log --stat
    Ver os nomes dos arquivos ajuda bastante a entender o que mudou sem precisar abrir cada commit individualmente

  • O formato de que eu realmente gosto é exigir estilo de conventional commit no título do PR
    O título do PR pode ser editado pelo maintainer mesmo depois do merge, não exige reescrever o histórico de commits e, junto com ferramentas como release-drafter, permite automatizar changelogs significativos nas releases do GitHub. Isso oferece a granularidade apropriada para os stakeholders mencionados pelo autor — separando funcionalidade, correção e breaking changes — e também automatiza um semver razoável para o próximo rascunho de release no GitHub
    A crítica do texto de que componentes como parse-lib não deveriam ser opcionais está correta, e também concordo que forçar conventional commits desencoraja novas contribuições. Mas as alternativas também não parecem exatamente melhores
    Ainda assim, um identificador de breaking change como fix!(parse-lib): Don't leave sparse holes when parsing JSON arrays traz bastante informação. Mostra que é uma correção de bug em um componente específico, que a correção inevitavelmente veio acompanhada de uma breaking change e carrega um significado como um incremento minor de semver. Isso dá para usar no título do PR

  • Admito que me empolguei demais com conventional commits como forma de incentivar disciplina nos commits, e no fim isso virou hábito
    Hoje, às vezes, me parece limitador e arbitrário. Em alguns projetos, sem eu nem saber se aquilo era a convenção real, acabei me aproximando mais do estilo Linux/Go/Node; e, em monorepos com várias configurações, parecia mais natural escrever [service]: [what changed] do que inventar um type à força. Daqui para frente, pretendo experimentar mais com meu estilo pessoal de commits com base no que parece útil, em vez de tentar me encaixar numa convenção rígida, e scoped commits parecem um bom ponto de partida

  • chore(lobsters): add my 2 cents on conventionals commits [JIRA-69420]
    Concordo com quase tudo, mas vejo de forma diferente a parte sobre “mostrar aos contribuidores um registro revisionista que reduz a confiabilidade da história contada pelo log de commits”. O autor parece estar falando principalmente de branches públicas, e nesse caso é um conselho razoável. Mas isso não deveria valer para branches privadas. Basta tornar o resultado final fácil de entender para quem vai revisar a mudança — ou seja, o maintainer ou eu mesmo daqui a 10 anos —, sem necessidade de deixar um fluxo de pensamento inconsistente ou, pior ainda, uma pilha de commits address review

  • A resposta para “por que scope é opcional?” é que, em projetos pequenos, simplesmente o projeto inteiro é o scope
    Concordo que o “type” do commit não é tão útil assim, mas também não vejo muita diferença entre scoped commits e conventional commits. Scoped seria só um conventional sem o “type”, e a distinção entre fix·feat·refactor·chore também é aceitável
    Se todo mundo só pega o padrão do commitlint e usa como está, talvez a questão não seja simplesmente fazer as pessoas lidarem melhor com isso?