[Bruno Mentges de Carvalho] Padronizando o versionamento do seu software com Semantic Versioning

Um dos grandes problemas quando trabalhamos com múltiplos times de desenvolvimento e existem softwares que dependem entre si é saber quando uma versão continua compatível com a anterior. Muito se discute sobre como devemos versionar nosso software visando evitar o problema chamado Dependency Hell (Inferno das Dependências). Esse problema comumente aparece ou com dependency lock, ou seja, seu software não pode mais andar pra frente sem antes fazer um release de todas as dependências, ou com version promiscuity que é quando você assume compatibilidade com versões futuras sem ter certeza.

Foi aí que surgiu uma especificação formal para resolver esses problemas que se chama Semantic Versioning, ou, em português, Versionamento Semântico e essa especificação se encontra aqui: http://semver.org/ (em inglês). Não é nada novo, devo avisar, mas é uma forma de especificar o significado dos números que você usa para versionar seu software. O modelo é simples, o conhecido X.Y.Z onde X é a Major Version, Y é a Minor Version e Z é a Patch Version, exemplo: Meu Software versão 2.5.1.

Para efeito de continuidade, vou traduzir aqui as regras que são poucas mas bem interessantes:

  1. Software que usa Semantic Versioning DEVE declarar a public API. Essa API pode ser declarada no código ou existir em documentação. Quando for feita, ela deverá ser precisa e compreensiva.
  2. Um número de versão normal DEVE ter a forma de X.Y.Z, onde X,Y e Z são inteiros. X é o major version, y é o minor version e Z é o patch version. Cada elemento DEVE aumentar numericamente. Por exemplo: 1.9.0 < 1.10.0 < 1.11.0.
  3. Um número de versão especial PODE ser denominado ao adicionar uma string abritrária logo após o patch version. Essa string DEVE conter somente alfanuméricos mais o símbolo menos [0-9A-Za-z-] e DEVE começar com um caracter alpha [A-Za-z]. Versões especiais devem satisfazer e ter menor precedência que a versão normal associada. Precedência DEVE ser determinada pela ordenação lexicográfica ASCII. Exemplo: 1.0.0beta1 < 1.0.0beta2 < 1.0.0
  4. Uma vez que foi lançada uma versão, o conteúdo daquela versão NÃO DEVE ser modificada. Qualquer modificação deve ser lançada como uma nova versão.
  5. Major version que começe com 0 (0.y.z) é para desenvolvimento inicial. Qualquer coisa pode mudar a qualquer momento. A public API não pode ser considerada estável.
  6. A Versão 1.0.0 define a public API. A maneira com que o número de versão aumenta é agora dependente dessa API e em como ela muda.
  7. Patch version Z (x.y.Z | x > 0) DEVE ser incrementada se somente bug fixes que são compatíveis com versões anteriores são introduzidos. Um bug fix é definido como uma mudança interna que corrige um comportamento incorreto.
  8. Minor Version Y (x.Y.z | x > 0) DEVE ser incrementada se novas funcionalidades que são compatíveis com versões anteriores são introduzidas à public API. Ela PODE ser incrementada se muitas novas funcionalidades ou melhorias forem introduzidas no código privado. Ela PODE incluir patches.
  9. Major version X (X.y.z | X > 0) DEVE ser incrementada se qualquer mudança que quebre a compatibilidade com versões anteriores são introduzidas na public API. Ela PODE incluir mudanças minor e de patch.

É isso. São essas as regras. Mas qual a importância disso se nada disso é novo ? A importância é que se todos seguem essa especificação, todos terão o mesmo entendimento do que significam os números de sua versão e se planejar ao ter que fazer upgrade. Se só o que seu software adicionou foram melhorias e novas funcionalidades que não quebram nenhum comportamento com as versões antigas, eu sei que posso fazer um release tranquilo sem precisar alterar nada do meu lado.

Tem um FAQ legal na url da especificação que traz dúvidas comuns. Lá também orienta quem quer começar agora a usar mesmo tendo um sistema legado cheio de tags. Vale dar uma conferida e tentar espalhar essa especificação. Nós aqui do meu time de desenvolvimento já começamos a usar.