DarkRiDDeR12 мин

Метрики продукта для инженера: построить цепочку, а не поднять conversion

МетрикиИнженерия

Инженер ускоряет экран и видит рост conversion на графике. Через несколько дней оказывается, что поменялся не выбор пользователя, а способ считать открытие: часть повторных попыток исчезла из denominator. Цена ошибки — выпуск решения по красивому числу, повторное расследование и потеря времени у продукта, аналитики и разработки.

Причина в разорванной цепочке. Latency, click и confirm часто живут в разных отчётах, а failure остаётся техническим alert. Проверка начинается не с нового dashboard: нужно назвать одно решение, один вход в воронку, одно правило attribution и один guardrail. Действие — записать их в contract до того, как смотреть delta.

От технического изменения к пользовательскому решению

Для примера возьмём synthetic изменение: экран подтверждения получает предзагруженную форму. Гипотеза не звучит как «latency важен». Она звучит уже: «если форма открывается без дополнительного ожидания, больше пользователей, которые открыли checkout, доходят до confirm; при этом render failures не должны стать чаще». Здесь loading step — механизм, opened и confirmed — наблюдаемые точки, а failure — цена, которую нельзя спрятать за conversion.

Причинная воронка fixed synthetic примера: техническое изменение ведёт к открытию checkout, подтверждению и решению пользователя; сбоку отдельно проходит guardrail render failure. Каждое ребро подписано событием и границей интерпретации.
Воронка не утверждает причинность сама по себе. Она заставляет до измерения указать, какой шаг наблюдаем, где attribution и какое ухудшение останавливает выпуск.
Цепочка и проверка
ЗвеноЧто фиксируемСимптом ошибкиДействие
Изменениеvariant и ownerневозможно сказать, что сравнивалиостановить карточку
Открытиеcheckout_opened, subject, perioddenominator плаваетсчитать unique subjects
Подтверждениеcheckout_confirmed + requestIdшаг нельзя отнести к попыткезаписать attribution rule
Guardrailrender_failed / openedconversion растёт вместе с отказамиhold и расследовать

Граница модели и терминов

В статье «событие» — записанный факт с именем, субъектом, cohort, периодом и контекстом. Cohort — группа, которой показан один вариант. Attribution — правило, по которому действие относят к этому варианту. Guardrail — отдельная метрика, которая не даёт купить рост локального показателя деградацией рядом. Это не словарь для дашборда: каждое поле должно отвечать на вопрос, почему изменение разрешили или остановили.

OpenTelemetry в закреплённой версии требует уникальное имя события и документированную структуру. Для продуктовых событий это полезная дисциплина: product.checkout_confirmed не содержит динамический id, а subject, requestId, cohort и period лежат отдельно. Но соглашение об имени не доказывает связь с решением пользователя. Эту связь сначала формулирует владелец продукта и проверяет инженерный контракт.

Один fixed synthetic пример

import { createFixedProductMetricInput, inspectFixedProductMetric, prepareFixedProductDecision } from './upgrade-2025-07.mjs';

const report = inspectFixedProductMetric(
  createFixedProductMetricInput('fixed-valid-v1'),
);
const decision = prepareFixedProductDecision(report);

console.log({ accepted: report.accepted, cohorts: report.byCohort, status: decision.status });
// Fixed literals only: no HTTP, file, telemetry, clock or production action.

В наборе четыре открытия, два подтверждения и одно synthetic render failure. Модель считает unique subjects, а не число строк: один повторный event не должен незаметно увеличить denominator. У treatment один из двух открывших подтвердил действие; у control подтверждает один из двух. Это не результат реального продукта и не статистический вывод: небольшой fixed набор нужен только для проверки того, что contract сохраняет cohort, period, denominator и guardrail рядом.

Контракт события и роль поля
ПолеПримерПроверкаНельзя заключать
eventproduct.checkout_openedимя описывает тип фактачто пользователь доволен
subjectu-bdeduplicate denominatorчто это реальная личность
cohorttreatmentсравнить один вариант с controlчто варианты случайно распределены
period2025-07-14не смешать окначто эффект сохранится завтра
requestIdr-2связать шаги одной попыткичто причина уже доказана
errorTypesynthetic-timeoutпосчитать guardrailчто это production incident

