Introdução ao dbt: transformação de dados como se fosse código de produto

1. O que é dbt e por que ele revolucionou a engenharia de dados

1.1. Definição e origem do dbt no ecossistema moderno de dados

O dbt (data build tool) é um framework open-source que permite transformar dados dentro do data warehouse utilizando SQL como linguagem principal, mas com práticas de engenharia de software — versionamento, testes, documentação e CI/CD. Criado por Tristan Handy em 2016 e mantido pela dbt Labs, o dbt nasceu da necessidade de tratar transformações de dados com o mesmo rigor que o código de produto.

Antes do dbt, as transformações SQL eram scripts soltos, sem controle de versão adequado, sem testes automatizados e com dependências implícitas entre tabelas. O dbt resolve isso ao estruturar cada transformação como um "model" — um arquivo SQL que pode ser testado, documentado e versionado.

1.2. Paradigma "analytics engineering"

O dbt popularizou o conceito de analytics engineering — uma disciplina que fica entre a engenharia de dados e a análise de negócios. Nesse paradigma, a carga dos dados (Extract e Load) é feita por ferramentas como Fivetran, Airbyte ou Stitch, e a transformação (Transform) fica a cargo do dbt. Essa separação EL + T permite que times de dados foquem em lógica de negócio em vez de infraestrutura.

1.3. Comparação com abordagens tradicionais

Abordagem tradicional (scripts SQL soltos):

-- script_vendas_final_v3.sql
-- Cuidado: não executar antes da meia-noite!
DROP TABLE IF EXISTS vendas_agregadas;
CREATE TABLE vendas_agregadas AS
SELECT 
    data,
    SUM(valor) as total_vendas
FROM vendas_brutas
WHERE status = 'confirmado';
-- João: adicionar filtro de data depois

Abordagem com dbt:

-- models/vendas_agregadas.sql
{{ config(materialized='table') }}

SELECT 
    data,
    SUM(valor) as total_vendas
FROM {{ ref('vendas_brutas') }}
WHERE status = 'confirmado'

A diferença é clara: no dbt, usamos {{ ref() }} para declarar dependências, o que permite lineage automática, testes e materialização controlada.

2. Conceitos fundamentais do dbt

2.1. Models

Models são arquivos .sql que contêm uma única instrução SELECT. Cada model se torna uma view ou tabela no warehouse. Exemplo:

-- models/dim_clientes.sql
SELECT 
    cliente_id,
    nome,
    email,
    data_cadastro,
    CASE 
        WHEN total_compras > 1000 THEN 'VIP'
        ELSE 'Regular'
    END as categoria
FROM {{ source('ecommerce', 'clientes') }}

2.2. Sources e Seeds

  • Sources: definem tabelas de origem externa (sistemas OLTP, APIs). São declaradas em YAML e permitem testes de freshness.
  • Seeds: arquivos CSV que podem ser carregados como tabelas no warehouse, úteis para dados de referência pequenos.
-- schema.yml
sources:
  - name: ecommerce
    tables:
      - name: clientes
        freshness:
          warn_after: {count: 12, period: hour}

2.3. Tests, Snapshots e Exposures

  • Tests: verificações de qualidade (unique, not_null, accepted_values, customizados).
  • Snapshots: capturam mudanças em tabelas tipo Type-2 SCD (Slowly Changing Dimensions).
  • Exposures: documentam como os dados são usados downstream (dashboards, relatórios).

3. Estrutura de um projeto dbt: código de produto aplicado a dados

3.1. Organização de pastas

meu_projeto_dbt/
├── models/
│   ├── staging/
│   ├── marts/
│   └── intermediate/
├── tests/
├── snapshots/
├── macros/
├── seeds/
├── dbt_project.yml
└── packages.yml

O arquivo dbt_project.yml configura o projeto:

name: 'meu_projeto'
version: '1.0.0'
profile: 'snowflake'

models:
  meu_projeto:
    staging:
      +materialized: view
      +schema: staging
    marts:
      +materialized: table
      +schema: analytics

3.2. Materializações

  • view: cria uma view no warehouse (padrão).
  • table: recria a tabela a cada execução.
  • incremental: adiciona apenas novos registros.
  • ephemeral: modelo temporário usado apenas como CTE.

3.3. Documentação e lineage

O dbt gera automaticamente um site de documentação com o comando dbt docs generate. Esse site mostra:
- Diagrama de lineage interativo (árvore de dependências)
- Descrições de colunas e modelos
- Resultados de testes

4. Ciclo de vida de desenvolvimento com dbt

4.1. Comandos principais

