Eu trabalho como engenheiro na Bitboundaire e, para nós, releases não são “eventos”. Elas são apenas parte do ruído cotidiano.

Não esperamos por um grande release de sexta-feira. Não acumulamos mudanças para um “deploy de fim de mês”. Produtos evoluem todos os dias, founders mudam de direção todos os dias, e os usuários definitivamente não organizam suas vidas em torno do nosso calendário de releases. Se nos importamos com eles, precisamos acompanhar esse ritmo.

Foi por isso que construímos uma forma de trabalhar em que fazer deploy 24/7 é algo normal, seguro e, sinceramente, tranquilo. Isso não se baseia em heroísmo nem em cultura YOLO. Baseia-se em estrutura, disciplina e uma ideia simples:

Nós realmente nos importamos com as pessoas que dependem do que entregamos.

Todo o resto é apenas transformar esse cuidado em algo concreto.

Fatiando o Trabalho para Manter Deploys Pequenos

A primeira coisa que torna possível fazer deploys 24/7 é a forma como estruturamos o trabalho. Se você começa com tickets gigantes, termina com deploys assustadores. É simples assim.

Eu tento evitar tarefas como “Implementar fluxo de cadastro”. Uma tarefa dessas normalmente esconde dezenas de preocupações: UI, roteamento, validações, estados de erro, integrações externas, analytics, observabilidade, e por aí vai. Colocar tudo isso em um único PR resulta em branches de longa duração, revisões dolorosas e ansiedade no momento do deploy.

Em vez disso, fatiamos os fluxos em partes pequenas e independentes.

Fatias de backend
  • Contrato do endpoint de cadastro
    ⁠ . Formatos de request/response, códigos de status, modelo de erro
    ⁠ . Entendimento compartilhado com o frontend
  • Regras de domínio do cadastro
    ⁠ . Regras de negócio, checagens de segurança, rate limiting quando necessário
  • Camada de persistência do cadastro
    ⁠ . Integração com banco de dados, migrations, lógica de repositório
  • Observabilidade do cadastro
    ⁠ . Logs, traces e métricas para eventos e falhas de cadastro
Fatias de frontend
  • Componentes de UI do cadastro
    ⁠ . Inputs, botões, mensagens de erro, loaders
    ⁠ . Ainda sem backend, apenas primitivas de UI
  • Layout da página de cadastro
    ⁠ . Estrutura da página, roteamento, layout
  • Integração da API de cadastro
    ⁠ . Conectar a página ao backend
    ⁠ . Tratar o fluxo feliz de ponta a ponta
  • Erros e casos de borda do cadastro
    ⁠ . Falhas de API, problemas de rede, erros de validação

Cada fatia tem um escopo estreito e uma definição clara de pronto. Isso mantém o raio de impacto pequeno a cada deploy. Não é apenas uma questão estética de arquitetura; é uma forma de respeito à produção e aos usuários que nunca pediram para fazer parte dos nossos experimentos.

Código e Testes Caminham Juntos

Existe uma regra que aplicamos com bastante rigor: não empurramos testes para “depois”.

Para cada pequeno bloco de trabalho, código e testes avançam juntos. Se a implementação está “pronta”, mas os testes não, a tarefa não está pronta. Dependendo da mudança, isso pode significar alguns testes unitários focados em lógica pura, testes de integração para componentes que conversam com bancos de dados ou serviços externos, ou testes E2E para jornadas críticas do usuário.

Na prática, isso nos traz três grandes benefícios:

  • Cada tarefa tem sua própria rede de segurança
  • O risco de regressões diminui bastante
  • O comportamento esperado do sistema fica documentado de forma executável

Não estamos perseguindo um percentual de cobertura apenas para nos sentirmos bem. Estamos nos recusando a terceirizar a descoberta de bugs para os nossos usuários.

Para mim, essa é uma forma muito direta de viver o lema “we truly care”: qualidade não é opcional, e não é algo que talvez adicionaremos se sobrar tempo.

