dbt Best Practices

Free Lesson

Advertisement

dbt Best Practices

Best Practices Architecture

Architecture Diagram
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     DBT BEST PRACTICES FRAMEWORK                            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚                    PRACTICE DIMENSIONS                               β”‚   β”‚
β”‚  β”‚                                                                     β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚   β”‚
β”‚  β”‚  β”‚   CODE       β”‚  β”‚  PROJECT     β”‚  β”‚    OPERATIONS            β”‚ β”‚   β”‚
β”‚  β”‚  β”‚   STYLE      β”‚  β”‚  STRUCTURE   β”‚  β”‚                          β”‚ β”‚   β”‚
β”‚  β”‚  β”‚              β”‚  β”‚              β”‚  β”‚                          β”‚ β”‚   β”‚
β”‚  β”‚  β”‚ β€’ Naming     β”‚  β”‚ β€’ Layers     β”‚  β”‚ β€’ CI/CD                  β”‚ β”‚   β”‚
β”‚  β”‚  β”‚ β€’ Formatting β”‚  β”‚ β€’ Modules    β”‚  β”‚ β€’ Monitoring             β”‚ β”‚   β”‚
β”‚  β”‚  β”‚ β€’ Comments   β”‚  β”‚ β€’ Packages   β”‚  β”‚ β€’ Alerting               β”‚ β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                              β”‚                                              β”‚
β”‚                              β–Ό                                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚                    QUALITY ASSURANCE                                 β”‚   β”‚
β”‚  β”‚                                                                     β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚   β”‚
β”‚  β”‚  β”‚   TESTING    β”‚  β”‚  DOCUMENTA-  β”‚  β”‚    CODE REVIEW           β”‚ β”‚   β”‚
β”‚  β”‚  β”‚              β”‚  β”‚  TION        β”‚  β”‚                          β”‚ β”‚   β”‚
β”‚  β”‚  β”‚ β€’ Unit       β”‚  β”‚ β€’ Descriptionsβ”‚  β”‚ β€’ Peer review            β”‚ β”‚   β”‚
β”‚  β”‚  β”‚ β€’ Integrationβ”‚  β”‚ β€’ Lineage    β”‚  β”‚ β€’ Automated checks       β”‚ β”‚   β”‚
β”‚  β”‚  β”‚ β€’ Data       β”‚  β”‚ β€’ Examples   β”‚  β”‚ β€’ Style enforcement      β”‚ β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Naming Conventions

Architecture Diagram
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     NAMING CONVENTIONS                                       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚                    MODEL NAMING                                      β”‚   β”‚
β”‚  β”‚                                                                     β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚
β”‚  β”‚  β”‚  Pattern: {layer}_{entity}                                  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚                                                             β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Staging:                                                   β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”œβ”€β”€ stg_orders          (1:1 with source)                 β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”œβ”€β”€ stg_customers       (1:1 with source)                 β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  └── stg_products        (1:1 with source)                 β”‚   β”‚   β”‚
β”‚  β”‚  β”‚                                                             β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Intermediate:                                              β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”œβ”€β”€ int_orders_joined   (joins staging models)            β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”œβ”€β”€ int_orders_aggregated (aggregations)                  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  └── int_orders_cleaned  (data cleaning)                   β”‚   β”‚   β”‚
β”‚  β”‚  β”‚                                                             β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Marts:                                                     β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”œβ”€β”€ fct_orders          (fact table)                      β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”œβ”€β”€ dim_customers       (dimension table)                 β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  └── agg_orders_daily    (aggregated)                      β”‚   β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                              β”‚                                              β”‚
β”‚                              β–Ό                                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚                    OTHER NAMING                                     β”‚   β”‚
β”‚  β”‚                                                                     β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚
β”‚  β”‚  β”‚  Sources:                                                   β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”œβ”€β”€ {source}_{table}    (e.g., shopify_orders)            β”‚   β”‚   β”‚
β”‚  β”‚  β”‚                                                             β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Tests:                                                     β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”œβ”€β”€ test_{model}_{column} (e.g., test_orders_amount)      β”‚   β”‚   β”‚
β”‚  β”‚  β”‚                                                             β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Macros:                                                    β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”œβ”€β”€ {verb}_{entity}    (e.g., create_table, join_tables)  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚                                                             β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Variables:                                                 β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”œβ”€β”€ {entity}_{setting} (e.g., start_date, enable_audit)   β”‚   β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Project Structure

