Na minha empresa, todo o nosso desenvolvimento (correções de bugs e novos recursos) é realizado em filiais separadas. Quando está completo, enviamos para o controle de qualidade que o testa nesse ramo e, quando eles nos dão luz verde, o mesclamos em nosso ramo principal. Isso pode levar entre um dia e um ano.
Se tentarmos compactar qualquer refatoração em uma ramificação, não sabemos por quanto tempo ela ficará "fora", para que possa causar muitos conflitos quando ela for incorporada novamente.
Por exemplo, digamos que eu queira renomear uma função porque o recurso no qual estou trabalhando está fazendo muito uso dessa função e descobri que seu nome não se encaixa realmente em seu objetivo (novamente, este é apenas um exemplo). Então, procuro todos os usos dessa função e os renomeio para seu novo nome, e tudo funciona perfeitamente, então a envio para o controle de qualidade.
Enquanto isso, novos desenvolvimentos estão acontecendo, e minha função renomeada não existe em nenhum dos ramos que estão sendo extraídos do main. Quando meu problema for mesclado novamente, todos eles serão resolvidos.
Existe alguma maneira de lidar com isso?
Não é como se a gerência aprovasse uma questão apenas para refatorar, portanto ela precisa ser incluída em outros trabalhos. Ele não pode ser desenvolvido diretamente no main, porque todas as alterações precisam passar pelo controle de qualidade e ninguém quer ser o idiota que quebrou o main, para que ele possa fazer um pouco de refatoração não essencial.
Respostas:
Existem vários problemas que estão se misturando para tornar a refatoração um desafio neste ambiente. Misturados a isso estão alguns problemas não técnicos ("mas isso é um problema de gerenciamento e uma batalha que ainda não venci").
O primeiro problema é o ramo de longa duração. Essas ramificações têm dificuldade em rastrear alterações fora da visualização do desenvolvedor. Para endereçar isto:
Outra questão que está se misturando a isso é que eu aludi aos pontos acima é a mudança do papel do ramo ao longo do tempo. Começa como um ramo de desenvolvimento em que os desenvolvedores se comprometem e se torna uma área de teste (que teste está sendo feito aqui que pode ser significativo em todo o aplicativo?), Que é então mesclado em estável (e presumivelmente liberado - é isso? testado novamente?).
Com um recurso mais curto, do início ao fim, é mais fácil que a refatoração possa ser captada por outras ramificações.
Incentive os desenvolvedores a obter todo o ambiente. Apenas mudanças na escolha da cereja podem levar a ... digamos, ambientes interessantes para desenvolvedores. Embora a escolha da cereja tenha seus usos, pode ser preocupante que esse seja o modo padrão de puxar alterações para um ramo.
A refatoração é algo que idealmente é feito constantemente, ou se não constantemente, sempre que houver um mínimo de tempo de inatividade. Ramifique, faça uma refatoração simples, execute os testes de unidade para verificar se tudo ainda está funcionando (sua unidade foi testada, certo? Certo? ) E depois volte ao estábulo. Passe as informações para outros desenvolvedores para extrair as alterações que você refatorou em suas próprias ramificações.
É importante que os desenvolvedores possuam a qualidade do código. Enquanto a direção dos recursos vem de fora e as alocações de tempo geralmente não são as nossas, a qualidade do código é algo que é necessário nos orgulhar e dedicar tempo.
Você pode encontrar as seguintes perguntas úteis na busca de alocação de tempo para lidar com dívidas técnicas:
Você também pode procurar ferramentas como o sonar, que podem ajudar a identificar as áreas do código que precisam de mais trabalho para refatoração. O plugin de dívida técnica - é algo que pode ser usado para ajudar a apontar o acúmulo de dívida ao longo do tempo na base de código.
Frequentemente, é necessário salientar que o ROI para lidar com dívidas técnicas é um tempo de resposta mais rápido para recursos e correções de bugs da equipe de desenvolvimento.
fonte
Normalmente, estou desenvolvendo uma versão refatorada em "paralelo" com a corrente, ou seja, na mesma base de código, mas não referenciando-a do aplicativo principal. E quando uma nova solução é feita e testada, estou iniciando a refatoração real.
Exemplo 1. Suponha que eu tenha uma coisa, seja ela função, interface, módulo ou qualquer outra coisa. E eu quero refatorar. Estou criando o Thing2 na mesma base de código, é uma versão refatorada do Thing. Quando estiver pronto e testado, refatoro tudo o que faz referência a Thing, para substituí-lo por Thing2. Geralmente, essa etapa leva uma quantidade relativamente pequena de tempo.
Se a refatoração real levar muito tempo para se manter sincronizada sem estragar a equipe, eu pegarei todos os recursos relevantes e os refatorarei em paralelo também.
Exemplo 2. Eu tenho um novo backend de renderização, que é uma versão refatorada do antigo. Mas não é compatível com o frontend de renderização antigo. Portanto, preciso refatorar o frontend. E novamente: na mesma base de código. Quando tudo estiver pronto, estou apenas mudando a classe da instância de front-end; idealmente, será necessário um pequeno commit.
Sim, recursivamente, pode-se concluir que tudo deve ser feito em paralelo. Mas isso geralmente acontece quando há muito acoplamento na base de código ou está mudando muito rápido.
Finalmente, quando o novo código é integrado e funciona bem, os recursos antigos podem ser removidos da base de código e os novos recursos podem ser renomeados para obter nomes antigos.
Geralmente, a idéia é preparar novos recursos em paralelo e passar a usá-los em um pequeno passo.
John Carmack usa essa abordagem (ou pelo menos semelhante), talvez seu blog explique melhor: (link)
fonte
Pode parecer uma dificuldade no lado técnico quando, na verdade, está no lado dos requisitos.
Onde o desenvolvimento é orientado para diferentes requisitos em diferentes ramos é a verdadeira dificuldade. Os gerentes e arquitetos da equipe devem tomar decisões que possam permitir a coexistência das diferentes necessidades comerciais.
O processo ZBB e o Co-Dev "comprometem-se" quando são tomados após a tomada de decisões corretas, com entradas relevantes de todos os desenvolvedores, e devem permitir que você implemente o que você precisa sem ter que pensar - Como vou mesclar meu código.
ZBB significa orçamento baseado em zero . Ao dizer Co-Dev, eu quis dizer poucas pessoas que estão trabalhando em programação paralela.
fonte
O problema me parece que você está trabalhando demais nas filiais. O custo dos conflitos cresce exponencialmente com o comprimento que todos ficam em uma filial, portanto, com conflitos muito longos, você tem poucas chances de fazer qualquer refatoração.
fonte
Seu problema é o modelo de filial que você está usando. Você pode desenvolver uma ramificação e, quando estiver pronta e pronta para o controle de qualidade, a ramificação será mesclada a um 'tronco intermediário', às vezes chamado de Integração ou Teste. Ao desenvolver o próximo recurso, você pode ramificar desse tronco intermediário.
Esse modelo permite desenvolver vários recursos em paralelo em diferentes ramificações, mesclando-os todos na ramificação de integração para enviar ao controle de qualidade e também manter um único tronco de liberações (você mescla o controle de qualidade da base de código recebido ao tronco principal quando eles o certificam )
Você está assumindo que suas alterações entregues ao controle de qualidade serão aprovadas sem grandes modificações - se o código de controle de qualidade voltar com instruções para remover metade das alterações, será necessário reverter, mas se isso não acontecer, fará seu desenvolvimento muito mais suave. Então, você basicamente retira ramificações de novos recursos do que será o código da linha principal (por exemplo, tronco após a fusão do código passado para o controle de qualidade), em vez do que é hoje (por exemplo, tronco atual) e, portanto, não estará mais desenvolvendo a base de código da versão anterior .
fonte