Общий маршрут до решения

  1. Назвать решение. Не «смотрим conversion», а «оставляем вариант только если подтверждение не растёт ценой failure».
  2. Записать причинную цепочку. Техническое изменение → видимый шаг → действие пользователя → outcome и отдельный guardrail.
  3. Зафиксировать cohort, период и denominator. Эти поля пишут до подсчёта, иначе результат подстраивают под удобный ответ.
  4. Проверить negative path. Нехватка attribution, иной period или иной denominator должны остановить decision, а не превратиться в null на графике.
  5. Сохранить decision record. Указать owner, evidence, ограничения и следующий запуск; human owner, а не функция, принимает product decision.

Все события, варианты, результаты и решения ниже — fixed synthetic JS literals. Модуль не читает файлы, сеть, clock, telemetry, Git, CI, production или user data и не выполняет side effect.

Что считать, а что не выдавать за доказательство

Microsoft Research различает local feature metrics, более общие success metrics и guardrail. Это хороший ориентир для раскладки, но не готовая формула для любого продукта. В нашем примере confirm/opened — local metric: он показывает, добрался ли пользователь до целевого шага. Он не равен долгосрочному outcome и не доказывает, что предзагрузка стала причиной. Поэтому decision record хранит формулировку гипотезы и отдельно пишет: «нужна проверка design и достаточного наблюдения».

Если attribution отсутствует, функция возвращает missing-attribution-rule. Это важнее нулевого графика: нельзя понять, относится ли confirm к показанному варианту, другому устройству или повторной попытке. Следующий шаг не «взять больше строк», а зафиксировать ключ связи и проверить, что он есть у обоих событий. Только после этого имеет смысл обсуждать latency или текст кнопки.

Ограничение и следующий шаг

Эта практика не заменяет randomized experiment, расчёт мощности, privacy review или реальный ownership. Fixed literals не показывают статистическую значимость и не содержат денег, команд или production telemetry. Следующий шаг: выберите одну воронку, выпишите denominator в виде множества субъектов и добавьте test, где confirmation пришёл без requestId. Ожидаемый результат — hold с понятной причиной, а не искусственный рост conversion.

Историческая граница июля 2025

Использованы OpenTelemetry v1.31.0 от 11 марта 2025 и работы Microsoft Research 2017 и 2019 годов. Они существовали до 31 июля 2025. Из них взяты только дисциплина события, различение metric roles и риск разного набора наблюдений. Конкретная causal chain, поля и stop decisions — инженерная конструкция этой статьи, не нормативное следствие источников.

Проверяемые источники

  • OpenTelemetry Semantic Conventions v1.31.0, events (immutable commit c01aa89, 11 March 2025) — версия: tag v1.31.0; immutable commit c01aa89d9a13042e56536c60975139c50e764796, 2025-03-11. Событие имеет уникальное имя; структура события и применимые attributes должны быть документированы, а dynamic values не должны становиться частью имени. Граница: Это соглашение о семантике telemetry. Оно не определяет продуктовую метрику, causal effect, выбор denominator или критерий ship.
  • Microsoft Research: Safe Velocity with Controlled Rollouts (ICSE-SEIP 2019) — версия: ICSE-SEIP 2019 author version, published 2019; HTTPS checked 2026-07-31. Работа различает local feature, success и guardrail metrics; guardrail нужен, чтобы выпуск не ухудшал важные показатели, а local metric помогает объяснить движение более общей метрики. Граница: Это описание controlled rollouts Microsoft. Оно не доказывает, что любое изменение local metric вызвало пользовательский результат в другом продукте.
  • Microsoft Research: A Dirty Dozen Metric Interpretation Pitfalls (KDD 2017) — версия: KDD 2017 author version, published 2017; HTTPS checked 2026-07-31. Работа показывает, что разные наборы наблюдений в treatment и control делают metric delta недостоверной; рекомендует разбирать numerator и denominator и отслеживать telemetry loss. Граница: Пример относится к controlled experiments. Он не заменяет дизайн эксперимента, расчёт мощности, privacy policy или проверку конкретного pipeline.