Architecture Diagram
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     PROJECT STRUCTURE BEST PRACTICES                        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚                    RECOMMENDED STRUCTURE                             β”‚   β”‚
β”‚  β”‚                                                                     β”‚   β”‚
β”‚  β”‚  my_project/                                                       β”‚   β”‚
β”‚  β”‚  β”œβ”€β”€ dbt_project.yml                                               β”‚   β”‚
β”‚  β”‚  β”œβ”€β”€ packages.yml                                                  β”‚   β”‚
β”‚  β”‚  β”œβ”€β”€ profiles.yml                                                  β”‚   β”‚
β”‚  β”‚  β”‚                                                                  β”‚   β”‚
β”‚  β”‚  β”œβ”€β”€ models/                                                       β”‚   β”‚
β”‚  β”‚  β”‚   β”œβ”€β”€ staging/                                                  β”‚   β”‚
β”‚  β”‚  β”‚   β”‚   β”œβ”€β”€ _sources.yml        ◄── Source definitions            β”‚   β”‚
β”‚  β”‚  β”‚   β”‚   β”œβ”€β”€ stg_customers.sql                                    β”‚   β”‚
β”‚  β”‚  β”‚   β”‚   β”œβ”€β”€ stg_orders.sql                                       β”‚   β”‚
β”‚  β”‚  β”‚   β”‚   └── stg_products.sql                                     β”‚   β”‚
β”‚  β”‚  β”‚   β”‚                                                            β”‚   β”‚
β”‚  β”‚  β”‚   β”œβ”€β”€ intermediate/                                             β”‚   β”‚
β”‚  β”‚  β”‚   β”‚   β”œβ”€β”€ int_orders_joined.sql                                β”‚   β”‚
β”‚  β”‚  β”‚   β”‚   β”œβ”€β”€ int_orders_aggregated.sql                            β”‚   β”‚
β”‚  β”‚  β”‚   β”‚   └── int_orders_cleaned.sql                               β”‚   β”‚
β”‚  β”‚  β”‚   β”‚                                                            β”‚   β”‚
β”‚  β”‚  β”‚   └── marts/                                                   β”‚   β”‚
β”‚  β”‚  β”‚       β”œβ”€β”€ finance/                                              β”‚   β”‚
β”‚  β”‚  β”‚       β”‚   β”œβ”€β”€ fct_orders.sql                                   β”‚   β”‚
β”‚  β”‚  β”‚       β”‚   β”œβ”€β”€ dim_customers.sql                                β”‚   β”‚
β”‚  β”‚  β”‚       β”‚   └── fct_revenue.sql                                  β”‚   β”‚
β”‚  β”‚  β”‚       β”‚                                                        β”‚   β”‚
β”‚  β”‚  β”‚       β”œβ”€β”€ marketing/                                            β”‚   β”‚
β”‚  β”‚  β”‚       β”‚   β”œβ”€β”€ fct_campaigns.sql                                β”‚   β”‚
β”‚  β”‚  β”‚       β”‚   └── dim_campaigns.sql                                β”‚   β”‚
β”‚  β”‚  β”‚       β”‚                                                        β”‚   β”‚
β”‚  β”‚  β”‚       └── product/                                              β”‚   β”‚
β”‚  β”‚  β”‚           β”œβ”€β”€ fct_events.sql                                   β”‚   β”‚
β”‚  β”‚  β”‚           └── dim_users.sql                                    β”‚   β”‚
β”‚  β”‚  β”‚                                                                β”‚   β”‚
β”‚  β”‚  β”œβ”€β”€ seeds/                    ◄── CSV seed data                  β”‚   β”‚
β”‚  β”‚  β”œβ”€β”€ snapshots/                ◄── SCD snapshots                  β”‚   β”‚
β”‚  β”‚  β”œβ”€β”€ tests/                    ◄── Custom data tests              β”‚   β”‚
β”‚  β”‚  β”œβ”€β”€ macros/                   ◄── Reusable macros                β”‚   β”‚
β”‚  β”‚  β”œβ”€β”€ analysis/                 ◄── Ad-hoc analysis                β”‚   β”‚
β”‚  β”‚  └── docs/                     ◄── Documentation                  β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Testing Strategy

