Apresentando uma política de ramificação de controle de versão a uma equipe pequena

17

Sou um empreiteiro que começou recentemente com uma empresa.

A equipe é composta por 3 desenvolvedores, que consistem em 2 desenvolvedores de nível júnior a médio, com outro no mesmo nível começando em breve e eu (6 Anos xp). Para ambos os desenvolvedores existentes, é o primeiro trabalho fora da universidade / faculdade, e eles nunca tiveram um desenvolvedor sênior supervisionando seu trabalho antes.

Não há uma política explícita de controle de versão. Os desenvolvedores fazem todo o desenvolvimento no tronco e, em seguida, implantam na produção diretamente de suas máquinas de desenvolvimento. A equipe existente não está familiarizada com ramificações.

Estou mudando tudo isso e introduzindo CI, servidores de teste / preparo / produção de TDD, etc, juntamente com uma política de controle de versão para complementar isso.

O sistema de controle de origem é o TFS, que eu nunca usei antes. Está configurado como um repositório gigante.

Eu escrevi algumas dicas para eles, mas há algo mais que eu deva adicionar / alterar, tendo em mente a experiência da equipe?

Política de Controle de Versão

O desenvolvimento é feito no tronco

Se uma mudança for estimada em mais de uma semana, ela deve ser feita em uma ramificação, com mesclagens regulares do tronco na ramificação para impedir que os dois fiquem fora de sincronia.

Liberar ramificações criadas para o código de produção. Esse ramo deve conter apenas código estável. Podemos ter um ramo de lançamento que é atualizado a partir do tronco uma vez por sprint, ou podemos fazer um ramo de lançamento separado para cada semana.

Se uma correção de bug urgente que afeta o código de produção precisar ser feita, ela será feita na ramificação de lançamento e mesclada novamente no tronco.

Se adotarmos a estratégia de ramificação de uma liberação, o tronco será mesclado na ramificação de liberação uma vez por sprint no final do sprint.

Se adotarmos a estratégia de ramificação separada por liberação, o tronco NUNCA será mesclado na ramificação de liberação

Em alguns cenários, pode ser necessário corrigir o bug duas vezes em ramificações diferentes, se as ramificações divergirem demais. Se estamos fazendo sprints curtos, isso não deve acontecer com muita frequência.


Eu pretendo ter três servidores. Ambiente de teste que está sempre executando o código mais recente no repositório. Um ambiente de temporariedade que está executando o candidato à versão mais recente para preparar / testar o código do Release Candidate e para fins de UAT e o ambiente de produção.

A razão pela qual pretendo fazer isso é que, até agora, o cliente fez apenas software interno. O mais novo projeto é para um cliente de mídia de alto perfil, e sinto que a equipe precisa adotar um modelo de desenvolvimento mais profissional do que o que faz no momento.

Por exemplo, no momento, um usuário pode telefonar para a equipe com um relatório de erro. Os desenvolvedores localizam e corrigem o erro, fazem um teste rápido do globo ocular em suas próprias máquinas e, em seguida, implantam diretamente na produção. Nenhum teste automatizado ou qualquer coisa.


Em retrospectiva, acho que o ramo de recursos é um passo longe demais e eu removerei isso.

Então, basicamente, tudo se resume a: a) nenhuma ramificação; b) uma ramificação de liberação e o tronco; ec) uma ramificação de liberação por liberação e o tronco.

Eu estava inclinado para o último. Meu pensamento inicial seria que eu teria um candidato a lançamento e um lançamento para estar ao vivo em servidores separados (UAT / Produção) ao mesmo tempo, mas efetivamente o tronco é o candidato a lançamento a qualquer momento, portanto, uma filial por liberação está inclinada para a loucura. Meu único pensamento seria se não quiséssemos que nossas partes interessadas vissem o código de desenvolvimento, talvez precisássemos de um ramo candidato a lançamento separado, mas o YAGNI e tudo mais .....

