Desenvolvimento baseado em tronco

Saiba por que essa prática de gerenciamento de controle de versão é prática comum entre as equipes de DevOps.

Kev Zettler Kev Zettler

Resumo: O desenvolvimento baseado em tronco é uma prática de gerenciamento de controle de versão na qual os desenvolvedores fazem o merge de atualizações pequenas e frequentes em um “tronco” ou ramificação principais. Devido à simplificação das fases de merge e integração, é uma prática que ajuda a alcançar a CI/CD, acelera a entrega de software e aumenta o desempenho organizacional.

Nos primeiros dias do desenvolvimento de software, os programadores não tinham o luxo dos modernos sistemas de controle de versão. Em vez disso, eles desenvolveram duas versões de seu software ao mesmo tempo como um meio de rastrear e reverter mudanças, se necessário. Com o tempo, esse processo provou ser trabalhoso, caro e ineficiente.

À medida que os sistemas de controle de versão amadureceram, vários estilos de desenvolvimento surgiram, permitindo que os programadores encontrem bugs com mais facilidade, codifiquem em paralelo com seus colegas e aceleram a cadência de lançamento. Hoje, a maioria dos programadores aproveita um dos dois modelos de desenvolvimento para disponibilizar software de qualidade — Gitflow e desenvolvimento baseado no central.

O Gitflow, que foi popularizado primeiro, é um modelo de desenvolvimento mais rigoroso, onde apenas certos indivíduos podem aprovar alterações no código principal. Essa restrição mantém a qualidade do código e minimiza o número de bugs. O desenvolvimento baseado em tronco é um modelo mais aberto, já que todos os desenvolvedores têm acesso ao código principal. Assim, as equipes podem iterar rápido e implementar CI/CD.

O que é desenvolvimento baseado em tronco?

O desenvolvimento baseado em tronco é uma prática de gerenciamento de controle de versão em que os desenvolvedores fazem o merge de atualizações pequenas e frequentes em um "tronco" ou ramificação principais. É uma prática comum entre as equipes de DevOps e faz parte do ciclo de vida de DevOps porque simplifica as fases de merge e integração. Na verdade, o desenvolvimento baseado em tronco é prática obrigatória de CI/CD. Os desenvolvedores podem criar ramificações de curta duração com alguns pequenos commits se comparadas a outras estratégias de ramificação de recursos de longa duração. À medida em que crescem a complexidade da base de código e o tamanho da equipe, o desenvolvimento baseado em tronco ajuda a manter o fluxo de versões de produção.

Gitflow vs. desenvolvimento baseado em tronco

O Gitflow é um modelo alternativo de ramificação do Git que usa ramificações de recursos de longa duração e várias ramificações primárias. O Gitflow tem mais ramificações de vida longa e commits maiores do que o desenvolvimento baseado em tronco. Sob este modelo, os desenvolvedores criam uma ramificação de recurso e retardam o merge com a ramificação de tronco principal até que o recurso esteja completo. Essas ramificações de recursos de longa duração exigem mais colaboração para fazer o merge pois eles têm um risco maior de se desviarem da ramificação do tronco e introduzir atualizações conflitantes.

O Gitflow também tem linhas de ramificação primárias separadas para desenvolvimento, hotfixes, recursos e versões. Existem diferentes estratégias para fazer o merge de commits entre essas ramificações. Como há mais ramificações para fazer malabarismos e gerenciar, muitas vezes há mais complexidade que requer sessões de planejamento adicionais e revisão da equipe.

O desenvolvimento baseado em tronco é muito mais simplificado, já que seu foco é a ramificação principal como a fonte de correções e lançamentos. No desenvolvimento baseado em tronco, a ramificação principal é adotada como uma ramificação sempre estável, sem problemas e pronta para implementação.

Benefícios do desenvolvimento baseado em tronco

O desenvolvimento baseado em troncos é uma prática necessária para a integração contínua. Se os processos de build e teste forem automatizados, mas os desenvolvedores trabalharem em ramificações de recursos isoladas e longas que são raramente integradas em uma ramificação compartilhada, a integração contínua não vai estar à altura do seu potencial.