Architecture Diagram
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     TESTING STRATEGY                                        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚                    TEST PYRAMID                                      β”‚   β”‚
β”‚  β”‚                                                                     β”‚   β”‚
β”‚  β”‚                           β–²                                         β”‚   β”‚
β”‚  β”‚                          β•± β•²                                        β”‚   β”‚
β”‚  β”‚                         β•±   β•²                                       β”‚   β”‚
β”‚  β”‚                        β•± E2E β•²         End-to-end tests            β”‚   β”‚
β”‚  β”‚                       ╱───────╲        (few, slow, expensive)       β”‚   β”‚
β”‚  β”‚                      β•±         β•²                                    β”‚   β”‚
β”‚  β”‚                     β•±Integrationβ•²     Integration tests             β”‚   β”‚
β”‚  β”‚                    ╱─────────────╲    (moderate, medium speed)       β”‚   β”‚
β”‚  β”‚                   β•±               β•²                                 β”‚   β”‚
β”‚  β”‚                  β•±     Unit        β•²   Unit tests                   β”‚   β”‚
β”‚  β”‚                 ╱───────────────────╲  (many, fast, cheap)          β”‚   β”‚
β”‚  β”‚                β•±                     β•²                              β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                              β”‚                                              β”‚
β”‚                              β–Ό                                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚                    TEST COVERAGE TARGETS                             β”‚   β”‚
β”‚  β”‚                                                                     β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚
β”‚  β”‚  β”‚  Model Tests:                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”œβ”€β”€ Every model has tests                                  β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”œβ”€β”€ Every primary key is tested for uniqueness             β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”œβ”€β”€ Every foreign key is tested for relationships          β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”œβ”€β”€ Critical columns are tested for not_null               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  └── Business rules are tested with custom tests            β”‚   β”‚   β”‚
β”‚  β”‚  β”‚                                                             β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Source Tests:                                               β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”œβ”€β”€ Source freshness is monitored                          β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  └── Critical source columns are tested                     β”‚   β”‚   β”‚
β”‚  β”‚  β”‚                                                             β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  Coverage Goals:                                             β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”œβ”€β”€ Model coverage: 100%                                   β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β”œβ”€β”€ Column coverage: 80%                                   β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  └── Business rule coverage: 90%                            β”‚   β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Detailed Explanation

Best practices in dbt ensure maintainable, scalable, and reliable data transformations.

Code Style

  1. Consistent formatting - Use consistent indentation and spacing
  2. Descriptive naming - Clear, meaningful names for all objects
  3. Modular code - Small, focused models and macros
  4. Documentation - Comprehensive descriptions and examples

Project Structure

  1. Layered architecture - staging β†’ intermediate β†’ marts
  2. Domain organization - Group by business domain
  3. Consistent patterns - Apply patterns consistently
  4. Separation of concerns - Clear boundaries between layers

Testing Strategy

  1. Test everything - Models, sources, macros
  2. Automate tests - Run tests in CI/CD
  3. Monitor results - Track test pass/fail rates
  4. Alert on failures - Notify on test failures

Performance Optimization

  1. Use incremental models - For large fact tables
  2. Partition and cluster - Optimize for query patterns
  3. Monitor performance - Track query times
  4. Optimize continuously - Improve based on metrics

Documentation

  1. Document all models - Clear descriptions
  2. Track lineage - End-to-end data flow
  3. Provide examples - Sample queries and outputs
  4. Keep documentation current - Update with changes

Code Examples

Model Documentation Template

# models/marts/fct_orders.yml
version: 2

models:
  - name: fct_orders
    description: >
      Fact table containing all order transactions. This is the central
      fact table for the order analytics domain.
      
      **Grain**: One row per order
      
      **Key Business Questions**:
      - What is our total revenue?
      - How many orders do we process?
      - What is the average order value?
      
      **Data Source**: Shopify via Fivetran
      **Refresh Frequency**: Hourly
      **Owner**: Data Engineering Team
    
    config:
      tags: ['finance', 'core', 'production']
      meta:
        owner: data-engineering
        team: analytics
        cost_center: finance
    
    columns:
      - name: order_id
        description: "Unique identifier for each order"
        data_tests:
          - unique
          - not_null
        meta:
          system: shopify
          pii: false
      
      - name: customer_id
        description: "Foreign key to dim_customers"
        data_tests:
          - not_null
          - relationships:
              to: ref('dim_customers')
              field: customer_id
        meta:
          pii: false
      
      - name: order_date
        description: "Date when the order was placed"
        data_tests:
          - not_null
        meta:
          format: YYYY-MM-DD