MrBliz
fonte
3
você considerou adicionar uma explicação de por que escolheu esse caminho? digamos, da mesma forma que é feito aqui . Além disso, você verificou a "Orientação de ramificação do Microsoft Team Foundation Server" (referida, por exemplo, aqui )?
mosquito
3
Tente este
gbjbaanb
1
Lembre-se de que estou usando o TFS e não um DVCS como o GIT. Isso parece um pouco específico.
MrBliz
2
O final desse link diz: "Todo mundo trabalha fora do tronco. Ramifique quando você libera o código. Ramifique uma liberação quando você precisar criar uma correção de bug para o código já liberado. Ramificar para protótipos." Eu sugeriria que, para um começo simples, você apenas marque as liberações quando tiver certeza razoável de que elas estão concluídas. A menos que você tenha vários desenvolvedores trabalhando em vários recursos, não há muita necessidade de ter mais de uma ramificação. Todo mundo adiciona recursos, todos corrigem o candidato a lançamento, todos concordam quando está pronto para etiquetar. Isso significa que você só precisará entregar ramificações para correções de erros mais tarde.
Taft
1
Fico desconfortável em colocar isso como resposta, porque é muito baseado em opiniões, mas tive grande sucesso em convencer as pessoas a usar uma etiqueta "último bem conhecido" (LKG), que é uma etiqueta em movimento no porta-malas que identifica a última "bênção". "versão (CCB, teste etc.). É dito aos desenvolvedores que os lançamentos serão feitos a partir dessa etiqueta LKG, não da cabeça do tronco, e além disso, eles são livres para usar quaisquer abordagens que façam sentido para eles no momento. Eu descobri que esse padrão gera espontaneamente ramificações de recursos quando é a hora certa, sem nenhum esforço inicial ou trabalho extra nas partes dos desenvolvedores.
Cort Ammon - Restabelece Monica

Respostas:

16

Para uma equipe de 3-4 desenvolvedores, você está propondo MUITAS ramificações.

Cada filial que você cria é uma sobrecarga adicional que vem com um custo (tempo gasto na fusão, mantendo o controle de onde está, etc.). Você precisa ter certeza de que o benefício que obtém de uma filial supera o custo.

Lembre-se de que o único benefício real de uma ramificação é o isolamento de código. Isso significa que você precisa de um motivo concreto para querer ter o código isolado.

Ter uma ramificação de liberação separada para cada sprint é insano. Por que você precisa do código de um sprint isolado do código para o próximo? Por que não apenas ter um único ramo de liberação estável que é transportado a cada sprint?

Se uma mudança for estimada em mais de uma semana, ela deve ser feita em uma ramificação, com mesclagens regulares do tronco na ramificação para impedir que os dois fiquem fora de sincronia.

Quase qualquer novo recurso não trivial levará pelo menos uma semana em tempo real depois de você considerar o desenvolvimento, os testes do desenvolvedor, as interrupções diárias e outras atividades, etc.

Além disso, o que é uma "mesclagem regular"? Diariamente? Semanal? Cada mesclagem leva tempo - você precisa garantir que o ramo de mesclagem de destino seja construído e executado após as alterações. Em uma equipe pequena, a mesclagem frequente é uma sobrecarga.

Temos uma equipe de 4 desenvolvedores trabalhando em mais de 1 milhão de linhas de código e é assim que operamos:

  • Ramo principal onde todo o desenvolvimento é feito
  • Uma ramificação por versão principal (feita aproximadamente uma vez por ano)

A única regra principal é: não faça o check-in do código que não cria.

É isso aí. Simples, fácil de entender, obtém o isolamento de que precisamos (a qualquer momento, podemos criar uma versão compilada para qualquer versão).

As vantagens de ter todo o trabalho de desenvolvimento realizado em um único ramo:

  1. Os desenvolvedores estão sempre sincronizados entre si. Nenhuma fusão dolorosa porque dois desenvolvedores estavam em suas próprias ramificações por semanas criando alterações incompatíveis.
  2. Construções quebradas são encontradas no mesmo dia. Temos uma compilação noturna que executa o código mais recente no main. Se alguém fizer check-in de código que não é compilado por algum motivo, saberemos imediatamente.
  3. Com todo mundo sempre trabalhando no mesmo código, aumenta as chances de um bug ser encontrado mais cedo ou mais tarde.
  4. Nenhuma sobrecarga de mesclagem além das correções direcionadas para liberar ramificações. Em uma equipe pequena, essa é a grande.
17 de 26
fonte
10
"Lembre-se de que o único benefício real de uma ramificação é o isolamento do código. Isso significa que você precisa de um motivo concreto para querer que o código seja isolado." - E a revisão de código? Eu acho que é uma boa razão, mesmo com apenas dois desenvolvedores.
BlueRaja - Danny Pflughoeft
2
A revisão e ramificação de código não são realmente relacionadas. Você está dizendo que não deseja que o código seja verificado em um ramo específico antes de ser revisado?
17 de 26
5
@ 17of26, sim. A revisão de código é normalmente usada como pré - requisito para estar na linha principal. Portanto, você precisa mostrar o código de alguma forma antes disso: no monitor, em um email ou - em muitas configurações - em uma filial. Isso funciona melhor com uma ferramenta de gerenciamento de repositório como GitHub ou gerrit.
Paul Draper
3
O TFS suporta revisões de código por meio de prateleiras, que são áreas temporárias de retenção no controle de origem. O código pode permanecer lá até que seja revisado e depois verificado.
17 de
2
Eu acho que o ponto é que os ramos não são realmente o mecanismo certo a ser usado para fazer revisões de código.
17 de 26
31

