Como você lida com a integração de código de várias filiais / desenvolvedores em cada sprint?

42

Acabei de receber uma ligação retro, onde os desenvolvedores expressaram preocupação com a integração de suas histórias no ramo principal a cada sprint. Todos os desenvolvedores codificam dentro de sua própria ramificação e, no final do sprint, todos se fundem em uma ramificação principal.

Em seguida, um desenvolvedor (geralmente o mesmo) fica com a tarefa de garantir que tudo se integre bem ao código de outros desenvolvedores (a maioria das alterações está na mesma página. Por exemplo, uma história de exibição de dados, história de filtragem de dados e um indicador de SLA).

Como podemos reduzir esse fardo e facilitar a mesclagem de nosso código? Na minha perspectiva, fazer com que o PO ou SM priorize as histórias de maneira mais eficiente, para que não tenhamos esse tipo de dependência no mesmo sprint, pode resolver alguns dos problemas. Como todo mundo lida com isso? Ou isso é apenas parte do processo?

Cortador de biscoito
fonte
18
Você não tem um ramo de desenvolvimento onde a integração contínua é feita?
Kayaman
13
Estou com a Kayaman aqui, a melhor prática para isso é implementar a integração contínua.
RandomUs1r
27
Feliz dia da fusão! Sempre que seu problema é muito semelhante a algo no The Daily WTF, você sabe que está com problemas.
user3067860
Mesclar cedo, mesclar frequentemente: {escreva o menor código de teste que falhará (vermelho), escreva o menor código de produção que passará (verde), refatorar, retestar, mesclar} enquanto não terminar.
CTRL-ALT-DELOR
11
Primeiro check-in vence! Nunca seja o último! :-)
ChuckCottrill

Respostas:

88

Se você estiver usando o Git, cada desenvolvedor puxará da developramificação para sua própria ramificação de recursos, para garantir que eles não fiquem muito longe da linha de base atual. Eles podem fazer isso diariamente, para que as tarefas que levam mais de alguns dias permaneçam em sincronia e os problemas de mesclagem sejam resolvidos enquanto ainda são pequenos.

Quando o desenvolvedor termina seu trabalho, ele cria uma solicitação de recebimento . Quando aprovado, isso é mesclado na developramificação.

A developramificação deve sempre ter código de trabalho e estar pronta para liberação a qualquer momento. Quando você realmente faz um lançamento, mescla develop-o mastere marca-o.

Se você tiver um bom Continuous Integration Server, ele criará cada filial quando as alterações forem registradas, principalmente para solicitações pull. Alguns servidores de compilação se integram ao seu servidor Git para aprovar ou reprovar automaticamente uma solicitação de recebimento se a compilação falhar ou se os testes automatizados falharem. Essa é outra maneira de encontrar possíveis erros de integração.

Berin Loritsch
fonte
73
A parte importante (que está implícita apenas na sua resposta) é que as ramificações devem ser mescladas assim que estiverem prontas, geralmente com apenas 1 a 5 confirmações e não apenas no final do sprint. Uma ramificação por recurso / matéria, não uma ramificação por desenvolvedor. Isso requer que as histórias sejam realmente minúsculas, ou seja, demorem no máximo dois dias.
amon
@ amon, concordou. Adicionadas as palavras "ramo de recursos", mas tentando manter essa resposta bastante pequena. Há muitos bons artigos que aprofundam esse processo.
Berin Loritsch 18/06/19
5
Não fique isolado em seu próprio ramo. É assim que o inferno da mesclagem começa. Use o desenvolvimento da linha principal, isole o trabalho em andamento atrás das alternâncias de recursos ou outra configuração em tempo de execução.
Rob Crawford
3
@Zibbobz Minha equipe usa "Ramos de Recursos" explícitos para aqueles que são basicamente tratados como o ramo de desenvolvimento, mas apenas para solicitações de recebimento e confirmações relacionadas a essa alteração. Geralmente, dependendo de quanto tempo ele precisa permanecer separado, todos os dias alguém mescla as alterações para que se desenvolvam no recurso e resolva quaisquer problemas. Dessa forma, os galhos são os mais semelhantes possíveis quando chega a hora de mesclar. Como uma nota, este é apenas para realmente grandes alterações significativas
reffu
9
"isolar o trabalho em andamento por trás das alternâncias de recursos ou outras configurações em tempo de execução" Você acabou de evitar o inferno de mesclar entrando no inferno de configuração. "Merge hell" é apenas um problema para um desenvolvedor de cada vez e é facilmente evitado simplesmente sincronizando-se regularmente, ter toneladas de configuração efêmera é um inferno para todos os desenvolvedores futuros para sempre.
Cubic
23

