Naming conventions для моделей
В предыдущем уроке мы посмотрели три слоя. Каждый слой имеет свой префикс имени файла. Это не косметика — имена несут информацию о роли модели, и хорошие имена позволяют читать DAG без открытия dbt docs.
В этом уроке — полный набор conventions из community / dbt Labs guide, типичные ошибки и почему именно эти соглашения, а не другие.
Сводная таблица префиксов
| Слой | Префикс | Формат имени | Пример |
|---|---|---|---|
| staging | stg_ | stg_<source>__<table>.sql | stg_jaffle__customers.sql |
| intermediate | int_ | int_<purpose>.sql | int_order_items_pivoted.sql |
| marts (fact) | fct_ (опционально) | fct_<entity>.sql или <entity>.sql | fct_orders.sql, orders.sql |
| marts (dim) | dim_ (опционально) | dim_<entity>.sql или <entity>.sql | dim_customers.sql, customers.sql |
Кроме того есть несколько менее распространённых:
| Префикс | Применение | Пример |
|---|---|---|
base_ | Чистка до staging (используется в больших проектах) | base_jaffle__customers_unioned.sql |
agg_ | Aggregations (в больших mart-проектах) | agg_revenue_daily.sql |
rpt_ | Report-таблицы (специально для BI) | rpt_executive_dashboard.sql |
wide_ | Wide-таблицы с денормализацией | wide_customer_360.sql |
В курсе придерживаемся базового набора: stg_, int_, fct_, dim_ или без префикса для marts.
staging: stg_<source>__<table>
Полный формат: stg_<source>__<table>. Двойное подчёркивание между source и table — это важная convention из dbt Labs.
Зачем __ (а не _):
- Парсимость.
stg_jaffle__customer_ordersявно: source =jaffle, table =customer_orders. Одинарное_создало бы амбивалентность: где кончается source и начинается table? - Уникальность среди источников. Два source могут иметь таблицу
customers. У вас получитсяstg_jaffle__customersиstg_shopify__customers— никаких коллизий. - Эстетика и привычка. Все профессиональные dbt-проекты пишут так. Если придёшь в team — все ожидают этот формат.
Антипаттерны:
staging_customers.sql— нет префиксаstg_, нет source. Через 6 месяцев не помните, откуда оно пришло.stg_customers.sql— без source. Если source один (только jaffle), допустимо в маленьком проекте. В production-проектах с 3+ sources — обязательно с source.stg_jaffle_customers.sql— одинарное подчёркивание, не парсится. Где конец source:jaffleилиjaffle_customer?stg_jaffle.customers.sql— точка в имени файла. ОС/git могут путаться.
intermediate: int_<purpose>
int_<purpose>.sql — имя описывает что делает модель, не откуда берётся.
Хорошие примеры:
int_order_items_pivoted.sql— order_items в widе-формат.int_payments_joined.sql— JOIN payments на orders.int_active_customers.sql— фильтр активных клиентов.int_revenue_by_segment.sql— pre-aggregation по сегментам.
Плохие примеры:
int_orders.sql— слишком общее. Что делает? Pivot? JOIN? Agregate?int_jaffle_customers.sql— не нужен префикс source в intermediate. Intermediate — это наша логика, не привязка к source.int_customers_v2.sql— версионирование в имени файла — антипаттерн (используйте git).
Если imediate-модель относится к домену, можно положить её в поддиректорию:
models/intermediate/
finance/
int_payments_joined.sql
int_revenue_by_segment.sql
marketing/
int_campaign_costs_pivoted.sql
В этом случае имя файла не нужно префиксить finance_ — это видно из директории.
marts: с префиксами или без
Здесь сообщество разделено на два лагеря.
Лагерь 1 — Kimball-style с префиксами:
models/marts/
fct_orders.sql ← fact-таблица
fct_payments.sql ← fact
dim_customers.sql ← dimension
dim_products.sql ← dimension
Префикс сразу говорит роль таблицы. Удобно для классической data warehousing терминологии.
Лагерь 2 — без префиксов, бизнес-имена:
models/marts/
orders.sql
payments.sql
customers.sql
products.sql
Логика: «аналитики не различают fact и dim в SQL, для них это просто таблицы». В BI Tableau показывает customers без префикса, дашборд читается естественно.
Оба варианта валидны. Выбирайте один на проект и придерживайтесь. Mixing — антипаттерн (некоторые с fct_, некоторые без).
В курсе используем Kimball-style с префиксами, потому что это сильнее видно в DAG и проще для junior-обучения.
Поддиректории внутри marts
В больших проектах marts тоже разбивают на домены:
models/marts/
core/
fct_orders.sql ← общие fact'ы и dim'ы
dim_customers.sql
dim_products.sql
finance/
fct_payments.sql
revenue_daily.sql
marketing/
campaign_attribution.sql
fct_sessions.sql
ops/
fulfillment_metrics.sql
core/ — это общие marts, на которые опираются другие домены. finance/, marketing/, ops/ — domain-specific marts.
Это аналог bounded context из Domain-Driven Design.
Имена колонок: snake_case, бизнес-первое
В staging уже переименовали колонки в snake_case. В marts добавляются новые колонки, и для них есть свои conventions:
- snake_case для всех колонок.
total_amount,is_active,created_at. - Не сокращения.
customer_id, неcust_id.amount, неamt. Исключения для очень распространённых:id,ts. - Booleans с
is_/has_префиксом.is_active,is_deleted,has_orders,has_subscription. - Timestamps с
_atсуффиксом.created_at,updated_at,deleted_at. - Dates с
_dateсуффиксом (когда это именно date, не timestamp).order_date,birth_date. - Count’ы с префиксом или суффиксом
count.order_countилиcount_orders. - Money с unit’ом в имени (для multi-currency проектов).
amount_usd,price_eur.
Пример хорошей таблицы dim_customers:
customer_id -- primary key
first_name
last_name
email
is_email_verified
created_at -- timestamp когда создан
first_order_date -- date первого заказа
last_order_date -- date последнего заказа
order_count -- count'ов
lifetime_revenue_usd -- USD сумма
is_active -- boolean
tier -- категория (standard / premium / vip)
ID-колонки и primary keys
Соглашение: primary key = <entity>_id, не id.
customers.customer_id, неcustomers.id.orders.order_id, неorders.id.
Зачем: в JOIN’ах вы пишете ON o.customer_id = c.customer_id, а не ON o.customer_id = c.id. Это симметричный JOIN, легко читается, не нужно помнить, какая таблица справа какая слева.
Foreign keys — то же имя, что primary key referenced таблицы:
- В
ordersколонкаcustomer_idуказывает наcustomers.customer_id. - В
order_itemsколонкаorder_idуказывает наorders.order_id.
Пример полного дерева Jaffle Shop
models/
staging/
jaffle/
_jaffle__sources.yml
_jaffle__models.yml
stg_jaffle__customers.sql
stg_jaffle__orders.sql
stg_jaffle__order_items.sql
stg_jaffle__payments.sql
stg_jaffle__products.sql
intermediate/
finance/
_int_finance__models.yml
int_order_items_pivoted.sql
int_payments_joined.sql
marketing/
_int_marketing__models.yml
int_active_customers.sql
marts/
core/
_core__models.yml
fct_orders.sql
dim_customers.sql
dim_products.sql
finance/
_finance__models.yml
fct_payments.sql
revenue_daily.sql
marketing/
_marketing__models.yml
customer_segmentation.sql
seeds/
reference/
country_codes.csv
product_categories.csv
Глянули на дерево — сразу понимаете архитектуру:
- jaffle — source с 5 таблицами,
- финансы и маркетинг — два домена,
- intermediate-блоки идут по доменам,
- marts разделены на core (общее) и domain-specific.
Это читаемая структура. В команде новый человек открыл проект — и через 10 минут ориентируется.
Антипаттерны в naming
Как читается DAG из имён
Хорошие имена позволяют читать DAG без открытия dbt docs. Пример: вы видите модель fct_orders.sql и читаете её код:
SELECT * FROM {{ ref('stg_jaffle__orders') }}
JOIN {{ ref('int_order_items_pivoted') }} ...
JOIN {{ ref('dim_customers') }} ...
Из одних имён понятно:
fct_orders— это fact-таблица в marts.- Зависит от
stg_jaffle__orders— staging для таблицы orders из jaffle source. - Зависит от
int_order_items_pivoted— intermediate, который делает pivot order_items. - Зависит от
dim_customers— dimension клиентов из marts.
Никакой документации не нужно: имена самодостаточны. Это вершина naming conventions — когда код читается как proza.
Попробуй сам
Возьмите свой dbt-проект (или Jaffle Shop). Переименуйте файлы согласно conventions.
Чек-лист:
- staging: все файлы
stg_<source>__<table>? Двойное подчёркивание? snake_case? - intermediate: все файлы
int_<purpose>? Поддиректории по доменам? - marts: единый стиль (с
fct_/dim_или без)? Без сокращений? - YAML-файлы:
_<group>__<type>.yml(например,_jaffle__sources.yml)? Подчёркивание в начале — чтобы YAML файлы группировались в начале листинга. - Колонки в SQL: snake_case? Bool с
is_/has_? Timestamp с_at? Date с_date?
После переименования запустите dbt run. Если что-то ломается — это потому, что были hardcoded ссылки на старые имена в downstream models. Найдите и исправьте.
Бонус: добавьте dbt source freshness и dbt build. Проверьте, что DAG корректно строится по новым именам.
Ключевые выводы
- Префиксы по слоям:
stg_(staging),int_(intermediate),fct_/dim_или без префикса (marts). Mixing — антипаттерн. - staging имена:
stg_<source>__<table>— двойное подчёркивание между source и table. Уникальные через source, парсимые. - intermediate имена:
int_<purpose>— описывает действие, не source. Поддиректории по доменам в больших проектах. - marts имена: либо Kimball-style (
fct_orders,dim_customers), либо без префикса (orders,customers). Выбирайте один стиль и держитесь. - Колонки: snake_case, не сокращения,
is_/has_для bool,_atдля timestamp,_dateдля date. - Primary key:
<entity>_id, не простоid. Foreign key — то же имя в referencing-таблице. - YAML-файлы:
_<group>__<type>.yml, начинаются с подчёркивания — чтобы в листинге группироваться сверху. - Хорошие имена позволяют читать DAG без документации — каждое имя сообщает роль и зависимости.