O desenvolvimento baseado em troncos facilita o atrito da integração de código. Quando os desenvolvedores terminam um novo trabalho, eles devem fazer o merge o novo código na ramificação principal. No entanto, eles não devem fazer o merge de mudanças no tronco até que eles tenham verificado que eles podem construir com sucesso. Durante essa fase, podem surgir conflitos se as modificações tiverem sido feitas desde o início do novo trabalho. Em particular, esses conflitos são cada vez mais complexos à medida que as equipes de desenvolvimento crescem e a base de código dimensiona. É o caso de quando os desenvolvedores criam ramificações separadas que se desviam da ramificação de origem e outros desenvolvedores estão em simultâneo fazendo o merge do código sobreposto. Por sorte, o modelo de desenvolvimento baseado em tronco reduz esses conflitos.

Permite a integração contínua de código

O modelo de desenvolvimento baseado em tronco conta com a presença de um repositório com um fluxo constante de commits escoando para a ramificação principal. A adição de um pacote de teste automatizado e o monitoramento da forma de verificação do código para esse fluxo de commits permite a integração contínua. Quando o novo código passa por merge para o tronco, testes automatizados de integração e de forma de verificação do código são executados para validação da qualidade do código.

Garante a revisão contínua do código

Os commits rápidos e pequenos de desenvolvimento baseado em tronco fazem da revisão do código um processo mais eficiente. Com ramificações pequenas, os desenvolvedores podem ver e rever pequenas alterações com rapidez. Essa situação é muito mais fácil em comparação com uma ramificação de recursos de longa duração em que um revisor lê páginas de código ou faz a inspeção manual de uma grande área de superfície de alterações de código.

Permite versões consecutivas de código de produção

As equipes devem fazer merges frequentes e diários para a ramificação principal. O desenvolvimento baseado em tronco busca manter “verde” a ramificação do tronco, o que significa que ela está pronta para implementação em qualquer commit. Testes automatizados, convergência de código e revisões de código oferecem a um projeto de desenvolvimento baseado em tronco garantias de que ele está pronto para ser implementado na produção a qualquer momento. Assim a equipe ganha agilidade para implementações frequentes na produção e para definir mais metas de versões de produção diárias.

Desenvolvimento baseado em troncos e CI/CD

À medida que o CI/CD cresceu em popularidade, os modelos de ramificação foram refinados e otimizados, levando ao aumento do desenvolvimento baseado em tronco. Agora, o desenvolvimento baseado em tronco é um requisito de integração contínua. Com a integração contínua, os desenvolvedores realizam o desenvolvimento baseado no central em conjunto com testes automatizados que são executados após cada commit para um tronco. Assim é garantido que o projeto funcione em todos os momentos.

Práticas recomendadas de desenvolvimento baseadas em troncos

O desenvolvimento baseado em troncos garante os lançamentos de código das equipes sejam mais rápidos e consistentes. Veja a seguir uma lista de exercícios e práticas que vão ajudar a refinar a cadência da sua equipe e desenvolver um cronograma otimizado de versão.

Desenvolver em pequenos lotes

O desenvolvimento baseado em tronco segue um ritmo rápido para entregar código à produção. Se o desenvolvimento baseado em tronco fosse como música, seria um staccato rápido — notas curtas e sucintas em rápida sucessão, com os commits de repositório sendo as notas. Manter commits e ramificações pequenas permite um ritmo mais rápido de merges e implementações.

Pequenas mudanças de um par de commits ou modificação de algumas linhas de código minimizam a sobrecarga cognitiva. É muito mais fácil para as equipes terem conversas significativas e tomar decisões rápidas ao revisar uma área limitada de código versus um conjunto extenso de alterações.

Marcação de recurso

Marcações de recurso complementam bem o desenvolvimento baseado em tronco, permitindo que os desenvolvedores coloquem novas alterações em um caminho de código inativo para ativar mais tarde. Essa ação permite que os desenvolvedores abram mão da criação de uma ramificação de recurso de repositório separada e, no lugar, façam o commit de um novo código de recurso direto na ramificação principal dentro de um caminho de marcação de recurso.

