Перейти до змісту
Увійти

Теорія

Події, властивості й користувачі

Мова продуктових даних: що записує подія і чим властивості події відрізняються від властивостей користувача.

~9 хв читання · 9 вправ · 250 балів

Перед початком

Де ти працюєш

Тебе щойно взяли до продуктової команди Halves — невеликого мобільного застосунку, який ділить спільні витрати між сусідами по квартирі, парами й компаніями в подорожах. Основний застосунок безплатний, а платний план Halves Plus додає сканування чеків, регулярні рахунки та інші можливості. Застосунок записує все, що роблять люди, але сирі логи важко читати й легко перерахувати неправильно.

У цьому курсі ти відповідатимеш на справжні запитання Maya, продуктової лідерки, і Theo, маркетолога з росту, за даними самого Halves: від подій і метрик до воронок, утримання, експериментів і юніт-економіки. Перший урок починається з найменшої частини: що насправді каже один рядок логу подій.

Як прочитати один рядок події

Подія — це запис про те, що щось сталося. Кожен рядок логу подій відповідає на три запитання:

  • хто: user_id, акаунт, який це зробив;
  • що: назва події, як-от app_opened чи expense_added;
  • коли: event_time, записаний в UTC, щоб телефони з різних часових поясів стали в один ряд.

Решта колонок — властивості події: подробиці саме цього моменту. Для expense_added вони кажуть, як внесено витрату (manual, receipt_scan, recurring) і на яку суму. Для settle_up_recorded вони містять суму та settlement_id. Колонка може бути порожньою, якщо до цієї події вона не стосується.

Один паперовий чек, приколотий до коркової дошки, до нього прикріплені маленька фігурка людини, крихітний годинник і бирка.
Одна подія: хто, що й коли, плюс подробиці, які описують лише цей момент.

Корисна звичка — перш ніж щось рахувати, прочитати рядок як повне речення: «u020 вручну вніс витрату на 91 дол. у застосунку на Android о 18:12 UTC 4 червня». Якщо речення не складається, ти ще не знаєш, що саме рахуєш.

Набір даних · 13 рядків

Тринадцять рядків із логу подій Halves, 1–4 червня

Кілька рядків, вибраних з експорту за минулий тиждень, у порядку часу. Час в UTC.

event_timeuser_ideventplatformentry_methodamount_usdsettlement_id
2026-06-01T06:00:00Zu001expense_addedserverrecurring420
2026-06-01T06:41:00Zu008app_openedios
2026-06-01T06:44:00Zu007app_openedios
2026-06-01T06:46:00Zu007expense_addediosreceipt_scan116
2026-06-01T16:36:00Zu020app_openedandroid

Перші 5 з 13 рядків

Завантажити CSV

Сусідні рядки — окремі події. Відкриття застосунку за дві хвилини до того — це власний рядок, а платіж другові має іншу назву події.

Троє сусідів по квартирі за кухонним столом ділять довгий паперовий чек, розірваний на рівні смужки; один із них тримає телефон.
Halves живе в таких моментах: спільний рахунок і компанія, яка хоче поділити його чесно.
  • Так
    «u020 вручну вніс витрату на 91 дол. у застосунку на Android о 18:12 UTC 4 червня».
  • Не так
    «О 18:12 u020 відкрив застосунок і заплатив 91 дол.»

    Зливає три різні рядки в одну історію.

Властивості події та властивості користувача

Подробиці бувають двох видів, і якщо їх сплутати, звіти ламаються.

Властивості події описують один момент: суму цієї витрати, спосіб її внесення, розрахунок, до якого належить цей платіж. Наступна подія тієї самої людини може мати інші значення.

Властивості користувача описують людину: дату реєстрації, канал залучення, домашній часовий пояс, план. Вони однакові для всіх подій цієї людини, тож живуть один раз у таблиці користувачів, рядок на людину.

Набір даних · 6 рядків

Ті самі шість людей у файлі користувачів

Один рядок на людину. Ці значення не змінюються від події до події.

user_idsignup_dateplatformacquisition_channeltimezoneis_internal
u0012026-04-23iosinviteEurope/Kyivfalse
u0072026-05-08iosreferral_linkAsia/Bangkokfalse
u0082026-05-08iosapp_store_searchAsia/Bangkokfalse
u0132026-05-11iospaid_socialEurope/Lisbonfalse
u0142026-05-30iosreferral_linkEurope/Kyivfalse

Перші 5 з 6 рядків

Завантажити CSV

Швидкий тест: чи може значення відрізнятися між двома подіями з різницею в хвилину? Якщо так, це властивість події. Сума витрати може змінитися за хвилину, а канал, з якого людина зареєструвалася, — ні.

