Pular para o conteúdo
developer-experience

4 Horas de Build: Anatomia de um Colapso de Developer Experience

Quando milhares de testes, centenas de GB de RAM e uma cultura tóxica se encontram: a anatomia completa de um desastre de developer experience

36 min de leitura

Also in English

O Momento em que Milhares de Testes Passam… e o Build Falha

3h58min

Você olha o Jenkins. Build rodando há 3 horas e 58 minutos.

Todos os testes passaram. Mais de 7 mil métodos @Test × 3 bancos de dados (originalmente eram 4, Oracle foi desabilitado porque consumia memória demais). Todos verdes. Surefire gerando reports XML…

VAI PASSAR! 🎉

4 horas e 2 minutos.

❌ BUILD FALHOU

Error: Could not write report to target/surefire-reports
Cause: No space left on device

Você respira fundo. Vai ter que rodar de novo.

E você terá que esperar novamente.

Essa foi minha realidade durante o tempo que estive em uma fintech. Não vou mencionar nomes. Não vou identificar pessoas. Mas vou contar cada detalhe técnico dessa história — porque é a única forma de entender como sistemas aparentemente racionais produzem loucura coletiva.

Os números absurdos

O sistema

~7.000 testes × 3 bancos de dados = mais de 20 mil execuções de testes

  • (Originalmente 4 bancos — Oracle desabilitado por consumir memória demais)
  • Mais combinações com Keycloak: ~30 mil execuções totais por build
  • Milhares de containers criados e destruídos
  • ~150GB de RAM em uso simultâneo
  • ~5GB de logs por tentativa
  • Pipeline: 4 horas quando funcionava, 8h quando retry
  • GitFlow + liberações em batch (feature → develop → release → master)
  • Custo anual estimado: ~$200K só em infraestrutura de CI

Não, você não leu errado. Eram mais de 7 mil métodos @Test — mas cada build completo executava cada um deles 3 vezes: uma para H2, uma para MySQL, uma para MSSQL. (Originalmente eram 4 bancos — Oracle foi desabilitado porque consumia memória demais. Sim, o consumo já era insustentável e tentaram reduzir. Não ajudou.) Isso sozinho já eram mais de 20 mil execuções. E ainda tinha combinações com 3 versões diferentes de Keycloak, chegando a aproximadamente 30 mil execuções totais por build.

Fazer uma mudança de uma linha significava esperar o dia inteiro. Abrir um pull request era planejar a tarde. Resolver um merge conflict virava maratona.

E ainda tinha GitFlow. Feature branch → develop → release branch → master. Cada merge, mais uma espera interminável. Cada branch, mais uma chance de conflito. Liberações em batch significavam que sua mudança ficava travada esperando o próximo release — às vezes semanas.

E não, você não podia rodar os testes localmente. Não na sua máquina. Não no seu laptop. A suite completa exigia recursos que só a infraestrutura de CI tinha: múltiplos bancos de dados, Kafka, Zookeeper, Schema Registry, versões específicas de Keycloak. Tentar rodar localmente? Seu laptop derretia antes de terminar o primeiro teste.

4 horas era o único feedback que você tinha.

“Mas por que não otimizar?”

Convivemos com isso durante todo o tempo que estive lá. Reuniões, propostas, análises, sala de guerra. E vou contar exatamente o que encontramos no caminho — e por que nada mudou.

Anatomia do Problema

Problemas Técnicos

”No space left on device”: o fantasma recorrente

Build #1234: ✅ SUCESSO
Build #1235: ✅ SUCESSO
Build #1236: ❌ FALHOU - No space left on device
Build #1237: ❌ FALHOU
Build #1238: ✅ SUCESSO (alguém reiniciou algo, ninguém sabe o quê)
Build #1239: ❌ FALHOU

Este erro se tornou o mais recorrente. Mas o que exatamente ficava sem espaço? Disk space? Inodes? Quota do pod? Permissões? O time de DevOps não tinha contexto da aplicação para investigar completamente, e desenvolvedores não tinham acesso às ferramentas de infraestrutura. O que ficava claro era o consumo desenfreado e irresponsável de recursos.

A matemática era brutal. Cada worker Tekton acumulava Docker images cached (~10GB), camadas Docker (~5GB), Maven .m2 cache (~3GB), build artifacts (~2GB), test reports (~500MB), e o verdadeiro vilão: logs gigantescos. Some a isso containers fantasmas que nunca foram limpos corretamente (1-3GB), e você chega facilmente em 22-28GB por worker.

O problema não estava apenas no node do Kubernetes. Estava em todo lugar. Cada pod Tekton tinha um limite de storage efêmero consumido vorazmente: imagens Docker, volumes de containers, logs crescentes, build artifacts temporários. Total: ~20GB por pod.

Quando o build rodava por 3 horas ou mais gerando logs infinitos, os recursos simplesmente se esgotavam.

Era um sistema desenhado para consumir recursos de forma irresponsável e colapsar sob seu próprio peso.

Os logs: o verdadeiro vilão

Um único build gerava ~5GB de logs. Não é erro de digitação.

Maven vomitava ~200MB de output. Spring Boot, iniciando múltiplos workers em paralelo, gerava ~600MB de startup logs. TestContainers, orquestrando Docker, MySQL, MSSQL, H2, Kafka, Zookeeper, Keycloak, produzia ~1.5GB de logs. A execução dos testes em si? Mais ~2GB. Jenkins pipeline adicionava ~500MB. Total: ~5GB por build.

Três builds por dia = 14.4GB/dia. Uma semana = 100GB só de logs.

Nenhum editor conseguia abrir. VSCode crashava. Vim dava “Out of memory”. Sublime Text congelava e transformava o laptop em torradeira elétrica.

O time de DevOps não tinha contexto completo da aplicação — estava separado de Dev por silos organizacionais que tornavam verdadeira colaboração impossível.

