# Стандарт уроков курса «Кликстрим на ClickHouse» > Дата: 2026-06-01. Поправка: 2026-06-05 (по итогам уроков 0–2 — добавлены §2 «Регистр > и голос», описание шапки урока и §5 «Грабли, на которые мы уже наступили»). > Назначение: рабочий чеклист, по которому пишется **каждый** урок. Открывается при > создании урока. Рамка курса (зачем/что/скоуп) — в `PRD.md`; карта уроков и > маршрут — в `LEARNING_PLAN.md`. --- ## 1. Шаблон урока Каждый урок строится по единому шаблону: 1. **Зачем и где в проде** — что за паттерн и где он встречается в обычной кликстрим-аналитике (без привязки к конкретной компании). 2. **Руки** — что запустить и что понаблюдать (Kafka UI / ClickHouse / Grafana). 3. **Загляни внутрь** — чтение отполированного эталонного кода с пояснениями. 4. **Управляемая правка** — одно-два маленьких изменения с **видимым результатом**. Например: добавить поле в Materialized View и увидеть его в `*_raw`; «сломать» запись и увидеть `+1` в таблице ошибок `parse_errors`; сменить `kafka_group_name` и увидеть, как топик читается заново. Менти меняет — видит эффект — объясняет. **Верни как было** — каждая правка завершается явным шагом отката к чистому состоянию (откатить изменение либо `make generated-history-analytics && make up`), чтобы самостоятельный менти не застрял со сломанным стендом без ментора. (Урок 0 — без этого шага, только наблюдение.) 5. **Проверь себя** — самопроверка (раздел 4). 6. **Что должно получиться** — **конкретный видимый результат**, который менти проверяет сам: скрин эффекта правки (например, красный DAG или `+1` в таблице ошибок) плюс один абзац «своими словами» про паттерн урока или запрос, который пришлось написать. Это и есть самопроверка (раздел 4); те же вопросы «своими словами» менти разбирает с ментором на еженедельном созвоне. (Урок 0 — без правки, поэтому результат здесь — что менти увидел при наблюдении.) ### Шапка урока Кроме шести секций, каждый урок открывается единым блоком-цитатой (`>`) сверху — он задаёт рамку до того, как менти дойдёт до первой секции: - **Формат:** одной фразой, что менти делает, — `**практика** — будешь сам запускать…` или `**наблюдение** — ничего не запускаем и не меняем…`. Старые пометки «Статус: черновик» и «Режим: руки» не возвращаем: менти читал их как «материал не готов» и «непонятно, как понимать»; - **Пререквизит:** какой урок пройден и что менти уже умеет; - **Эталонный путь:** ссылка(и) на разбираемый файл; - **Поток данных одной строкой:** та же стрелочная схема, что стоит в начале эталонного файла; - **О чём урок простыми словами:** 1–2 фразы совсем простым языком, без терминов, — чтобы менти с первой строки понял, о чём речь. В конце урока — короткий **мост к следующему**: какой честный вопрос остаётся открытым и как его закроет следующий урок. ## 2. Регистр и голос Этот раздел — про то, *как* написан урок. Он появился по итогам уроков 0–2: мы начали со сжатого регистра и переписывали — дешевле сразу писать мягко. **Кто читатель.** Менти прошёл курсовую, уровень — «обзорно» (понять идею и потрогать, а не стать экспертом). Поддержка — еженедельный созвон с ментором, а не «сессия»; на нём менти разбирает вопросы «своими словами». **Правила регистра:** - **термин расшифровываем на первом употреблении** — коротко, своими словами (как `ODS`, `DQ-split`, `Materialized View`, `*OrNull` в уроках 1–2). Не оставляем слово голым; - **человеческий тон, без жаргона ради жаргона** — короткие предложения, прямое обращение к менти («открой», «посмотри», «помнишь из урока 0»); - **`###`-подзаголовки внутри длинных секций** — особенно в «Загляни внутрь»: каждый смысловой кусок под своим заголовком, а не сплошной стеной; - **плотные абзацы-«стены» бьём на пункты** с конкретикой; - **разжёвывать, а не сжимать.** Урок может выйти заметно длиннее первого черновика — для «обзорно» это норма, а не повод резать. **House style (оставляем осознанно, `ai-text-lint` на это не правим):** тире «—», буква «ё», жирные зачины абзацев, двоеточие перед списком. **Перед финалом** — прогнать текст урока через `/ai-text-lint` (контекст `article`) и убрать настоящие AI-маркеры (например, слова вроде «ключевой», «является»), но house style выше не снимать. ## 3. Стандарт качества эталонного кода Эталонные пути полируем до **учебного качества**; остальной код стенда остаётся под капотом — его не трогаем. **Чеклист (минимум).** Файл доведён, если: 1. комментарии на русском объясняют **зачем**, а не пересказывают код; 2. шаги явные и названы своими именами, без неочевидных трюков; 3. в начале файла — поток данных одной строкой (как в STG: `Kafka → kafka_*_raw → MV → *_raw`); 4. ошибки и проверки качества данных видны — понятно, куда смотреть; 5. нет мусора: мёртвого кода, закомментированных экспериментов, разнобоя в именах. **Тест одного прохода (главный критерий и защита от громоздкости).** > Менти читает файл один раз сверху вниз и может пересказать своими словами, > *что* происходит и *зачем* — не прыгая по файлу, не гугля, не расшифровывая трюки. Если тест не проходит — правим строго одним из трёх способов: (1) упростить код; (2) добавить ровно одну строку «зачем» там, где код честно неочевиден; (3) убрать лишнее под капот или в короткую пометку. **Добавить ещё комментариев — не способ.** **Две защиты от раздувания:** - комментируем только неочевидное «зачем» (очевидную строку комментировать нельзя — лишний текст сам по себе мешает понимать); - «близко к проду» ≠ «вся прод-сложность прямо в коде урока»: один прод-паттерн на урок показываем чисто, остальные прод-заботы — короткой пометкой «в проде иначе: …». Вердикты аудита по конкретным путям — в `LEARNING_PLAN.md`. ## 4. Самопроверка (по-простому) Отдельный тест-фреймворк не строим. Опираемся на то, что в стенде уже есть: - штатные быстрые проверки (smoke) из `docs/TEST_PLAN.md`; - встроенные проверки в `etl_pipeline_dag.py` (DAG падает на пустой витрине или нарушении целостности); - `make generated-history-analytics && make up` для чистого сброса и повтора штатного пути. В каждом уроке — маленькая табличка самопроверки в формате **действие → где смотреть → что ожидать**, а для управляемой правки — какой видимый результат должен появиться. ## 5. Грабли, на которые мы уже наступили Короткий список ошибок из уроков 0–2 — чтобы следующий урок их не повторил. - **Проверяй на стенде, а не «на глаз».** Любой категоричный claim про числа или целостность подтверждай командой на стенде. Так нашёлся баг с `kafka_ts` в уроке 1 (значение типа `DateTime64` молча резалось через `toInt64`, и время по всему стенду уехало в `1970`) и подтвердилось, что меньший размер таблиц контекста в уроке 2 — это схлопывание повторов по `click_id` (проверяется через `uniqExact`), а не потеря данных. - **Имена таблиц и колонок в тексте сверяй с реальным DDL.** То, что написано в уроке, должно совпадать с `sql/ddl/...`, иначе менти запутается, когда выполнит запрос на стенде. - **Один паттерн на урок; будущие темы только анонсируй.** Не раскрывай то, что относится к следующим урокам (пример: жёсткий гейт на «сирот» — это урок 4, в уроке 3 мы их только вводим как понятие). - **Спорные API ClickHouse сверяй через MCP Context7** (зачем и в каком порядке — в `AGENTS.md`), не полагайся на память: именно типы и поведение функций уже один раз подвели.