Eu trabalhei em uma equipe onde lutamos com o mesmo problema. Descobrimos que quanto menos tempo tínhamos antes de integrar, menos difícil se tornava. Eu sei que muitas pessoas que ensinam integração contínua falam sobre cometer a cada poucos minutos - provavelmente, na verdade, cometemos a cada hora mais ou menos.

Também descobrimos que apenas construir não era suficiente. Precisávamos de um bom nível de cobertura de teste para garantir que não quebrássemos acidentalmente o código um do outro.

Daniel
fonte
2
Esta é a minha experiência também. Realmente não importa com que frequência você confirma, mas uma vez confirmada rapidamente, a integração / mesclagem da confirmação economiza muito esforço. Certa vez, participei de um projeto em que tínhamos três ramos de desenvolvimento divergentes, cada um com meses de trabalho. Mesclá-los não era divertido. Eu aprendi muito com esse erro :)
amon
4
Sim - é isso que significa "integração contínua"! Você está continuamente integrando suas alterações às alterações dos outros desenvolvedores!
Rob Crawford
@ Rob, concordou. Minha afirmação não pretendia sugerir que a integração contínua não fosse, bem, contínua. Só que não fizemos o ideal e ainda vimos muitos benefícios em nos aproximarmos dele.
Daniel
12
  • Mantenha seus galhos de curta duração (parece que você já está fazendo isso).
  • Deixe os resultados dos seus testes falarem por si mesmos.
  • Não espere o final do sprint.

Você nem precisa se inscrever no TDD para este. Tudo que você precisa são de alguns testes que provam que os recursos de seus desenvolvedores estão funcionando corretamente. Isso pode incluir testes de unidade e testes de integração, mas, idealmente, serão dois testes automatizados de ponta a ponta dos recursos críticos. Material do pacote de regressão padrão.

Depois que a mesclagem for concluída, você poderá verificar o relatório de teste de automação juntos e verificar se tudo foi integrado com êxito.

Concordo com uma das outras respostas em que o autor declarou que os Git PRs resolveriam esse problema, fazendo com que cada desenvolvedor mesclasse seu próprio trabalho.

Outro ponto que considero importante o suficiente para deixar até o último parágrafo. Sugiro que você execute testes manuais em suas compilações noturnas, em vez de esperar até o final do sprint. Os desenvolvedores devem se unir assim que o recurso estiver completo, para que ele possa ser integrado, implantado e testado o mais rápido possível.

Liath
fonte
6

Não

Dependendo do seu idioma e dos arquivos que você está editando, pode não fazer sentido para cada desenvolvedor editá-los em suas próprias ramificações. Por exemplo, em C #, achei melhor apenas uma pessoa editar os arquivos de designer de interface do usuário de cada vez. Esses arquivos são gerados automaticamente e, portanto, o código às vezes é movido sem motivo aparente - e isso causa estragos na maioria das ferramentas de mesclagem.

Isso significa que algumas histórias podem bloquear outras até que o trabalho da interface do usuário seja concluído. E / ou, uma nova história é criada apenas para o layout da interface do usuário, com as outras histórias implementando a funcionalidade. Ou talvez um desenvolvedor faça toda a interface do usuário, enquanto outros implementam a funcionalidade dessa interface.

Em uma nota relacionada, se você souber que várias histórias tocarão no mesmo arquivo, evite trabalhar nelas ao mesmo tempo. Não coloque todos no mesmo sprint ou não comece a trabalhar até que um ou mais estejam concluídos.