Sabe qual foi a solução? Outra equipe teve que desenvolver uma ferramenta custom em Python para fazer parse de arquivos de ~5GB, jogar os dados para Google Sheets e visualizar no Looker. E não parava por aí: a ferramenta precisava de correções recorrentes para continuar funcionando.

Porque aparentemente era mais fácil criar e manter uma pipeline completa de dados (Python → Google Sheets → Looker) do que estruturar logs corretamente ou ter observabilidade real.

As 13 camadas de abstração

Carregando diagrama...
As 13 camadas entre você e o código que está testando. Cada camada adiciona complexidade de debug exponencialmente.

Debugar era impossível.

Teste falhou? Boa sorte descobrindo em qual das 13 camadas o problema está.

Container não sobe? Pode ser Docker, pode ser Kubernetes, pode ser Tekton, pode ser TestContainers, pode ser a rede, pode ser resource limits, pode ser… você tem 4 horas para descobrir.

E as ferramentas para isso? Acesso ao kubectl estava bloqueado por política de segurança. Prometheus, Grafana e Loki também. SSH nos nodes? Mesma situação. Logs diretos do Kubernetes? Indisponível.

Você tinha acesso apenas ao Jenkins UI. E aos ~5GB de logs que nem o DevOps conseguia abrir.

Impossível rodar localmente

E aqui está o detalhe que torna tudo pior: você não podia rodar a suite de testes na sua máquina.

A suite completa exigia recursos que só a infraestrutura de CI tinha:

Suite completa exige
  • MySQL container rodando
  • MSSQL container (licenciado)
  • H2 in-memory database
  • Oracle container (desabilitado - consumia memória DEMAIS)
  • Kafka + Zookeeper + Schema Registry
  • 3 versões diferentes de Keycloak
  • ~150GB de RAM em uso simultâneo
  • Storage para logs que crescem exponencialmente
Seu laptop tem
  • 16GB de RAM (se você tivesse sorte)
  • SSD de 256GB ou 512GB
  • Docker Desktop com limites de recursos
  • Sistema operacional que precisa funcionar
  • Outras aplicações abertas (IDE, browser)
  • Ventilador tentando não derreter tudo
  • Esperança (não ajuda)

Tentar rodar localmente? Seu laptop derretia antes do primeiro teste terminar. Docker Desktop travava. Sistema operacional entrava em modo sobrevivência.

A consequência: O feedback do CI era o ÚNICO feedback que você tinha. Não havia “rodar alguns testes localmente para validar rápido”. Não havia “iterar rapidamente até funcionar”. Era commit → push → orar → esperar.

E se falhasse? Esperar tudo novamente.

Surefire: o golpe final

O cenário mais frustrante acontecia assim:

3h58min: Todos os testes passaram. Verdes. Sucesso. 3h59min: Surefire gerando relatórios XML… 4h00min: Error: Could not write report to target/surefire-reports

Todos os testes passaram. Mas o build falhou.

Bug conhecido do Surefire. Não resolvido. Solução oficial: “retry”.

Então você clica em “Rebuild”. E espera o mesmo ciclo se repetir.

Carregando diagrama...
O ciclo do sofrimento: 4 horas de espera, tudo verde, falha na última etapa, retry automático.

O impacto psicológico era real.

3 retries seguidos. 12 horas de build para uma mudança de 5 linhas. E então o build passa — sem que você tenha mudado nada. Frustração pura.

Problemas Organizacionais: Por que o sistema nunca foi consertado

Mas aqui está a questão que ninguém quer fazer: por que um sistema que causa sofrimento psicológico tão óbvio continua ativo? Por que 4 horas de feedback não desencadearam urgência de mudança?

A resposta não é técnica. A resposta é organizacional.

Antes de falar dos problemas técnicos específicos, preciso estabelecer uma verdade incômoda: todo mundo sabia que existia uma disfunção organizacional completa.

A cadeia que ia desde desenvolvedores até profissionais que deveriam dar suporte estava quebrada. O motivo? Silos estruturais e pessoas no panteão dos intocáveis.

Havia profissionais que, por tempo de casa, reputação histórica ou posição política, estavam acima de questionamentos. Principais arquitetos do sistema: mais de uma década na empresa. Conhecimento enciclopédico. Reputação construída ao longo dos anos. E uma posição organizacional que os tornava intocáveis.

Decisões técnicas ruins permaneciam ruins porque quem as tomou não podia ser contestado. Processos disfuncionais continuavam disfuncionais porque mudá-los significaria admitir que alguém importante errou. E todos sabiam disso — mas a estrutura organizacional protegia ativamente a disfunção.

Dev vs Infra: o jogo de empurra-empurra

Carregando diagrama...
O impasse organizacional: Dev culpa Infra, Infra culpa Dev, ninguém assume ownership.

Time de Dev: “Precisamos de mais recursos. O build está colapsando, faltam recursos.”

Time de Infra: “Não é problema de recursos. ~7.000 testes é ridículo. Otimizem.”

Dev: “Mas os testes são necessários! É um sistema financeiro!”

Infra: “Então quebrem em pipelines menores. Staged builds.”

Dev: “Não podemos. Precisamos validar todas as combinações banco × Keycloak.”

Infra: “Então aumentem os recursos de cloud.”

Dev: “Você acabou de dizer que não é problema de recursos!”

Infra: ”…”

Dev: ”…”

Reunião termina sem resolução.

Essa conversa aconteceu. Literalmente. Diariamente.

Perspectiva Dev
  • Recursos insuficientes causam falhas recorrentes
  • Precisamos de mais workers paralelos
  • Precisamos de ferramentas de debug (kubectl, Prometheus)
  • Infra não entende a complexidade do sistema
Perspectiva Infra
  • ~7.000 testes é over-engineering absurdo
  • Pipeline mal desenhada causa desperdício
  • Ferramentas de debug já existem, peçam acesso correto
  • Dev quer mais recursos para compensar código ineficiente

