Descriptions: модели, колонки, sources
В dbt документация — это часть кода. Все descriptions хранятся в YAML рядом с моделями, версионируются в git, проходят code review.
Главный носитель документации — поле description:. Оно есть на каждом узле: source, table, column, model, snapshot, seed, macro. Когда вы запускаете dbt docs generate && dbt docs serve, эти descriptions становятся UI, в котором аналитики ищут «что значит revenue_usd?» или «откуда приходит таблица orders?».
В этом уроке — что писать в descriptions, что обязательно, типичные паттерны.
Где живут descriptions
В YAML рядом с моделями. Пример _jaffle__models.yml:
version: 2
models:
- name: stg_jaffle__customers
description: "Чищенные клиенты из jaffle source. Переименование колонок, фильтр is_deleted = false."
columns:
- name: customer_id
description: "Primary key — уникальный ID клиента"
- name: email
description: "Email клиента, нормализован (lowercase, trimmed)"
- name: created_date
description: "Дата регистрации (cast from timestamp)"
То же для source:
version: 2
sources:
- name: jaffle
description: "Основная БД Jaffle Shop. Загружается Fivetran каждый час."
tables:
- name: customers
description: "Зарегистрированные клиенты"
columns:
- name: id
description: "PK клиента"
Поле description принимает обычную строку ("...") или multi-line через pipe (|):
description: |
Многострочное описание.
Можно использовать **markdown**, ссылки [http](https://...),
code blocks:
```sql
SELECT * FROM ...
Будет отрисовано в dbt docs UI.
---
## Что обязательно документировать
В production-проекте есть минимальный стандарт. Если в команде есть code review-чеклист — обычно проверяет это:
<DiagramContainer title="Обязательная документация" color="blue">
<Grid columns={3}>
<FlowColumn>
<DataBox variant="success" size="sm" title="Source">
{'Каждый source: имя, описание (откуда приходит, как загружается, частота). Freshness expectations. PK колонок (для тестов).'}
</DataBox>
<DataBox variant="success" size="sm" title="Staging">
{'Каждая stg_-модель: что чистится, что фильтруется. PK + FK колонки с descriptions. Тесты на ключи.'}
</DataBox>
</FlowColumn>
<FlowColumn>
<DataBox variant="success" size="sm" title="Intermediate">
{'Каждая int_-модель: что вычисляется, для каких marts. Часто пропускается, но в больших проектах нужно.'}
</DataBox>
<DataBox variant="success" size="sm" title="Marts (fact)">
{'Каждая fct_-модель: **GRAIN** (критично!). Бизнес-определение. Метрики (что значит amount, count и т.д.).'}
</DataBox>
</FlowColumn>
<FlowColumn>
<DataBox variant="success" size="sm" title="Marts (dimension)">
{'Каждая dim_-модель: business entity definition. SCD type. Slow или fast changing.'}
</DataBox>
<DataBox variant="success" size="sm" title="Бизнес-метрики">
{'Любая колонка-метрика (revenue_usd, conversion_rate): **формула**, бизнес-смысл, edge cases.'}
</DataBox>
</FlowColumn>
</Grid>
</DiagramContainer>
Что НЕ нужно документировать (избыточно):
- `id`-колонки очевидного назначения: `customer_id`, `order_id` (если они называются именно так).
- Утилитарные колонки `created_at`, `updated_at` если они стандартного назначения.
- `_loaded_at`, `_synced_at` — Fivetran/Airbyte метаданные.
Если description совпадает с именем колонки — лучше не писать (`customer_id` -> description "ID клиента" — ничего не даёт).
---
## Паттерны хороших descriptions
### Pattern 1: Что и зачем
Для модели:
```yaml
description: |
**Что**: агрегат revenue по дням и регионам.
**Зачем**: используется в дашборде "Daily Revenue Dashboard" для exec team.
**Grain**: один день + один регион.
**Когда обновляется**: ежедневно в 02:00 UTC через dbt Cloud Job.
Краткие подзаголовки помогают сканировать description глазами.
Pattern 2: Формула бизнес-метрики
Для колонки с метрикой:
columns:
- name: conversion_rate
description: |
Конверсия в покупку.
Формула: `paid_orders / total_sessions` за период.
Edge cases:
- Сессии без orders не считаются (denom не учитывает).
- Returned orders включены в paid_orders (бизнес-решение).
- Period = последние 30 дней (rolling window).
Метрика без формулы — бесполезна. Аналитик откроет код и сам всё прочитает, но это плохой UX.
Pattern 3: Grain в fact-моделях
- name: fct_orders
description: |
**GRAIN: ОДИН ЗАКАЗ** (order_id уникален).
Если нужны позиции — см. `fct_order_items` (grain = order_id + line_id).
SUM(amount) даёт **revenue по заказам**, не по позициям.
Grain в bold капс — намеренно. Это самое частое, что забывают при чтении модели.
Pattern 4: SCD type и история
- name: dim_customers
description: |
Dimension таблица клиентов.
SCD Type 1: атрибуты (name, email, address) перезаписываются. Истории нет.
Для атрибуции revenue на момент по tier — используйте `customers_snapshot` (SCD Type 2).
Это критично, чтобы аналитики не пытались искать историю там, где её нет.
Pattern 5: Edge cases и known quirks
- name: stg_jaffle__customers
description: |
Чищенные customers из jaffle source.
**Известные особенности**:
- Тестовые аккаунты (email LIKE '%@test.example.com') **не фильтруются** на этом слое.
Если нужно их исключить — фильтруйте в downstream-mart.
- Клиенты до 2024-01-01 могут иметь NULL email (легаси система).
- Email нормализуется (lowercase, trim), но дубликаты по email возможны.
«Известные особенности» — секция, которая спасает downstream-разработчиков от часов отладки.
Source descriptions — особенно важны
Source — это граница доверия. Всё, что приходит из source, может быть грязным. Поэтому source-descriptions должны отвечать:
- Откуда приходит? Имя source-системы, как заливается (Fivetran, Airbyte, manual ETL).
- Как часто обновляется? Раз в час? Раз в день? Realtime?
- Кто owner? Команда, отвечающая за этот source (для эскалаций «данные сломались»).
- Какие известные проблемы? Часто appear NULL’ы. Дубликаты по PK иногда. Schema может меняться без warning.
Пример:
sources:
- name: jaffle
description: |
**Source**: Production app Jaffle Shop (Postgres).
**Loader**: Fivetran, Coffer connector, sync каждые 60 минут.
**Owner**: Backend team (Slack: #app-backend).
**Freshness SLA**: данные должны быть не старше 6 часов.
**Known issues**:
- В `orders` иногда дубликаты по id (рассинхрон Fivetran). Тесты на unique должны быть с severity:warn.
- Колонка `customer.address` стала JSON в 2025-Q3 (раньше была строкой). Старые строки могут быть невалидным JSON.
schema: raw_jaffle
freshness:
warn_after: { count: 6, period: hour }
error_after: { count: 24, period: hour }
loaded_at_field: _fivetran_synced
tables:
- name: customers
description: |
Все зарегистрированные клиенты Jaffle Shop.
Soft-delete через `deleted_at IS NOT NULL`.
columns:
- name: id
description: "PK. Sequential integer от 1."
data_tests:
- not_null
- unique
- name: email
description: "Email клиента. Может быть NULL для legacy-аккаунтов до 2024."
Эта структура сразу даёт downstream-инженеру всё нужное: куда писать, когда последний раз обновлялись, что может ломать.
Column descriptions — обязательные случаи
Когда обязательно писать column description:
| Случай | Пример |
|---|---|
| Метрика с формулой | conversion_rate, average_order_value |
| Колонка с unit’ом | amount_usd, duration_seconds, weight_kg |
| Boolean с неочевидным смыслом | is_active (что значит «активный»?) |
| Категориальная колонка | tier (какие возможные значения?) |
| Колонка с edge cases | email (может быть NULL для legacy?) |
| FK на другую таблицу | customer_id (refers to dim_customers.customer_id?) |
Когда не нужно писать column description:
| Случай | Почему |
|---|---|
| Очевидное имя | customer_id без context’а — и так понятно |
| Тривиальные timestamp | created_at, updated_at — стандарт |
| Метаданные ETL | _loaded_at, _synced_at — Fivetran/Airbyte стандарт |
Не делайте «description ради description». Лучше пусто, чем description: "ID клиента" на колонке customer_id.
Mistakes в descriptions
Markdown в descriptions
Поле description: поддерживает markdown. Можно использовать:
- Bold через
**text**. - Italic через
*text*. inline codeчерез backticks.- Лист через
-или*. - Ссылки
[label](url). - Code blocks через тройные backticks.
- Headings через
#,##(внутри description — обычно не используется).
description: |
Сумма заказа в USD.
**Формула**: `quantity * unit_price` для каждой позиции, затем `SUM` по заказу.
*Не включает*: tax, shipping.
См. также:
- [Revenue accounting policy](https://company.notion.so/revenue-policy)
- Связанная метрика: `revenue_usd_net_tax` (включает tax)
В dbt docs UI это будет красиво отрисовано.
Reusing descriptions через doc blocks
Если одна description нужна в нескольких моделях — выноси в doc block (.md файл). Об этом следующий урок (14.2). Пример:
models/_docs.md:
{% docs customer_id %}
**Primary key клиента**. Sequential integer от 1. Никогда не reused.
В downstream-моделях — FK на `customers.customer_id` или `dim_customers.customer_id`.
{% enddocs %}
В YAML:
- name: customer_id
description: '{{ doc("customer_id") }}'
Это полезно для FK-колонок, которые упоминаются в 10+ моделях.
Попробуй сам
Откройте свой dbt-проект. Найдите модель без descriptions (или с плохими). Например, fct_orders.sql. Опишите её в YAML:
- Model description: что это, grain, частота обновления, для каких use-cases.
- Каждая колонка:
- PK и FK -> описание + тесты not_null, unique.
- Метрики -> формула + unit + edge cases.
- Бизнес-категории -> возможные значения + значения NULL.
- Source — если ещё не описан, опишите. Owner, частота, freshness, known issues.
Запустите dbt docs generate && dbt docs serve. Откройте UI, найдите вашу модель. Прочитайте description «глазами аналитика» — это понятно?
Бонус: дайте dbt docs прочитать коллеге, который не знаком с проектом. Может ли он понять, что значит каждая колонка fct_orders? Если нет — это сигнал, что описания нужно улучшать.
Ключевые выводы
- Descriptions в YAML — основной носитель документации в dbt. Хранятся рядом с моделями, версионируются в git.
- Обязательно документировать:
- source: откуда, кем, как часто загружается.
- fact-модели: grain + business definition.
- бизнес-метрики: формула + unit + edge cases.
- dimension-модели: SCD type.
- Multi-line через
|для длинных описаний. Markdown работает (bold, italic, code, links, lists). - Не дублируйте имя колонки — это шум. Лучше пусто, чем
customer_id -> "ID клиента". - Не выдумывайте описания, если не понимаете модель. Лучше пусто и TODO, чем неверная информация — она будет уводить downstream-разработчиков в ложном направлении.
- Doc blocks для reuse: одна description упоминается в 10 моделях — выноси в
.mdфайл.