ServicesÀ proposNotesContact Me contacter →
EN FR
Note

Anatomie d'un package dbt

Ce qui distingue un package dbt d'un projet ordinaire — les trois principes de conception, la structure de répertoires standard et la configuration dbt_project.yml pour les packages réutilisables.

Planté
dbtdata engineering

Un package dbt est un projet dbt — mêmes fichiers, même structure, même modèle d’exécution, avec dbt_project.yml comme seul fichier obligatoire. La différence est l’intention : un package est conçu pour être installé dans le projet de quelqu’un d’autre via dbt deps. Cela change chaque décision de conception. Dans un projet ordinaire, coder en dur un nom de schéma est acceptable. Dans un package, cela échoue dès qu’un autre utilisateur l’installe.

Trois principes

Trois principes distinguent un package bien construit d’un projet ordinaire :

  1. Configurable. Aucun nom de base de données, référence de schéma ou identifiant de table codé en dur. Tout ce que les utilisateurs pourraient avoir besoin de personnaliser passe par var(). Voir Patterns de modèles packageables dbt pour les détails d’implémentation.
  2. Namespaced. Les noms de modèles incluent le préfixe du package pour éviter les collisions. my_package__customers, pas customers. Quand un utilisateur a cinq packages installés, les noms génériques comme customers ou daily_summary entreront en collision.
  3. Adapter-aware. Le SQL qui diffère selon les warehouses utilise adapter.dispatch() pour que le package fonctionne sur Snowflake, BigQuery, Redshift et d’autres. Le pattern dispatch gère cela proprement.

Ces principes ne sont pas aspirationnels — ils sont le niveau minimum requis pour un package que d’autres personnes peuvent réellement utiliser. Fivetran maintient plus de 100 packages qui suivent tous ce pattern. Les propres packages de dbt Labs font de même. Le pattern est éprouvé à l’échelle.

Structure de répertoires standard

La structure utilisée par dbt Labs et Fivetran pour leurs propres packages est devenue le standard communautaire :

dbt-my_package/
├── dbt_project.yml # Obligatoire : configuration du package
├── packages.yml # Dépendances en amont
├── macros/
│ ├── my_macro.sql
│ └── _macros.yml # Documentation des macros
├── models/
│ ├── base/
│ └── marts/
├── tests/generic/ # Tests génériques personnalisés
├── integration_tests/ # Sous-projet pour les tests
│ ├── dbt_project.yml
│ ├── packages.yml # Référence le parent via local: ../
│ ├── seeds/ # Données mock
│ ├── models/
│ └── tests/
├── .github/workflows/ # Configuration CI
├── README.md
├── CHANGELOG.md
└── LICENSE

Le sous-répertoire integration_tests/ est la pièce la plus distinctive. Contrairement aux projets ordinaires qui testent sur place, un package ne peut pas se tester lui-même en isolation — il est conçu pour être installé à l’intérieur d’un autre projet. Le pattern des tests d’intégration résout cela avec un sous-projet qui installe le package parent comme dépendance locale.

L’organisation des modèles à l’intérieur d’un package suit la même architecture en trois couches qu’un projet ordinaire, mais avec une structure plus plate. La plupart des packages sautent entièrement la couche intermédiaire puisqu’ils fournissent des briques de construction, non des transformations complètes.

dbt_project.yml pour les packages

Le fichier projet contient quelques paramètres importants spécifiquement pour les packages :

name: 'my_package'
version: '0.1.0'
require-dbt-version: [">=1.3.0", "<3.0.0"]
config-version: 2
models:
my_package:
+materialized: view
vars:
my_package_schema: 'my_data'
my_package_database: null
my_package__some_model_enabled: true

Plages de versions

La plage require-dbt-version devrait inclure à la fois dbt Core 1.x et Fusion 2.x (dbt 2.0). Définir la borne supérieure à <3.0.0 couvre les deux runtimes. Sans cela, les utilisateurs sur des versions incompatibles obtiennent des erreurs de compilation obscures plutôt qu’un message clair « version incompatible ».

Matérialisation par défaut

La matérialisation par défaut doit être view, pas table. Quand quelqu’un exécute dbt deps && dbt run, votre package ne devrait pas créer 30 tables physiques dans leur warehouse. Les utilisateurs peuvent toujours surcharger vers table pour les performances dans leur propre dbt_project.yml :

models:
my_package:
+materialized: table

C’est l’inverse des recommandations pour les projets ordinaires, où les tables sont la valeur par défaut recommandée. La différence est la propriété : dans votre propre projet, vous voulez de la visibilité pour le débogage. Dans le projet de quelqu’un d’autre, vous voulez une empreinte légère.

Valeurs par défaut des variables

Chaque option configurable doit avoir une valeur par défaut sensée déclarée sous vars. La convention de nommage est {nom_package}_{paramètre} pour les paramètres de schéma/base de données et {nom_package}__{modèle}_enabled pour les feature flags (double underscore pour séparer le nom du package du nom du paramètre).

vars:
my_package_schema: 'my_data' # Où se trouvent les données source
my_package_database: null # null = utiliser target.database
my_package__daily_summary_enabled: true # Bascule des modèles individuels
my_package_events_identifier: 'events' # Surcharges de noms de tables

Déclarer les valeurs par défaut ici signifie que les utilisateurs n’ont besoin de surcharger que les paramètres différents de leur environnement. Un utilisateur dont la table d’événements s’appelle raw_events définit une seule variable ; tout le monde reçoit la valeur par défaut.

Qu’en est-il du nom du package ?

Le champ name dans dbt_project.yml devient le namespace pour tout ce qui se trouve dans votre package. Il préfixe les références de modèles, les noms de variables et les définitions de sources. Choisissez-le avec soin car le modifier après la publication est un changement breaking pour chaque utilisateur.

Utilisez le snake_case, gardez-le court et rendez-le descriptif. revenue_tools est meilleur que my_company_revenue_analytics_package_v2. Le nom doit indiquer à quelqu’un ce que fait le package en deux ou trois mots.

Quand un projet ordinaire devient un package

La plupart des packages commencent sous forme de code que vous avez déjà écrit et testé en production dans vos propres projets. L’étape de packaging consiste essentiellement à :

  1. Remplacer les références codées en dur par des appels var()
  2. Préfixer les noms de modèles avec le nom du package
  3. Ajouter des implémentations dispatch pour la portabilité entre warehouses
  4. Construire une suite de tests d’intégration
  5. Rédiger la documentation

Inutile de construire un package de zéro. Extrayez ce qui fonctionne déjà, rendez-le configurable et vérifiez-le avec des tests. Le Hub est accessible via une seule PR lorsque vous êtes prêt, mais un package Git partagé entre les projets de votre équipe est un excellent point de départ.