Por Que Testes Parecem “Lentos” (E Por Que Eles São, na Verdade, o Que Faz Você Ser Rápido)

Eu entendo por que muita gente resiste a testes. Se o seu modelo mental de entrega é “eu só preciso fazer isso funcionar e subir”, escrever testes parece trabalho extra que desacelera tudo. Você enxerga o tempo para escrever o teste, mas não vê o tempo que vai perder no futuro depurando algo que quebrou numa sexta-feira.

O que realmente acontece sem testes é o seguinte: cada nova mudança carrega todo o custo do medo. Você mexe em um arquivo e, de repente, começa a adivinhar o que mais pode quebrar. Passa mais tempo clicando manualmente em fluxos, mais tempo olhando logs, mais tempo perguntando “isso é seguro de deployar?”. A primeira entrega pode parecer rápida, mas cada entrega seguinte fica mais lenta, mais arriscada e mais estressante.

Com testes, você paga um pequeno custo explícito no início para evitar um custo enorme e oculto depois. Quando uma funcionalidade tem testes sólidos ao redor, posso alterá-la na semana seguinte ou no mês seguinte com muito mais confiança. O CI vira uma rede de segurança, não apenas um checkbox. Deploys deixam de ser discussões e passam a ser rotina. Com o tempo, os testes não apenas protegem a qualidade; eles multiplicam a velocidade ao permitir que você avance sem refazer a mesma validação manual repetidamente.

Então sim, escrever testes pode fazer uma tarefa isolada parecer mais lenta. Mas se você se importa em entregar o tempo todo, e não apenas “dessa vez”, testes são a única forma de realmente ficar mais rápido conforme o sistema cresce.

Essa diferença fica muito clara quando comparamos com times que dependem de um “time de testes” separado para fazer regressão manual. No papel, parece eficiente: desenvolvedores “andam rápido” e um grupo de testers “garante a qualidade”. Na prática, você só moveu o custo para o final do pipeline e o multiplicou.

Cada mudança agora espera em uma fila. Um ciclo completo de regressão pode levar horas ou dias. Desenvolvedores ficam ociosos ou trocando de contexto enquanto aguardam. Testers passam o tempo repetindo os mesmos caminhos de clique, em vez de explorar casos de borda ou melhorar a qualidade.

Do ponto de vista financeiro, é ainda pior. A empresa paga múltiplos salários para humanos simularem, manualmente, o que uma suíte de testes poderia fazer em minutos usando computação barata. Cada release vira um projeto, não uma operação. Quanto mais funcionalidades você adiciona, mais trabalho manual cria e mais pessoas precisa contratar apenas para manter tudo funcionando. Parece crescimento, mas na verdade é atrito.

Com testes automatizados sob responsabilidade dos desenvolvedores, a curva de custo se inverte. Você investe um pouco mais de tempo por mudança no início e depois deixa as máquinas rodarem seu portfólio de regressão milhares de vezes por praticamente nada. Humanos deixam de agir como servidores de CI lentos e caros e passam a fazer trabalhos de maior alavancagem: análise de risco, pensamento de produto, testes exploratórios onde a automação não alcança.

Em termos de velocidade e custo, testes não são um imposto. Eles são a única forma de o sistema escalar sem esgotar as pessoas ou exigir um exército de gente clicando em botões o dia inteiro.

Nosso Pipeline de CI/CD: Transformando Cultura em Automação

Nada disso funcionaria se o pipeline não reforçasse essas práticas.

Na maioria dos projetos, a stack se parece mais ou menos com isso: workflows de Git, AWS CDK ou Terraform para infraestrutura e um ambiente de staging que espelha a produção o máximo possível. As ferramentas importam menos do que a forma como o fluxo é estruturado.