Você escreveu algumas dicas para eles, mas não explicou por que sua abordagem é melhor do que a que eles já usam . Isso pode ser problemático. Se você estiver com o espírito "Vamos fazer do meu jeito, porque eu tenho seis anos de experiência profissional e você não" (e lendo sua pergunta, parece exatamente dessa maneira), esteja pronto para ser odiado por os membros de sua equipe que tentarão fazer o que puderem para não aplicar seus conceitos.

Eles têm um problema que precisa ser resolvido? É crucial responder a essa pergunta primeiro, porque eles realmente têm um problema e aceitam suas sugestões, ou estão funcionando perfeitamente como estão atualmente, e você está apenas pressionando o seu modo de trabalhar , apenas porque prefere trabalhe dessa maneira.

Eventualmente, forçá-los a usar ramificações pode ter um impacto extremamente negativo . Trabalhar com um tronco é fácil, especialmente em ambiente Agile. Um desenvolvedor confirma alterações no tronco, lidando com pequenos conflitos e essas alterações são imediatamente usadas pela plataforma de Integração Contínua. Com galhos:

  • Um desenvolvedor precisa pensar onde a mudança deve estar localizada,

  • Alguém tem que gerenciar ramificações e mescla ramificações para o tronco,

  • Mesclagens entre ramificações são feitas com menos frequência do que confirmações, o que significa que alguém precisa lidar com conflitos maiores e mais difíceis de lidar do que um conflito entre duas confirmações,

  • Todo commit não encontra necessariamente seu caminho para a Integração Contínua, o que atrasa as informações que os desenvolvedores obtêm sobre os efeitos que um commit pode ter (especialmente regressões).

O fato de que:

A equipe existente não está familiarizada com ramificação

torna as coisas ainda piores. Eu trabalhei em uma equipe de programadores inexperientes, onde um gerente inexperiente decidiu brincar com filiais. Isso resultou em muito ( muito ) tempo perdido e é exatamente o que você deseja evitar para um projeto que tem prazos.

Arseni Mourzenko
fonte
3
Bem, neste modelo, como você vai parar o código instável que entra em produção sem ramificação?
MrBliz
2
@ MrBliz: através de switches. Você pode ativar um recurso para desenvolvedores, mas desativá-lo para usuários finais, se ele não estiver pronto para o RTM.
Arseni Mourzenko
3
Tendo em mente a experiência dos desenvolvedores com quem estou trabalhando e a atual falta de testes automatizados, não acho que seria uma boa ideia para a nossa situação.
MrBliz
4
@ MrBliz, você para o código instável que entra em produção isolando-o nas ramificações de lançamento (esse é exatamente o objetivo deles) e testando -o. Ramos de recursos não ajudam nisso; de fato, elas apresentam um risco maior de introduzir instabilidade por fusões grandes, não integradas e difíceis de controlar #
396
1
@ MrBliz sim, eu notei isso (e acho que você acertou, se apenas falhou em explicar o raciocínio para apoiar isso). É que nem o seu comentário nem esta resposta mencionam explicitamente se trata de ramos de lançamento ou recurso (ou ambos?), Então eu comentei para enfatizar a diferença . FWIW ser vago sobre esta é provavelmente a única coisa que eu não gosto sobre esta resposta
mosquito
3

Como Mainma diz, tenha cuidado com a ramificação. Você menciona ramificações a cada poucas semanas, é realmente necessário ter muitos ramos?

Como alternativa, você também pode ter um modelo 'pull' em vez de um modelo push. Se você estivesse usando Git ou Mercurial, poderia ter um servidor de integração para validar suas alterações antes de enviar para o servidor central. No TFS, você pode fazer algo semelhante usando check-ins fechados . Dessa forma, você pode ter validação e evitar a complexidade das ramificações.

Mathiasdm
fonte
Efetivamente, haveria apenas três ramificações ativas (liberação, candidato à liberação e tronco) por vez e, na maioria das vezes, apenas a ramificação e o tronco de liberação.
MrBliz
Ramificações antigas serão excluídas no TFS ou ocultadas com mais precisão.
MrBliz