Ir para o conteúdo principal
Parceiros

Apresentando o Consort: Desenvolvimento orientado por testes em um banco de dados com ramificação

Um framework agentivo de código aberto, desenvolvido pela Databricks Field Engineering, para desenvolvimento orientado a testes em um banco de dados real com ramificação.

por Kevin Hartman

  • O que muda com a ramificação de banco de dados
  • Um fluxo de trabalho de desenvolvimento agêntico com ramificação de banco de dados
  • Como experimentar o Consort você mesmo

Durante 25 anos, criei software com base nas práticas com as quais cresci: o TDD de Kent Beck, a Refatoração de Martin Fowler, o Clean Code de Uncle Bob, a Entrega Contínua de Jez Humble e Dave Farley, e o Design de Banco de Dados Evolucionário de Pramod Sadalage e Scott Ambler.

Com as práticas modernas de desenvolvimento de software, o código pode ser ramificado, os ambientes são conteinerizados e a infraestrutura se torna código. Mas uma parte da stack nunca acompanhou esse ritmo: o banco de dados. Ele continuou lá como um monólito rígido, e aceitamos muitas soluções alternativas por causa disso, como mocks em vez do banco real, um ambiente de staging compartilhado e alterações de esquema executadas como uma cerimônia cuidadosa.

Há algum tempo venho conversando com equipes de desenvolvimento de software sobre o Lakebase Postgres e como ele muda o que costumávamos fazer. Você já deve ter me ouvido dizer: Ramifique seu banco de dados como você ramifica seu código. Mas o que isso significa na prática e como posso aplicar isso?

O que muda com a ramificação de banco de dados

Os testes de integração voltam para o loop interno

Testar em um banco de dados real costumava ser uma preocupação do loop externo. Inicializar um banco de dados, populá-lo com esquema e dados, versionar o esquema e fazer isso por teste unitário era caro demais, então eu não fazia. Ninguém fazia. Em vez disso, escrevíamos testes unitários contra objetos mock, não porque os mocks fossem bons, mas porque um banco de dados real no loop interno estava fora de alcance. E sabemos que os mocks divergem com o tempo; eles perdem o alinhamento com o comportamento real do banco de dados e, quanto mais você os mantém, menos comportamentos reais eles verificam.

A ramificação copy-on-write elimina a razão de existir dos mocks. Você cria uma ramificação isolada do banco de dados real em um tempo praticamente constante, independentemente do tamanho dos dados. O primeiro teste que escrevo, no estilo TDD, roda em uma ramificação ativa de dados reais, não em um fake. Posso executar testes destrutivos, quebrar tudo, bagunçar meu esquema e nunca tocar no que o resto da equipe está usando. É a minha branch. Quando termino, eu a descarto.

Código e esquema são entregues como um só

Como o esquema agora viaja como migrações versionadas (Alembic, Flyway ou Knex, dependendo da stack), uma alteração de esquema e o código do qual ela depende movem-se juntos como uma única unidade. Você faz o merge do esquema (not os dados), e o código se alinha a ele. Dois engenheiros para quem mostrei isso, em equipes diferentes, chegaram à mesma expressão para definir isso: Data CD.

O problema em produção às 2h da manhã é detectado antes de acontecer

Quando algo quebra em produção, geralmente é às 2h da manhã, e você precisa fazer engenharia reversa para descobrir o que mudou. A ramificação inverte esse fluxo. A cada pull request, e novamente no merge, você cria uma ramificação de banco de dados nova a partir do ambiente de destino, executa as migrações e a suíte de testes completa nela, encontrando a regressão ou o conflito antes da implantação. A alteração de esquema está no pull request como uma migração, de modo que seu DBA a revisa lá como proprietário do código, e não como um ticket em uma fila de pendências.

Promover uma alteração de esquema costumava ser uma cerimônia de alto risco. Agora você ramifica o ambiente de produção (prod), aplica a alteração, testa de forma isolada e a promove. Fazer o mesmo em uma configuração padrão do Postgres na nuvem exige uma pilha de scripts de DevOps frágeis e desperdiça um tempo humano precioso.

Nada disso é um recurso de banco de dados que você simplesmente ativa. É uma mudança em quando os testes difíceis acontecem, totalmente deslocados para a esquerda, no loop onde você realmente está escrevendo o código.

Um framework de desenvolvimento agêntico com ramificação de banco de dados

Agora que a infraestrutura para ramificação está disponível, o que faltava na discussão era algo que a colocasse para funcionar em um loop de desenvolvimento real. É por isso que criei o Consort.

O Consort é um framework de desenvolvimento agêntico de código aberto que usa a ramificação do Lakebase como base para sua compilação orientada por testes. Se você conhece o Scrum, a ideia está no nome. Cada papel na equipe (product owner, autor de especificações, revisor de arquitetura, DBA, estrategista de testes e uma dupla de navegador/piloto) torna-se um agente. Eles atuam juntos, liderados por um condutor, e, por fim, atuam como um conjunto (consort).

