Versionamento Semântico

Neste artigo você vai ver:

Uma breve história sobre Sistemas de Controle de Versão (VCS)

Computadores tornaram-se máquinas muito amigáveis. Se você errar e excluir acidentalmente alguns parágrafos de um documento importante, não há motivo para pânico – basta clicar em desfazer (nosso ilustre CTRL+Z). 

Mas nem sempre foi assim…

Nos primórdios da revolução digital, a maioria das pessoas nem sequer tinha ouvido falar de computadores. Na época, os desenvolvedores de software não tinham acesso a um sistema de controle de versão e, assim, trabalhavam com uma única pessoa que possuía a versão principal de um projeto. 

Essa pessoa só compartilhava a parte específica do código em que alguém precisava trabalhar. Então, um desenvolvedor retornava o código finalizado e, finalmente, tudo era verificado quanto a padrões antes que a versão antiga fosse totalmente substituída pela nova versão.

Tudo somado, foi um processo bastante trabalhado, doloroso e tedioso. A menos que alguém fizesse cópias recorrentes, não havia acesso fácil às versões anteriores. Este cenário começou a mudar em 1972, quando o desenvolvedor Marc Rochkind resolveu que não conseguia mais lidar com isso. Ele acabou criando o Sistema de Controle de Código Fonte (SCCS), o primeiro sistema de controle de versão!

Era bastante limitado em termos de funcionalidade – apenas uma pessoa poderia trabalhar em um arquivo por vez e o desenvolvimento simultâneo era gerenciado com bloqueios (checkout locks). No entanto, ele também resolveu muitos problemas: as várias versões não precisavam ocupar mais espaço em disco, e as otimizações de mesclagem se tornaram muito mais fáceis.

A segunda geração do VCS foi composta por ferramentas como o RCS, CVS e SVN, que vieram com melhorias em toda a linha de desenvolvimento em seus tempos. Em geral, elas davam aos usuários muito mais flexibilidade, mas uma coisa permanecia: as revisões precisavam ser mescladas antes que pudessem ser confirmadas. 

Era hora de resolver esse problema e levar o controle de versão para uma nova era, onde apareceram sistemas de controle de versionamento como o Mercurial e Git. Destes, o Git se tornou rapidamente predominante no mercado de desenvolvimento de software, sendo o único conhecido pela geração de desenvolvimento de software pós 2010.

Com os sistemas de controle de versões evoluídos e toda a gama de funcionalidades que passam a ficar disponíveis neles, veio a necessidade de criar e manter formas efetivas de versionamento dos sistemas. Aqui, vamos abordar uma delas: o Versionamento Semântico.

Versionamento de Código

Como citado brevemente no caso histórico acima, Controle de Versão de um software é o gerenciamento das mudanças do código fonte do mesmo. Para desenvolvedores, é crítico ter um sistema de controle de versão, para que seja possível que múltiplos desenvolvedores possam contribuir com o código sem um interferir no outro. 

Os desenvolvedores podem cooperar entre si com alterações no código quando necessário; caso precise, no futuro, é possível obter o histórico das alterações e até restaurar uma versão anterior do código. O git, d‌entre‌ os ‌vários‌ sistemas de ‌controle‌ ‌de‌ ‌versionamento (VCS – Version Control System) ‌disponíveis ‌no‌ ‌mercado, é ‌o‌ ‌mais‌ ‌utilizado‌‌ atualmente.

Após alterações no código fonte do software, é preciso ter uma versão para ser disponibilizada para a produção. Cada versão lançada deve ter um número/código único para sua identificação. Assim, surge a necessidade do versionamento semântico. ‌

Versionamento Semântico

O versionamento semântico, quando realizado de forma correta, ajuda os usuários a entenderem o estágio em que a aplicação está. Em desenvolvimento de software, nós versionamos aplicações seguindo o Versionamento Semântico (Semantic Versioning), o que nada mais é que um modelo geral em que todos usuários possam entender.

Regras do versionamento

O versionamento semântico propõe um conjunto simples de regras de como os números das versões são atribuídos e incrementados.

Considere o formato de versão X.Y.Z (Major.Minor.Patch, ou seja, Maior, Menor, e Correção, respectivamente). X, Y, e Z são inteiros não negativos. Cada elemento deve ser incrementado em 1. Por exemplo: 1.9.0 -> 1.10.0 -> 1.11.0.

Para cada lançamento do software, ele deve ter um número único da versão e, uma vez lançado, o código dessa versão não pode mais ser alterado. Qualquer necessidade de alteração no software, ele deverá ser lançado com um novo número de versão.