Standardized Staging Model

-- models/staging/stg_orders.sql
{{
    config(
        materialized='view',
        schema='staging'
    )
}}

with source as (
    select * from {{ source('shopify', 'orders') }}
),

renamed as (
    select
        -- Primary keys
        id as order_id,
        customer_id,
        
        -- Dimensions
        status as order_status,
        financial_status,
        fulfillment_status,
        
        -- Measures
        {{ dbt_utils.money_snapshot(amount) }} as order_amount,
        {{ dbt_utils.money_snapshot(total_discounts) }} as discount_amount,
        {{ dbt_utils.money_snapshot(total_tax) }} as tax_amount,
        
        -- Timestamps
        created_at as order_created_at,
        updated_at as order_updated_at,
        
        -- Metadata
        _fivetran_synced as synced_at
    from source
)

select * from renamed

Standardized Fact Model

-- models/marts/fct_orders.sql
{{
    config(
        materialized='incremental',
        unique_key='order_id',
        incremental_strategy='merge',
        partition_by={
            "field": "order_date",
            "data_type": "date"
        },
        cluster_by=['customer_id', 'order_status'],
        tags=['finance', 'core', 'production']
    )
}}

with orders as (
    select * from {{ ref('stg_orders') }}
),

customers as (
    select * from {{ ref('dim_customers') }}
),

order_items as (
    select * from {{ ref('stg_order_items') }}
),

final as (
    select
        -- Primary key
        orders.order_id,
        
        -- Foreign keys
        orders.customer_id,
        
        -- Dimensions
        customers.customer_name,
        customers.segment as customer_segment,
        orders.order_status,
        orders.order_date,
        
        -- Measures
        orders.order_amount,
        orders.discount_amount,
        orders.tax_amount,
        count(order_items.item_id) as item_count,
        
        -- Timestamps
        orders.order_created_at,
        orders.order_updated_at,
        current_timestamp() as dbt_updated_at
    from orders
    left join customers on orders.customer_id = customers.customer_id
    left join order_items on orders.order_id = order_items.order_id
    group by 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
)

select * from final

{% if is_incremental() %}
where dbt_updated_at > (select max(dbt_updated_at) from {{ this }})
{% endif %}

Testing Template

# models/marts/fct_orders_tests.yml
version: 2

models:
  - name: fct_orders
    tests:
      - dbt_utils.unique_combination_of_columns:
          combination_of_columns:
            - order_id
      
      - dbt_utils.accepted_range:
          min_value: 0
          max_value: 1000000
          column_name: order_amount
    
    columns:
      - name: order_id
        data_tests:
          - unique
          - not_null
      
      - name: customer_id
        data_tests:
          - not_null
          - relationships:
              to: ref('dim_customers')
              field: customer_id
      
      - name: order_amount
        data_tests:
          - not_null
          - dbt_utils.accepted_range:
              min_value: 0
              max_value: 1000000
      
      - name: order_date
        data_tests:
          - not_null
          - dbt_utils.expression_is_true:
              expression: "order_date <= current_date()"

Macro Template

-- macros/generate_generic_test.sql
{% macro generate_generic_test(test_name, model, column_name, config) %}
    {% set test_sql %}
        select
            '{{ test_name }}' as test_name,
            '{{ model }}' as model_name,
            '{{ column_name }}' as column_name,
            count(*) as failures
        from {{ model }}
        where {{ column_name }} is null
    {% endset %}
    
    {% set result = run_query(test_sql) %}
    
    {{ return(result) }}
{% endmacro %}

Performance Metrics

MetricDescriptionTarget
Code QualityLinting and style checks100% pass
Test CoveragePercentage of models tested>90%
Documentation CoveragePercentage documented>95%
Build Success RatePercentage of successful builds>99%
Average Build TimeTime to build all models<30min

Best Practices

  1. Follow naming conventions - Consistent, descriptive names
  2. Use layered architecture - staging β†’ intermediate β†’ marts
  3. Test everything - Models, sources, macros
  4. Document comprehensively - Descriptions, lineage, examples
  5. Use version control - All code in Git
  6. Implement CI/CD - Automated testing and deployment
  7. Monitor performance - Track metrics continuously
  8. Review code regularly - Peer reviews and audits

Advertisement

Need Expert dbt Help?

Get personalized tutoring, project support, or professional consulting.

Advertisement