Imagine a seguinte situação, você é um dos desenvolvedores de um sistema que está dividido em diversos módulos cada qual em seu branch e tem como tarefa analisar e realizar o merge das alterações no branch master.

Ao abrir o projeto percebe que o último commit de um dos módulos do projeto está descrito como “Pequenas Alterações na Parte X”. Em seguida ao analisar o histórico de atualizações se depara com um número absurdamente grande de commits em relação ao que de fato foi programado e pior, a grande maioria dessas atualizações tem uma descrição tão vaga quanto a última.

Por fim ao analisar individualmente percebe que cada commit diz respeito a apenas algumas poucas linhas de código, quando não à apenas uma linha. O histórico do projeto está agora tão desorganizo que ninguém sabe dizer ao certo quais foram as modificações realizadas sem ter que passar horas analisando detalhadamente o código.

Está é a razão para adotarmos algum tipo de padronização junto ao sistema de controle de versão que permita o registo adequado das atividades e um fácil entendimento do fluxo de trabalho ao longo do tempo.

1. Controle de Versão

Formalmente um sistema de controle de versão é um programa com o proposito de gerenciar alterações em programas de computador, documentos, sites ou outras coleções de informações. 

Muito provavelmente você já precisou escrever algum documento e quando chegou ao final o nomeou como “versão final” acreditando que tudo estava acabado, porém ao avaliar melhor percebeu que alterações precisavam ser realizas e para não perder a versão anterior realizou uma cópia do arquivo o nomeando como “versão final 2”. O problema é que novamente foram necessárias alterações e quando você deu por si já estava chegando próximo a casa dos dois dígitos.

Isso também ocorre com o desenvolvimento de software no qual constantemente precisamos realizar atualizações que precisam ser registradas e documentadas.

Por esta razão que devemos utilizar algum sistema que gerencie e mantenha a integridade de nossos arquivos, lembre-se que um projeto pode conter milhares de alterações as quais seriam inviáveis de serem gerenciadas manualmente. Para esse fim o programa mais conhecido é o Git, mas existem muitos outros como por exemplo o CVS, SVN, Mercurial, etc.

2. Criando um Bom Commit

Nas seções seguintes vou descrever alguns padrões que podem ser utilizados para se realizar um commit, entretanto existem boas praticas presentes em todos eles e que mesmo que você opte por não usar nenhum padrão com certeza terá que utilizar estas regras a fim de manter o versionamento do seu projeto organizado.

  • Na mensagem de commit use o modo imperativo, por exemplo “Adiciona feature” ao invés de “Adicionando feature” ou “Adicionada feature”;
  • A primeira linha do seu commit deve ter no máximo 72 caracteres.
  • Descreva as alterações com detalhes no corpo do commit;
  • Apenas faça um commit no seu projeto quando existirem alterações suficientemente relevantes, isto é, não faça um novo commit toda vez que alterar uma única linha em um arquivo a não ser que seja algo muito específico e significativo por si só. Ao invés disso se ainda estiver desenvolvendo aguarde até que exista um conjunto importante de alterações e nesse momento realize um novo commit. Dessa forma você garantirá que cada commit irá representar um conjunto significativo de modificações dando assim um verdadeiro significado ao mesmo.

A estrutura básica de um commit nesse formato é:

[Description]
<Blank Line>
[Optional Body]
<Blank Line>
[Optional Footer(s)]

Veja abaixo um exemplo de um commit usando esta estrutura:

git commit -m "Adiciona as classes de acesso ao banco de dados
>
>Adiciona o arquivo Connection.php com a classe para acesso
>ao banco de dados MySQL
>
>Correção do Issue #12"

3. Padrões para o Controle de Versão

Se você realizar uma busca rápida na internet não será difícil perceber que existem uma infinidade de padrões disponíveis para uso, isso se deve ao fato de que por mais que existam padrões bem definidos e mantidos pela comunidade cada projeto poderá adaptar ou criar sua própria especificação de acordo com sua necessidade, entretanto o que todos tem em comum é que são compostos por duas partes.

