La plupart des équipes adoptent les contrats de modèles dbt en les appliquant rétrospectivement aux modèles existants : le modèle existe, et quelqu’un écrit le YAML pour le décrire. Une approche alternative pour les nouveaux modèles destinés à servir des consommateurs en aval est de définir le contrat avant d’écrire du SQL.
L’analogie avec la conception d’API
Les ingénieurs logiciels ne construisent pas un endpoint d’API et ne déterminent ensuite ce que devrait être le schéma de réponse. Ils définissent l’interface — quels champs la réponse contiendra, quels types ils auront, quelles contraintes s’appliquent — s’accordent avec les clients qui la consommeront, puis l’implémentent. La définition de l’interface vient en premier ; l’implémentation suit.
Les modèles de données peuvent fonctionner de la même façon. La question n’est pas “qu’est-ce que mon SQL produit ?” — c’est “de quoi les consommateurs ont-ils besoin ?” Définir le contrat en premier signifie commencer par cette question et faire en sorte que le SQL satisfasse la réponse plutôt que l’inverse.
Le workflow contract-first
Étape 1 : S’accorder sur l’interface. C’est une conversation entre l’équipe qui construit le modèle et les équipes qui le consomment. Quelles colonnes le consommateur a-t-il besoin ? Quels types ? Quelles contraintes ? Cela se passe avant qu’un code soit écrit. Le résultat est un accord, pas du YAML.
Étape 2 : Écrire le contrat YAML. Traduire l’accord en une définition de modèle dbt avec contract: {enforced: true}, des déclarations de colonnes avec les types, et toutes les contraintes :
models: - name: mrt__analytics__customers access: public config: materialized: table contract: enforced: true columns: - name: customer__id data_type: integer constraints: - type: not_null - type: primary_key - name: customer__name data_type: text - name: customer__lifetime_value data_type: numeric(38,2) - name: customer__segment data_type: text - name: customer__is_active data_type: booleanÉtape 3 : Implémenter le modèle. Écrire le SQL qui satisfait le contrat. Si votre requête retourne une colonne avec le mauvais type, ou retourne des colonnes que le YAML ne déclare pas, dbt compile vous le dit immédiatement :
Compilation Error in model mrt__analytics__customers This model has an enforced contract that failed.
| column_name | definition_type | contract_type | mismatch_reason || ------------------------ | --------------- | ------------- | ------------------ || customer__lifetime_value | TEXT | NUMERIC(38,2) | data type mismatch |L’étape de compilation est la boucle de rétroaction. Vous ne lancez pas le build complet et ne vérifiez pas les sorties de tests — vous compilez, vous voyez exactement ce qui ne correspond pas, et vous le corrigez. La CI valide le reste.
Étape 4 : Marquer le contrat comme l’interface canonique. Une fois que le modèle se construit proprement, définissez access: public et communiquez la version aux consommateurs. Ils peuvent commencer à référencer ref('your_project', 'mrt__analytics__customers') en sachant que le contrat garantit la forme.
Pourquoi cet ordre est important
L’approche de rétro-application — écrire le modèle, ajouter le contrat pour le décrire — traite le contrat comme de la documentation de ce qui existe déjà. Le contrat reflète les décisions d’implémentation prises sans apport des consommateurs.
Le contract-first inverse la dépendance. Les consommateurs expriment leurs besoins. Le contrat capture ces besoins. Le SQL existe pour satisfaire le contrat. C’est une différence significative en pratique :
- Les colonnes dont les consommateurs n’ont pas besoin ne se retrouvent pas dans le contrat, ce qui garde les marts ciblés
- Les décisions de type sont prises consciemment plutôt que de prendre par défaut ce que SQL retourne
- Les changements breaking nécessitent une renégociation explicite, parce que le contrat était l’accord original
- Plusieurs consommateurs en aval peuvent réviser le YAML proposé et signaler des problèmes avant que l’implémentation commence
Le coût de friction est une coordination initiale, qui semble plus lente. La contrepartie est que l’interface du modèle est délibérément conçue plutôt qu’accidentellement documentée.
Intégration ODCS + Data Contract CLI
L’Open Data Contract Standard (ODCS) va encore plus loin. Vous pouvez définir un contrat en utilisant la spécification YAML d’ODCS — qui capture les SLA, les métadonnées de propriété et les règles de qualité au-delà de ce que dbt gère — puis générer le YAML du modèle dbt à partir de celui-ci en utilisant le Data Contract CLI :
datacontract export --format dbtLe YAML dbt généré est un sous-ensemble du contrat plus large, concentré sur les garanties structurelles que dbt peut appliquer au moment de la compilation. Le contrat ODCS plus large vit comme un document autonome couvrant l’accord complet sur le data product : qui en est propriétaire, quels SLA s’appliquent, quelles règles de qualité sont intégrées.
Cela fait le pont entre deux niveaux de contrat :
- Niveau organisationnel : le contrat ODCS, convenu entre producteurs et consommateurs, couvrant l’ensemble du cycle de vie du data product
- Niveau technique : le contrat de modèle dbt, appliqué au moment de la compilation, couvrant les garanties structurelles
Le workflow : définissez le contrat ODCS (avec ou sans outillage, un fichier YAML suffit), exécutez datacontract export --format dbt pour générer les déclarations de colonnes initiales, puis ajoutez le SQL d’implémentation. Les changements apportés au contrat organisationnel peuvent être ré-exportés pour maintenir le YAML dbt à jour.
Pour les équipes qui n’ont pas encore besoin des métadonnées organisationnelles d’ODCS, l’approche contract-first ne le nécessite pas. Vous écrivez simplement le YAML vous-même, vous vous accordez avec les consommateurs avant d’écrire le SQL, et vous utilisez dbt compile comme boucle de rétroaction d’implémentation.
Point de départ pratique
L’approche contract-first est la plus précieuse pour :
- Les nouveaux modèles qui seront
access: public - Les modèles dans une configuration dbt Mesh où des consommateurs cross-projet existent dès le premier jour
- Les tables à enjeux élevés (tableaux de bord exécutifs, flux de données partenaires) où la stabilité de l’interface est immédiatement importante
Pour les modèles internes dont personne d’autre ne dépend, la surcharge d’une conception formelle contract-first n’est pas justifiée. L’investissement en gouvernance s’adapte au nombre de consommateurs qui dépendent de l’interface.
La stratégie de déploiement pour les modèles existants décrit comment appliquer des contrats sur des modèles déjà construits. Le contract-first est la version prospective de ce travail — l’approche qui rend le rétro-application inutile.