Data contract no dbt: como impedir que o pipeline quebre em silêncio
· dbt, data contract, qualidade de dados
Em resumo: um data contract declara a forma que uma tabela promete entregar — colunas,
tipos e restrições. No dbt, você liga isso no modelo (contract: enforced: true). Aí, quando o
dado sai do combinado, o build falha na hora — antes de o erro virar relatório, antes de
alguém decidir algo em cima de número torto. Falha cedo e falha alto. É a maneira mais direta de
trocar a falha silenciosa por um erro que você vê no mesmo dia.
O que é um data contract?
É um acordo explícito sobre o formato de uma tabela: quais colunas existem, de que tipo são, o que pode ser nulo e o que precisa ser único. Sem contrato, cada consumidor adivinha. Cada um monta a sua versão da verdade e torce para a fonte não mexer em nada. Com contrato, o formato é lei — e quem quebra a lei é barrado na entrada, não descoberto no fechamento.
O problema que ele resolve é o mais perigoso de todos. Não é o pipeline que quebra: é o que
completa sem erro e entrega número errado. Uma fonte muda um tipo, o autodetect decide
sozinho, uma coluna some, e o build roda verde porque ninguém nunca disse a ele o que era "certo".
Verde não quer dizer correto.
Como o dbt implementa isso (model contracts)
O dbt tem contratos de modelo nativos.
Você declara colunas e tipos no YAML e ativa o contrato. Na hora de materializar, o dbt confere a
estrutura do SELECT contra tudo o que você prometeu — coluna por coluna, tipo por tipo. Bateu,
grava. Não bateu, ele para o build com erro claro, em vez de gravar dado fora de forma.
models:
- name: fct_transactions
config:
contract:
enforced: true
columns:
- name: transaction_id
data_type: string
constraints:
- type: not_null
- name: amount
data_type: numeric # dinheiro é numeric, nunca float
constraints:
- type: not_null
- name: created_at
data_type: timestamp
Repare no amount como numeric. O contrato também é onde você crava o tipo do dinheiro — e
impede que um autodetect distraído o transforme em float e comece a somar centavo errado três
meses depois, quando o estrago já está espalhado no fechamento. Dinheiro nunca é float.
Uma precisão que evita frustração: o contrato sempre impõe o shape — nome e tipo das colunas
— e o build falha se divergir. Já as constraints como not_null dependem do banco. O Postgres
impõe todas; o Snowflake, só not_null; o BigQuery e o Databricks declaram, mas não impõem (fica
como metadado). Trave a forma com o contrato; para as regras de valor, combine com testes.
Contract-first: o contrato antes do dado
O ganho maior vem de inverter a ordem. Escreva o contrato primeiro e construa o modelo para cumpri-lo. Assim, o formato da camada que o BI consome (a Gold) vira uma decisão de projeto, não um acidente do que a fonte mandou hoje de manhã. O relatório passa a depender de um formato estável e auditável, e qualquer mudança de origem esbarra no contrato antes de contaminar a saída. A ordem muda tudo.
Num pipeline antifraude que montei, a camada Gold ficou 100% sob contrato. Quando uma fonte mudava
um tipo, o build passava a falhar na hora — não virava relatório errado no fechamento. E isso
deixou de ser modismo: existe um padrão aberto, o
ODCS (Open Data Contract Standard), hoje
sob a Linux Foundation, e capital entrando no tema — a Gable levantou
US$ 20 mi de série A
para o movimento shift-left. O próprio dbt segue a onda com a engine
Fusion, em Rust e com lineage em nível de coluna.
E quando o schema muda mesmo?
Contrato barra o que quebra a forma na materialização. Só que ele não te avisa sozinho que a origem mudou — ele reage, não vigia. Combine com duas coisas:
- Monitorar mudança de schema na entrada, para saber que a fonte mudou de layout assim que acontece.
- Quarentena para as linhas que violam regra: segurá-las e sinalizá-las em vez de deixá-las passar ou sumir.
Contrato (a forma é lei), monitor (a origem mudou) e quarentena (o que não presta fica visível) são as três camadas de um pipeline que quebra alto, não em silêncio.
Perguntas frequentes
Preciso reescrever meu pipeline para usar data contract?
Não. Você começa por um modelo só — em geral a tabela Gold que o BI mais consome. Declara as
colunas, liga enforced: true, roda. O resto do pipeline continua igual. Contrato é incremental por
natureza: um modelo hoje, o próximo na semana que vem, sem parar nada para isso.
Data contract substitui os testes do dbt? Não, e nem tenta. Os dois cobrem coisas diferentes. O contrato garante a forma — colunas, tipos, o que é not null — na hora de materializar; os testes checam o conteúdo, coisas como "esse valor está no intervalo esperado?" ou "essa chave é mesmo única nos dados?". Um trava a estrutura, o outro examina os números. Você quer os dois.
Funciona para quem não usa dbt?
O contract: enforced: true é do dbt. Mas a ideia — declarar a forma e barrar quem sai dela — não
depende de ferramenta nenhuma. Dá para fazer com validação de schema no código, com constraints no
próprio banco ou com uma camada de qualidade na entrada. Sem dbt, o mecanismo muda; o princípio, não.
Implemento isso em pipelines ETL/ELT. Se o seu pipeline "roda bem" mas o número às vezes vem errado, o contrato é o primeiro lugar onde eu olho.
É exatamente isso que faço em Pipeline de dados que quebra alto e cedo — nunca em silêncio.
Leia também
Peça um diagnóstico do seu fechamento
Deixe seu contato e eu retorno com uma leitura rápida de onde seu relatório depende de uma pessoa — sem compromisso.
Resposta humanaSem cobrança até a propostaNDA bilateral