mmathis
fonte
Honestamente, a ferramenta de controle de versão em uso é mais crítica para a ramificação e fusão bem-sucedidas. Mesmo com o código C # e o presumivelmente código WinForms ou WebForms com o qual você deve trabalhar, normalmente não muda muito . Se estiverem, talvez você precise fazer alguns modelos antes de brincar com o código. UIs baseados XAML são tão estáveis como código regular e código intermediário não é verificada.
Berin Loritsch
2
O código de designer do @BerinLoritsch WinForms pode realmente mudar muito, mesmo com pequenas alterações visuais. Descobri que as próprias linhas de código são as mesmas, mas a ordem é muito diferente - especialmente quando vários desenvolvedores estão fazendo edições ao mesmo tempo. Talvez seja um problema da ferramenta VCS (usamos várias, talvez apenas as que estão erradas), mas para nós é muito mais simples alterar um pouco o processo.
mmathis
2
@BerinLoritsch Eu tenho que colocar aqui em segundo lugar pelo menos para ganhar formulários (nunca usei formulários da web). O designer da interface do usuário do winforms adora reordenar aleatoriamente todo o código no arquivo do designer em resposta a uma alteração trivial em algum lugar do formulário. A menos que você desfaça manualmente os novos pedidos antes de cada confirmação (algo que pode ser facilmente de 10 ou 15 minutos em um formulário complexo), o histórico do arquivo de designer é absolutamente inútil, e se duas pessoas estiverem trabalhando na interface do usuário de um formulário ao mesmo tempo, isso resultará em um conflito de fusão do inferno. O bloqueio geralmente é uma opção terrível, mas as formas de win são realmente as menos más.
Dan Neely
@ DanNeely, essa é apenas uma das razões pelas quais nossa equipe migrou do código WinForms. Outro motivo é que o designer é terrivelmente frágil e algumas de nossas formas complexas não podiam ser editadas visualmente de qualquer maneira. Acabamos tendo que fazer mudanças diretamente no código por trás - provavelmente por que não me lembro de muita agitação por lá. Isso e nossos usuários trabalhando com telas de alta densidade realmente nos levaram ao WPF. Um processo doloroso com uma alta curva de aprendizado, mas uma boa recompensa no final. A maioria das histórias na lista de pendências era para diferentes partes do aplicativo.
Berin Loritsch 18/06/19
@BerinLoritsch mesmo aqui. Os formulários de vitória pagaram grande parte das minhas contas durante a maior parte de uma década no meu emprego anterior, mas ficarei feliz em nunca mais tocá-lo novamente no futuro.
Dan Neely
2

Outra abordagem possível para evitar fusões tardias e grandes são os sinalizadores de recursos : você protege suas alterações com um sinalizador configurável (idealmente dinamicamente) que impede que elas se tornem ativas antes do planejado.

Isso permite que você mescle suas alterações antecipadamente de volta ao masterramo de desenvolvimento conjunto ou a ele sem interromper nada. Outros desenvolvedores podem mesclar essas alterações novamente em suas ramificações de recursos (ou refazê-las de acordo).

Como as outras respostas já apontaram, isso deve ser combinado com uma solução de integração contínua.

Os sinalizadores de recursos têm benefícios adicionais (por exemplo, facilitam a realização de testes A / B). Veja este artigo de Martin Fowler para obter mais informações.

Florian Brucker
fonte
0

Estamos seguindo uma abordagem de ramificação de desenvolvimento separada para cada recurso e, em seguida, estamos mesclando as ramificações em uma ramificação de controle de qualidade para teste no ambiente de teste de integração.

Depois que os testes de regressão e integração são concluídos, movemos facilmente os recursos que estão prontos para serem usados, para o ramo de lançamento.

Se tudo correr bem, mesclamos o branch de liberação novamente para o branch master.

emarshah
fonte
0

Simplificando, confirmar e mesclar muitas vezes reduz a janela de oportunidade para conflitos de mesclagem e reduz bastante os conflitos. A outra parte é realmente planejar pelo lead, o que pode garantir ainda mais que o trabalho flua sem problemas.

As outras respostas oferecem uma excelente visão sobre as práticas recomendadas para confirmações e, seguindo essas, você provavelmente reduzirá a grande maioria dos seus problemas de mesclagem. Mais combinações são quase certamente uma necessidade, mas para uma equipe menor, sua abordagem de ramo por pessoa provavelmente funciona bem o suficiente. Claro, não dói (muito) entrar em práticas mais extensíveis!

No entanto, ninguém parece ter abordado uma das perguntas mais importantes - o que fazer quando todos estão tocando nas mesmas áreas de código. É aqui que é útil ter um líder que esteja familiarizado com a base de código e possa reconhecer dependências de diferentes tarefas. Se eles não organizarem o tempo do trabalho e as confirmações, você provavelmente acabará com conflitos de mesclagem e resolução linha por linha. Organizar as tarefas \ cronometrar é muito mais difícil com uma equipe maior, mas com uma equipe pequena é possível identificar essas tarefas conflitantes. O líder poderia até mudar todas as tarefas relacionadas para o mesmo engenheiro, para evitar o conflito por completo.

Marte
fonte