Чому це важливо: властивість події відповідає на «що сталося», властивість користувача — на «хто це зробив». Більшості продуктових запитань потрібні обидві, наприклад «чи додають люди з платних соцмереж більші витрати?» Береш події, знаходиш кожен user_id у таблиці користувачів і групуєш за властивістю користувача.

  • Так
    Властивість події: amount_usd = 116. Властивість користувача: acquisition_channel = referral_link.
  • Не так
    Вважати entry_method властивістю користувача: «u007 — користувач, який сканує чеки».

    Спосіб може змінитися вже з наступною витратою.

Як приєднати властивості користувача до подій

Більшість запитань поєднує обидві таблиці. «Чи додають люди з платних соцмереж більше витрат, ніж запрошені?» потребує витрат із логу подій і каналу з таблиці користувачів.

Стандартний хід — об'єднання (join) за user_id:

  1. береш потрібні події, тут expense_added;
  2. для кожного рядка шукаєш його user_id у таблиці користувачів;
  3. додаєш потрібну властивість користувача, тут acquisition_channel;
  4. групуєш й рахуєш за нею.
Властивості події описують один момент і змінюються від події до події, властивості користувача описують людину. Знайди user_id, щоб розбити те, що сталося, за тим, хто.
Об'єднай два файли за user_id, щоб розбити події за тим, хто їх зробив.

Копіювати канал на кожну подію не треба. Властивість користувача, збережена один раз, не «роз'їжджається»: якщо підтримка виправить комусь канал, кожен минулий і майбутній звіт підхопить виправлення. Копія на кожній події заморожує те значення, яке надіслали тоді, і подвоює кількість місць, де може сховатися помилка.

Деякі аналітичні системи все ж додають кілька властивостей користувача до подій для зручності. Це нормально, якщо всі знають, яка копія є джерелом правди, і це таблиця користувачів.

  • Так
    Події expense_added → знайти user_id у таблиці користувачів → згрупувати за acquisition_channel.
  • Не так
    Просити розробників додати acquisition_channel до кожної події, перш ніж відповісти Theo.

    Відповідь уже є, треба лише одне об'єднання таблиць.

Що варто записувати як подію

Подія — це те, що стається в певний момент: створено групу, прийнято запрошення, показано paywall, додано витрату. Факт, який просто є правдою якийсь час, як-от часовий пояс, модель телефона чи поточний баланс, — це властивість або те, що застосунок обчислює, а не подія.

Ще два правила тримають лог придатним роками:

  • Називай події як об'єкт плюс дієслово в минулому часі, однаково на всіх платформах: expense_added, group_created, invite_accepted. Якщо Android пише addExpense, а iOS — expense_added, кожен звіт показує дві половинки одного числа, поки хтось не помітить.
  • Записуй те, від чого залежить рішення, а не кожне натискання й екран. Кожна подія має лишатися правильною в кожному релізі, і хтось має її перевіряти. Перегляд екрана заслуговує на подію, лише коли він потрібен для запитання, як-от показ paywall, бо важлива конверсія з нього.

Баланси — добрий приклад: вони постійно змінюються, але лише через витрати й розрахунки. Записуй ці події, і баланс завжди можна відновити з них.

  • Так
    invite_accepted, paywall_viewed з trigger = receipt_scan, group_created з group_type = trip
  • Не так
    balance_is_40, timezone_kyiv, addExpense лише на Android

    Стани, записані як події, і одна дія під двома назвами.

Стани і зміни стану

Багато продуктових фактів ідуть парами: стан і момент, коли він змінюється.

  • Бути на Halves Plus — це стан. Він належить людині як властивість користувача, наприклад plan = plus, щоб будь-який звіт можна було розбити на безплатних і платних користувачів.
  • Почати тріал, перейти на оплату, скасувати — це зміни. Кожна стається в один момент, тож кожна є подією: trial_started, subscription_started, subscription_cancelled зі своїм часом.

Записати стан як подію — поширена помилка. Подія на кшталт user_is_premium, що надсилається при кожному відкритті застосунку, спрацьовує знову і знову для тієї самої людини. Її кількість показує, як часто передплатники відкривають застосунок, а не скільки їх є, і досі не каже, коли хтось почав тріал.

Протилежна помилка — зберігати лише стан. Якщо є plan = plus, але нічого не записується в момент зміни, ти знаєш, хто платить сьогодні, але не знаєш, коли людина почала, тож не побудуєш воронку тріалу і не виміряєш конверсію за 7 днів.

  • Так
    Властивість користувача plan = plus; події trial_started і subscription_cancelled з часом.
  • Не так
    Подія user_is_premium при кожному відкритті застосунку.

    Стан, перевдягнений у подію: повторюється і ніколи не позначає зміну.