Patch: incrementado apenas se estiver publicando correção de bug e mantendo a compatibilidade com a versão anterior.


Minor: incrementado se estiver adicionando funcionalidade nova ou se alguma existente for marcada como obsoleta. E é preciso que seja mantido a compatibilidade com a versão anterior. 

Quando a versão Minor for incrementada, a versão Patch deve ser redefinida para o valor zero.


Major: essa versão é incrementada quando houver alterações que não são compatíveis com a versão anterior já publicada, não importando se contém ou não funcionalidades novas.

Quando a versão Major for incrementada, tanto a versão Minor quando a Patch devem ser redefinidas para o valor zero.

Fase inicial de desenvolvimento

A simples coisa a se fazer é iniciar o desenvolvimento de uma nova aplicação/produto/API com a versão 0.1.0, e então ir incrementando a versão Minor para cada release seguinte.

Quando o software começar a ser utilizado em produção ou você tiver uma API estável, você deverá alterar a versão para 1.0.0

Passo a passo do versionamento

1. Versões 0.Y.Z – desenvolvimento antes de lançar aplicação para produção

1.1 Versão 0.Y.0 – novas funcionalidades

  • Um time inicia o desenvolvimento de uma nova aplicação. Nessa fase inicial e embrionária, a versão da aplicação se inicia em 0.1.0. Após cada funcionalidade nova ser desenvolvida, o valor referente à Minor version é incrementado: 0.1.0  –>  0.2.0  –>  0.3.0 e assim sucessivamente.

1.2 Versão 0.Y.Z – correção de bugs

  • Caso exista algum bug em uma dessas versões (por exemplo: bug encontrado na versão 0.3.0), a correção desse bug deverá ser lançada juntamente com a versão 0.3.1. Seguinte a essa versão, se houver um novo bug, será gerada a versão 0.3.2.

1.3 Versão 0.Y.0 – novas funcionalidades

  • Com o software na versão 0.3.2, se o time lança uma nova funcionalidade, sua versão passa a ser 0.4.0.

2. Versões X.Y.Z – após lançar aplicação para produção

2.1 Versão 1.0.0

  • Sem quebra de compatibilidade
  • Após uma versão ser disponibilizada como estável ou o software ser lançado em produção, a versão é alterada para 1.0.0.

2.2 Versão x.Y.0 – novas funcionalidades

  • Sem quebra de compatibilidade
  • Para novas funcionalidades, caso não haja quebra de compatibilidade, o valor referente à Minor version é incrementado: 1.0.0  –>  1.1.0  –>  1.2.0 e assim sucessivamente.

2.3 Versão 1.Y.Z – correção de bugs

  • Caso exista algum bug em uma dessas versões (por exemplo: bug encontrado na versão 1.3.0), a correção desse bug deverá ser lançada juntamente com a versão 1.3.1. Seguinte a essa versão, se houver um novo bug, será gerada a versão 1.3.2.

2.4 Versão 1.Y.0 – novas funcionalidades

  • Sem quebra de compatibilidade
  • Com o software na versão 1.3.2, o time lança uma nova funcionalidade, sem quebra de compatibilidade, e sua versão passa a ser 1.4.0.

2.5 Versão X.0.0 – novas funcionalidades

  • Com quebra de compatibilidade
  • Com o software na versão 1.4.3, por exemplo, o time lança uma nova funcionalidade que quebra alguma compatibilidade com a versão anterior. Sendo assim, o valor referente à Major version é incrementado e os demais são alterados para zero; sua versão passa a ser a 2.0.0.

A quebra de compatibilidade se dá no momento que em que a API do software em desenvolvimento tem uma alteração que quebra o contrato de quem a utiliza. 

Por exemplo: você tem um endpoint que retorna um objeto com as propriedades “id”, “nome” e “telefone”. Após uma nova versão, a API passa a retornar apenas “id” e “nome”. Com essa alteração, há uma quebra do contrato, pois seu usuário espera que a propriedade “telefone” seja retornada, mas ela não existe mais no contrato.

Exemplo prático – Java

As versões do Java são sempre 1.x.y, ou seja, ainda não houve quebra de compatibilidade da linguagem Java. Por causa disso, é possível executarmos códigos antigos com as versões recentes do Java.

Para cada versão do Java, é incrementada a Minor version (quando temos novas funcionalidades na linguagem) ou é incrementado o Patch (quando temos correções de bugs).

Com base no que vimos até agora, pode ser que a imagem acima, retirada da Wkipedia, cause alguma confusão. Isso porque a próxima versão após a 1.4 foi a 5.0. No entanto, isso foi mais um item de marketing do que de Versionamento Semântico conforme é utilizado pelos desenvolvedores. Tanto que, se olharmos no próprio site da documentação da Oracle, temos essa explicação:

“Os números de versão “1.5.0” e “5.0” são usados para identificar a release do Java 2 Platform Standard Edition. A versão “5.0” é a versão do produto, enquanto “1.5.0” é a versão de desenvolvedor. O número “5.0” é usado para refletir melhor o nível de maturidade, estabilidade, escalabilidade e segurança do J2SE.

O número “5.0” foi alcançado ao eliminar o “1” inicial. de “1.5.0”. Onde você esperava ver a versão 1.5.0, agora é 5.0 (e onde era 1.5, agora é 5).”

Ou seja, o Versionamento Semântico foi mantido corretamente, e o Java não possui quebra de compatibilidade pois ainda está na versão 1.x.y.

Exemplo prático – Angular

Agora um exemplo em que o Versionamento Semântico não era realizado de forma correta, ou pelo menos não seguia as regras do site http://semver.org/.

Na sua primeira versão, o seu nome era AngularJS, e suas versões eram: … 1.4, 1.5, 1.6….

Como podemos observar, eram incrementados a Minor Version, onde não haveria quebra de compatibilidade, mas na verdade, em cada uma dessas versões existiam quebras de compatibilidade.

Quando houve a grande mudança do Angular, seu número de versão foi alterado para 2.0.0. Assim, passaram a seguir as regras do Versionamento Semântico. Agora, para cada versão que possui quebra de compatibilidade, é incrementada a Major Version corretamente, como pode ser visto na imagem a seguir:

Linha do tempo do desenvolvimento

A seguir, temos um diagrama com exemplo de alterações de um software com as modificações dos números das versões.

  • Passo 1: Com a implementação de uma nova funcionalidade, a versão do software muda de 1.0.0 para 1.1.0.
  • Passo 2: Após a versão 1.1.0 ser criada, foi descoberto um bug no sistema (bug #1). Com a resolução desse bug, foi criada a versão 1.1.1.
  • Passo 3: A partir da versão 1.1.1 já existente, foi desenvolvida uma nova funcionalidade, gerando assim a versão 1.2.0.
  • Passo 4: Neste momento, foi descoberto um novo bug no software (bug #2), mas esse bug está tanto na versão 1.1.1 quanto na versão 1.2.0. Com isso, é preciso realizar a alteração nas duas versões, criando-se assim duas novas versões.
    Versão 1.1.1 gerando a versão 1.1.2.
    Versão 1.2.0 gerando a versão 1.2.1. 
  • Passo 5: Nova funcionalidade desenvolvida. Na sua publicação, é gerada a versão 1.3.0, que contém também a correção do bug #2 do passo 4.

Alguns problemas do Versionamento Semântico

O site developerexperience cita alguns problemas que o versionamento semântico pode trazer para o time. Entre eles, tamos:

  • Trabalho sem sentido;
  • Função desnecessária;
  • Aumento de custo.

Se você está desenvolvendo um software, mas o usuário não analisa as versões do software e não atualiza nem deixa de atualizar o software baseado no tipo de alteração que ele sofreu, talvez não seja necessário utilizar o versionamento semântico.

Isso se aplica principalmente quando não se tem um bom versionamento semântico, ou quando se comete um erro ao lançar uma nova versão. Vamos pegar um exemplo: suponhamos que, durante a resolução de um bug, tenha sido feita a alteração de alguma parte do software que gerou uma incompatibilidade com a versão anterior. Só que a equipe de desenvolvimento viu o problema apenas após a publicação da versão de correção de bug. Logo, a versão, que deveria ter seu número atualizado com incremento do número do Major version, acabou sendo lançada com atualização do Patch.

Um erro desse tipo no lançamento uma versão da aplicação, caso ocorra, pode gerar um grande problema — tendo em vista que existem muitas ferramentas no mercado para atualização automática das dependências baseada no versionamento semântico.

Conclusão 

Como vimos, o versionamento semântico feito da forma correta é muito poderoso. Com ele, é possível sabermos qual o tipo de alteração feita em uma atualização de software apenas com uma rápida análise do número da versão. Em três números, o time consegue comunicar importantes informações para seus usuários. Isso permite que eles possam automatizar a tarefa corriqueira de manter o software atualizado de acordo com o nível de segurança desejado.

Links de Referência: 

5f7dc8c18032dcd1fa046b0b_hader-de-araujo
Desenvolvedor Sênior
Profissional sempre à procura de evolução, conhecimento e aprendizado.

Artigos relacionados

Este site utiliza cookies para proporcionar uma experiência de navegação melhor. Consulte nossa Política de Privacidade.