Scrum e desenvolvimento estável criam uma contradição?


11

Faço parte de um grupo de desenvolvimento com 5 equipes, totalizando cerca de 40 desenvolvedores. Estamos seguindo a metodologia Scrum, com sprints de 3 semanas. Temos uma configuração de integração contínua (Jenkins), com um pipeline de construção que leva várias horas (devido a extensos testes automatizados). Basicamente, o processo de desenvolvimento funciona bem.

No entanto, observamos que, depois de alguns dias em um novo sprint, nossa compilação geralmente fica instável e permanece instável até o final do sprint "parar de confirmar". O efeito adverso disso é que as etapas de compilação estão muito abaixo do pipeline, especialmente os testes de interface do usuário / Web não são executados por vários dias (porque são acionados apenas em uma compilação 'verde'). Consequentemente, os erros recém-introduzidos geralmente são detectados apenas muito tarde no sprint.

  • Cada confirmação é verificada em relação a um conjunto básico de testes. Uma vez verificada, a alteração é enviada para mestre após uma revisão de código (Gerrit)
  • Os testes básicos de unidade são executados a cada 30 minutos, duração inferior a 10 minutos
  • Os testes de integração são executados a cada 2h, duração 1h
  • Os testes de interface do usuário / Web são executados em testes de integração bem-sucedidos, com duração de várias horas

Dependendo de quem é responsável pela estabilidade da compilação durante o sprint (essa responsabilidade é repassada por cada sprint), pode haver "paradas de confirmação" ad-hoc intermediárias para que a compilação volte a ficar estável.

Então, nós queremos:

  1. Nossas equipes de desenvolvimento desenvolvem e cometem alterações durante um sprint sem obstáculos
  2. Nosso processo de construção é abandonado se uma etapa da construção falhar, pois os resultados subsequentes da construção têm pouco significado
  3. Nosso processo de criação para fornecer aos desenvolvedores um feedback de qualidade em tempo hábil

Dado (2), os pontos (1) e (3) parecem contradizer-se. Alguém tem uma boa prática de como lidar com isso?

( No momento, estamos perdendo o ponto (2) e permitindo a continuação da compilação, mesmo em etapas com falha na compilação. Ainda não tenho nenhum comentário sobre como isso influencia nossa qualidade )

Obrigado Simon


3
Eu diria que, se uma compilação está sendo executada several hours, esse é o verdadeiro problema. significa que a solução combinada é muito grande e muito ampla. Você deve procurar componenteizar a solução e, em seguida, ter pequenos blocos de código como pacotes (disponíveis de uma maneira ou de outra nos principais idiomas de todas as plataformas). Portanto, quaisquer alterações serão inseridas apenas nos componentes e serão detectadas muito mais rapidamente. A compilação completa basicamente unirá os componentes já combinados e também será mais rápida. Você só executaria possivelmente alguns testes para garantir que os componentes certos fossem resolvidos.
zaitsman

O seu ambiente de construção é no local ou na nuvem?
Lauri Laanti

@LauriLaanti, nosso ambiente de construção é no local, uma instância de Jenkins com três escravos.
Simon

Respostas:


7

Alguns princípios básicos primeiro: - As principais alterações devem sempre estar em uma ramificação do recurso no seu VCS - As ramificações do recurso devem passar em todos os testes antes de mesclar no tronco. Adicionado - Confirmações sempre devem ser construídas - Uma compilação interrompida requer ação imediata do responsável pela comunicação e / ou do restante da equipe. - Um teste com falha só deve abortar os testes restantes se for um teste crítico .

Se você, como uma equipe, seguir essas práticas e aplicá-las, por exemplo: "nome e vergonha" quando a compilação for interrompida, você deve seguir em frente, pois quaisquer confirmações que possam interromper a compilação estarão em um ramo de recurso. Outras confirmações que quebram a compilação terão que ser tratadas imediatamente e você obterá os resultados dos testes posteriores.

Você também pode adicionar um teste automático da última compilação "bem-sucedida" (não necessariamente a que passa nos testes de integração), para os testes de interface do usuário / Web como uma execução noturna, relatando a primeira coisa da manhã.


3
Uma boa prática a ser adicionada aqui é que as ramificações de recursos devem passar em todos os testes antes de serem mescladas à linha principal
Bart van Ingen Schenau 11/17/17

@BartvanIngenSchenau - bom ponto adicionado!
22617 Steve Barnes

