Estamos desenvolvendo projetos, mas reutilizamos muito código entre os projetos e temos muitas bibliotecas que contêm nosso código comum. À medida que implementamos novos projetos, encontramos mais maneiras de fatorar o código comum e colocá-lo nas bibliotecas. As bibliotecas dependem umas das outras e os projetos dependem das bibliotecas. Cada projeto e todas as bibliotecas usadas nesse projeto precisam usar a mesma versão de todas as bibliotecas às quais estão se referindo. Se lançarmos um software, teremos que corrigir bugs e talvez adicionar novos recursos por muitos anos, às vezes por décadas. Temos cerca de uma dúzia de bibliotecas, as mudanças geralmente abrangem mais de duas e várias equipes trabalham em vários projetos em paralelo, fazendo alterações simultâneas em todas essas bibliotecas.
Recentemente, mudamos para o git e configuramos repositórios para cada biblioteca e cada projeto. Usamos o stash como um repositório comum, fazemos novas coisas nas ramificações de recursos, fazemos solicitações pull e as mesclamos somente após a revisão.
Muitos dos problemas com os quais lidamos nos projetos exigem que façamos alterações em várias bibliotecas e no código específico do projeto. Isso geralmente inclui alterações nas interfaces da biblioteca, algumas das quais são incompatíveis. (Se você acha que isso soa suspeito: fazemos interface com hardware e ocultamos hardware específico por trás de interfaces genéricas. Quase sempre que integramos o hardware de algum outro fornecedor, nos deparamos com casos que nossas interfaces atuais não antecipavam e, portanto, precisamos refiná-las.) exemplo, imagine um projeto P1
usando as bibliotecas L1
, L2
e L3
. L1
também usa L2
e L3
, e L2
usa L3
também. O gráfico de dependência é assim:
<-------L1<--+
P1 <----+ ^ |
<-+ | | |
| +--L2 |
| ^ |
| | |
+-----L3---+
Agora imagine que um recurso para este projeto exija alterações P1
e as L3
quais alterem a interface do L3
. Agora adicione projetos P2
e P3
à mistura, que também se referem a essas bibliotecas. Não podemos nos permitir mudar todos eles para a nova interface, executar todos os testes e implantar o novo software. Então, qual é a alternativa?
- implementar a nova interface em
L3
- faça uma solicitação de
L3
recebimento e aguarde a revisão - mesclar a mudança
- crie uma nova versão do
L3
- comece a trabalhar no recurso
P1
, fazendo com que ele se refira aoL3
novo lançamento, e implemente o recurso naP1
ramificação do recurso - faça uma solicitação pull, revise-a e mesclada
(Eu notei que eu esqueci de mudar L1
e L2
para a nova versão. E eu nem sei onde enfiar isso no, porque ele teria que ser feito em paralelo com P1
...)
Esse é um processo tedioso, propenso a erros e muito longo para implementar esse recurso, requer análises independentes (o que torna muito mais difícil a revisão), não é escalável e provavelmente nos afastará dos negócios porque ficamos tão atolados no processo que nunca fazemos nada.
Mas como empregamos ramificação e marcação para criar um processo que nos permita implementar novos recursos em novos projetos sem muita sobrecarga?