Um caminho comum para mim é:

  • Começo em uma branch local, focado em uma mudança pequena e clara
  • Quando está pronta, abro um PR para staging. Esse é o primeiro gate antes de qualquer coisa chegar perto da produção
  • O CI roda nesse PR: lint, checagem de tipos, testes unitários, testes de integração e CDK diff ou outras validações de infraestrutura. Se algo quebrar, quebra cedo

Depois que o PR é aprovado e mergeado em staging, o código é deployado no ambiente de staging, que espelha a produção: mesma forma de infraestrutura, mesmos serviços, padrões de dados realistas. Após o deploy, rodamos testes E2E para fluxos-chave.

Se tudo se comporta corretamente, abrimos um PR de staging para main. Nesse ponto, estamos basicamente dizendo “isso está pronto para produção”. A branch main está sempre deployável, e os deploys em produção são pequenos e previsíveis, não um grande “evento de release”.

Como o staging espelha a produção, não estamos adivinhando como as coisas vão se comportar em prod. Respeitamos a produção o suficiente para garantir que ela nunca seja o primeiro lugar onde testamos algo “de verdade”.

Espelho da Produção: Treinar Antes de Valer

O espelho da produção é o que mantém a produção tranquila para nós.

Nosso ambiente de staging não é um playground com configurações aleatórias. Ele é intencionalmente próximo da produção: mesma topologia (serviços, filas, bancos de dados, rede), mesmo processo de deploy, mesma stack de observabilidade.

Sempre deployamos lá primeiro. Rodamos testes E2E lá. Às vezes, permitimos que usuários internos ou stakeholders testem funcionalidades por trás de flags internas antes de expor qualquer coisa aos clientes reais.

Quando promovemos uma mudança para produção, o código, os artefatos e os caminhos de execução já rodaram em um ambiente realista. Não estamos torcendo para dar certo. Nós já vimos funcionar.

Se você realmente se importa com estabilidade, investe em um lugar onde pode praticar as partes difíceis antes que usuários reais sintam o impacto. É exatamente para isso que o staging serve para nós.

Feature Flags: Deploy sem Release

Feature flags são outra parte central desse setup. Elas nos permitem separar deploy de release.

Usamos bastante ferramentas como PostHog para gerenciar flags e rollouts.

Um padrão comum é o dark launch de uma funcionalidade: deployamos o código em produção, mas o expomos apenas para perfis internos ou um pequeno grupo. Assim, conseguimos testar comportamento, fluxos de dados e observabilidade no ambiente real com risco mínimo.

A partir daí, fazemos o rollout gradualmente: primeiro para o time, depois para uma pequena fatia de usuários, depois para um segmento maior e, só no final, para todos. Se logs, métricas ou feedback de usuários indicarem algo estranho, podemos desligar a flag rapidamente, em vez de fazer rollback de um deploy inteiro.

Como as flags nos permitem entregar partes incompletas com segurança, a branch main pode permanecer deployável mesmo enquanto uma funcionalidade ainda está em desenvolvimento ativo. É assim que mantemos alta frequência de entrega sem transformar usuários reais em beta testers por surpresa.

Como Nos Comportamos para Tornar Deploys 24/7 Reais

Nada disso funciona se o time se comportar como se ainda estivesse vivendo em um mundo de releases em big bang.

Dentro da Bitboundaire, existem algumas expectativas que levamos a sério.

Preferimos PRs pequenos por padrão. Muitas mudanças pequenas são mais fáceis de revisar, mais fáceis de entender e muito mais fáceis de reverter do que um diff gigante. PRs enormes geralmente são um sinal de que algo deu errado antes, na forma como o trabalho foi fatiado.

Mantemos reviews de código rápidos. Review é parte do trabalho, não um extra opcional. Reviews lentos criam branches longas e deploys frágeis. Se queremos deploys 24/7, precisamos de ciclos de feedback rápidos, inclusive entre engenheiros.

Evitamos branches de feature de longa duração. Quanto mais tempo uma branch fica aberta, mais o mundo muda ao redor dela e mais doloroso é fazer o merge. Branches curtas, que se integram frequentemente ao staging, mantêm o risco sob controle.