As marcações de recursos são um incentivo direto para pequenas atualizações em lotes. Em vez de criar uma ramificação de recurso e esperar para construir a especificação completa, os desenvolvedores podem, em vez disso, criar um commit de tronco que introduza a marcação de recurso e envie novos commits de tronco que constroem a especificação de recurso dentro da marcação.

Implementar testes automáticos abrangentes

Testes automatizados são necessários para qualquer projeto de software moderno que pretenda alcançar CI/CD. Existem vários tipos de testes automatizados que são executados em diferentes estágios do pipeline de versão. Testes de unidade de execução curta e integração são executados durante o desenvolvimento e após o merge de código. Testes completos de execução, pilha completa e de ponta a ponta são executados em fases posteriores do pipeline em um ambiente completo de staging ou produção.

Testes automatizados ajudam o desenvolvimento baseado no central, mantendo um pequeno ritmo de lote à medida que os desenvolvedores fazem o merge de novos commits. O conjunto de testes automatizado analisa o código para quaisquer problemas e faz a aprovação ou negação automáticas. Assim os desenvolvedores podem criar commits com rapidez e executar esses commits por meio de testes automatizados para ver se elas introduzem novos problemas.

Realizar revisões de código assíncronas

No desenvolvimento baseado no central, a revisão de código deve ser realizada imediatamente e não ser colocada em um sistema assíncrono para revisão posterior. Testes automatizados oferecem uma camada de revisão de código preventivo. Quando os desenvolvedores estão prontos para revisar a solicitação pull de um membro da equipe, eles podem primeiro verificar se os testes automatizados passaram e a forma de verificação do código aumentou. Assim o revisor tem garantia imediata de que o novo código atende a certas especificações. O revisor pode então se concentrar em otimizações.

Ter três ou menos ramificações ativas no repositório de código do aplicativo

Uma vez que uma ramificação passa por merge, a exclusão dela é prática recomendada. Um repositório com uma grande quantidade de ramificações ativas tem alguns efeitos colaterais infelizes. Embora possa ser benéfico para as equipes verem que trabalho está em andamento examinando ramificações ativas, esse benefício é perdido se houver ramificações obsoletas e inativos ainda por perto. Alguns desenvolvedores usam interfaces de usuário do Git que podem se tornar incontornáveis para trabalhar ao carregar um grande número de ramificações remotas.

Fazer o merge de ramificações no tronco pelo menos uma vez por dia

As equipes de desenvolvimento baseadas em tronco de alto desempenho devem fechar e fazer o merge de qualquer ramificação aberta e pronta para merge, no mínimo todos os dias. Esse exercício ajuda a manter o ritmo e define uma cadência para o controle de versões. No fim do dia, a equipe pode marcar o tronco principal como um commit de versão, que tem o efeito colateral útil de gerar um incremento ágil e diário de versão.

Número reduzido de congelamentos de código e fases de integração

As equipes agilidade de CI/CD não precisam de congelamentos ou pausas planejadas de código para fases de integração, embora uma organização possa precisar delas por outros motivos. O “contínuo” em CI/CD implica que as atualizações estão constantemente fluindo. As equipes de desenvolvimento baseadas em troncos devem tentar evitar o bloqueio de congelamentos de código e planejar de acordo para garantir que o pipeline de versão não esteja parado.

Crie rápido e execute na hora

Para manter uma cadência de lançamentos rápidos, os tempos de execução de compilação e teste devem ser otimizados. As ferramentas de build de CI/CD devem usar camadas de cache quando apropriado para evitar cálculos caros para estáticos. Os testes devem ser otimizados para usar stubs apropriados para serviços de terceiros.

Conclusão...

O desenvolvimento baseado em tronco é hoje em dia o padrão para equipes de engenharia de alto desempenho, pois define e mantém uma cadência de lançamento de software usando uma estratégia simplificada de ramificação do Git. Além disso, o desenvolvimento baseado no central oferece às equipes de engenharia mais flexibilidade e controle sobre como entregam software para o usuário final.