Ambos estavam certos. E ambos estavam errados.

O problema real não era técnico. Era político e estrutural.

Não era só ego — embora houvesse ego em abundância. Era uma estrutura organizacional que protegia certas pessoas de qualquer questionamento técnico:

  • Questionou uma decisão arquitetural? “Foi assim que eu desenhei porque tenho mais de uma década de experiência.”
  • Sugeriu uma mudança no pipeline? “Eu que criei esse pipeline. Sei exatamente por que cada etapa está lá.”
  • Apontou desperdício nos testes? “Você está sugerindo reduzir cobertura? Em um sistema financeiro?”

Decisões tomadas há 5, 10 anos permaneciam intocadas não porque ainda faziam sentido, mas porque questionar a decisão era questionar quem a tomou. Não era possível ter conversas técnicas honestas.

Toda discussão virava defesa de reputação. Melhorias eram vistas como críticas pessoais. Dados concretos — análise de desperdício, métricas de build, custos operacionais — eram ignorados se contradissessem decisões históricas.

E o pior: eles provavelmente tinham razão quando tomaram essas decisões. O contexto havia mudado. O sistema havia crescido. Ferramentas evoluíram. Mas admitir isso significaria admitir que decisões passadas não eram mais ótimas. E em uma cultura onde senioridade é medida por nunca estar errado, admitir erro é impossível.

O papel de ponte (Dev ↔ Infra)

Eu era o interlocutor entre Dev e Infra. Não por escolha. Por necessidade. A estrutura organizacional reforçava ativamente a disfunção — silos garantiam que ninguém tinha visão completa do problema. E eu acabei sendo a única pessoa que entendia ambos os lados.

Desenvolvedores me perguntavam: “Por que não podemos ter kubectl? Por que não temos Grafana? Por que os builds falham tanto?” Infraestrutura me questionava: “Por que ~7.000 testes? Por que não fazem staged pipeline? Por que TestContainers precisa de milhares de containers?”

Eu traduzia. Mediava. Explicava. Negociava.

E recebia pressão dos dois lados:

  • Dev me via como extensão da Infra: “Você tem acesso. Você pode pedir as ferramentas.”
  • Infra me via como extensão do Dev: “Você entende o código. Convença eles a otimizar.”
  • Gestão me via como a solução: “Você entende os dois. Resolva.”

Não tinha autoridade para mudar decisões. Não tinha budget para comprar ferramentas. Não tinha autonomia para alterar arquitetura. Mas tinha toda a responsabilidade quando as coisas quebravam.

Ser ponte entre Dev e Infra sem poder de decisão é a forma mais eficiente de burnout profissional que eu conheço. Você sente a dor dos dois lados, entende as limitações de ambos, mas não pode resolver nenhum dos problemas estruturais que causam o conflito.

Zero ferramentas de debug

Ferramentas que eu PRECISAVA
  • acesso ao kubectl para inspecionar pods
  • SSH nos nodes Kubernetes
  • Prometheus queries diretas
  • Grafana dashboards com métricas relevantes
  • Logs estruturados (JSON)
  • Distributed tracing
  • Acesso aos volumes persistentes
  • Permissão para rodar comandos debug nos pods
Ferramentas que eu TINHA
  • Jenkins UI (ver builds)
  • Download de logs de ~5GB que nem abrem
  • Chat corporativo
  • Oração
  • Esperança
  • Frustração gratuita e ilimitada

Debug era feito às cegas.

Exemplo real: “No space left on device”. Você não pode fazer kubectl exec para investigar. Pode ser permissão, quota do pod, inode limit, ou qualquer outra coisa. O erro diz “no space”, mas você nunca descobriria o quê. Essa é a realidade da falta de ferramentas.

A ironia cruel: havia 3 profissionais DevOps, além de um Principal e Arquitetos que intermediavam a situação, e alguns Gerentes. Mas os silos organizacionais garantiam que DevOps não tinha contexto completo da aplicação, e desenvolvedores não tinham acesso à infraestrutura. Resultado: ninguém conseguia resolver.

Por que não liberar acesso?

“Política de segurança.”

“Mas eu literalmente faço deploy de código nesse cluster.”

“Isso é diferente. Deploy usa processos controlados. kubectl é acesso direto.”

“E se eu prometo não fazer kubectl delete?”

“Não é questão de confiança. É policy.”

“Então quem pode debugar?”

“DevOps.”

“DevOps sabe Java e Spring Boot, mas não tem contexto completo do domínio da aplicação. E nós desenvolvedores não temos as ferramentas de infraestrutura.”

“Vocês precisam se comunicar melhor.”

Comunicar melhor. Como se o problema fosse escolher a ferramenta de comunicação correta. Como se não fosse uma disfunção estrutural onde pessoas que deveriam dar suporte não tinham ferramentas nem contexto para dar suporte, e pessoas que precisavam de suporte não tinham autonomia para resolver problemas.

”…”

A descoberta bombástica: 50% era desnecessário

Depois de semanas analisando os testes, descobri algo que ninguém queria acreditar:

quase 4 mil testes — metade da suite — eram puro desperdício.

A VERDADE INCONVENIENTE

Análise dos ~7.000 testes: Mais de 1.500 testes testavam MapStruct — código gerado pelo compilador. 900 testes eram duplicados por herança de classes Abstract*Test. 1.000 testes testavam Lombok — getters e setters gerados automaticamente. 100 testes validavam Bean Validation — anotações @NotNull, @Size que o próprio framework garante. ~200 null checks óbvios testando se null é null.

Todo o sofrimento… metade era desnecessário.

Carregando diagrama...
50% dos testes testavam frameworks, compiladores ou eram duplicados. Apenas 27% testavam lógica de negócio real.

MapStruct gera código em tempo de compilação. Você escreve uma interface:

@Mapper
interface OrderMapper {
    OrderDTO toDTO(Order entity);
}

E o MapStruct gera a implementação. Automaticamente. Compilado. Type-safe.

