Achei esse post como rascunho aqui no meu blog, eu acabei postando ele no LeGauss em duas partes (parte 1, parte 2), por que não postar aqui também, agora na íntegra.
Introdução
Vou falar agora sobre um assunto de extrema importância e que é subestimado durante a graduação. Mesmo no curso de computação da USP, só ouvi falar disso uma única vez em cinco anos de curso. Tive que aprender sobre versionamento nas minhas atividades extracurriculares por minha própria conta.
Mas, apesar de ignorado pelo meio acadêmico, o versionamento está presente em todo o resto do mundo do software. Na verdade, não existe desenvolvimento de software sem o uso do versionamento. Mas o que é versionamento?
Como o próprio nome sugere, versionar significa colocar sob versão. Por exemplo, versão 1.0, 2.3.5 ou Beta. Basicamente, cada um adota um determinado padrão para a nomenclatura das suas versões, mas todos funcionam da mesma maneira. Quando os programas sofrem alterações recebem uma nova versão que reflete isso e cada versão é única durante a vida de um software.
A distribuição Ubuntu, por exemplo, adota o ano e mês de lançamento para compor a versão, ou seja, o Ubuntu 10.10 tem esse nome porque foi lançado em outubro de 2010. Outras pessoas gostam de adotar o padrão de três números 1.1.1, onde, da esquerda para a direita significa grande, media e pequenas modificações. Ainda existem umas versões especiais, como Alpha, que representa um software ainda em fase de desenvolvimento, Beta, que significa que um programa está em fase de testes finais ou RC (Release Candidate - Candidato a lançamento), que se assemelha à Beta, é um software maduro aguardando uma homologação para ser lançado oficialmente.
Mas o que é, de fato, versionar???
Versionamento é usado para se rastrear as modificações que um software sofre ao longo do tempo. Dessa forma, é possível saber se estamos com a versão mais atual, ou senão, qual update realizar. Cada versão nova pode corrigir bugs, adicionar novas funcionalidades ou melhorar o desempenho, por isso é importante manter tudo atualizado (com algumas exceções).
Se você está trabalhando em um ambiente controlado que integra diversas tecnologias, você só pode fazer o update do seu software depois de um estudo sobre o impacto disso no seu ambiente de trabalho. Por exemplo, pode ser que um dos seus software passe a salvar os arquivos de forma diferente e você importava esses arquivos com outra ferramenta que só lê esses arquivos na versão anterior, então neste caso, um update da primeira ferramenta não pode ser executado.
O versionamento é feito armazenando-se as pequenas modificações sofridas pelo software. Dessa forma é possível recuperar os diferentes estados do software ao longo do tempo. Isso é importante quando queremos passar adiante as modificações, pois não se precisa fornecer todo o software novamente, mas somente as modificações que ocorreram desde a última atualização, resultando em um arquivo muito menor e um processo de atualização mais rápido.
Você também tem a liberdade de voltar à versões anteriores e seguir uma linha de desenvolvimento diferente, também conhecido como fork de um projeto.
O que versionar?
Desenvolver um software envolve muitos elementos, então, quais deles devem ser colocados sob versionamento? No mínimo, você versiona o código fonte, ou o diretório onde encontra-se o projeto. Também versiona-se qualquer documentação sobre o projeto e qualquer arquivo extra que seja distribuído junto com o software.
Alias, você também pode versionar documentos e outros tipos de arquivos pessoais. Somente tome cuidado com o versionamento de binários, que é um pouco diferente de arquivos de texto.
Por que versionar?
Você deve estar se perguntando, o que isso importaria para você, que não trabalha em um grande projeto ou coisa assim?
Se você trabalha em algum programa, mesmo que pequeno, mas em parceria com outras pessoas ou apenas gostaria de compartilhar seus resultados já é possível colher as vantagens do versionamento, pois essas ferramentas também possuem mecanismos para otimizar o trabalho em equipe e facilitar o trabalho simultâneo de várias pessoas em um mesmo programa. Compartilhar os arquivos e suas modificações usando um gerenciador de versionamento é bem simples.
Versionar também é uma boa forma de backup, já que o código fonte e outros arquivos ficam em um servidor, e você pode sincronizar a pasta do projeto de onde quiser. Apesar que:
VERSIONAMENTO NÃO É BACKUP
Não use o versionamento simplesmente como uma forma de backup, existem ferramentas e técnicas bem melhores para isso.
Vamos considerar um exemplo
Vamos inventar um cenário onde fiquem mais claras as vantagens do versionamento.
Vamos supor que você esteja fazendo um programa que calcule números primos, como por exemplo, uma implementação do
Crivo de Eratostenes. Porém, você não está fazendo esse programa sozinho, você conta com a ajuda de um amigo que vai te ajudar com algumas partes do programa.
Assim, o desenvolvimento de dará da seguinte forma, você vai fazer umas funções e ele fará outras (não necessariamente ao mesmo tempo) e vocês juntarão as duas partes. Para tanto, existem os seguinte métodos:
Método tradicional
Se você não está familiarizado com versionamento, o que é o mais provável, você certamente optará por este método.
Você começa a desenvolver o programa, então envia por e-mail o código fonte para o seu amigo para que ele continue a desenvolver. Ele envia para você de volta o arquivo mais completo, e isso se segue por um tempo.
O problema começa quando ambos começar a depurar seus respectivos código e enviar as correções um para o outro. Isso é feito enviando o seu código inteiro para o seu amigo e, como ele provavelmente terá um código diferente do seu, vai precisar caçar e implementar as mudanças na mão, e o mesmo vale para você.
Na maior parte do tempo, os programas serão bem diferentes um do outro, e a caixa de e-mail ficará lotada de arquivos fontes e se tornará bem complicado distinguir entre as versões, afinal "quando foi que você me enviou a aquela correção mesmo? Com que assunto estava o e-mail?".
Método tradicional - compacto
O método compacto parece mais atrativo mas é ainda pior. Ao invés de se enviar o código fonte inteiro, envia-se somente a função que foi modificada no próprio corpo do e-mail e indica-se onde substituí-la no código. Fica ainda pior de rastrear a evolução do software e saber quais alterações precisar ser feitas ou não.
Método tradicional - hardcore linux
Se você é um usuário linux, existem algumas facilidades para se enviar modificações em um arquivo texto. Você pode criar um arquivo contendo somente as modificações que ocorreram usando o comando diff e gerando um arquivo de patch.
Esse arquivo contém todas as modificações para transformar um arquivo em outro, ou seja, da última versão que você enviou ao seu amigo para a versão que você está agora. Por conseqüência, esse arquivo é menor que o fonte. O patch pode ser aplicado usando-se o comando patch, que aplica automaticamente todas as modificações e faz com que o arquivo fique na última versão.
Apesar disso, esse modo ainda possui problemas de rastreabilidade de modificações do código fonte. Antes de começar a modificar o arquivo, você tem que manualmente aplicar o patch para garantir compatibilidade com o projeto e ambos devem ter uma versão de referência separadas no computador nas quais devem aplicar os patchs seus e do seu amigo.
Método com versionamento
E finalmente o método com versionamento. Primeiramente, é escolhida uma das diversas ferramentas disponíveis. Então é criado um repositório em um servidor com os arquivos do projeto. Esse servidor será quem fará o controle da versão e distribuirá as versões entre os membros do projeto.
Cada um que for trabalhar nesse projeto fará um checkout de todos os arquivos do projeto do servidor para uma pasta local. Então, sempre que quiser fazer alguma alteração no projeto, basta fazer um update para atualizar seus arquivos para a última versão, alterar o programa como você quiser, e depois realizar um commit para enviar as modificações para o servidor.
A cada commit no servido uma revisão é criada. Boas práticas de programação obrigam cada um que realizar um commit em um projeto a também anexar um comentário nessa revisão, o que torna a rastreabilidade da evolução do projeto bem mais fácil. Pode-se ainda apelidar as revisões e, assim, criar uma versão. Por exemplo, após 100 commits você estará na revisão 100 e estará lançando a versão 1.0 do seu programa.
A ferramenta de versionamento sabe exatamente qual versão você se encontra e baixará todas as modificações que ocorreram na ordem certa do programa desde a última vez que você o atualizou.
Nos caso em que você já alterou sua versão e ela não era a mais nova, a própria ferramenta tentará fazer um merge das modificações, ou seja, a ferramenta tentará incorporar as suas modificações na versão atual automaticamente, bastando apenas, depois disso, realizar novo commit para atualizar a versão do servidor. Caso o merge automático falhe, ainda é possível realizá-lo na mão.
Dessa forma, ambos sabem como o software está evoluindo pois as modificações são rastreáveis. As ferramentas permitem você transitar entre as revisões (você não precisa trabalhar necessariamente na última), você pode fazer um fork do projeto e iniciar um novo projeto a partir da metade desse. E o mais importante de tudo, você pode compartilhar seu projeto e pessoas podem facilmente baixar, haquear o código e propor alterações que você pode escolher facilmente incorporar no seu programa.
Sistemas de versionamento
Eu disse que haviam várias ferramentas disponíveis, e por causa disso, não me estenderei demais nessa parte, mas citarei as principais com as quais eu já tive alguma experiência.
As ferramentas distinguem-se entre dois grandes grupos. As ferramentas de versionamento centralizadas e aquelas distribuídas. No final, todas acabam possuindo um servidor central para disponibilizar os arquivos do projeto, mas existe uma diferença sutil na utilização desse servidor.
Nas ferramentas centralizadas, o servidor é o mais importante. Todas as modificações são feitas com relação a ele. Sem acesso ao servidor, simplesmente não há como trabalhar, a não ser realizando modificações locais e depois enviando tudo de uma vez para o servidor quando esse estiver disponível.
Nas ferramentas distribuídas, o foco está nos programadores. O servidor é apenas um ponto de junção para todos os membros do projeto, mas o projeto pode continuar a evoluir em ele. Os programadores podem realizar commits locais caso o servidor não esteja disponível e depois enviar todos os commits de uma vez. A diferença aqui é que, enquanto no caso anterior todas as modificações formaram um único commit, e nesse caso cada modificação gerou o seu próprio commit com seu próprio comentário, tornando muito mais fácil rastrear as modificações e realizar um futuro merge do projeto.
Só para esclarecer, as boas práticas de versionamento determinam que um commit é uma unidade lógica de trabalho. Ele pode representar uma correção de um erro, uma funcionalidade nova ou uma melhoria. Ele também não está restrito a um único arquivo.
Um merge é a incorporação de commits no projeto principal. Quanto mais fragmentado e melhor separado os commits, mas fácil será juntá-los ao projeto principal.
Centralizadas: CVS e SVN
O modelo de versionamento
centralizado foi o primeiro que surgiu, junto com as primeiras ferramentas. Desse grupo, vale a pena destacar o CVS e o SVN.
CVS ou Concurrent Version System (Sistema de Versões Concorrentes) foi um dos primeiros a surgir, já não é o melhor que existe, mas ainda está em funcionamento em muitos lugares, talvez pela simplicidade, talvez por ter chegado primeiro e muitos estarem acostumados com ele, além de existir extensões e plugins para inúmeras ferramentas de desenvolvimento, que incorporam o CVS dentro da ferramenta.
O sucessor do CVS é o SVN ou Subversion. Ele trabalha no mesmo princípio do CVS mas traz muitas melhorias. Atualmente é um dos principais sistemas de versionamento que exite e inclusive possui diversos sites fornecendo hospedagem gratuitas para projetos usando o SVN, como o
google. A maioria dos sites que fornecem hospedagem gratuita fazem isso apenas para projetos de software livres mas há alguns que permitem desenvolvimento privado, como o
Project Locker.
Distribuídas: Mercurial, git, etc
Dentre os modelos distribuídos, posso citar o
Mercurial,
GIT ou
Bazaar como os principais. No caso do GIT, além do Project Locker, existem serviços como o
Git Hub e o
Gitorious que também permitem o cadastro de projetos que sejam livres.
Recentemente tenho trabalhado com o Mercurial e tenho tido boas experiências. Uso o serviço
Bitbucket que permite projetos tanto livres como privados. Em sua última atualziação, o Bitbucket também passou a oferecer hospedagem para progetos em GIT.
Além do suporte de versionamento esses sites costumam também disponibilizar uma wiki e uma página especial para reportar bugs para o seu projeto.
Algumas dicas
Você não precisa usar as ferramentas de versionamento no terminal (apesar de que, com a prática, vai parecer mais simples). No caso do SVN no windows você pode usar o
TortoiseSVN, que cria no menu do windows explorer um menu para realizar as tarefas de versionamento.
No caso do Mercurial existe o
TortoiseHg, tanto para Windows, Linux ou Mac, que também é uma ferramenta visual. Se você está usando alguma IDE, é bem possível que existam plugins para ela que facilitem o uso de versionamento.
Para o GIT, no windows, existe a possibilidade de usar o
TortoiseGit.
É possível versionar qualquer tipo de arquivo. Imagens, binários, documentos além dos arquivos de código fonte. O problema é que a ferramenta só consegue calcular as alterações entre duas versões em arquivos de texto puros, como os códigos fontes. Ao versionar um arquivo que não é um texto puro, a ferramenta verá que a data de modificação do arquivo é maior que a data da ultima versão, então ele substitui a versão anterior pela mais nova. Na prática, ele está só criando novas cópias, o que não é um uso muito inteligente de espaço no servidor, mas quebra um bom galho.
Conclusões
Versionar é mais importante do que parece. Infelizmente, só sentimos falta dele quando surgem os problemas. Através do versionamento fica mais fácil controlar as mudanças, distribuir patches e trabalhar de forma colaborativa. A prática do versionamento já está bem madura no mundo e é possível encontrar diversas ferramentas e tecnologias para atender as mais diversas necessidades.
Mesmo sem o uso de alguma ferramenta própria, também é recomendável adotar o uso de versões no nome dos arquivos, principalmente se eles podem mudar e você vai distribuí-los. Por exemplo, você tem o trabalho_de_historia.odt no seu computador e vai enviá-lo para o seu grupo para esse avaliar o resultado. Haverão sugestões você mudará algumas coisas, alguém mudará algumas coisas e, no final, você precisa mandar o trabalho pra professora e você tem três arquivos trabalho_de_historia.odt espalhados no seu computador, um na pasta downloads, um na documents e um na sua pasta de trabalhos. Qual é o mais recente para você entregar a professora?
A dica é use um nome como trabalho_de_historia_v1.odt no seu documento e incremente esse valor sempre que o arquivo for alterado, dessa forma, pelo nome do arquivo, você sempre saberá qual é o mais recente.