Files
clickstream-ch-kafka-supers…/docs/course/LEARNING_PLAN.md
T
ddadmin f56166181b docs(course): смягчён регистр уроков 0–1 и убран статус «черновик»
- Зачем:
  - на уроке 2 решили писать разжёванным языком; уроки 0–1 и шапки курса
    остались в сжатом регистре, а слово «черновик»/«Режим: руки» путало менти.
- Что:
  - урок 1: расшифрованы staging, MergeTree-дедуп, Materialized View и
    виртуальные колонки; секция «Загляни внутрь» разбита на ###-подзаголовки;
    плотные абзацы разбиты на пункты; добавлен зачин «О чём урок простыми словами».
  - урок 0: добавлен зачин «О чём урок простыми словами» (лёгкая полировка).
  - шапки всех уроков: «Статус: черновик. Режим: руки/наблюдение» заменены на
    понятное «Формат: практика/наблюдение — …».
  - PRD/LEARNING_PLAN/LESSON_STANDARD: убрано слово «черновик» из статуса.
- Проверка:
  - grep -rn "черновик" docs/course/ — пусто;
  - прочитать урок 1 сверху вниз: термины раскрыты на первом употреблении.
2026-06-05 18:00:13 +03:00

14 KiB
Raw Blame History

План обучения: курс «Кликстрим на ClickHouse»

Дата: 2026-06-03 (аудит путей выполнен; середина расщеплена — один паттерн на урок, всего 7 уроков, см. §1–2). Назначение: высокоуровневый маршрут менти по курсу — карта уроков, порядок, результаты аудита эталонных путей. Рамка курса (зачем/что/скоуп) — в PRD.md; как устроен отдельный урок — в LESSON_STANDARD.md.

Раздел 3 содержит финальные вердикты аудита и конкретный список правок — их применяем при написании соответствующих уроков, а не отдельным забегом.


1. Маршрут

Порядок линейный — уроки 1→4 повторяют сам пайплайн (STG → ODS → DDS → оркестрация), а урок 0 — разминка перед ним. Мониторинг (5) и Superset (6) более самостоятельны и работают как надстройки поверх готовых данных.

Принцип нарезки — один прод-паттерн на урок (LESSON_STANDARD §2). Поэтому середина пайплайна разнесена: типизация+DQ (ODS) и сборка сущностей (DDS) — разные уроки. Витрины DM не отдельный урок: их показываем в деле там, где их потребляют — в мониторинге (DQ-витрины) и BI (traffic/utm-витрины).

Что нужно знать заранее по Kafka: перед уроком 0 менти смотрит обзорное видео по Kafka из роадмапа — оно даёт словарь терминов. Урок 0 связывает этот словарь с тем, что менти сразу видит в живом стенде.

2. Карта уроков

# Урок Эталонный путь (файлы стенда) Статус Режим
0 Вводный урок по Kafka Kafka UI: топики, партиции, offset'ы, consumer-группы, отставание (lag) обязательный наблюдение
1 Заземление Kafka → ClickHouse sql/ddl/stg/10_stg.sql (Kafka engine → MV → MergeTree) обязательный руки
2 STG → ODS: типизация и DQ-split sql/ods/20_stg_to_ods.sql + DDL sql/ddl/ods/20_ods.sql обязательный руки
3 ODS → DDS: сборка сущностей sql/dds/30_ods_to_dds.sql + DDL sql/ddl/dds/30_dds.sql (argMax, UNION, сироты) обязательный руки
4 Оркестрация в Airflow airflow/dags/etl_pipeline_dag.py (зависимости, гейты, остановка при нарушениях) обязательный руки
5 Мониторинг Prometheus + Grafana + экспортёры обязательный наблюдение
6 BI-витрина Superset поверх ClickHouse опциональный руки

Урок 0 — обязательная разминка (без правок кода, только наблюдение); уроки 1–4 — с управляемыми правками; урок 5 ближе к наблюдению (глубину уточняем, см. «Открытые вопросы» в PRD.md).

Где «MV vs батч»: контраст из цели №2 PRD — это мост уроков 1→2. Урок 1 (STG) заканчивается вопросом «мы приземлили поток через MV — почему дальше не MV?»; урок 2 (ODS) отвечает: батч ради наблюдаемости и управляемости пересчёта. Отдельным уроком контраст не выделяем — он живёт на стыке.

Витрины DM показываем в деле в уроках 5–6; единственную концепцию DM («VIEW сейчас, материализуем если затормозит») даём короткой заметкой в финале урока 3.

3. Аудит эталонных путей

Вердикт по каждому пути — один из трёх: годно как есть / точечно править / переписать (критерии «учебного качества» — в LESSON_STANDARD.md).

Финальная оценка (детальный аудит от 2026-06-03):