Por que testar código gerado por um compilador?

“Para garantir que o mapeamento está correto.”

Mas é gerado automaticamente. Se compilou, funciona.

“E se mudar a versão?”

Então você confia no compilador mas não confia no framework?

“É bom ter cobertura.”

1.000 testes de Lombok.

@Data
class Order {
    private String id;
    private BigDecimal amount;
}

Lombok gera getters, setters, equals, hashCode, toString. Em tempo de compilação.

E tínhamos 1.000 testes validando que getId() retorna o id. Que setAmount(x) seta o amount.

900 testes duplicados por herança.

Padrão comum:

abstract class AbstractServiceTest {
    @Test void testCreate() { /* ... */ }
    @Test void testUpdate() { /* ... */ }
    @Test void testDelete() { /* ... */ }
}

class OrderServiceTest extends AbstractServiceTest {}
class AccountServiceTest extends AbstractServiceTest {}
class LedgerServiceTest extends AbstractServiceTest {}
// ... 300 classes

Cada subclasse herdava os mesmos testes. 900 testes rodavam código idêntico com setup diferente.

Solução: Testes parametrizados. Um teste, múltiplas execuções. Redução: 900 → 30 testes.

Ninguém quis fazer.

“Vai quebrar cobertura de código.”

“Mas estamos testando a mesma coisa 900 vezes!”

“É o padrão que sempre usamos.”

Três Verdades Que Ninguém Quer Ouvir

Antes de analisar os frameworks, vamos ao cerne: três verdades que estruturam tudo que você vai ler.

Primeira verdade: métricas mentem quando contexto é ignorado

Você pode ter 100% de cobertura de testes e ainda assim estar testando as coisas erradas. Como vimos, milhares de testes verificando código gerado por compiladores (MapStruct, Lombok). Cobertura: 100%. Valor: zero.

Você pode ter Deployment Frequency “boa” no dashboard enquanto desenvolvedores evitam fazer mudanças porque cada uma significa um feedback loop interminável. A métrica está verde. O time está em burnout.

Métricas são termômetros, não diagnósticos. Um termômetro mostra 38°C. Pode ser gripe. Pode ser infecção grave. Pode ser sepse. O número sozinho não diz nada.

Segunda verdade: 50% do problema era desperdício puro

Não era “tudo necessário por causa da complexidade do sistema”. Era desperdício. Puro e simples.

Como detalhamos anteriormente, quase 4 mil testes testavam frameworks ao invés de lógica de negócio. A maior otimização não foi técnica. Foi admitir que metade do trabalho era inútil e ter coragem de deletar.

Em culturas onde “sempre foi assim” é argumento válido, desperdício se acumula até que sistema colapsa sob próprio peso. Builds intermináveis. ~$200K/ano. Burnout generalizado.

Terceira verdade: ferramentas inadequadas + cultura tóxica = desastre inevitável

Nenhum framework sozinho salva. Nem DORA, nem SPACE, nem DevEx, nem qualquer outro que vier.

Se profissionais que deveriam dar suporte estão protegidos em silos intocáveis, ferramentas não resolvem. Se decisões técnicas são bloqueadas por ego ao invés de dados, métricas não resolvem. Colaboração > Ego. Sempre.

Não existe solução técnica para problema organizacional. E quanto mais rápido você aceitar isso, mais rápido pode decidir: lutar para mudar ou sair antes de quebrar.

Quando Todos os Frameworks Concordam: Isso é Disfunção

Agora, vamos ver como essas três verdades se manifestam em cada framework de produtividade. Esta série explora DORA[1] (entrega), SPACE[2] (multidimensional) e DevEx[3] (experiência do desenvolvedor).

Métricas DORA: quando as métricas mentem

são desenhadas para medir capacidade de entrega. Mas há um detalhe importante: havia implantação em ambiente de testes, não produção.

O fluxo era: Build → Deploy em ambiente de testes → Testadores faziam testes manuais → Empacotamento (helm-charts) → Entrega ao cliente em batch.

Não havia continuous deployment. Releases eram agrupados e entregues em ciclos. GitFlow gerenciava branches (feature → develop → release → master). Feedback vinha dos testadores, não de telemetria de produção.

Deployment Frequency: ✅ Dezenas de deploys/dia (ambiente de testes com snapshots)

Parecia OK no dashboard — testadores usavam versões snapshot, então não demorava para implantar em testes. Mas aqui está o detalhe: 60% desses deploys tinham builds que falhavam na primeira tentativa. E lembre-se: metade dos 7.000 testes testava MapStruct, Lombok e frameworks — desperdício puro. A métrica verde esconde colapso real.

A realidade do ciclo de desenvolvimento era outra:

  • 4 horas de feedback loop para cada tentativa de build
  • Múltiplos retries = dias de espera real
  • 60% de falha na primeira tentativa
  • Desenvolvedores evitando mudanças para não “gastar” um build

Lead Time for Changes: ❌ 2-3 DIAS (às vezes SEMANAS)

Feature branch → Build (4h) → Merge para develop → Build (4h) → Falhou → Retry (4h) → Passou → Esperar próximo release → Merge para release branch → Build (4h) → Deploy para testes → Validação manual → Merge para master

E isso assumindo que nenhum build falhou. Um único retry? +4 horas. Build falhou duas vezes? +8 horas.

GitFlow + liberações em batch multiplicavam o lead time. Uma mudança simples ficava travada esperando o próximo ciclo de release. Às vezes semanas.

Uma mudança trivial virava maratona. Não por complexidade técnica. Por fricção de processo.

Time to Restore: ❌ 6-8 horas

Bug encontrado pelos testadores no ambiente? 6-8 horas até ter um fix deployado:

  • 1h para debugar (sem ferramentas adequadas)
  • 4h de build (se passar na primeira)
  • 1-2h para deploy e validação manual
  • Se o build falhar: +4h para cada retry

