Erreurs courantes dans les packages dbt qui brisent les principes de conception fondamentaux de la conception de packages — configurabilité, namespacing et adapter-awareness.
Références de schémas codées en dur
-- Mauvais : fonctionne dans votre projet, casse chez tout le mondeFROM my_database.raw_stripe.paymentsC’est l’anti-pattern le plus courant. FROM my_database.raw_stripe.payments fonctionne dans votre projet parce que vous contrôlez le warehouse. Chaque autre utilisateur a un nom de base de données, un nom de schéma ou un nom de table différent.
Correction : Toujours utiliser source() avec var() pour la configuration du schéma et de la base de données. Voir les patterns de modèles packageables pour l’implémentation complète.
-- Bon : se résout selon la configuration de l'utilisateurFROM {{ source('my_package', 'payments') }}sources: - name: my_package schema: "{{ var('my_package_schema', 'raw_stripe') }}" database: "{{ var('my_package_database', target.database) }}"Le pattern source() + var() ajoute quelques lignes de YAML mais fait la différence entre un package qui s’installe partout et un qui ne fonctionne que sur votre machine.
Implémentations dispatch manquantes
Si votre package utilise du SQL qui varie selon le warehouse et que vous n’écrivez qu’une implémentation default__, les utilisateurs sur d’autres adapters obtiennent un comportement inattendu ou des erreurs.
-- Ne fonctionne que sur Snowflake/Postgres{% macro default__my_date_trunc(datepart, date_expression) %} DATE_TRUNC('{{ datepart }}', {{ date_expression }}){% endmacro %}Le DATE_TRUNC de BigQuery prend les arguments dans un ordre différent : DATE_TRUNC(date_expression, datepart). Un utilisateur BigQuery installant ce package obtient un bug de résultat incorrect silencieux ou une erreur de syntaxe selon l’expression.
Correction : Ajouter des implémentations dispatch pour chaque adapter que vous déclarez supporter. Si votre README dit « fonctionne sur Snowflake, BigQuery et Redshift », testez sur les trois.
{% macro bigquery__my_date_trunc(datepart, date_expression) %} DATE_TRUNC({{ date_expression }}, {{ datepart }}){% endmacro %}Avant d’écrire des macros dispatch personnalisées, vérifiez si dbt Core fournit déjà un équivalent intégré. Depuis dbt-utils v1.0, les macros cross-database comme datediff, dateadd, safe_cast et hash se trouvent dans le namespace dbt. {{ dbt.datediff(...) }} gère les différences d’adapters pour vous.
Contraintes de versions trop strictes
# Force chaque utilisateur à utiliser exactement cette versionpackages: - package: dbt-labs/dbt_utils version: "0.20.1"L’épinglage sur une version spécifique oblige chaque utilisateur à utiliser exactement cette version et crée des conflits de dépendances avec d’autres packages. Si un autre package requiert dbt-utils >=1.0.0 et que le vôtre s’épingle à 0.20.1, dbt deps échoue avec un conflit de version que l’utilisateur doit déboguer.
Correction : Utiliser les plages de versions les plus larges qui fonctionnent réellement.
packages: - package: dbt-labs/dbt_utils version: [">=0.20.0", "<1.0.0"]Testez votre package par rapport au minimum et au maximum de la plage dans votre matrice CI. S’il passe aux deux extrémités, la plage est sûre.
Noms de modèles génériques
Un modèle appelé customers entrera en collision avec le propre modèle customers de l’utilisateur. Un modèle appelé daily_summary entrera en collision avec tout autre package qui a jugé que daily_summary était un bon nom générique.
-- Collision en attente-- models/customers.sqlSELECT * FROM {{ source('my_package', 'customers') }}Correction : Préfixer tout avec le nom de votre package.
-- models/my_package__customers.sqlSELECT * FROM {{ source('my_package', 'customers') }}Cela s’applique à tous les types de modèles : base, intermédiaire et mart. Voir les patterns de namespacing pour la convention complète. La verbosité est une fonctionnalité — revenue_tools__monthly_mrr est sans ambiguïté d’une façon que monthly_mrr ne sera jamais.
Matérialisation en table par défaut
models: my_package: +materialized: tableQuand quelqu’un exécute dbt deps && dbt run, votre package ne devrait pas créer 30 tables physiques dans leur warehouse. Les tables consomment du stockage, prennent plus de temps à construire et créent des objets warehouse que l’utilisateur n’a pas demandés.
Correction : Par défaut, utiliser view dans le dbt_project.yml du package. Laisser les utilisateurs surcharger pour les performances.
models: my_package: +materialized: viewLes utilisateurs souhaitant la matérialisation en table peuvent surcharger dans leur propre projet :
models: my_package: +materialized: tableC’est l’inverse des recommandations normales pour les projets ordinaires, où table est 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 et les performances de requête. Dans le projet de quelqu’un d’autre, vous voulez une empreinte légère que l’utilisateur peut personnaliser.
Pas de require-dbt-version
name: 'my_package'version: '0.1.0'# require-dbt-version est absentSans require-dbt-version, les utilisateurs sur des versions dbt incompatibles obtiennent des erreurs de compilation obscures plutôt qu’un message clair. Un utilisateur sur dbt 1.1 essayant d’utiliser une fonctionnalité de dbt 1.6 verra un échec de compilation Jinja qui ressemble à un bug dans votre package plutôt qu’à une incompatibilité de version.
Correction : Toujours définir require-dbt-version avec une plage couvrant les versions que vous avez réellement testées.
require-dbt-version: [">=1.3.0", "<3.0.0"]Avec le moteur Fusion (dbt 2.0) désormais disponible, [">=1.3.0", "<3.0.0"] est une valeur par défaut raisonnable couvrant à la fois dbt Core 1.x et dbt 2.x. Testez aux deux extrémités dans le CI pour vous en assurer.
Bonus : ne pas documenter les noms de variables
Ce n’est pas un anti-pattern de code, mais il est tout aussi courant. Si votre package a 15 appels var() et que le README ne les liste pas, les utilisateurs doivent lire votre code source pour savoir comment configurer le package.
Correction : Documenter chaque variable dans votre README avec son nom, son objectif et sa valeur par défaut. Un tableau fonctionne bien :
| Variable | Description | Valeur par défaut |
|---|---|---|
my_package_schema | Schéma où se trouvent les données source | 'my_data' |
my_package_database | Base de données pour les données source | target.database |
my_package__daily_summary_enabled | Active le modèle de résumé quotidien | true |
Les utilisateurs devraient pouvoir configurer votre package à partir du README sans lire un seul fichier SQL.