Learning Platform
Глоссарий Troubleshooting
Урок 16.01 · 20 мин
Начальный
DocumentationDescriptionsYAMLdbt docs

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 должны отвечать:

  1. Откуда приходит? Имя source-системы, как заливается (Fivetran, Airbyte, manual ETL).
  2. Как часто обновляется? Раз в час? Раз в день? Realtime?
  3. Кто owner? Команда, отвечающая за этот source (для эскалаций «данные сломались»).
  4. Какие известные проблемы? Часто 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 casesemail (может быть NULL для legacy?)
FK на другую таблицуcustomer_id (refers to dim_customers.customer_id?)

Когда не нужно писать column description:

СлучайПочему
Очевидное имяcustomer_id без context’а — и так понятно
Тривиальные timestampcreated_at, updated_at — стандарт
Метаданные ETL_loaded_at, _synced_at — Fivetran/Airbyte стандарт

Не делайте «description ради description». Лучше пусто, чем description: "ID клиента" на колонке customer_id.


Mistakes в descriptions

Антипаттерны 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:

  1. Model description: что это, grain, частота обновления, для каких use-cases.
  2. Каждая колонка:
    • PK и FK -> описание + тесты not_null, unique.
    • Метрики -> формула + unit + edge cases.
    • Бизнес-категории -> возможные значения + значения NULL.
  3. Source — если ещё не описан, опишите. Owner, частота, freshness, known issues.

Запустите dbt docs generate && dbt docs serve. Откройте UI, найдите вашу модель. Прочитайте description «глазами аналитика» — это понятно?

Бонус: дайте dbt docs прочитать коллеге, который не знаком с проектом. Может ли он понять, что значит каждая колонка fct_orders? Если нет — это сигнал, что описания нужно улучшать.


Ключевые выводы

  1. Descriptions в YAML — основной носитель документации в dbt. Хранятся рядом с моделями, версионируются в git.
  2. Обязательно документировать:
    • source: откуда, кем, как часто загружается.
    • fact-модели: grain + business definition.
    • бизнес-метрики: формула + unit + edge cases.
    • dimension-модели: SCD type.
  3. Multi-line через | для длинных описаний. Markdown работает (bold, italic, code, links, lists).
  4. Не дублируйте имя колонки — это шум. Лучше пусто, чем customer_id -> "ID клиента".
  5. Не выдумывайте описания, если не понимаете модель. Лучше пусто и TODO, чем неверная информация — она будет уводить downstream-разработчиков в ложном направлении.
  6. Doc blocks для reuse: одна description упоминается в 10 моделях — выноси в .md файл.
Production-grade descriptions: что писать и как поддерживать живыми
Проверка знанийKnowledge check
В команде новый аналитик. Открывает model `fct_orders` в dbt docs, видит description: 'Заказы клиентов'. Чего не хватает в description для production-проекта?
ОтветAnswer
«Заказы клиентов» — это **минимальный** description, который не отвечает на главные вопросы аналитика. В production-проекте должно быть:\n\n1. **GRAIN**. Что значит одна строка? Один заказ? Одна позиция? Без этого SUM(amount) может означать revenue или ничего.\n\n2. **Бизнес-определение**. Что значит «заказ»? Включает cancelled? Только paid? До или после refund?\n\n3. **Частота обновления и lag**. Real-time? Раз в час? Раз в день? Как недавно были события в последней версии?\n\n4. **Ключевые метрики** (если они в этой модели): amount = сумма после скидок до tax? До или после refund?\n\n5. **Связанные модели**: `fct_order_items` для drill-down позиций. `dim_customers` через customer_id. `customers_snapshot` для tier на момент.\n\nХороший description:\n\n```yaml\n- name: fct_orders\n description: |\n **Grain**: один заказ (order_id уникален).\n **Бизнес**: завершённые заказы (excludes cancelled, includes refunded).\n **Обновление**: каждые 30 минут через cron, lag ~5 минут.\n **Метрики**:\n - amount: revenue после скидок, до tax, до refund.\n - net_amount: revenue после refund.\n **Связанные**: fct_order_items (positions), dim_customers (current attrs),\n customers_snapshot (tier-at-order-time).\n```
Проверка знанийKnowledge check
В YAML модели: `- name: revenue_usd`. Какая из descriptions для этой колонки — лучшая?
ОтветAnswer
**Лучшая** — та, которая отвечает на бизнес-вопрос, даёт формулу, и предупреждает об edge cases:\n\n```yaml\n- name: revenue_usd\n description: |\n Выручка в USD после скидок, до tax.\n\n **Формула**: SUM(quantity * unit_price * (1 - discount_pct)) для всех позиций в заказе.\n\n **Не включает**: tax, shipping, refund. Для после-refund используйте net_revenue_usd.\n\n **Currency conversion**: для не-USD заказов курс берётся на дату заказа из dim_currency_rates.\n\n **Edge cases**:\n - Cancelled orders: 0.\n - Refunded orders: оригинальная сумма (не учитывает refund).\n```\n\nПлохие альтернативы:\n\n- `description: "Выручка"` — не даёт ничего нового по сравнению с именем.\n- `description: "Сумма в долларах США"` — повторяет тип, не отвечает на «что значит revenue».\n- `description: "Выручка в USD"` — то же. Не объясняет бизнес-логику.\n- `description: "Revenue per order"` — на английском в русскоязычной команде; и не объясняет formula/edge cases.\n\nХороший description экономит аналитикам **часы**. Один человек написал — десятки прочитали. Это лучший ROI в data-проекте.

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 5. В `_marts__models.yml` для `fct_orders` написано: `description: "Заказы клиентов"`. Что обязательно дополнить для production-проекта?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 4