Change Failure Rate: ❌ ~30%

30% dos deploys no ambiente de testes apresentavam problemas descobertos pelos testadores:

  • Bugs que passaram nos ~7.000 testes
  • Problemas de configuração (helm-charts)
  • Incompatibilidades de ambiente
  • Workarounds que quebraram outras features

O problema do DORA neste contexto

DORA captura sintomas, não causas. As métricas pareciam “aceitáveis” em relatórios gerenciais — mas a realidade era inferno.

Deployment Frequency não distingue entre “deploys confiáveis” e “deploys que só passam no retry”. Lead Time não captura os 3 builds que falharam antes do sucesso. Change Failure Rate de 30% parece razoável, mas esconde que 60% dos builds falhavam na primeira tentativa antes mesmo de chegar aos testadores.

E o pior: feedback vinha de testadores manuais em ambiente de testes, não de telemetria de produção em minutos. Bugs críticos só eram descobertos semanas depois, quando o helm-chart chegava ao cliente.

Framework SPACE: as cinco dimensões do sofrimento

expande a análise para múltiplas dimensões. E cada uma delas estava destruída:

S - Satisfaction and well-being: ❌ 2/10

Frustração generalizada. Burnout crescente. Impacto emocional severo.

P - Performance: ⚠️ 7/10

Código era bom. Qualidade técnica era alta. Mas processo horrível sabotava tudo.

A - Activity: ❌ 4h de feedback loop

Atividade constante, mas a maior parte dela era esperar. Esperar build. Esperar retry. Esperar análise de logs. E enquanto isso, 50% do trabalho era testar frameworks que não precisavam ser testados.

C - Communication and collaboration: ❌ Guerra entre times

Blame game constante. Silos impermeáveis. Ponte no meio do fogo cruzado. Zero colaboração real.

E pior: principals inacessíveis por ego. Questionar decisões? Impossível. “Sempre foi assim porque EU decidi há muitos anos.”

E - Efficiency and Flow: ❌ Interrupções constantes

Impossível entrar em flow. Cada mudança exigia coordenação com 3 times, 2 aprovações e orações para que o build passasse.

SPACE como diagnóstico

O que SPACE revelaria

  • Satisfação no chão — visível em questionários
  • Performance alta sendo desperdiçada
  • Colaboração fragmentada — Dev vs Infra
  • Principals/arquitetos inacessíveis por ego defensivo
  • Eficiência destruída por fricção de processo

O que SPACE não resolveria

  • Por que a satisfação está baixa (causa raiz)
  • Como resolver o conflito Dev vs Infra (estrutura de poder)
  • Quem tem autoridade para mudar (decisão política)
  • Custo humano do sistema (burnout invisível)

SPACE diagnostica bem o onde — mas não o como nem o por quê.

DevEx Framework: Developer Experience destruída

olha para as três dimensões centrais de experiência: Fluxo, Feedback e Carga Cognitiva.

Todas elas estavam completamente destruídas.

Carregando diagrama...
As 3 dimensões do DevEx formam um ciclo vicioso: sem fluxo, sem feedback e carga cognitiva insustentável.

Fluxo: DESTRUÍDO

4 horas de espera por feedback. Impossível trabalhar em mais de uma coisa sem perder contexto. Desenvolvedores começavam uma mudança, esperavam 4h, já estavam em outra tarefa quando o resultado chegava. E metade dessa espera era para rodar testes desnecessários de frameworks.

Feedback: AUSENTE

Feedback ambíguo, tardio e impossível de analisar. Logs impossíveis de processar. Ferramentas de debug negadas. Debug às cegas.

Carga Cognitiva: MÁXIMA

13 camadas de abstração. Conhecimento tribal (só os seniors mais antigos entendiam). Infra hostil (sem kubectl, sem observabilidade). Conflito político constante.

O que DevEx mostra

Quando as três dimensões estão quebradas simultaneamente, não existe produtividade possível.

Não importa quão bom seja o código. Não importa quão competente seja o time. O ambiente é hostil cognitivamente — e esgota até as pessoas mais resilientes.

DX Core 4: as quatro faces do colapso

O DX Core 4[4] é um framework mais recente que expande o DevEx original para 4 dimensões interdependentes: Flow, Feedback, Cognitive Load e Alignment.

O que diferencia DX Core 4? Ele mostra como essas dimensões não existem isoladamente — elas se reforçam mutuamente. Um problema em Flow causa problemas em Feedback. Carga Cognitiva alta quebra Alignment. E assim por diante.

No nosso caso, todas as 4 dimensões estavam em colapso simultâneo. E pior: cada uma amplificava as outras.

Carregando diagrama...
As 4 dimensões do DX Core 4 formam um ciclo de reforço negativo: cada problema amplifica os outros.

Flow: DESTRUÍDO

Estado de flow? Impossível com ciclos de feedback tão longos. Você inicia um PR, roda o build, e quando o resultado finalmente chega — você já está em outra tarefa completamente diferente. Contexto perdido. Mental cache invalidado. Tem que recarregar na memória o que diabos você estava fazendo.

Como vimos anteriormente, não havia alternativa de rodar localmente — o laptop não aguentava a suite completa. Era commit, push, esperar.

Pior ainda: múltiplas tentativas. Build falha, você ajusta uma linha, roda de novo. Mesma espera. No fim do dia, 2-3 tentativas consumiram 8-12 horas de tempo real para validar uma mudança que deveria levar minutos. Handoffs constantes. Contexto perdido. Carga mental crescente.

Interrupções diárias viraram norma. “O build falhou de novo, você pode olhar?” Reunião. Chat corporativo. E-mail. Sala de guerra. Impossível ter 2 horas de trabalho profundo ininterrupto. Flow state virou conceito teórico — algo que você lia em blog posts mas nunca experimentava na prática.

Feedback: AUSENTE