Урок Путь Файлы Вердикт
1 STG (Kafka→CH) sql/ddl/stg/10_stg.sql точечно править (баг конвертации kafka_ts, найден на стенде)
2 STG→ODS sql/ods/20_stg_to_ods.sql + DDL sql/ddl/ods/20_ods.sql точечно править
3 ODS→DDS (+ демоут DM) sql/dds/30_ods_to_dds.sql + DDL sql/ddl/dds/30_dds.sql; DM sql/dm/40_dds_to_dm.sql + sql/ddl/dm/40_dm.sql точечно править
4 Airflow DAG airflow/dags/etl_pipeline_dag.py точечно править
5 Мониторинг configs/*, экспортёры годно как есть (для режима наблюдения)

Карты путей раздела 2 включают и DDL целевых таблиц (sql/ddl/{ods,dds}/*), а не только батч-трансформации: без формы целевых таблиц слой читается неполно.

3.1. Список правок (применяем при написании урока)

Правки точечные, делаем не отдельным забегом, а в составе соответствующего урока.

Урок 1 — STG (sql/ddl/stg/10_stg.sql):

  • Баг конвертации kafka_ts (найден прогоном на стенде 2026-06-03). Было fromUnixTimestamp64Milli(toInt64(_timestamp_ms)) во всех 4 MV: _timestamp_ms это DateTime64(3), toInt64() срезает его до секунд, и fromUnixTimestamp64Milli читает секунды как миллисекунды → kafka_ts = 1970-01-21 по всему стенду. Исправлено на _timestamp_ms AS kafka_ts (прямое присвоение, мс сохраняются). Прежний аудит ошибочно пометил путь «годно как есть» — потому что его не прогоняли.
  • Колоночные комментарии-пересказы (-- Партиция, -- Имя топика) безвредны — не трогаем.
  • В финале урока — мост к уроку 2: вопрос «почему дальше не MV?».

Урок 2 — STG→ODS, типизация + DQ-split (sql/ods/20_stg_to_ods.sql + DDL sql/ddl/ods/20_ods.sql):

  • Кандидат на war-story по типам: баг kafka_ts из урока 1 (toInt64(DateTime64) молча срезал миллисекунды → 1970). Это идеальная иллюстрация темы урока — «тихая потеря данных на неверном типе». Решить при написании, давать ли как пример.
  • Добавить однострочный «поток данных» в шапку 20_stg_to_ods.sql (stg.*_raw → ods.* + ods.*_errors) — п.3 чеклиста.
  • Добавить строку «зачем»: основная таблица = валидный ключ (но может иметь parse_errors по неключевым полям), а *_errors = любая ошибка. Без этого непонятно, почему одна строка попадает в оба места (двойной учёт) — проваливается тест одного прохода.
  • Убрать мусор: в sql/ddl/ods/20_ods.sql (стр. ~15–25) — восемь DROP TABLE IF EXISTS stg.mv_*_to_ods (чистка legacy-MV). Шум прошлой архитектуры, мента читает его раньше сути. Вынести из учебного файла.
  • Минор: в 20_ods.sql разнобой партиционирования (browser по event_date, остальные по src_ingest_ts) — одна строка «почему» либо унифицировать.
  • В «Зачем» урока — ответ на мост из урока 1: батч ради наблюдаемости/управляемости.

Урок 3 — ODS→DDS, сборка сущностей (sql/dds/30_ods_to_dds.sql + DDL sql/ddl/dds/30_dds.sql):

  • Добавить однострочный «поток данных» в шапку 30_ods_to_dds.sql (ods.* → dds.click + dds.event) — п.3 чеклиста.
  • В финале урока — recap всей цепочки STG→ODS→DDS: защита от фрагментации после расщепления середины (менти должен собрать сквозную модель, а не три изолированных слоя).
  • Демоут DM оформляем здесь: убрать мусор в sql/dm/40_dds_to_dm.sql (стр. ~14–37, закомментированный «пример материализации витрины») и превратить его в короткую заметку «VIEW сейчас, материализуем если затормозит, см. docs/ARCHITECTURE.md». Добавить «поток данных» в шапку 40_dds_to_dm.sql.
  • Минор: sql/ddl/dm/40_dm.sql — магическое 1919 в groupArraySample (строка «зачем» или упростить).
  • Сами витрины DM показываем в деле в уроках 5–6, отдельного разбора не делаем.

Урок 4 — Airflow DAG (airflow/dags/etl_pipeline_dag.py):

  • Главная правка (код↔доки): сделать check_dds_integrity честным гейтом — добавить assert_dds_integrity (PythonOperator), роняющий DAG при orphan_events > 0. Сейчас «проверка» только считает сирот в xcom и пишет их в dq_summary, но DAG остаётся зелёным, хотя LESSON_STANDARD §3 и PRD §2 (цель 3) обещают остановку при нарушении целостности. После правки доки и код сходятся.
  • Управляемая правка урока 4 строится на этом гейте: менти намеренно ломает целостность (вставляет «осиротевшее» событие) и видит, как DAG краснеет на assert_dds_integrity. Опирается на понятие сирот из урока 3.
  • Добавить ASCII-поток задач в docstring DAG (precheck → transform: wait → ods → dq → branch → dds → integrity → dm → validate) — для теста одного прохода.
  • Замечание: check_ods_quality тоже measure-only (метрики в xcom, без гейта) — это ок и намеренно (DQ по parse_errors информативен, но не блокирует). В тексте урока развести: какие проверки гейтят пайплайн, а какие только измеряют.

Урок 5 — мониторинг (configs/*):

  • Конфиги (prometheus.yml, экспортёры, provisioning Grafana) полировать под «учебное качество кода» не нужно: дашборды/JSON не читаются построчно. Вся учебная нагрузка ложится на текст урока (маршрут по дашбордам + смысл панелей).
  • При написании проверить, что имена дашбордов/панелей/метрик в тексте совпадают с реальными (configs/grafana/provisioning/dashboards/*.json).
  • Кандидат на мини-правку (зеркало урока 4): погасить сервис → увидеть, как панель/ алерт в Grafana краснеет. Решает открытый вопрос PRD про глубину урока (даёт «сломал-увидел» вместо чистого наблюдения) — обсудить при написании.

4. Что дальше

Пишем уроки по одному, по шаблону из LESSON_STANDARD.md, начиная с урока 1 (Kafka→CH). Урок 0 (разминка на Kafka UI) можно готовить параллельно — он не зависит от полировки кода. Правки кода из §3.1 применяем в составе соответствующего урока.