From 3556566f64ac233be89b410f4aca0b2809bd07d5 Mon Sep 17 00:00:00 2001 From: Dmitry Dementev Date: Thu, 3 Sep 2026 17:28:51 -0400 Subject: [PATCH] =?UTF-8?q?docs(labs):=20=D0=BE=D0=B1=D1=80=D0=B0=D1=89?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=C2=AB=D0=B2=D1=8B=C2=BB=20=D0=B2?= =?UTF-8?q?=D0=BE=20=D0=B2=D1=81=D0=B5=D1=85=20=D1=83=D1=87=D0=B5=D0=B1?= =?UTF-8?q?=D0=BD=D1=8B=D1=85=20=D0=B7=D0=B0=D0=B4=D0=B0=D0=BD=D0=B8=D1=8F?= =?UTF-8?q?=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Зачем: - README и путеводитель обращаются к читателю на «вы», а ТЗ в docs/labs/ были на «ты»; после пересборки индекса смесь стала заметна. - Что: - во всех восьми файлах docs/labs/ местоимения, глаголы и повелительное наклонение переведены во второе лицо множественного числа. - названия ступеней в таблице README оставлены как в спеке. - Проверка: - grep по формам «ты/твой», 'ё' и 'менти' по docs/labs/ молчит; git diff --check чистый; ревью диффа свежей сессией. --- docs/labs/README.md | 16 +++++------ docs/labs/dq-errors-daily.md | 10 +++---- docs/labs/events-enriched.md | 8 +++--- docs/labs/session-overview.md | 14 +++++----- docs/labs/superset-chart.md | 47 +++++++++++++++++---------------- docs/labs/superset-dashboard.md | 32 +++++++++++----------- docs/labs/top-pages-daily.md | 14 +++++----- docs/labs/utm-effectiveness.md | 14 +++++----- 8 files changed, 79 insertions(+), 76 deletions(-) diff --git a/docs/labs/README.md b/docs/labs/README.md index 6d33143..0618e4a 100644 --- a/docs/labs/README.md +++ b/docs/labs/README.md @@ -1,7 +1,7 @@ # Учебные задания -Программа состоит из двух частей: основная включает семь ступеней, которые ты -проходишь по порядку, а факультативы выбираешь по желанию. Причины такого +Программа состоит из двух частей: основная включает семь ступеней, которые вы +проходите по порядку, а факультативы выбираете по желанию. Причины такого порядка и формы заданий описаны в [программе учебных лаб](../specs/2026-09-01-labs-program.md#2-устройство-программы-основная-программа-и-факультативы). ## Основная программа @@ -21,7 +21,7 @@ ## Ступень 1: пять витрин слоя DM Слой DM в стенде построен наполовину: витрины трех сюжетов дашборда и контроль -качества уже построены, остальные пять витрин строишь ты. Каждая из них — +качества уже построены, остальные пять витрин строите вы. Каждая из них — самостоятельное ТЗ: в нем есть состав витрины, зерно, источники и способ проверки. @@ -59,7 +59,7 @@ DDS, и задания остаются независимыми. Исключе остается обычным представлением. Довод — [дока DM](../architecture/dm.md), «Форма: по зерну, не по цене запроса». -**Ключ шардирования — твое решение.** Ни одно ТЗ ключа не называет. +**Ключ шардирования — ваше решение.** Ни одно ТЗ ключа не называет. Правило выбора и требование к донору — [дока хранилища](../architecture/storage.md), «Раскладка по шардам»: донор объявляется через `AS <цель>_rep` и шардируется тем же ключом, что цель, @@ -69,7 +69,7 @@ DDS, и задания остаются независимыми. Исключе `dm.revenue_daily_dist` в [`sql/ddl/55-dm-tables.sql`](../../sql/ddl/55-dm-tables.sql). **Где лежит код.** DDL домашек — свой файл `sql/ddl/70-labs.sql`: он -применяется после стендовых по порядку имени, и твои объекты не мешаются +применяется после стендовых по порядку имени, и ваши объекты не мешаются со стендовыми. У агрегатов рядом со стендовыми ложатся еще три запроса — `sql/dm/<витрина>_scope.sql` спрашивает у хранилища, какие дни пересобирает запуск, `_rebuild.sql` собирает их в донор, `_replace.sql` заменяет @@ -106,14 +106,14 @@ DDS, и задания остаются независимыми. Исключе **Предупреждение.** Запросы самой проверки лежат в `sql/dq/` открыто, и имена называют витрину и роль сверки. Проверка на инвариантах неизбежно близка к ответу: чтобы сверить витрину, надо ее пересчитать. Прятать эти -файлы никто не станет — но открыв их до того, как задание сделано, ты -обменяешь урок на готовый SQL. +файлы никто не станет — но открыв их до того, как задание сделано, вы +обменяете урок на готовый SQL. Смотреть туда стоит после своей сборки: сравнить два решения полезно, списать одно — нет. ## Факультативы -Эти задания ты берешь по желанию. Полный список сюжетов — в разделе +Эти задания вы берете по желанию. Полный список сюжетов — в разделе [«Факультативы — пять разделов»](../specs/2026-09-01-labs-program.md#4-факультативы--пять-разделов) программы. diff --git a/docs/labs/dq-errors-daily.md b/docs/labs/dq-errors-daily.md index 48bb5e0..878b017 100644 --- a/docs/labs/dq-errors-daily.md +++ b/docs/labs/dq-errors-daily.md @@ -67,7 +67,7 @@ марта удалены. Отсюда правило прогона: пересобираются **только те дни загрузки, которые -еще есть в источнике**. Спроси у источника список живых дней и замени +еще есть в источнике**. Спросите у источника список живых дней и замените партиции ровно этих дней. Соблазн «собрать все заново в донор и подменить таблицу целиком» здесь стоит дороже обычного: истекшие по `TTL` дни исчезли бы из витрины навсегда, а вместе с ними — единственная оставшаяся память о @@ -79,9 +79,9 @@ ## Ключ шардирования -Твое решение по [правилу донора](../architecture/storage.md), «Раскладка по +Ваше решение по [правилу донора](../architecture/storage.md), «Раскладка по шардам». Витрина крошечная: классов брака у событий и заказов вместе меньше -десятка. Учти это в защите ключа — иногда правильный ответ звучит как +десятка. Учтите это в защите ключа — иногда правильный ответ звучит как «перекос здесь ничего не стоит, и вот почему». ## Как проверить себя @@ -91,8 +91,8 @@ день за границей `TTL` сверять не с чем, и его отсутствие в источнике не ошибка. -Собери прямой счет по обеим таблицам ошибок, соедини с -`dm.dq_errors_daily_v` полным внешним соединением по ключу и посчитай +Соберите прямой счет по обеим таблицам ошибок, соедините с +`dm.dq_errors_daily_v` полным внешним соединением по ключу и посчитайте строки, где ключа нет с одной из сторон или где расходится `error_rows`. Ноль — зеленый. diff --git a/docs/labs/events-enriched.md b/docs/labs/events-enriched.md index 5081b44..2c20ca7 100644 --- a/docs/labs/events-enriched.md +++ b/docs/labs/events-enriched.md @@ -91,10 +91,10 @@ ## Как проверить себя -Деловой ключ — `event_id` внутри дня. Собери прямой ответ из `dds.event_v` -за тот же день, соедини с витриной полным внешним соединением и посчитай -строки, где ключа нет с одной из сторон или где различаются значения -деловых колонок. Ноль — зеленый. +Деловой ключ — `event_id` внутри дня. Соберите прямой ответ из +`dds.event_v` за тот же день, соедините с витриной полным внешним +соединением и посчитайте строки, где ключа нет с одной из сторон или где +различаются значения деловых колонок. Ноль — зеленый. Отдельно проверяются три производные колонки: `event_hour`, `page_path` и `referer_host` должны совпасть с тем же выражением, посчитанным по diff --git a/docs/labs/session-overview.md b/docs/labs/session-overview.md index c0d9b0f..9cc5c0b 100644 --- a/docs/labs/session-overview.md +++ b/docs/labs/session-overview.md @@ -64,7 +64,7 @@ DDS уже перевел код источника в слово. Словар С `visitors` история тоньше, и в ней главная ловушка задания. Складывать уникальных по строкам нельзя: один и тот же посетитель, попавший в две -строки, будет посчитан дважды. Проверь на стенде — и увидишь, что сумма +строки, будет посчитан дважды. Проверьте на стенде — и увидите, что сумма `visitors` по устройствам за день **сходится** с `dm.daily_traffic_v`. Это не отменяет правила, а показывает, откуда берется совпадение: в мире @@ -87,17 +87,17 @@ DDS уже перевел код источника в слово. Словар ## Ключ шардирования -Твое решение по [правилу донора](../architecture/storage.md), «Раскладка по +Ваше решение по [правилу донора](../architecture/storage.md), «Раскладка по шардам». Здесь у измерения всего три встречающихся значения, и распределены они неровно: планшеты — тонкая полоса, а телефоны и настольные машины держат -основную массу. Прежде чем брать хеш от одного `device_category`, посчитай, -сколько строк ляжет на каждый шард, и назови, чем тебя устраивает результат. +основную массу. Прежде чем брать хеш от одного `device_category`, посчитайте, +сколько строк ляжет на каждый шард, и назовите, чем вас устраивает результат. ## Как проверить себя -Деловой ключ — `device_category` внутри дня. Собери прямой агрегат из -`dds.session_v` за день, соедини с `dm.session_overview_v` полным внешним -соединением и посчитай строки, где ключа нет с одной из сторон или где +Деловой ключ — `device_category` внутри дня. Соберите прямой агрегат из +`dds.session_v` за день, соедините с `dm.session_overview_v` полным внешним +соединением и посчитайте строки, где ключа нет с одной из сторон или где расходится любой счетчик. Ноль — зеленый. Две проверки покрупнее ловят грубую ошибку сразу: diff --git a/docs/labs/superset-chart.md b/docs/labs/superset-chart.md index 4383e26..e639b21 100644 --- a/docs/labs/superset-chart.md +++ b/docs/labs/superset-chart.md @@ -10,20 +10,20 @@ ## Роль графика -В задании 3 ты собрал витрину `dm.session_overview_v`. Теперь покажи, с каких -устройств чаще уходят после первой страницы. Построй столбиковый график доли -отказов по `device_category` за весь период витрины. Измерение одно — -`device_category`, метрика тоже одна. +В задании 3 вы собрали витрину `dm.session_overview_v`. Теперь покажите, с +каких устройств чаще уходят после первой страницы. Постройте столбиковый +график доли отказов по `device_category` за весь период витрины. Измерение +одно — `device_category`, метрика тоже одна. ## Что сделать -Заведи физический датасет в подключении к `ClickHouse`: схема `dm`, объект -`session_overview_v`. Назови по-русски хотя бы две колонки: +Заведите физический датасет в подключении к `ClickHouse`: схема `dm`, объект +`session_overview_v`. Назовите по-русски хотя бы две колонки: - `device_category` — «Категория устройства»; - `report_date` — «Дата отчета». -В редакторе датасета, на вкладке «Metrics», создай метрику: +В редакторе датасета, на вкладке «Metrics», создайте метрику: | Поле | Значение | |---|---| @@ -33,35 +33,35 @@ | `D3 format` | `.1%` | Доля считается из сумм слагаемых: среднее готовых долей соврет. Поэтому -метрике нужно это выражение. Сохрани ее в датасете, а не в графике: подписи и -формат задаются в датасете, а график их использует. Так во всех будущих -графиках у метрики будут одинаковые подписи. Это правило описано в +метрике нужно это выражение. Сохраните ее в датасете, а не в графике: +подписи и формат задаются в датасете, а график их использует. Так во всех +будущих графиках у метрики будут одинаковые подписи. Это правило описано в [справочнике Superset](../architecture/superset.md#дерево-импорта). -Не используй вкладку «Custom SQL» конструктора графика. Созданная там метрика -доступна только этому графику, а нужна метрика датасета. +Не используйте вкладку «Custom SQL» конструктора графика. Созданная там +метрика доступна только этому графику, а нужна метрика датасета. -Создай столбиковый график с метрикой «Доля отказов». В поле «X-axis» укажи -«Категория устройства», а «Dimensions» не заполняй. Дашборд создавать не -нужно: сохраненного графика достаточно. +Создайте столбиковый график с метрикой «Доля отказов». В поле «X-axis» +укажите «Категория устройства», а «Dimensions» не заполняйте. Дашборд +создавать не нужно: сохраненного графика достаточно. -По умолчанию в графике выбран период «No filter». Оставь его таким или задай -явные даты. Относительный период, например «Last week», даст пустой +По умолчанию в графике выбран период «No filter». Оставьте его таким или +задайте явные даты. Относительный период, например «Last week», даст пустой график: модельный календарь стенда отстает от настоящего. Последнюю дату -витрины посмотри в SQL Lab: +витрины посмотрите в SQL Lab: ```sql SELECT max(report_date) FROM dm.session_overview_v; ``` -Стендовые объекты не меняй. Что переживает `make up`, а что стирает +Стендовые объекты не меняйте. Что переживает `make up`, а что стирает `make clean`, описано в главе [«Немного Superset»](../handbook/superset.md#стендовые-объекты-и-ваши). ## Как проверить себя График проверяется глазами, поэтому задачи для него в `homework_check` нет. -В SQL Lab выполни запрос: +В SQL Lab выполните запрос: ```sql SELECT device_category, @@ -71,9 +71,10 @@ GROUP BY device_category ORDER BY device_category; ``` -Сверь с графиком значение для каждой категории. В разделе «Customize» включи -«Show Value» или наведи указатель на столбик. Запрос возвращает проценты с одним знаком, -как формат `.1%`, поэтому числа должны совпасть один в один. +Сверьте с графиком значение для каждой категории. В разделе «Customize» +включите «Show Value» или наведите указатель на столбик. Запрос возвращает +проценты с одним знаком, как формат `.1%`, поэтому числа должны совпасть +один в один. ## Приемка diff --git a/docs/labs/superset-dashboard.md b/docs/labs/superset-dashboard.md index 2d3d246..d3081f4 100644 --- a/docs/labs/superset-dashboard.md +++ b/docs/labs/superset-dashboard.md @@ -9,30 +9,31 @@ ## Роль дашборда -Собери обзор трафика и поведения посетителей. Он должен отвечать на три +Соберите обзор трафика и поведения посетителей. Он должен отвечать на три вопроса: что происходило в магазине, какие страницы, устройства и рекламные каналы дали результат, были ли ошибки приема данных. Стендовый дашборд «Бизнес-сюжеты» собран из готовых витрин. Свой дашборд -собери из пяти витрин, которые ты построил в заданиях. Копировать раскладку -стендового дашборда не нужно: выбери форму, в которой ответы читаются без +соберите из пяти витрин, которые вы построили в заданиях. Копировать раскладку +стендового дашборда не нужно: выберите форму, в которой ответы читаются без пояснений рядом с экраном. ## Свои объекты — отдельно -Не добавляй графики в стендовый дашборд и не правь его датасеты. При +Не добавляйте графики в стендовый дашборд и не правьте его датасеты. При инициализации Superset импорт с `--overwrite` заменит ручные правки стендовых объектов файлами из репозитория. `make up` свой дашборд не стирает; срок жизни таких объектов описан в [доке Superset](../architecture/superset.md), «Импорт при каждой инициализации». -Заведи отдельные датасеты и графики, собери из них свой дашборд. Назови его, -например, «Мои витрины DM». Это то же правило, по которому DDL домашек лежит -в `sql/ddl/70-labs.sql`: стендовые объекты уже есть, свои создаешь ты. +Заведите отдельные датасеты и графики, соберите из них свой дашборд. +Назовите его, например, «Мои витрины DM». Это то же правило, по которому DDL +домашек лежит в `sql/ddl/70-labs.sql`: стендовые объекты уже есть, свои +создаете вы. ## Датасеты -Заведи в подключении `ClickHouse` пять физических датасетов схемы `dm`: +Заведите в подключении `ClickHouse` пять физических датасетов схемы `dm`: - `events_enriched_v`; - `top_pages_daily_v`; @@ -43,7 +44,7 @@ ## Состав дашборда Каждая из пяти витрин должна появиться хотя бы в одном графике. Точный тип -графика выбери сам. На дашборде покажи следующее: +графика выберите сами. На дашборде покажите следующее: | Витрина | Что показать | |---|---| @@ -53,7 +54,7 @@ | `dq_errors_daily_v` | число ошибок по дню загрузки, источнику и классу | | `utm_effectiveness_v` | трафик, покупки и заявленную выручку по рекламным каналам | -Для долей используй слагаемые из витрин. Например, доля отказов считается +Для долей используйте слагаемые из витрин. Например, доля отказов считается как сумма `bounce_sessions`, деленная на сумму `sessions`. Среднее по готовым долям для такого графика не подходит — урок задания 3 остается в силе. @@ -64,19 +65,20 @@ Эта лаба проверяется глазами. У расположения панелей и понятных подписей нет счетного инварианта, поэтому задачи для нее в `homework_check` нет. -Открой список дашбордов и проверь: +Откройте список дашбордов и проверьте: - «Бизнес-сюжеты» остался отдельным стендовым дашбордом; -- твой дашборд открывается без ошибок и содержит график от каждого из пяти +- ваш дашборд открывается без ошибок и содержит график от каждого из пяти датасетов; - подписи, единицы измерения и легенды читаются без обращения к SQL; - прямой трафик не исчез из графика UTM, а заявленная выручка не выдана за серверную; - пустой график ошибок нормален, если в таблицах брака сейчас нет строк. -Последний проход сделай как читатель: найди на экране самый заметный канал, -страницу и устройство, затем проверь, понятно ли из подписей, что именно -сравнивается. Если ответ приходится угадывать, поправь график или его название. +Последний проход сделайте как читатель: найдите на экране самый заметный +канал, страницу и устройство, затем проверьте, понятно ли из подписей, что +именно сравнивается. Если ответ приходится угадывать, поправьте график или +его название. ## Приемка diff --git a/docs/labs/top-pages-daily.md b/docs/labs/top-pages-daily.md index 350253b..254a3f0 100644 --- a/docs/labs/top-pages-daily.md +++ b/docs/labs/top-pages-daily.md @@ -64,7 +64,7 @@ пересобирать нужно только то, что еще не собрано: хвост дней, которых в витрине нет, — от первого несобранного прожитого дня до последнего прожитого. Готовые дни трогать незачем, а вот дыру, оставленную частичным -отказом, объем прогона обязан подобрать: ищи не последний собранный день, а +отказом, объем прогона обязан подобрать: ищите не последний собранный день, а первый несобранный. Механика — сборка отрезка в донор одной вставкой и замена дневных партиций @@ -72,16 +72,16 @@ ## Ключ шардирования -Твое решение по [правилу донора](../architecture/storage.md), «Раскладка по -шардам». Подумай, чем эта витрина отличается от `revenue_daily`: там кроме +Ваше решение по [правилу донора](../architecture/storage.md), «Раскладка по +шардам». Подумайте, чем эта витрина отличается от `revenue_daily`: там кроме дня было одно измерение из шести близких по объему значений, здесь — страницы, которых много и которые по популярности очень неровные. ## Как проверить себя -Деловой ключ — `page_path` внутри дня. Собери прямой агрегат из -`dds.event_v` за день, соедини с `dm.top_pages_daily_v` полным внешним -соединением по ключу и посчитай строки, где ключа нет с одной из сторон или +Деловой ключ — `page_path` внутри дня. Соберите прямой агрегат из +`dds.event_v` за день, соедините с `dm.top_pages_daily_v` полным внешним +соединением по ключу и посчитайте строки, где ключа нет с одной из сторон или где расходится любой из четырех счетчиков. Ноль — зеленый. Две проверки попроще, ими удобно ловить грубую ошибку до полного @@ -94,7 +94,7 @@ Проверки ловят разное. Фильтр `WHERE event_type = 'pageview'` первая из них пропускает: отбор строк по типу не меняет счет событий того же типа. Расхождение покажет только вторая — вместе с `cart_adds` обнулятся и -`purchases`. Проверку выбирают по тому, умеет ли она покраснеть на твоей +`purchases`. Проверку выбирают по тому, умеет ли она покраснеть на вашей ошибке, а не по тому, как быстро она пишется: [проверка, которая не умеет краснеть, бесполезна](../architecture/testing.md). diff --git a/docs/labs/utm-effectiveness.md b/docs/labs/utm-effectiveness.md index 3ad86b1..22fefa2 100644 --- a/docs/labs/utm-effectiveness.md +++ b/docs/labs/utm-effectiveness.md @@ -88,21 +88,21 @@ UTM у бэкенда нет, метки живут только в кликст ## Ключ шардирования -Твое решение по [правилу донора](../architecture/storage.md), «Раскладка по +Ваше решение по [правилу донора](../architecture/storage.md), «Раскладка по шардам». Зерно здесь составное, из трех колонок, и решение «взять хеш от -одной из них» надо защищать отдельно: назови, какая доля строк придется на +одной из них» надо защищать отдельно: назовите, какая доля строк придется на самое частое значение выбранной колонки. ## Конфликт, ради которого витрина и написана -Собери за один и тот же день две суммы: `sum(declared_revenue)` из своей +Соберите за один и тот же день две суммы: `sum(declared_revenue)` из своей витрины и `sum(revenue)` из `dm.revenue_daily_v`. Они не сойдутся, и это верное поведение обеих витрин. Базы у двух сумм при этом сравнимые: `revenue_daily` складывает цену позиций на количество и ни скидки, ни доставки в себя не берет — ровно то, что видит клиент. Значит все расхождение до копейки объясняется тем, что случилось с -заказом, а не тем, как считали деньги. Ищи ответы среди таких причин: +заказом, а не тем, как считали деньги. Ищите ответы среди таких причин: - отмененный заказ из кликстрима никуда не девается: событие покупки случилось, а `revenue_daily` считает только оплаченные; @@ -113,7 +113,7 @@ UTM у бэкенда нет, метки живут только в кликст Как эти же расхождения выглядят на зерне заказа, показывает стендовая витрина `dm.purchase_vs_orders_v` с ее классами расхождений: это готовый -ответ на вопрос «а сколько именно и из-за чего». Запиши свой вывод — +ответ на вопрос «а сколько именно и из-за чего». Запишите свой вывод — в двух-трех фразах, своими словами. Проверять сходимость этих двух сумм не нужно и нельзя: они и не должны @@ -122,8 +122,8 @@ UTM у бэкенда нет, метки живут только в кликст ## Как проверить себя Деловой ключ — тройка `utm_source`, `utm_medium`, `utm_campaign` внутри -дня. Собери прямой агрегат из `dds.event_v` за день, соедини с -`dm.utm_effectiveness_v` полным внешним соединением и посчитай строки, где +дня. Соберите прямой агрегат из `dds.event_v` за день, соедините с +`dm.utm_effectiveness_v` полным внешним соединением и посчитайте строки, где ключа нет с одной из сторон или где расходится любая из пяти величин. Ноль — зеленый.