Feedback tardio para qualquer mudança = decisões tardias = mais retrabalho. Você faz uma suposição às 9h da manhã, só descobre se estava certa às 13h. E se estava errada? O ciclo recomeça.

O Ciclo OODA (Observe, Orient, Decide, Act — Observar, Orientar, Decidir, Agir) é um conceito militar de tomada de decisão rápida adaptado para desenvolvimento de software. Quanto mais rápido você completa o ciclo, mais rápido aprende e se adapta. Com 4 horas de feedback, o ciclo fica tão lento que perde completamente sua eficácia.

E quando o feedback finalmente chegava, era inútil. Logs impossíveis de abrir. Mensagens como “No space left on device” sem indicar ONDE (disco do node? volume? tmpfs? qual dos milhares de containers?). Surefire failures sem stack trace útil. Erro genérico que poderia significar literalmente qualquer coisa.

Acionabilidade? Zero. Erro encontrado, mas sem ferramentas para investigar. Acesso ao kubectl? Negado. Prometheus? Negado. Grafana? Negado. Logs impossíveis de analisar sem crashar o editor. Debug às cegas, tentando adivinhar o problema por telepatia. “Será que é disco? Será que é memória? Será que é TestContainers deixando containers órfãos? Vai saber.”

Cognitive Load: MÁXIMA

DX Core 4 separa carga cognitiva em 3 tipos: Intrinsic (complexidade inerente do problema), Extraneous (complexidade desnecessária) e Germane (capacidade de aprender).

Intrinsic Load era alto, mas legítimo: ~7.000 testes reais, múltiplos bancos de dados (MySQL, MSSQL, H2 — Oracle havia sido desabilitado por consumir memória demais), Kafka + Zookeeper + Schema Registry + Keycloak, lógica de negócio complexa envolvendo transações financeiras. Essa carga fazia sentido existir.

Extraneous Load era absurdo: 13 camadas de abstração desde Jenkins até containers individuais. Quase 4 mil testes testando frameworks ao invés de negócio. Conhecimento tribal concentrado em poucos seniors. Conflito político constante. Ferramentas básicas de debug negadas. Cada camada adicionava fricção cognitiva desnecessária.

Germane Load era zero. Não havia espaço mental para aprender, melhorar, crescer. Todo o cérebro estava ocupado sobrevivendo ao caos operacional diário: builds falhando, logs impossíveis, reuniões de guerra, conflitos entre times.

O problema? Extraneous Load consumia 80-90% da capacidade cognitiva. Sobrava quase nada para fazer o trabalho de verdade (Intrinsic) ou para melhorar o processo (Germane). Era como tentar programar enquanto alguém grita no seu ouvido e apaga suas linhas de código aleatoriamente.

Alignment: QUEBRADO

Clareza de objetivos? Zero. Nenhum objetivo comum. Cada lado empurrando responsabilidade para o outro. Enquanto isso, o build continuava falhando.

Estrutura de decisão? Inexistente — ou pior: bloqueada por ego. Principals com muitos anos de casa tratavam decisões passadas como dogma inquestionável. Ego prevalecia sobre dados.

Segurança psicológica? Negativa. Propor solução resultava em “Você não entende a complexidade.” Questionar decisão virava “Você não tem experiência suficiente.” Admitir não saber algo era impossível — vinha imediatamente “É culpa do outro time.” O resultado: medo generalizado. Medo de falar. Medo de propor. Medo de admitir não saber. Medo de questionar. Ambiente tóxico onde sobrevivência política importava mais que solucionar o problema.

O ciclo de reforço negativo

DX Core 4 revela algo assustador: problemas em uma dimensão amplificam problemas nas outras.

  1. Feedback lento (4h) → quebra Flow (contexto perdido)
  2. Flow quebrado → aumenta Cognitive Load (recarregar contexto mentalmente)
  3. Cognitive Load alta → quebra Alignment (pessoas exaustas entram em conflito)
  4. Alignment quebrado → piora Feedback (times não colaboram para melhorar ferramentas)

E o ciclo recomeça. Cada iteração piora as 4 dimensões simultaneamente.

No nosso caso: 2 anos de ciclo vicioso. Entropia crescente. Até que as pessoas começaram a sair.

Como Resolver em 6 Meses (Se Ego Permitisse)

Síntese: O que cada framework revelou que os outros não

InsightDORASPACEDevExDX Core 4
Métricas escondem realidade---
Satisfação no chão---
Fluxo impossível--
Ciclo de reforço negativo---
50% desperdício identificadoParcial-

O insight único do DX Core 4: Não basta diagnosticar cada dimensão isoladamente. O que importa é como elas se reforçam mutuamente. Um problema em Flow causa problemas em Feedback. Carga Cognitiva alta quebra Alignment. E assim por diante.

DORA capturou sintomas — lead time alto, change failure rate. SPACE identificou a guerra entre times. DevEx mostrou a destruição cognitiva. Mas só DX Core 4 mostrou o ciclo vicioso completo onde cada problema amplifica os outros.

O que cada framework proporia

FrameworkSolução PropostaCusto EstimadoImpacto Esperado
DORAStaged pipeline (smoke→unit→e2e)
Simplificar GitFlow → trunk-based
Reduzir lead time com builds incrementais
Médio
2-3 meses de trabalho
Lead Time: 2-3 dias→4-8h
Deployment Frequency: 2-3/sem→diário
MTTR: 6h→2h
SPACEFerramentas de debug (kubectl, Grafana, Loki)
Estrutura de colaboração entre times
Autonomia
Baixo (ferramentas)
Alto (mudança cultural)
Satisfaction: 2→7
Collaboration: guerra→parceria
Efficiency: fricção reduzida
DevExEliminar 50% dos testes desnecessários
Logs estruturados (JSON)
Feedback rápido (build <10min)
Baixo (delete testes)
Médio (estruturar logs)
Flow: 4h→30min de feedback
Carga Cognitiva: redução 40%
Feedback: claro e acionável
DX Core 4Eliminar Extraneous Load (testes frameworks, camadas)
Estabelecer acordo entre times (Alignment)
Criar estrutura de decisão clara
Médio
Requer liderança forte
Cognitive Load: -70%
Alignment: conflito→colaboração
Flow: 4h→1h
Feedback: ambíguo→claro

