Trois techniques rendent les modèles dbt installables par n’importe qui : sources configurables avec var(), flags d’activation/désactivation et noms de modèles avec namespace. L’approche de l’équipe Fivetran pour ces patterns est devenue un standard de facto. Omettre l’un d’eux cassera les installations dans des environnements avec des structures de schémas ou de nommage différentes.
Sources configurables avec var()
Ne codez jamais en dur l’emplacement des données source. Ce qui est raw_stripe.payments dans votre warehouse est analytics.stripe_data.payment_events dans celui de quelqu’un d’autre. La fonction var() avec des valeurs par défaut sensées gère cela proprement.
Définition de source
sources: - name: my_package schema: "{{ var('my_package_schema', 'my_data') }}" database: "{{ var('my_package_database', target.database) }}" tables: - name: events identifier: "{{ var('my_package_events_identifier', 'events') }}"Trois niveaux de configurabilité ici :
- Schéma — où se trouvent les tables source. La plupart des utilisateurs devront le modifier.
- Base de données — par défaut sur la base de données target de l’utilisateur. Nécessaire uniquement pour les configurations cross-database.
- Identifiant — le nom réel de la table. Gère les cas où une table a un nom différent dans le warehouse de quelqu’un (
raw_eventsau lieu d’events).
Modèle base
-- models/base/base__my_package__events.sql
WITH source AS (
SELECT event_id, event_name, event_timestamp, user_id FROM {{ source('my_package', 'events') }}
)
SELECT event_id, event_name, event_timestamp, user_idFROM sourceLe modèle base référence source(), qui résout le schéma, la base de données et l’identifiant depuis la définition YAML. Les utilisateurs pointent le package vers leur propre schéma en définissant my_package_schema dans leur dbt_project.yml :
# dbt_project.yml de l'utilisateurvars: my_package_schema: 'raw_stripe' my_package_events_identifier: 'payment_events'C’est le même pattern de couche base utilisé dans les projets ordinaires, avec var() encapsulant les parties qui diffèrent selon les environnements.
Convention de nommage des variables
Suivez la convention établie par Fivetran et dbt Labs :
| Paramètre | Nom de variable | Exemple |
|---|---|---|
| Schéma | {package}_schema | my_package_schema |
| Base de données | {package}_database | my_package_database |
| Identifiant de table | {package}_{table}_identifier | my_package_events_identifier |
| Feature flag | {package}__{modèle}_enabled | my_package__daily_summary_enabled |
Le double underscore avant le nom de modèle dans les feature flags sépare le namespace du package du nom du paramètre, évitant l’ambiguïté avec les noms de packages multi-mots.
Activer/désactiver des modèles
Tous les utilisateurs n’ont pas besoin de chaque modèle de votre package. Les flags d’activation/désactivation permettent aux utilisateurs de désactiver les parties dont ils n’ont pas besoin, réduisant le temps de build et l’encombrement du warehouse.
-- models/marts/my_package__daily_summary.sql{{ config(enabled=var('my_package__daily_summary_enabled', true)) }}
SELECT DATE(event_timestamp) AS event_date, COUNT(DISTINCT user_id) AS unique_users, COUNT(*) AS total_eventsFROM {{ ref('base__my_package__events') }}GROUP BY 1La config enabled accepte directement un appel var(). Par défaut à true pour que les modèles soient inclus sauf désactivation explicite. Les utilisateurs se désabonnent dans leur dbt_project.yml :
vars: my_package__daily_summary_enabled: falseQuand un modèle est désactivé, dbt le ignore entièrement — pas de compilation, pas d’exécution, pas d’objet warehouse. Les modèles en aval qui référencent un modèle désactivé échoueront, donc documentez quels modèles peuvent être désactivés indépendamment. Un pattern courant est de regrouper les modèles en « modules » avec un seul flag :
vars: my_package__daily_models_enabled: true my_package__weekly_models_enabled: true my_package__monthly_models_enabled: false # Désactiver toutes les agrégations mensuellesNoms de modèles avec namespace
Chaque modèle de votre package devrait commencer par le nom du package. Si votre package s’appelle revenue_tools, nommez vos modèles revenue_tools__monthly_mrr et revenue_tools__churn_events, pas monthly_mrr et churn_events.
Cela évite les collisions de nommage lorsque les utilisateurs ont plusieurs packages installés. Sans préfixes, deux packages définissant tous deux un modèle customers entreront en conflit, et les messages d’erreur ne sont pas toujours clairs sur la cause.
La convention s’applique à tous les types de modèles :
| Couche | Exemple |
|---|---|
| Base | base__my_package__events |
| Intermédiaire | my_package__enriched_events |
| Mart | my_package__daily_summary |
Les modèles base suivent la convention de nommage base standard (base__source__entity) avec le nom du package comme source. Les modèles des couches supérieures utilisent le nom du package directement comme préfixe.
C’est verbeux, mais les collisions entre packages sont l’une des expériences de débogage les plus frustrantes en dbt. Un utilisateur ayant fivetran_stripe, fivetran_shopify et votre package revenue_tools installés a besoin de noms de modèles sans ambiguïté.
En synthèse
Voici une configuration complète de source et de modèle base pour un package appelé ad_analytics :
sources: - name: ad_analytics schema: "{{ var('ad_analytics_schema', 'raw_ads') }}" database: "{{ var('ad_analytics_database', target.database) }}" tables: - name: campaigns identifier: "{{ var('ad_analytics_campaigns_identifier', 'campaigns') }}" - name: ad_spend identifier: "{{ var('ad_analytics_ad_spend_identifier', 'ad_spend') }}"-- models/base/base__ad_analytics__campaigns.sql
WITH source AS (
SELECT * FROM {{ source('ad_analytics', 'campaigns') }}
),
renamed AS (
SELECT campaign_id, campaign_name, platform, start_date, end_date, budget_amount, currency_code FROM source
)
SELECT * FROM renamed-- models/marts/ad_analytics__daily_spend.sql{{ config(enabled=var('ad_analytics__daily_spend_enabled', true)) }}
SELECT DATE(spend_date) AS spend_date, c.campaign_name, c.platform, SUM(s.amount) AS total_spend, SUM(s.impressions) AS total_impressions, SUM(s.clicks) AS total_clicksFROM {{ ref('base__ad_analytics__ad_spend') }} sLEFT JOIN {{ ref('base__ad_analytics__campaigns') }} c ON s.campaign_id = c.campaign_idGROUP BY 1, 2, 3# dbt_project.yml (valeurs par défaut du package)vars: ad_analytics_schema: 'raw_ads' ad_analytics_database: null ad_analytics__daily_spend_enabled: trueLes utilisateurs personnalisent avec une configuration minimale :
# dbt_project.yml de l'utilisateurvars: ad_analytics_schema: 'my_company_ads'Tout le reste utilise les valeurs par défaut. L’utilisateur obtient un package fonctionnel avec une seule ligne de configuration.