Les contrats de modèle dbt sont explicites sur leur portée : ils ne s’appliquent pas aux sources. Jeremy Cohen était direct à ce sujet quand les contrats ont été livrés : « Je n’envisage pas non plus l’application des contrats aux sources de données. » Les contrats s’exécutent au moment de la compilation en comparant la sortie de votre SQL avec une déclaration YAML — mais les sources sont des tables externes entièrement en dehors du processus de build de dbt.
Cela crée une lacune réelle. Les données en amont qui alimentent vos modèles peuvent changer de schéma, et rien dans le système de contrats natif de dbt ne le détectera.
La lacune que laissent les contrats
La solution de contournement standard — placer un modèle base contractuel directement au-dessus d’une source — comble bien une partie de la lacune. Si Fivetran renomme une colonne dans la source, le contrat du modèle base échoue au moment de la compilation, et le build s’arrête. Vous l’apprenez tôt.
Mais cela ne détecte que les problèmes structurels, et seulement au moment de la transformation. Les données ont déjà atterri dans votre entrepôt avant que quoi que ce soit ne s’exécute. Plus important encore : si une colonne source qui contenait autrefois cinq valeurs distinctes en contient maintenant quinze, le contrat sur le modèle base ne le remarquera pas. Le nom de la colonne est correct, le type est correct, le contrat est satisfait — mais la sémantique a changé, et cette différence se propagera silencieusement dans vos transformations.
dbt-expectations sur les sources
dbt-expectations comble cette lacune. Les tests de niveau schéma du package fonctionnent sur les sources, vous offrant une validation structurelle que les contrats ne peuvent pas fournir là :
sources: - name: raw_data tables: - name: raw_orders data_tests: - dbt_expectations.expect_table_columns_to_match_set: column_list: ["order_id", "customer_id", "amount", "status"] - dbt_expectations.expect_table_column_count_to_equal: value: 4 columns: - name: status data_tests: - dbt_expectations.expect_column_values_to_be_in_set: values: ['pending', 'shipped', 'delivered', 'cancelled'] - name: amount data_tests: - dbt_expectations.expect_column_values_to_be_between: min_value: 0 max_value: 1000000expect_table_columns_to_match_set détecte les colonnes ajoutées ou supprimées. expect_table_column_count_to_equal détecte les changements structurels inattendus même quand vous n’avez pas énuméré les noms de colonnes. Les tests de niveau colonne valident les contraintes de contenu que les contrats ne peuvent pas exprimer même sur les modèles.
C’est particulièrement précieux pour les sources parce que :
- Les changements de schéma dans les sources se produisent en dehors de votre contrôle (l’outil EL fait ce que l’API envoie)
- Vous n’êtes souvent pas propriétaire du système en amont et ne pouvez pas y ajouter de contrats
- Les problèmes détectés à la source remontent avant l’exécution de toute transformation, ce qui est plus tôt et moins coûteux
Où placer les tests sources
Il y a un véritable compromis entre tester à la source versus tester sur le modèle base. Aucune option n’est évidemment correcte.
Tester directement sur les sources :
- Les problèmes remontent avant l’exécution de toute transformation
- Signal clair : c’est un problème de source, pas un bug de transformation
- Les tests s’exécutent sur des tables brutes qui peuvent être volumineuses et coûteuses à scanner
Tester sur les modèles base :
- Permet de combiner les vérifications structurelles (via les contrats) avec les vérifications de contenu en un seul endroit
- Les modèles base filtrent ou dédupliquent souvent, rendant les requêtes moins coûteuses
- En aval de toute transformation EL qui pourrait reformater les données sources
Une séparation pratique qui fonctionne bien : mettre les tests structurels peu coûteux sur les sources et les tests de contenu plus coûteux sur les modèles base.
Sur les sources :
expect_table_columns_to_match_set— c’est peu coûteux car c’est une vérification de métadonnées surINFORMATION_SCHEMA, pas un scan complet de la tableexpect_table_column_count_to_equal— idem, métadonnées uniquement
Sur les modèles base :
expect_column_values_to_be_in_set— une requête SQL sur toutes les lignes ; moins coûteuse sur un modèle base filtré que sur la source bruteexpect_column_values_to_be_between— même raisonnement ; les données filtrées scannent moins de lignes
Les vérifications de métadonnées sont légitimement peu coûteuses à exécuter directement sur les sources. Elles vous informeront de la dérive structurelle sans toucher aux données. Les vérifications de contenu touchent chaque ligne, donc elles appartiennent là où les données sont déjà filtrées.
Le pattern du modèle base contractuel
Combiner le modèle base contractuel avec les expectations au niveau source vous donne deux couches de protection avec des points de détection différents :
# Source : les expectations de niveau schéma détectent la dérive tôtsources: - name: raw_data tables: - name: raw_orders data_tests: - dbt_expectations.expect_table_columns_to_match_set: column_list: ["order_id", "customer_id", "amount", "status"]
# Modèle base : le contrat détecte la non-correspondance structurelle au moment de la compilationmodels: - name: base__orders config: contract: enforced: true columns: - name: order_id data_type: string - name: customer_id data_type: string - name: amount data_type: numeric - name: status data_type: string data_tests: - dbt_expectations.expect_column_values_to_be_in_set: column_name: status values: ['pending', 'shipped', 'delivered', 'cancelled']Le test source s’exécute après la fin du job EL, avant le démarrage de votre exécution dbt — détectant les nouvelles colonnes ou les colonnes supprimées avant qu’aucun SQL ne s’exécute. Le contrat du modèle base détecte les mêmes problèmes structurels au moment de la compilation (le modèle ne se build pas). Les tests de contenu du modèle base détectent la dérive sémantique qu’aucune vérification structurelle ne peut voir.
Cela est le plus important quand votre schéma source change fréquemment. Si vous ingérez depuis une API volatile ou une équipe en amont qui livre des changements sans préavis, cette approche à deux couches vous donne le signal le plus précoce possible — ce qui signifie le moins d’exécutions de pipeline gaspillées et le moins de confusion sur ce qui a cassé et où.
Ce que cela ne couvre toujours pas
La validation des sources avec dbt-expectations s’exécute après le chargement, une fois les données arrivées dans votre entrepôt. Ce n’est pas une vérification avant ingestion. Si vous avez besoin de valider avant le chargement, cela appartient à votre couche EL — dlt a des contrats de schéma natifs qui peuvent imposer la structure avant que les données n’atterrissent.
Pour les anomalies dans les données sources qui ne sont pas des problèmes de schéma — chutes de volume, décalages de distribution, taux de valeurs nulles inattendus — vous regardez la détection d’anomalies d’Elementary ou des outils similaires. Les tests de schéma détectent les changements structurels ; ils ne détectent pas « les données semblent structurellement correctes mais 30% des enregistrements sont manquants ».