A solução que nunca veio: “E se…”

CENÁRIO: E se os times tivessem trabalhado juntos?

Mês 1: Identificação

  • Análise conjunta dos testes
  • Descobrem que 50% são desnecessários
  • Priorizam: remover desperdício primeiro

Mês 2: Execução

  • Deletar testes de MapStruct e Lombok
  • Refatorar testes Abstract para parametrizados
  • Build cai de 4h para 2h
  • Falhas por consumo de recursos reduzidas em 60%

Mês 3: Consolidação

  • Staged pipeline: smoke (5min) → unit (30min) → integration (1h)
  • Logs estruturados (JSON, ~5GB → 500MB)
  • Simplificar GitFlow → trunk-based com feature flags
  • Feedback rápido para 90% dos casos

Resultado em 6 meses:

  • Lead time: 2-3 dias → 4-8 horas (80-90% redução)
  • Build time: 4h → 30min-1h com staged pipeline
  • Custo infra: ~$200K/ano → $50K/ano
  • Satisfação do time: 2/10 → 8/10

Economia anual: ~$150K

MAS:

❌ Conflito constante ❌ ~$500K desperdiçados ❌ Burnout generalizado

PORQUE: Ego > Colaboração

Delete, Observe, Colabore: O Plano Que Ficou no Papel

Se houvesse real colaboração entre Dev e Infra, com foco em resultado ao invés de ego, aqui está exatamente como a transformação aconteceria:

Ações Imediatas (Semana 1-4): O golpe mais fácil

1. Delete testes de frameworks (IMPACTO MÁXIMO, RISCO ZERO)

Delete testes de MapStruct, Lombok, null checks óbvios — como detalhamos anteriormente.

Sabemos que isso funciona: é literalmente apertar Delete. Sem risco. Sem “e se?”. Apenas diminuir desperdício. Resultado imediato: 40% do build desaparece.

Impacto total: Build 4h → 2h30min (~40% redução). Você aperta Delete numa sexta-feira e na segunda o time está 40% mais produtivo. É o tipo de vitória rápida que constrói momentum para mudanças maiores.

2. Logs estruturados (JSON)

Problema: ~5GB de texto puro, impossível de analisar.

Solução: Structured logging (JSON Lines)

{"timestamp":"2024-02-03T14:23:45Z","level":"ERROR","message":"No space left on device","context":{"worker":"tekton-7","test":"OrderServiceTest","phase":"surefire-report"}}

Com logs estruturados, o tamanho cai de ~5GB para ~500MB (compressão JSON + gzip). Parsing fica instantâneo usando ferramentas como jq ou grep. Análise vira trivial: query por campo específico, filtros complexos, agregações. E indexação com Loki se torna viável.

A solução completa: Loki para agregação e consulta de logs + Prometheus para métricas + Grafana para visualização unificada resolveriam toda a dor de observabilidade.

Risco? Baixíssimo — é mudança de configuração, não de código. Tempo de implementação: 1 semana no máximo.

Ações de Médio Prazo (1-3 Meses): Construindo sobre a vitória

1. Observabilidade real

Após o sucesso rápido de deletar testes, o próximo passo é finalmente enxergar o que está acontecendo.

Loki + Prometheus + Grafana para observabilidade completa: Loki agrega e indexa logs estruturados, Prometheus coleta métricas de build em tempo real (consumo de recursos por worker, container lifecycle, memory/CPU por teste, storage usage), Grafana unifica tudo em dashboards mostrando exatamente onde o gargalo está acontecendo agora — não 4 horas depois via logs impossíveis.

Alertas proativos para pegar problemas antes de virarem incêndio: recursos ultrapassaram limite? Alerta disparado antes de falhar. Build passou de 3h? Dashboard acende vermelho para investigar gargalo.

Custo: ~$200/mês com hosting managed. ROI: economia de ~10h/semana de debug às cegas = ~$5K/mês recuperados. Paga sozinho em 1 semana. É o tipo de investimento que CFO aprova sorrindo.

2. Refatorar Abstract tests para Parameterized

Como vimos anteriormente, 900 testes rodavam código idêntico por herança. JUnit 5 @ParameterizedTest resolve: um teste, múltiplas execuções. Mesma cobertura, menos código, manutenção infinitamente mais fácil.

3. Staged Pipeline

Problema: Tudo roda sempre. Feedback tardio.

Solução: Pipeline progressivo

Smoke (5min)
  ├─ Compilação
  ├─ Testes unitários rápidos (~500)
  └─ Se falhar: PARA AQUI ❌

Unit (30min)
  ├─ Todos os testes unitários (~4.000)
  ├─ Análise estática (SonarQube)
  └─ Se falhar: PARA AQUI ❌

Integration (1h)
  ├─ Testes de integração (H2 apenas)
  ├─ Testes de API (Keycloak mock)
  └─ Se falhar: PARA AQUI ❌

Full (2h) - Apenas em main/develop
  ├─ Matrix: 3 DBs × 3 Keycloaks
  └─ Testes E2E completos

Impacto:

  • 90% dos erros detectados em <30min
  • Feedback rápido para feature branches
  • Full validation apenas em branches principais

4. Simplificar fluxo de branches

Problema: GitFlow + batch releases = lead time inflado artificialmente.

Feature → develop → release → master = 4 merges × 4 horas de build = até 16 horas só de builds.

Solução: GitHub Flow ou trunk-based development

Feature branch → main (com feature flags)

Um único merge. Build incremental para feature branches. Full validation apenas para main. Feature flags controlam visibilidade em produção/testes.