O trabalho ocorre em duas vias: uma via de design focada primeiro nas especificações, onde a intenção é acordada e congelada, e uma via de compilação que executa o ciclo completo de vermelho/verde/refatoração em uma ramificação ativa do banco de dados real. Alguns componentes fazem com que tudo funcione perfeitamente quando um agente é quem escreve o código.

  • O agente recebe um limite real para testar. Dê algo concreto a um agente e ele resolverá o problema, pois consegue identificar quando o código não funciona. Dê a ele um teste hermético e com mocks, e ele alegremente entregará algo que parece passar, mas que falha no momento em que você o executa em um banco de dados real. Uma ramificação ativa de dados reais é o limite concreto; o agente não pode simplesmente presumir o comportamento de um banco de dados que está realmente lá.
  • O piloto não pode mudar as regras do jogo. O papel que escreve o código não pode alterar um teste para fazê-lo passar. A única exceção é uma substituição genuína, uma história posterior que legitimamente aposente um teste antigo. O status verde significa que o teste foi executado e passou na ramificação real do banco de dados, e não porque o agente disse que passou.
  • O condutor é código, não um agente. O papel que uma equipe chama de scrum master torna-se uma máquina de estados determinística. Ele direciona o trabalho, gerencia as etapas de aprovação humana e redireciona para a função responsável quando há algum conflito, de modo que o processo que conduz o ciclo não possa ser burlado ou perder o controle.
  • Ele não perde o foco da missão. A reclamação que mais ouço sobre outros frameworks é que, após alguns dias, o agente perde o foco da missão, você fica frustrado e reinicia o processo. O Consort mantém os artefatos de cada recurso em uma estrutura de diretórios dedicada, da qual os agentes leem como um contrato entre as funções. É a mesma passagem de bastão que uma equipe real realiza: cada especialista revisa o trabalho, adiciona suas considerações e o passa para o próximo.

Como estratégia de otimização (para que seus agentes não gastem o início de cada turno verificando tudo novamente), o Consort fornece a cada agente um pacote de contexto com escopo definido, os testes exatos a serem aprovados, os requisitos de design e onde esses testes estão localizados, em vez de deixá-lo solto em toda a base de código. O acesso sem escopo definido é o motivo pelo qual os agentes se perdem e passam uma eternidade debatendo-se sobre o código tentando descobrir o que fazer e para onde ir, até esquecerem o que DRY significa.

O arquiteto revisa a especificação antes que qualquer código seja escrito e define as camadas do design que importa para você, incluindo os requisitos de cross-functional, o empilhamento em camadas e padrões como DRY, SRP e SOLID. Esse design inicial é o motivo pelo qual você não acaba com tudo em um único arquivo. E quando você quer explorar, o Consort executa experimentos paralelos para uma história, cada um em sua própria ramificação de banco de dados e worktree, totalmente isolados, para que você possa testar mais de uma abordagem e manter o melhor experimento. Quando mostrei isso a outros engenheiros, eles costumavam reconhecer imediatamente como algo que eles mesmos estavam tentando criar.

Você pode acompanhar tudo isso e direcionar o rumo. Um plugin do VS Code mostra suas ramificações emparelhadas do Git e do Lakebase em todas as camadas, com alterações de código e esquema em uma única visualização de diff. Um painel de observabilidade mostra cada turno ao vivo: cada papel, seu prompt e os artefatos que ele produz para o próximo papel consumir. E, em cada etapa, você mesmo inspeciona o software em funcionamento, executando-o em sua própria ramificação, antes de aprová-lo para a próxima fase.

O que o Consort é (e o que não é)

O Consort é de código aberto e mantido pela comunidade. É um projeto que você pode adotar, executar e recomendar, com seu próprio ciclo de vida. Não é um recurso de plataforma integrado com um SLA.

Você não precisa reestruturar sua stack para usá-lo. O Lakebase é Postgres, então seu aplicativo finalizado roda nele sem a necessidade de um fluxo de trabalho de ramificação; o emparelhamento de ramificações do Git e do Lakebase é algo que você faz durante o desenvolvimento.

Durante 25 anos, o banco de dados foi a única parte da nossa stack que não podia ser ramificada. Agora ele pode. É isso que muda, e é por isso que criei o Consort.

Experimente você mesmo

Você só precisa do Lakebase. Obtenha-o na Edição Gratuita.

O restante da stack é aberto – Java, Python ou Node – e ele roda no Claude e possui um plugin complementar para o VS Code.

Quando estiver pronto, são apenas três comandos:

/consort:start guia você em um projeto. Comece com o exemplo StockFlow. Ele é inicializado com três arquivos, e você pode vê-lo crescer até se tornar uma base de código completa a partir daí.

Uma (r)evolução na criação de software

Se este trabalho inspira você e você quer torná-lo ainda melhor, estou procurando mais colaboradores e codeowners. Se você quiser participar ou apenas ver como funciona a estrutura interna, há um artigo no arXiv: https://arxiv.org/abs/2609.09671 ou visite o repositório: https://github.com/databricks-solutions/consort

(Esta publicação no blog foi traduzida utilizando ferramentas baseadas em inteligência artificial) Publicação original

Receba os posts mais recentes na sua caixa de entrada

Assine nosso blog e receba os posts mais recentes diretamente na sua caixa de entrada.