# Desenvolvimento local
dbt run          -- Executa todos os models
dbt build        -- Executa models + testes + snapshots
dbt compile      -- Gera SQL compilado (sem executar)
dbt run --select dim_clientes+ -- Executa modelo e seus dependentes

4.2. Testes e validação

-- tests/generic/positive_value.sql
{% test positive_value(model, column_name) %}
SELECT *
FROM {{ model }}
WHERE {{ column_name }} < 0
{% endtest %}
-- schema.yml
models:
  - name: fat_vendas
    columns:
      - name: valor_total
        tests:
          - positive_value

4.3. Versionamento e CI/CD

O dbt se integra nativamente com Git. Uma pipeline típica de CI/CD:

# .github/workflows/dbt_ci.yml
jobs:
  dbt_ci:
    steps:
      - uses: actions/checkout@v3
      - run: dbt deps
      - run: dbt build --select state:modified+ --defer

5. Padrões avançados e boas práticas

5.1. Macros e Jinja

Macros permitem reutilizar lógica SQL:

-- macros/clean_string.sql
{% macro clean_string(column_name) %}
    TRIM(REGEXP_REPLACE({{ column_name }}, '[^a-zA-Z0-9 ]', ''))
{% endmacro %}

-- Uso no model:
SELECT {{ clean_string('nome_cliente') }} as nome_limpo
FROM clientes

5.2. Estratégias de transformação incremental

Para grandes volumes, use modelos incrementais:

{{ config(
    materialized='incremental',
    unique_key='order_id',
    incremental_strategy='merge'
) }}

SELECT *
FROM {{ ref('stg_orders') }}
{% if is_incremental() %}
WHERE updated_at > (SELECT MAX(updated_at) FROM {{ this }})
{% endif %}

5.3. Hooks e operadores

Hooks executam comandos antes/depois das transformações:

-- dbt_project.yml
on_run_start:
  - "GRANT USAGE ON SCHEMA {{ target.schema }} TO ROLE ANALYTICS"
on_run_end:
  - "{{ log('Execução concluída!', info=True) }}"

6. Integração com o ecossistema de dados moderno

6.1. Conectando a data warehouses

O dbt suporta nativamente:
- Snowflake (via conexão nativa ou Snowpark)
- BigQuery (via service account)
- Redshift (via psycopg2)
- Databricks (via Spark SQL ou Delta Lake)
- PostgreSQL, DuckDB e outros

6.2. dbt + orquestradores

# Exemplo de DAG no Airflow
with DAG('dbt_pipeline', schedule='@daily') as dag:
    dbt_run = BashOperator(
        task_id='dbt_run',
        bash_command='dbt run --models marts+'
    )
    dbt_test = BashOperator(
        task_id='dbt_test',
        bash_command='dbt test --select marts+'
    )
    dbt_run >> dbt_test

6.3. dbt Cloud vs. dbt Core

Característica dbt Core dbt Cloud
Custo Gratuito Pago (SaaS)
Interface Linha de comando Web IDE
CI/CD Manual Integrado
Gerenciamento Você gerencia Gerenciado

7. Casos de uso práticos e resultados mensuráveis

7.1. Exemplo completo: pipeline de vendas

-- models/staging/stg_orders.sql
SELECT 
    order_id,
    customer_id,
    order_date,
    total_amount,
    status
FROM {{ source('raw', 'orders') }}
WHERE order_date >= '2020-01-01'

-- models/marts/dim_customers.sql
SELECT 
    customer_id,
    customer_name,
    city,
    segment
FROM {{ ref('stg_customers') }}

-- models/marts/fct_orders.sql
SELECT 
    o.order_id,
    o.customer_id,
    o.order_date,
    o.total_amount,
    c.customer_name,
    c.city
FROM {{ ref('stg_orders') }} o
JOIN {{ ref('dim_customers') }} c 
    ON o.customer_id = c.customer_id

7.2. Redução de tempo de entrega

Antes do dbt: adicionar nova fonte de dados levava 2-3 semanas (scripts manuais, testes manuais, documentação separada). Com dbt: 2-3 dias (model + teste + documentação automática).

7.3. Métricas de sucesso

  • 100% de testes passando em cada deploy
  • Documentação viva atualizada automaticamente
  • Tempo de onboarding de novos analistas reduzido de semanas para dias
  • Confiança do time nos dados (testes de qualidade rodam a cada execução)

O dbt transformou a engenharia de dados ao aplicar princípios de desenvolvimento de software — modularidade, testabilidade, versionamento e documentação — ao mundo das transformações SQL. Se você ainda não experimentou, comece com dbt init e veja como seus dados podem ser tratados como código de produto.

Referências