1 · How to structure the answer1 · Как структурировать ответ
The interviewer scores how you reason, not how fast you draw boxes. Say this scaffold out loud and walk it.
Интервьюер оценивает как ты рассуждаешь, а не как быстро рисуешь прямоугольники. Проговори этот каркас вслух и пройди по нему.
┌─ 1. CLARIFY ──────┐ ┌─ 2. PROPOSE ──────┐ ┌─ 3. TRADE-OFFS ───┐ ┌─ 4. DEEP-DIVE ────┐ ┌─ 5. FAILURE/OPS ──┐
│ restate prompt │ │ end-to-end at a │ │ for each choice: │ │ they pick OR you │ │ replay/backfill │
│ volume? latency? │─▶│ high level: │─▶│ name the alt + why │─▶│ volunteer the │─▶│ observability │
│ freshness SLA? │ │ ingest→land→ │ │ you chose it │ │ domain one: │ │ what breaks & │
│ revisions? consis-│ │ validate→model→ │ │ │ │ revisions/PIT or │ │ how you detect │
│ tency? consumers? │ │ serve (+QC/lineage)│ │ │ │ the quality gate │ │ │
└───────────────────┘ └────────────────────┘ └────────────────────┘ └───────────────────┘ └───────────────────┘
~3-5 min ~5-8 min woven in ~8-10 min close strong
┌─ 1. УТОЧНЕНИЕ ────┐ ┌─ 2. ПРЕДЛОЖЕНИЕ ──┐ ┌─ 3. КОМПРОМИССЫ ──┐ ┌─ 4. УГЛУБЛЕНИЕ ───┐ ┌─ 5. СБОИ/ОПС ─────┐
│ переформулировать │ │ end-to-end на │ │ для каждого выбора:│ │ они выбирают ИЛИ │ │ replay/backfill │
│ объём? задержка? │─▶│ высоком уровне: │─▶│ назвать альтернативу│─▶│ ты предлагаешь │─▶│ наблюдаемость │
│ SLA свежести? │ │ ingest→land→ │ │ + почему выбрал │ │ доменный аспект: │ │ что ломается & │
│ ревизии? согласов.│ │ validate→model→ │ │ │ │ ревизии/PIT или │ │ как обнаруживаешь │
│ консьюмеры? │ │ serve (+QC/lineage)│ │ │ │ гейт качества │ │ │
└───────────────────┘ └────────────────────┘ └────────────────────┘ └───────────────────┘ └───────────────────┘
~3-5 мин ~5-8 мин вплетено ~8-10 мин завершить сильно
2 · Requirements gathering — the five axes2 · Сбор требований — пять осей
Ask about each. Memorize the acronym mentally: V-L-F-C-R (Volume, Latency, Freshness, Consistency, Revisions) + consumers.
Спроси про каждую. Запомни мнемонику: V-L-F-C-R (Volume, Latency, Freshness, Consistency, Revisions) + консьюмеры.
| Axis | What to ask | Why it shapes the design |
|---|---|---|
| Volume / cardinality | How many vendors, series, observations/release? Growth? | Macro = thousands–millions of series, tiny per release. Drives "don't over-engineer". |
| Latency / timeliness | Which feeds are release-time-critical (CPI/NFP/GDP) vs monthly batch? | Event-trigger for critical; scheduled pull for the rest. |
| Freshness SLA | "On Terminal within N min of the official print"? Miss behavior? | Release-calendar-driven scheduling + deferrable sensor + escalation. |
| Consistency | Atomic release visibility, or can a client see partial data? | Stage-then-swap publish; ACID table formats. |
| Revisions | How are revisions delivered? Need point-in-time / as-of? | Append-only vintages, bitemporal grain. The domain differentiator. |
| Consumers | Terminal (point lookups), analytics (analytical scans), Enterprise/DL (bulk)? | One source of truth, multiple read shapes. |
| Ось | Что спросить | Почему это формирует дизайн |
|---|---|---|
| Объём / кардинальность | Сколько поставщиков, рядов, наблюдений/релиз? Рост? | Макро = тысячи–миллионы рядов, крошечный объём на релиз. Ведёт к «не переинженерить». |
| Задержка / своевременность | Какие фиды критичны по времени релиза (CPI/NFP/GDP) vs месячный батч? | Событийный триггер для критичных; запланированный pull для остальных. |
| SLA свежести | «В Terminal в течение N минут от официального релиза»? Поведение при промахе? | Планирование по календарю релизов + отложенный сенсор + эскалация. |
| Согласованность | Атомарная видимость релиза, или клиент может увидеть частичные данные? | Публикация stage-then-swap; ACID табличные форматы. |
| Ревизии | Как доставляются ревизии? Нужны point-in-time / as-of? | Append-only vintages, bitemporal grain. Доменный дифференциатор. |
| Консьюмеры | Terminal (point lookups), аналитика (аналитические сканы), Enterprise/DL (bulk)? | Один источник правды, множество форм чтения. |
3 · Reference architecture (ingest → serve)3 · Референсная архитектура (ingest → serve)
VENDORS INGEST LAND (bronze) VALIDATE+CONFORM (silver) MODEL (gold) SERVE
┌────────┐ push/pull ┌──────────┐ ┌────────────┐ ┌─────────────────────┐ ┌───────────┐ ┌──────────────┐
│ SFTP │──────────▶│ adapters │────▶│ IMMUTABLE │────▶│ parse · type · │───▶│ canonical │────▶│ Terminal │
│ API │ │ per feed │ │ raw object │ │ QUALITY GATE │ │ long fmt │ │ (lookups) │
│ Kafka │ │ (registry│ │ store │ │ (fail-closed) · │ │ +vintages │ │ analytics │
│ files │ │ driven) │ │ part by │ │ quarantine bad rows·│ │ +derived │ │ (scans) │
└────────┘ └──────────┘ │ load_date │ │ conform to ONE model│ │ series │ │ Enterprise/DL│
└────────────┘ └─────────────────────┘ └───────────┘ │ (bulk) │
└──────────────┘
══ CROSS-CUTTING ══▶ orchestration (release-calendar as data) · observability (freshness/completeness/validity) · lineage + metadata catalog
ПОСТАВЩИКИ INGEST LAND (bronze) VALIDATE+CONFORM (silver) MODEL (gold) SERVE
┌────────┐ push/pull ┌──────────┐ ┌────────────┐ ┌─────────────────────┐ ┌───────────┐ ┌──────────────┐
│ SFTP │──────────▶│ адаптеры │────▶│ НЕИЗМЕНЯЕМОЕ│────▶│ parse · type · │───▶│ каноничный│────▶│ Terminal │
│ API │ │ на фид │ │ сырое хран. │ │ ГЕЙТ КАЧЕСТВА │ │ long fmt │ │ (lookups) │
│ Kafka │ │ (реестр- │ │ объектов │ │ (fail-closed) · │ │ +vintages │ │ аналитика │
│ файлы │ │ управл.)│ │ part по │ │ карантин плохих · │ │ +производные│ │ (сканы) │
└────────┘ └──────────┘ │ load_date │ │ conform к ОДНОЙ │ │ ряды │ │ Enterprise/DL│
└────────────┘ │ модели │ └───────────┘ │ (bulk) │
└─────────────────────┘ └──────────────┘
══ СКВОЗНЫЕ ══▶ оркестрация (календарь релизов как данные) · наблюдаемость (свежесть/полнота/валидность) · lineage + каталог метаданных
The layers
Слои
- Ingest adapters (registry-driven): one adapter per transport; a feed registry holds cadence/format/contract/SLA/PK. New feed = config change.
- Land (bronze): raw payload written immutably, partitioned
vendor/dataset/load_date+ hash. The replay source. Never mutate. - Validate + conform (silver): typed staging; quality gate before publish; quarantine bad rows; conform every vendor into ONE model.
- Model (gold): grain
(series_id, observation_date, value, revision_id, publish_ts, status); derived (MoM/YoY) are downstream models. - Serve: warehouse for analytics; fast point-lookup for Terminal; bulk for Enterprise; as-of views first-class.
- Ingest адаптеры (управляемые реестром): один адаптер на транспорт; реестр фидов хранит частоту/формат/контракт/SLA/PK. Новый фид = изменение конфига.
- Land (bronze): сырой payload записан неизменяемо, партиционирован
vendor/dataset/load_date+ хеш. Источник для replay. Никогда не мутировать. - Validate + conform (silver): типизированный staging; гейт качества перед публикацией; карантин плохих строк; conform каждого поставщика в ОДНУ модель.
- Model (gold): grain
(series_id, observation_date, value, revision_id, publish_ts, status); производные (MoM/YoY) — это downstream-модели. - Serve: хранилище для аналитики; быстрый point-lookup для Terminal; bulk для Enterprise; as-of views первоклассные.
Bronze / Silver / Gold — say it plainly
Bronze / Silver / Gold — проговори просто
| Layer | Contract | Mutability |
|---|---|---|
| Bronze (raw) | schema-on-read | immutable, append |
| Silver (conformed) | schema-on-write, gated | idempotent rewrite per partition |
| Gold (served) | canonical + vintages | append-only vintages |
| Слой | Контракт | Изменяемость |
|---|---|---|
| Bronze (сырой) | schema-on-read | immutable, append |
| Silver (conformed) | schema-on-write, gated | идемпотентная перезапись на партицию |
| Gold (served) | canonical + vintages | append-only vintages |
4 · Ingestion layer4 · Слой ingestion
Push vs pull — decide per feedPush vs pull — решать на фид
| Push (vendor sends) | Pull (you fetch) | |
|---|---|---|
| Transport | webhook, Kafka, SFTP-drop+event | scheduled API poll, SFTP scan |
| Latency | low, reacts at publish | bounded by poll interval |
| Timing control | vendor controls; you must be ready | you control; risk overshooting SLA |
| Reliability need | idempotent receipt + dedup | retry + freshness sensor |
| Push (поставщик отправляет) | Pull (вы забираете) | |
|---|---|---|
| Транспорт | webhook, Kafka, SFTP-drop+event | запланированный API poll, SFTP scan |
| Задержка | низкая, реагирует при публикации | ограничена интервалом poll |
| Контроль времени | контролирует поставщик; вы должны быть готовы | контролируете вы; риск перестрелить SLA |
| Требование надёжности | идемпотентный приём + dedup | retry + сенсор свежести |
Rule: release-time-critical → push/event trigger + short-interval deferrable sensor safety net, driven off the release calendar (not a coarse cron). Periodic batch → scheduled pull. Land everything immutably regardless so downstream is identical.
Правило: критично по времени релиза → push/event trigger + короткоинтервальная отложенная страховочная сеть сенсора, управляемая календарём релизов (не грубым cron). Периодический батч → запланированный pull. Приземлять всё неизменяемо независимо, чтобы downstream был идентичен.
Heterogeneous formats (CSV / JSON / XML / fixed-width)Гетерогенные форматы (CSV / JSON / XML / fixed-width)
- Feed registry as config — per-vendor format, contract, PK, cadence, SLA. Generate adapters/DAGs from it.
- Normalize early in silver — date formats, decimal separators (
1.234,56vs1,234.56), unit codes, NULL/sign conventions. Vendor quirks live ONLY in staging. - Conflicting values across vendors for the same series → explicit precedence / tie-break rule + record provenance so you can explain which source won.
- Реестр фидов как конфиг — формат/контракт/PK/частота/SLA на поставщика. Генерировать адаптеры/DAG из него.
- Нормализовать рано в silver — форматы дат, десятичные разделители (
1.234,56vs1,234.56), коды единиц, NULL/знаковые конвенции. Причуды поставщика живут ТОЛЬКО в staging. - Конфликтующие значения разных поставщиков для одного ряда → явное правило приоритета / tie-break + запись provenance, чтобы объяснить, какой источник победил.
Schema-on-read vs schema-on-write — where each appliesSchema-on-read vs schema-on-write — где каждый применим
schema-on-read = store raw, impose structure at query time. schema-on-write = enforce structure at ingest, reject non-conforming.
schema-on-read = хранить сырое, налагать структуру при запросе. schema-on-write = насаждать структуру при ingestion, отклонять несоответствующее.
The split: schema-on-read at landing (capture even malformed files, lose nothing, replayable) → schema-on-write at the conformed/served layer (strictly typed, contract-enforced before publish). The quality gate IS the boundary between the two.
Разделение: schema-on-read при приземлении (захватить даже некорректные файлы, не потерять ничего, replayable) → schema-on-write в conformed/served слое (строго типизировано, контракт насаждается перед публикацией). Гейт качества — это граница между ними.
5 · Storage & partitioning5 · Хранение и партиционирование
Lakehouse vs warehouse vs time-series DB
Lakehouse vs хранилище vs time-series DB
| Option | What it is | Fit for econ time-series | Verdict |
|---|---|---|---|
| Columnar warehouse Snowflake / BigQuery | MPP columnar, SQL-native | Great for analytics scans, joins to reference data, date pruning | Primary served/analytics store |
| Lakehouse object store + Iceberg/Delta | Open table format, ACID, time-travel, cheap | Ideal raw landing + history archive; time-travel aids replay | Landing + archive layer |
| Time-series DB kdb+ / Influx / Timescale | Optimized for high-freq inserts + window queries | Overkill for monthly macro; kdb+ is tick-data world | Only if a feed is truly high-freq |
| Вариант | Что это | Подходит для econ time-series | Вердикт |
|---|---|---|---|
| Колоночное хранилище Snowflake / BigQuery | MPP колоночное, SQL-native | Отлично для аналитических сканов, join к референс-данным, date pruning | Первичное served/аналитика хранилище |
| Lakehouse object store + Iceberg/Delta | Открытый табличный формат, ACID, time-travel, дешёвый | Идеально для сырого landing + архив истории; time-travel помогает replay | Слой landing + архив |
| Time-series DB kdb+ / Influx / Timescale | Оптимизирована для высокочастотных insert + оконных запросов | Избыточно для месячного макро; kdb+ — это мир tick-data | Только если фид действительно высокочастотный |
My answer: lakehouse for immutable landing + archive feeding a columnar warehouse for the conformed/served layer. Not a tick-DB for monthly data. Lakehouse = openness + cost + replay; warehouse = query perf + concurrency + governance. Using both is the standard split, not a contradiction.
Мой ответ: lakehouse для неизменяемого landing + архива, питающего колоночное хранилище для conformed/served слоя. Не tick-DB для месячных данных. Lakehouse = открытость + цена + replay; хранилище = query perf + конкуренция + governance. Использовать оба — это стандартное разделение, а не противоречие.
Partitioning for time-series
Партиционирование для time-series
- Partition by
observation_date(coarserload_datefor raw). It's what you filter and reprocess on → cheap incrementals, partition-level idempotent overwrite, pruned as-of scans. - Cluster/sort within partition by
series_id→ fast single-series Terminal lookups. - Keep revisions inside the
observation_datepartition → a late revision rewrites exactly one partition. - Avoid over-partitioning (small-files / metadata bloat) AND skewed mega-partitions. Monthly macro may want monthly/per-load partitions, not daily.
- Партиционировать по
observation_date(грубееload_dateдля сырого). Это то, по чему фильтруешь и перепроцессируешь → дешёвые инкрементали, идемпотентная перезапись на уровне партиции, pruned as-of scans. - Cluster/сортировать внутри партиции по
series_id→ быстрые одноранговые Terminal lookups. - Хранить ревизии внутри партиции
observation_date→ поздняя ревизия переписывает ровно одну партицию. - Избегать избыточного партиционирования (маленькие файлы / bloat метаданных) И перекошенных мега-партиций. Месячное макро может хотеть месячные/per-load партиции, а не дневные.
series_id?" → Bad for time-range scans and for reprocessing a release (one release touches many series for one date → you'd rewrite thousands of partitions). Date-partition + series-cluster is the right split.series_id?» → Плохо для time-range сканов и для перепроцессинга релиза (один релиз касается многих рядов на одну дату → ты бы переписал тысячи партиций). Date-partition + series-cluster — это правильное разделение.6 · Revisions & point-in-time DOMAIN6 · Ревизии и point-in-time DOMAIN
The single most important econ concept. A CPI/GDP/NFP figure is revised for months; "the latest value" is not what a client knew at the time.
Самая важная концепция econ. Фигура CPI/GDP/NFP ревизуется месяцами; «последнее значение» — это не то, что клиент знал в тот момент.
Bitemporal grain
Bitemporal grain
# two time axes — keep BOTH observation_date # the period data is ABOUT (valid time) publish_timestamp # when WE knew it (transaction time) # grain (series_id, observation_date, revision_id, publish_timestamp, value, unit, status)
# две временные оси — хранить ОБЕ observation_date # период, о котором данные (valid time) publish_timestamp # когда МЫ узнали об этом (transaction time) # grain (series_id, observation_date, revision_id, publish_timestamp, value, unit, status)
- Append a new vintage, never overwrite.
- "Current" = view: latest revision per
(series_id, observation_date). - "As-of X" = view: latest revision where
publish_ts <= X.
- Дописать новый vintage, никогда не перезаписывать.
- "Current" = view: последняя ревизия на
(series_id, observation_date). - "As-of X" = view: последняя ревизия, где
publish_ts <= X.
Why it matters
Почему это важно
- Prevents look-ahead bias in any backtest / forecast evaluation / client analysis.
- A model trained on revised-after-the-fact numbers is silently cheating.
- One revised value changes several MoM/YoY/rolling points → recompute the affected derived window.
- Предотвращает look-ahead bias в любом backtest / forecast evaluation / анализе клиента.
- Модель, обученная на ревизованных постфактум числах, тихо жульничает.
- Одно ревизованное значение меняет несколько MoM/YoY/rolling точек → пересчитать затронутое производное окно.
7 · Serving / query layer7 · Слой отдачи / запросов
| Consumer | Read pattern | Serving shape |
|---|---|---|
| Terminal | interactive point lookups ("US CPI YoY now / as-of X") | low-latency; series_id-clustered; materialized latest-vintage view / cache |
| Analytics queries | analytical scans across many series/dates | columnar warehouse; date partition pruning |
| Enterprise / Data License | bulk extract / replication to client systems | scheduled bulk export / replication feed; idempotent, vintage-labeled |
| Консьюмер | Паттерн чтения | Форма отдачи |
|---|---|---|
| Terminal | интерактивные point lookups («US CPI YoY сейчас / as-of X») | низкая задержка; кластер по series_id; материализованный latest-vintage view / кеш |
| Аналитические запросы | аналитические сканы по многим рядам/датам | колоночное хранилище; date partition pruning |
| Enterprise / Data License | bulk-экстракт / репликация в системы клиента | запланированный bulk-экспорт / фид репликации; идемпотентный, vintage-labeled |
One source of truth: all three read the same vintage-aware canonical model. Current and as-of are views over one table — never recompute the same number two ways (that's how a client sees a discrepancy).
Один источник правды: все три читают одну и ту же каноничную модель, осведомлённую о vintages. Current и as-of — это views поверх одной таблицы — никогда не пересчитывай одно число двумя способами (так клиент видит расхождение).
Atomic release visibility
Атомарная видимость релиза
Stage-then-swap: build the release fully in staging, validate, then make it visible in one atomic op (partition swap / view repoint / Iceberg-Delta commit). Consumers read the previous consistent state until the swap. Never publish mid-write.
Stage-then-swap: собрать релиз полностью в staging, валидировать, затем сделать видимым одной атомарной операцией (partition swap / view repoint / Iceberg-Delta commit). Консьюмеры читают предыдущее согласованное состояние до swap. Никогда не публикуй посередине записи.
8 · Quality & observability — woven through8 · Качество и наблюдаемость — вплетено насквозь
Structure by WHERE (lifecycle) and WHAT (check type).
Структурировать по ГДЕ (жизненный цикл) и ЧТО (тип проверки).
WHERE (lifecycle)
ГДЕ (жизненный цикл)
- Ingest gate (fail-closed) — the heart. Bad data never reaches consumers. Quarantine bad rows; fail on systemic issues.
- Post-publish monitors — trend drift after the gate.
- Contract at the boundary — validate vendor schema on arrival.
- Ingest gate (fail-closed) — сердце. Плохие данные никогда не достигают консьюмеров. Карантин плохих строк; фейл на системных проблемах.
- Мониторы после публикации — отслеживать дрейф после gate.
- Контракт на границе — валидировать схему поставщика при прибытии.
Observability — golden signals for data
Наблюдаемость — золотые сигналы для данных
Freshness · Completeness · Volume · Validity · Schema — as metrics with SLAs, not log lines. Per-feed dashboard + lineage = blast radius at a glance.
Свежесть · Полнота · Объём · Валидность · Схема — как метрики с SLA, не лог-строки. Dashboard на фид + lineage = blast radius с одного взгляда.
WHAT (check types)
ЧТО (типы проверок)
- Schema/contract — columns, types, enum domains (catch drift)
- Completeness — rows vs expected; all series/dates present (gap detection)
- Freshness — landed within SLA of official release time
- Validity/range — plausible bounds, non-null, unit sanity
- Uniqueness/PK —
(series_id, observation_date, revision) - Referential — series_id in series master
- Anomaly — > N-sigma / sudden jump (catches a misplaced decimal or unit change)
- Схема/контракт — колонки, типы, enum-домены (ловить дрейф)
- Полнота — строки vs ожидаемые; все ряды/даты присутствуют (обнаружение пропусков)
- Свежесть — приземлилось в пределах SLA от официального времени релиза
- Валидность/диапазон — правдоподобные границы, non-null, unit sanity
- Уникальность/PK —
(series_id, observation_date, revision) - Референциальная — series_id в series master
- Аномалия — > N-sigma / резкий скачок (ловит неправильную десятичную или смену unit)
9 · Lineage, metadata, governance9 · Lineage, метаданные, governance
Lineage source → Terminal
Lineage источник → Terminal
- Model layer (dbt graph) + pipeline/asset layer (Airflow/Dagster, OpenLineage).
- Column-level lineage + load metadata (load_ts, file hash, vintage).
- Value: impact analysis, root-cause (wrong Terminal number → trace to source vintage), audit.
- Record which vintage fed a derived value → reproduce exactly what the client saw.
- Слой модели (dbt graph) + слой pipeline/asset (Airflow/Dagster, OpenLineage).
- Column-level lineage + метаданные загрузки (load_ts, file hash, vintage).
- Ценность: impact-анализ, root-cause (неверное число в Terminal → отследить до source vintage), аудит.
- Записывать, какой vintage питал производное значение → воспроизвести в точности то, что увидел клиент.
Metadata catalog
Каталог метаданных
- Feed registry (cadence, format, contract, SLA, owner)
- Series master (id, definition, unit, source, geography)
- Schema contracts versioned in source control
- Quality results per run · lineage graph · load audit (hash, ts, counts)
- Реестр фидов (частота, формат, контракт, SLA, владелец)
- Series master (id, определение, unit, источник, география)
- Контракты схем версионированы в source control
- Результаты качества на run · lineage graph · load audit (хеш, ts, counts)
10 · Reliability, failure modes, replay10 · Надёжность, режимы сбоев, replay
Failure modes checklist (name these — strong senior signal)
Чеклист режимов сбоев (называй их — сильный сеньорский сигнал)
| Failure | Detect | Recover |
|---|---|---|
| Vendor feed late / missing | freshness SLA breach (deferrable sensor) | page + runbook (re-pull, check vendor) |
| Vendor schema drift | contract check at gate | quarantine + alert; do not publish |
| Malformed rows | parse/validity check | quarantine bad, process good |
| Bad value / wrong unit | range / anomaly check | gate holds; vendor vs parse bug |
| Duplicate / replayed delivery | content-hash dedup | idempotent receipt, no double-count |
| Late-arriving revision | arrives for old observation_date | append vintage in that partition; recompute derived window |
| Pipeline bug published bad data | monitor / client report | idempotent reprocess from immutable raw |
| Partial release visible | — | stage-then-swap prevents it |
| Сбой | Обнаружить | Восстановить |
|---|---|---|
| Фид поставщика опоздал / отсутствует | нарушение SLA свежести (deferrable sensor) | page + runbook (re-pull, проверить поставщика) |
| Дрейф схемы поставщика | проверка контракта на gate | карантин + алерт; не публиковать |
| Некорректные строки | parse/validity check | карантин плохих, обработать хорошие |
| Плохое значение / неверный unit | range / anomaly check | gate держит; баг поставщика vs parse |
| Дубликат / переиграная доставка | content-hash dedup | идемпотентный приём, нет двойного счёта |
| Поздняя ревизия | приходит для старого observation_date | дописать vintage в ту партицию; пересчитать производное окно |
| Баг pipeline опубликовал плохие данные | монитор / жалоба клиента | идемпотентный reprocess из неизменяемого сырого |
| Частичный релиз видим | — | stage-then-swap предотвращает |
Replay / backfill story
История replay / backfill
- Immutable raw landing = the replay source. Re-derive any downstream state deterministically.
- Idempotent, partition-keyed reprocessing — re-run replaces partitions; backfill any range, any order, in parallel, converges.
- Triggers: bug fix, revision, new derived series, contract change → replay from raw.
- Lookback window in incrementals so late revisions to old dates aren't missed.
- Неизменяемое сырое landing = источник replay. Перевывести любое downstream-состояние детерминистски.
- Идемпотентный, partition-keyed reprocessing — перезапуск заменяет партиции; backfill любого диапазона, в любом порядке, параллельно, сходится.
- Триггеры: фикс бага, ревизия, новый производный ряд, изменение контракта → replay из сырого.
- Lookback window в инкременталах, чтобы поздние ревизии старых дат не пропустились.
Scale — where it actually bites (be honest)
Масштаб — где он действительно кусает (будь честен)
Raw row volume is NOT the challenge (macro is low-frequency). The pressure points: number of feeds (config-driven onboarding, not bespoke code) · serving concurrency (many Terminal/analytics clients) · history/vintage growth (every revision kept forever → partition + cheap object storage + archival tiers).
Объём сырых строк — НЕ челлендж (макро низкочастотный). Точки давления: количество фидов (config-driven onboarding, не bespoke-код) · конкуренция при отдаче (много Terminal/аналитики клиентов) · рост истории/vintages (каждая ревизия хранится вечно → партиция + дешёвое object storage + архивные tier).
11 · Cost11 · Стоимость
- Storage: raw + every vintage forever can balloon → cheap object storage for landing/archive; warehouse only for hot/served; tier cold history; compress (Parquet).
- Compute: push transforms to warehouse/Spark; incremental over full-refresh; avoid full scans; separate critical-feed compute from bulk.
- Don't over-engineer: no streaming infra, no tick-DB, no real-time-everything for monthly data. Matching architecture to modest volume IS the cost optimization.
- Хранение: сырое + каждый vintage навсегда может раздуться → дешёвое object storage для landing/архива; хранилище только для горячего/served; tier холодной истории; сжимать (Parquet).
- Вычисления: пушить трансформации в хранилище/Spark; инкрементально поверх full-refresh; избегать полных сканов; разделять вычисления критичных фидов от bulk.
- Не переинженерить: никакой стримингой инфраструктуры, никакой tick-DB, никакого real-time-всего для месячных данных. Совпадение архитектуры со скромным объёмом — это и ЕСТЬ оптимизация стоимости.
12 · Modernization12 · Модернизация
Inherit a fragile platform that breaks weekly → modernize without breaking consumers
Унаследовал хрупкую платформу, которая ломается еженедельно → модернизируй, не ломая консьюмеров
map consumers ─▶ stand up new path ─▶ parallel-run ─▶ reconcile ─▶ cutover ─▶ decommission old
(FIRST, (strangler-fig, (both to (counts, (consumer- (embed QC+tests
non-negotiable) not rip-replace) separate key diffs, by-consumer, so debt
targets) tolerances) keep fallback) doesn't return)
мапить консьюмеров ─▶ поднять новый путь ─▶ parallel-run ─▶ сверить ─▶ cutover ─▶ списать старое
(ПЕРВОЕ, (strangler-fig, (оба в (counts, (консьюмер- (встроить QC+тесты
без переговоров) не rip-replace) отдельные key diffs, за-консьюмером, чтобы долг
targets) tolerances) держать fallback) не вернулся)