@SteveBarnes, obrigado pela contribuição. Um commit no Gerrit está sempre em uma ramificação e só é mesclado com sucesso (meu primeiro ponto no processo de criação). É depois disso que o problema começa. Com 30 desenvolvedores comprometendo alterações várias vezes por dia, precisamos nos unir mais cedo e depois verificar. Não é uma ação imediata após uma compilação quebrado, mas como o tempo entre cometer e feedback de construção é de 2 horas, haverá vários outros commits no mesmo período. Possivelmente quebrando a próxima compilação.
Simon

@ Simon, o objetivo do "nome e vergonha" é fazer com que seus desenvolvedores parem de cometer códigos quebrados! Na maioria dos sistemas, é possível executar uma compilação de teste em um curto espaço de tempo usando ferramentas como ant, make, scons, etc. compilações ainda precisam ser feitas, é claro).
9788 Steve Barnes

8

Não tem nada a ver com Scrum. Sua construção deve ser continuamente estável, independentemente.

Ninguém deve fazer check-in, a menos que tenha realizado uma construção local e executado os testes de unidade localmente (e ambos foram aprovados, é claro). O processo local de criação e teste deve ser sensível a modificações e pode ignorar os testes de código que não foi alterado.

Qualquer pessoa que introduza algo que causa falha na compilação ou falha em um teste de unidade deve ser publicamente envergonhada . Se a construção for interrompida, ela deverá ser corrigida imediatamente.


2
Por um lado, deve-se enfatizar que construir estabilidade é responsabilidade de todos. Por outro lado, eu desaconselharia a vergonha do público, porque (1) os membros da equipe mais experientes têm maior responsabilidade em ajudar os membros juniores a alcançar a estabilidade de construção (por revisão de código, programação em pares ou apenas trabalhando juntos antes de um commit, ou por consertar uma construção quebrada), (2) a vergonha tira a segurança psicológica da equipe .
Rwong 11/03/19

1
Se as pessoas não querem se envergonhar, não devem quebrar a estrutura. Não é que esse seja um padrão irracionalmente alto. Se você tem desenvolvedores que não podem hackear, deixe que eles tenham seu próprio ramo para participar até descobrir como não quebrar o Commons crítico da equipe. (Dito isto, qualquer vergonha real deve ser de bom gosto).
John Wu

Em nosso processo, qualquer confirmação é ramificada (no Gerrit) e precisa passar por um conjunto básico de testes antes de mesclar para o mestre. Esses testes básicos não podem ser executados por uma hora, pois queremos codificar a revisão e mesclar rapidamente. É após a fusão onde começa o problema, consulte o meu comentário a @SteveBarnes
Simon

6

Seu problema parece ser que os testes demoram muito para serem executados. Felizmente, a lei de Moore nos forneceu uma solução para esse problema. Hoje, as CPUs de servidor high-end podem facilmente ter mais de 10 núcleos (e mais de 10 HyperThreads). Pode haver várias dessas CPUs em um único computador.

Se eu tivesse testes que demorassem tanto tempo, resolveria o problema com mais hardware. Eu compraria um servidor high-end e, em seguida, paralelizaria os testes para que eles tirassem vantagem total de todos os núcleos da CPU. Atualmente, se seus testes são de thread único, aproveitar 10 núcleos e 10 HyperThreds provavelmente torna os testes 15 vezes mais rápidos. Obviamente, isso significa que eles também usam 15 vezes a memória, portanto o computador precisa ter RAM suficiente.

Assim, as várias horas se transformarão em 10 a 30 minutos.

Você não disse quanto tempo a compilação leva, mas ferramentas de compilação padrão como make permitem paralelizar também a compilação. Se você paralelizar seus testes de unidade e o computador desenvolvedor típico tiver 4 núcleos e 4 HyperThreads, menos de 10 minutos de testes de unidade se transformarão em menos de 2 minutos. Então, talvez você possa aplicar uma política em que todos devem executar os testes de unidade antes de cometer?

Sobre a falha no teste para interromper outros testes: não faça isso no servidor de construção! Você deseja o máximo de informações possível sobre a falha e outros testes podem revelar algo importante. Obviamente, se a construção falhar, você não poderá executar testes de unidade. Se o desenvolvedor executar testes de unidade em sua própria máquina, convém abortar na primeira falha.

Não vejo nenhuma conexão entre o Scrum e seus problemas. Os problemas podem realmente ocorrer com qualquer processo de desenvolvimento.