A primeira parte diz respeito ao número de versão do projeto o qual comumente é representado por um conjuntos de números, já a segunda parte se refere a descrição do que foi realizado nesta versão e é composto por um bloco de texto descrevendo todas as alterações seguindo o padrão de commit da seção 2.

3.1. SemVer

Conhecido como Semantic Versioning Specification este padrão é voltado para projetos que tenham um número muito grande de dependências visando fugir do chamado “inferno da dependência” na qual a incompatibilidade dos pacotes ao tentar atualiza-los  impedem de levar seu projeto adiante de maneira fácil e segura.

Pensando nisso a especificação SemVer determina que o a versão deve ser gerenciada através de 3 número no formato MAJOR.MINOR.PATCH que devem ser incrementados da seguinte forma:

  • MAJOR: Quando forem realizadas alterações de API incompatíveis;
  • MINOR: Quando forem feitas correções de bugs compatíveis com versões anteriores;
  • PATCH: Quando você forem feitas correções de bugs compatíveis com versões anteriores.

A especificação também exige que seja criado uma API pública a qual pode ser declarada no próprio código ou existir estritamente na documentação.

Por fim são especificados um conjunto grande de regras que devem ser seguidas, porém tais regras não são adequadas para o gerenciamente de sistemas mais simples que não contam com um grande número de dependências, isso significa que esse é um padrão desenvolvido para o desenvolvimento de programas robustos e realmente grandes.

Se quiser saber mais sobre o assunto não deixe de ler a documentação oficial da especificação.

3.2. X.Y.Z

Está é uma adaptação do padrão SemVer muito mais simples para utilização no desenvolvimento de sistemas que não contam com um grande número de dependências e nem uma API, logo não é necessário implementar a maioria das regras impostas pelo padão.

Este padrão estabelece que a versão de um software deve ser tratado com um conjunto de 3 números no formato X.Y.Z sendo que:

  • X: Indica que o sistema tem mudanças que o torna incompatível com versões anteriores;
  • Y: Indica que o sistema tem mudanças compatíveis com versões anteriores, dentro do primeiro número;
  • Z:  Indica que o sistema tem mudanças menores, como correções de bugs, atualizações de segurança e funcionalidades que não prejudicam a compatibilidade com versões anteriores.

Em algumas situações define-se um quarto número, chamado de release que indica o número atual do build daquele código, dentro de um escopo de modificações.

Como exemplo suponha que temos um software em fase beta na versão v0.1.32 e nesse momento decidimos por gerar a sua versão final, podemos então nomeá-la como v1.0.0. Agora se por acaso precisamos realizar alguma atualização de segurança devemos incrementar o último digito dando origem a verão v1.0.1.

Quanto ao segundo número supondo que houveram 12 atualizações na versão original deverá ficar como v1.12.1. Isto quer dizer que qualquer uma destas 12 atualizações (v1.1.1, v.1.2.1, …, v1.12.1) será compatível com a versão 1 do produto.

Por fim se realizamos uma atualização a qual por alguma razão seus recursos se tornem incompatíveis com a versão anterior, devemos incrementar o primeiro digito dando origem a versão v2.0.0.

Não se esqueça que em todas estas atualizações devem ser usados as regras de criação de commit citados na seção 2. Seguindo essa convenção nós temos a possibilidade de saber agora qual a versão do software que estamos trabalhando, quais foram as modificações mais significativas, quais foram as correções de bug ou de problemas de segurança e por fim quais são as versões anteriores com o qual o nosso sistema é compatível.

Lembre-se que não é necessário seguir esse padrão ao pé da letra, cada equipe pode definir a forma como manterá suas versões, por exemplo o sistema operacional Ubuntu utiliza um gerenciamento de versão por YEAR.MONTH.PATCH_LEVEL.

3.3. Conventional Commits