Impacto:

  • Lead time: 2-3 dias → 4-8 horas
  • Menos merges = menos conflitos
  • Menos builds = menos custo
  • Releases mais frequentes e menores

Mas: Exige mudança cultural. Exige feature flags. Exige confiança em testes automatizados. Em uma organização com silos rígidos e medo de mudança? Improvável acontecer.

Ações de Longo Prazo (3-6 Meses)

1. Cultura blameless

Solução: Ownership compartilhado. Postmortems sem culpa perguntando “O que o sistema falhou?” ao invés de “Quem errou?”. Experimentação segura. Transparência total.

Custo monetário? Zero — é mudança cultural. Dificuldade? Altíssima. Requer liderança comprometida disposta a confrontar egos e estabelecer nova dinâmica. Sem isso, todo o resto falha.

2. Distribuir conhecimento

Problema: Conhecimento concentrado em poucos seniors com mais de 10 anos de casa. Apenas uma pessoa conhece cada parte crítica — se ela sair, o projeto paralisa. Isso é chamado “Bus Factor” (número de pessoas que, se atropeladas por um ônibus, causariam colapso do projeto). Nesse caso, Bus Factor = 1. Extremamente frágil.

Solução: Pair programming em infra para juniors aprenderem Kubernetes, Tekton, pipeline. Documentação viva com ADRs (Architecture Decision Records) e runbooks atualizados — não aquela documentação morta de 2018 que ninguém lê. Rotation: cada sprint, uma pessoa diferente vira “guardiã” da pipeline. Offboarding reverso: quando senior sai, júnior assume com mentoria — forçando transferência de conhecimento antes da saída.

Objetivo: bus factor de 1 para 5+. Qualquer pessoa do time consegue debugar e corrigir a pipeline sem depender do “chosen one”.

3. Developer Experience como prioridade estratégica

DevEx não é “nice to have” — é investimento em velocidade futura. Ferramentas adequadas (kubectl, Loki, Prometheus, Grafana) não são luxo, são requisito básico para produtividade. Autonomia para desenvolvedores debug problemas sozinhos ao invés de ficar bloqueado esperando DevOps. Processos claros e documentados que qualquer pessoa consegue seguir. Investimento contínuo em redução de fricção — cada sprint, uma coisa que incomoda é eliminada.

A métrica mais clara? Tempo de onboarding de novo desenvolvedor. Antes: 6 meses até contribuir com confiança (porque ambiente é hostil, conhecimento é tribal, ferramentas são negadas). Depois: 1 mês até primeira contribuição real. Quando o ambiente é amigável, pessoas produzem rápido.

O custo de não fazer nada

CUSTO DE MANTER STATUS QUO

Custo operacional direto: ~$200K/ano em infraestrutura CI/CD superdimensionada + $50K/ano em incidentes (hotfixes emergenciais, downtime, retrabalho). Total: ~$250K/ano queimados.

Custo oculto (o pior): Burnout inevitável. Moral no chão com satisfação 2/10. Velocidade decrescente — lead time aumentando mês a mês. Dívida técnica acumulando porque ninguém quer refatorar um sistema que já é pesadelo de trabalhar.

Custo humano: Frustração constante e impacto emocional severo. Relacionamentos completamente destruídos.

Custo de melhorar: $50K de investimento inicial em ferramentas + tempo de implementação. Alguns meses de esforço coordenado. ROI: 6 meses. Depois disso? $100K/ano economizados. Time feliz e produtivo. Velocidade crescente ao invés de decrescente. Dívida técnica sendo paga sistematicamente.

A questão não é “podemos investir?”. A questão é “podemos continuar não investindo?”.

Reconheceu sua empresa? Saia.

Se você reconheceu sua situação aqui, você tem três opções:

1. Estabeleça deadline

“Vou dar 6 meses para isso melhorar. Senão, saio.”

Deadline impõe urgência. Para você e para a organização.

2. Escale

Documente. Quantifique. Apresente para quem tem poder de decisão.

Não emoção. Números. ”~$200K/ano desperdiçados. Build 4h. Rotatividade 30%. Aqui está a solução e o ROI.”

3. SAIA

Se nada mudar após 1 e 2, saia.

Sua saúde mental vale mais que qualquer projeto. Burnout não é badge de honra. É sinal de que o sistema está quebrado — e você não precisa quebrar junto.

MENSAGEM FINAL

Não normalize o absurdo.

Build de 4 horas não é “normal para sistemas complexos”.

Testes testando compiladores não é “garantia de qualidade”.

Guerra entre times não é “como as coisas são”.

Ferramentas de debug negadas não é “política de segurança”.

É disfunção organizacional. E você não precisa aceitar.

Notas de Rodape

  1. [1]

    Forsgren, Nicole; Humble, Jez; Kim, Gene. Accelerate: The Science of Lean Software and DevOps. IT Revolution Press, 2018. Apresenta as 4 métricas DORA (deployment frequency, lead time, MTTR, change failure rate) e as 24 capacidades técnicas e organizacionais que sustentam alta performance em entrega de software.

  2. [2]

    Storey, Margaret-Anne; Zimmermann, Thomas; et al. The SPACE of Developer Productivity. ACM Queue, 2021. Framework que propõe 5 dimensões para medir produtividade de desenvolvedores: Satisfaction, Performance, Activity, Communication e Efficiency.

  3. [3]

    Noda, Abi; et al. DevEx: What Actually Drives Productivity. ACM Queue, 2023. Framework baseado em 3 dimensões (fluxo, feedback, carga cognitiva) para avaliar e melhorar developer experience de forma sistemática.

  4. [4]

    Forsgren, Nicole; Storey, Margaret-Anne; et al. DevEx in Action: A Study of Its Tangible Impacts. ACM Queue, 2024. Expansão do framework DevEx para 4 dimensões: Flow, Feedback, Cognitive Load e Alignment. Foca em intervenções pragmáticas e interdependências entre as dimensões.

Posts Relacionados

Comentários 💬