Серверні події та події застосунку

Про кожен рядок питай: хто або що його спричинило? Зазвичай відповідь дає колонка platform.

Події застосунку (ios, android) записує телефон, коли людина щось робить. Вони фіксують реальні дії, але телефон без зв'язку може надіслати їх на хвилини чи години пізніше, а видалений застосунок останніх подій не надішле взагалі.

Серверні події (server) записує бекенд. Вони не губляться через поганий зв'язок, тож добре підходять для грошей і підписок. Але деякі з них стаються, коли застосунку ніхто не торкається. У Halves передплатники Plus можуть зробити рахунок регулярним, як-от оренду, і сервер додає таку expense_added за розкладом о 06:00 UTC, поки користувач, можливо, спить.

Уночі невелика серверна шафа надсилає чек за оренду в телефон на тумбочці, поки його власник спить.
Серверна подія записується за розкладом, навіть коли застосунку ніхто не торкається.

Датасет: Тринадцять рядків із логу подій Halves, 1–4 червня · є вище

Тож platform = server з entry_method = recurring нічого не каже про те, чи людина користувалася Halves того дня. Якщо рахувати «людей, які додали витрату» просто за рядками, ці автоматичні витрати роздувають число. Щоб знати, чи людина користувалася продуктом, шукай її власні події із застосунку, як-от app_opened.

  • Так
    «Витрата u001 о 06:00 — регулярний рахунок, який додав сервер; подій із застосунку від u001 того дня немає».
  • Не так
    «u001 був активним 1 червня: додав витрату на 420 дол.»

    Сприймає автоматичну серверну подію як дію людини.

Рахуй людей, які діяли, а не id, що трапляються

Коли відомо, що частину рядків спричиняє система, простий підрахунок змінює зміст. «Скільки людей користувалися Halves?» — це не «скільки id користувачів трапляється в лозі».

Надійна послідовність для невеликого уривка:

  1. Відфільтруй рядки, які спричинила людина: тут platform дорівнює ios або android.
  2. Випиши різні значення user_id, що лишилися, щоб кожна людина рахувалася один раз, скільки б рядків у неї не було.
  3. Порівняй з нефільтрованим списком, щоб побачити, хто випав і чому.

У 13-рядковому уривку трапляється шість id. Один із них, u001, є лише в серверній регулярній витраті, тож щось зробили самі п'ятеро. Обидва числа правильні, але відповідають на різні запитання. Перше рахує акаунти, які згадує лог, друге — людей, які користувалися застосунком.

Датасет: Тринадцять рядків із логу подій Halves, 1–4 червня · є вище

Запиши, яке з них ти показуєш у звіті. Наступного уроку такі самі рішення визначать, скільки активних користувачів минулого тижня потрапить у звіт: 22, 19 чи 17.

  • Так
    Прибрати рядки server, потім порахувати різні user_id: 5 людей.
  • Не так
    Порахувати всі різні user_id в уривку: Halves користувалися 6 людей.

    Включає u001, який трапляється лише через серверний регулярний рахунок.

Одна дія, кілька рядків

Лог — це точний запис того, що побачила програма, а не перелік різних подій реального світу. Одна дія може залишити кілька рядків.

У Halves у розрахунку беруть участь двоє. Платник його записує, а коли інша людина підтверджує, її телефон ще раз записує settle_up_recorded. Обидва рядки мають той самий settlement_id: s004 від u013 о 12:27 і від u014 о 21:22, обидва на 185 дол. Кожен рядок правдивий, але на запитання «скільки розрахунків?» відповідає кількість різних значень settlement_id: три рядки, два розрахунки. З грошима так само: три рядки дають у сумі 437 дол., а платежі — 185 + 67 = 252 дол.

Датасет: Тринадцять рядків із логу подій Halves, 1–4 червня · є вище

Назви колонок про це не попередять. Треба знати, хто запускає кожну подію, де її записують і що означає її id; записати це — початок плану трекінгу.

Як це складається докупи: читай кожен рядок як речення; властивості кажуть, що сталося і з ким; колонка платформи — хто спричинив рядок; id — що таке одна одиниця. Далі урок Загальна кількість, унікальні користувачі й пастки підрахунку перетворює це прочитання на підрахунки.

  • Так
    Розрахунки = різні settlement_id = 2 (s004, s008); сплачено 252 дол.
  • Не так
    Розрахунки = рядки settle_up_recorded = 3; сплачено 437 дол.

    Рахує підтвердження s004 як другий платіж.

Готові потренуватися?

Виконайте вправи уроку й отримайте 250 балів, коли пройдете його вперше.

Розпочати вправи