Este padrão visa adicionar um ou mais tipos especificos no commit a fim de fornecer um conjunto fácil de regras para criar um histórico de commit explícito. Assim como no padrão SemVer este também descreve os recursos, correções e alterações importantes feitas nas mensagens de confirmação porém agora utilizando os termos BREAKING CHANGE, FEAT e FIX tal que:

  • FIX: Equivale ao PATCH e deve ser utilizada quando você farem feitas correções de bugs compatíveis com versões anteriores.
  • FEAT: Equivale ao MINOR e deve ser utilizada quando forem feitas correções de bugs compatíveis com versões anteriores;
  • BREAKING CHANGE: Equivale ao MAJOR e deve ser utilizada quando forem realizadas alterações incompatíveis.

Como vantagem ao se utilizar esse padrão podemos citar:

  • Geração de CHANGELOGs de forma automática;
  • É possível determinar automaticamente um aumento de versão semântica (com base nos tipos de commits recebidos);
  • Comunicar a natureza das mudanças aos colegas de equipe, ao público e a outras partes interessadas;
  • Disparar processos de build e deploy;
  • Torna mais fácil para as pessoas contribuírem com seus projetos, permitindo que explorem um histórico de commits mais estruturado.

A estrutura do commit deste padrão é:

<type>[optional scope]: <description>
<Blank Line>
[optional body]
<Blank Line>
[optional footer(s)]

Veja um exemplo extraído da documentação onde é realizado uma mensagem de commit com descrição e modificação que quebra a compatibilidade no corpo:

feat: permitir que o objeto de configuração fornecido estenda outras configurações

BREAKING CHANGE: a chave `extends`, no arquivo de configuração, agora é utilizada para estender outro arquivo de configuração

Este padrão também define um conjunto de regras que devem ser seguidas, logo vale muito a pena ler a documentação oficial a fim de entender por completo.

3.4. Angular Commit Message Format

Este é um padrão baseado no ‘Conventional Commits’ da seção 3.3 que foi adaptada para o desenvolvimento do Angulas JS e posteriormente foi abraçada pela comunidade do JavaScript.

Dentre todas os tipos dos quais estão descritos na documentação oficial o que mais se destaca é que além dos tipos padrões FIX e FEAT, também foram implementados os tipos BUILD, CHORE, CI, DOCS, STYLE, REFACTOR, PERF, REEVERT e TEST.

4. Usando Emotes

Usar emotes não é considerado um padrão porém é algo que muitas pessoas gostam de usar. A ideia é contextualizar as modificações através de uma imagem no inicio da mensagem de commit agrupando cada um em relação ao tipo de ação realizada.

Observe abaixo como fica a mensagem de commit adicionando o emote ao inicio:

git commit -m ":rocket: Adiciona as classes de acesso ao banco de dados
>
>Adiciona o arquivo Connection.php com a classe para acesso
>ao banco de dados MySQL"

5. Softwares para Padronização

Eu vou dedicar artigos específicos para explicar estas ferramentas mas acredito que vale uma menção honrosa ao Commitlint que nada mais é do que um programa que serve para verificar se suas mensagens de confirmação atendem ao formato de confirmação convencional e ao Commitizen que é um programa que roda no terminal e irá te fazer diversas perguntas no momento do commit a fim de te guiar durante este processo.

6. Considerações Finais

Nenhuma destas especificações precisa ser fielmente seguida, todo projeto tem os seus requisitos e o método de gerenciamento deverá ser aquele que melhor atenda a essas necessidades.

Entretanto por menor e mais simples que seja o projeto é extremante importante ter algum tipo de padronização no momento do commit, ao trabalhamos em grupo isso irá garantir uma estruturação adequada do projeto possibilitando que outros desenvolvedores possam dar continuidade ao trabalho.

7. Referências

https://semver.org/#summary

https://www.conventionalcommits.org/

https://pt.stackoverflow.com/questions/101896/como-definir-a-vers%C3%A3o-de-um-software#:~:text=O%20terceiro%20n%C3%BAmero%20indica%20que,a%20compatibilidade%20com%20vers%C3%B5es%20anteriores.

https://gist.github.com/crissilvaeng/dfb5b14f8eb2c25df4fd8a49f4f03252

https://qastack.com.br/software/255190/how-does-semantic-versioning-apply-to-programs-without-api

https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines



25 Posts