Esperamos que engenheiros sejam donos das funcionalidades de ponta a ponta: implementação, testes, dashboards e métricas que mostram se aquilo realmente funciona em produção. E quando incidentes acontecem, focamos em aprendizado: o que precisa mudar em testes, alertas ou processos para que isso não nos surpreenda novamente?

É aí que o “we truly care” aparece internamente. Não é um slogan na parede. Ele é visível nas restrições que aceitamos como time.

Por Que Founders Devem se Importar com Deploys 24/7

Esse setup todo não é apenas um hobby de engenharia. Ele muda a forma como o negócio se comporta.

Para founders, deploys 24/7 significam que ideias podem ser validadas muito mais rápido. O intervalo entre “acho que isso vai ajudar nossos usuários” e “temos dados reais de produção” fica muito menor. Em vez de apostar em um grande release, podemos fazer muitas apostas pequenas, ajustar e reforçar o que realmente funciona.

Como cada deploy é pequeno, o risco por mudança é baixo. Experimentos ficam menos assustadores. Não é preciso um grande “dia de release” para mostrar progresso a clientes ou investidores. O progresso se torna contínuo.

Isso também mantém o produto mais próximo da realidade. Feedback dos usuários e métricas de produção voltam rapidamente para o roadmap, em vez de ficarem presas atrás de um trem de releases. O que está rodando em produção nunca fica muito distante do que o time tem em mente.

Do meu ponto de vista, essa é uma das formas mais claras de mostrar aos founders que realmente nos importamos: não entregamos apenas funcionalidades, construímos uma máquina que permite que o produto deles se adapte com segurança sempre que o negócio precisa se mover.

Por Que Não Temos Medo da Sexta-feira às 17h

Em muitos times, deployar na sexta-feira às 17h é uma piada interna que significa “vamos nos arrepender disso”.

Para nós, é apenas mais um deploy. Não porque somos imprudentes, mas porque tudo ao redor foi desenhado para mantê-lo tranquilo:

  • O conjunto de mudanças é pequeno
  • O código já rodou em um espelho da produção
  • Testes E2E validaram os fluxos principais
  • Feature flags oferecem um botão rápido de desligar
  • A observabilidade nos avisa rapidamente se algo estiver errado
  • O rollback é simples e bem praticado

Também monitoramos taxas de erro, latência e etapas-chave do funil quase em tempo real, então geralmente sabemos em minutos se um deploy está saudável ou não.

Ainda respeitamos fusos horários e escalas de plantão. O objetivo não é se exibir. É chegar a um nível de confiança em que “fizemos deploy” não signifique automaticamente “prepare-se para uma crise”.

Cuidamos do fim de semana dos nossos colegas e da experiência dos nossos usuários ao mesmo tempo. A forma como estruturamos o trabalho e os deploys foi desenhada para proteger ambos.

Encerramento: Andar Rápido Porque Nos Importamos o Suficiente para Tornar Seguro

Deployar o tempo todo não é o objetivo final. Deployar de forma segura, respeitosa e consistente é.

Para mim, na Bitboundaire, isso se traduz em alguns hábitos concretos:

  • Fatiar o trabalho em partes pequenas, fáceis de entender e de reverter
  • Sempre entregar código junto com seus testes
  • Validar mudanças em um espelho da produção antes que usuários reais as vejam
  • Usar feature flags para separar deploy de release
  • Manter a cultura otimizada para mudanças pequenas, seguras e frequentes

É assim que transformamos o “we truly care” em algo visível: menos downtime, feedback mais rápido, menos estresse para engenheiros e um produto que realmente acompanha as ambições dos founders e as necessidades dos usuários.

No fim das contas, o que eu realmente tento otimizar é simples: deploys pequenos, tranquilos e confiáveis, que respeitam as pessoas dos dois lados da tela.