Eu concordo, com uma construção mais rápida, as coisas seriam muito mais fáceis. Nosso TechTeam passou dias melhorando a velocidade do nosso processo de construção, caso contrário, estaríamos esperando dias em vez de horas. Por enquanto, essa duração do feedback é fornecida em aprox. 2 horas. Então, eu estou procurando uma abordagem que tome isso como um "dado". (Claro, nós estamos tentando continuamente para acelerar a construir, mas para o futuro próximo, vai ser 2 horas.)
Simon

Alguns testes podem entrar em conflito com a execução paralela
deFreitas 17/03/17

Só é possível jogar mais hardware se os testes forem escritos de uma maneira em que possam ser executados independentemente entre si, sem a introdução de efeitos colaterais. Quanto mais você obtém do hardware, mais difícil fica ... muitos desenvolvedores não o fazem. acertar, então, enquanto eu concordo com você, primeiro me concentro em estruturar os testes da maneira certa.
c_maker

2

Não é possível ter mais instalações do Jenkins e fazer com que os desenvolvedores verifiquem uma instância separada do Jenkins?

Eu acho que a melhor solução aqui é fazer com que o código passe em todos os testes antes de ser verificado no ramo mestre e compilado / testado pela instância principal do Jenkins. Não permita que as pessoas façam check-in do código que quebra a compilação.

Verifico meu código no ramo de desenvolvimento, vejo se ele passa nos testes e crio uma solicitação de recebimento. Mas você poderia obviamente fazer com que Jenkins puxasse um ramo de recursos e teste esse.


1

O ponto (2) parece ser o ponto mais doloroso, por isso vou me concentrar nisso.

Talvez seja hora de dividir o projeto em vários módulos.

https://en.wikipedia.org/wiki/Dependency_inversion_principle

A. Os módulos de alto nível não devem depender dos módulos de baixo nível. Ambos devem depender de abstrações.

B. As abstrações não devem depender de detalhes. Os detalhes devem depender de abstrações.

Se um módulo falhar na construção, a construção para outros módulos poderá continuar, desde que esses outros módulos possam depender de uma interface e o código que compõe essa interface tenha sido construído com êxito.

Isso fornecerá feedback sobre quais outras falhas de compilação podem ocorrer, para que você tenha tempo para corrigir mais de um módulo quebrado antes que a próxima compilação aconteça.

Em geral, os princípios do SOLID são concebidos para lidar com bibliotecas e criar problemas. Em outras palavras - esse conjunto de princípios é concebido para resolver o tipo exato de problemas que você está enfrentando.


Como uma observação lateral (veja a resposta do juhist), você não pode fazer a compilação rodar mais rápido (por paralelismo) se não particionar a compilação em módulos separados.


0

Acho que sua equipe está perdendo um dos principais princípios do scrum: pronto, software funcionando. Um PBI não deve ser marcado como concluído até que seja aprovado na Definição de Concluído que sua equipe estabeleceu. A definição de Concluído é diferente para cada equipe, mas provavelmente incluiria coisas como:

  • O código possui testes de unidade
  • Teste de unidade aprovado como parte de uma construção automatizada
  • O código foi mesclado no main (e os conflitos foram resolvidos)
  • etc.

Então, essencialmente, o que está acontecendo é que sua equipe está marcando coisas que de fato não são feitas. Isso é um problema por si só.

Fora isso, tudo se resume ao gerenciamento de controle de versão adequado. Se você estiver usando o Git, todo o trabalho será feito no repositório local do desenvolvedor e eles não deverão enviar nada para o remoto, a menos que esteja "pronto" e potencialmente liberável. Trabalho incompleto nunca deve ser enviado ao seu repositório principal. Se o desenvolvedor precisar trabalhar em um ramo de recursos de vida útil mais longa e quiser ir para o remoto para garantir que eles não percam o trabalho, eles devem trabalhar com um garfo e, em seguida, você o mesclará no principal quando o O recurso está "pronto" e potencialmente liberável - não antes.

Para TFVC, é um pouco mais complicado porque tudo acontece no "remoto". Isso significa que os desenvolvedores devem, portanto, sempre trabalhar com ramificações, a menos que seja uma solução rápida. As mesmas regras se aplicam aqui como no Git, no entanto: software incompleto não é comprometido. Período. No controle de versão gerenciado corretamente, "main" deve sempre ser liberável. Se um commit foi feito desse modo "principal", você não está fazendo o certo.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.