Data Platform System Design — DE Interview PrepСистемный дизайн платформы данных — Подготовка к DE-интервью

Fast-revision cheatsheet for Data Engineering interviews. Tailored for Senior/Lead DE. Шпаргалка для быстрого повторения перед Data Engineering интервью. Заточена под Senior/Lead DE.
open-ended designоткрытый дизайн vendor econ time-seriesэкон. временные ряды поставщиков Terminal · analytics · enterpriseTerminal · аналитика · enterprise point-in-time / vintagespoint-in-time / vintages 60-min screen60-минутный скрининг

The one prompt to over-prepare: "Design a platform that ingests vendor-supplied economic time-series and serves them to Terminal, analytics queries, and Enterprise." Nearly everything below is a probe into one slice of it. Do not start drawing. Clarify first.

Единственный запрос для сверхподготовки: "Спроектируй платформу, которая забирает экономические временные ряды от поставщиков и отдаёт их в Terminal, аналитические запросы и Enterprise." Почти всё ниже — это зондирование одного среза. Не начинай рисовать. Сначала уточняй.

Credibility anchor: you've run Meta's ~3.6B events/day unified model and a 6.2B-record entity-resolution fix. The senior move here is recognizing economics data is low-volume, high-correctness — and not over-engineering for scale that isn't there.
Якорь доверия: ты управлял унифицированной моделью Meta на ~3.6B событий/день и фиксом entity-resolution на 6.2B записей. Сеньорский ход здесь — признать, что экономические данные — это малый объём, высокая корректность — и не избыточное инженерное решение для масштаба, которого нет.

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 мин               завершить сильно
    
#1 red flag: jumping to a diagram or a tech stack before clarifying requirements. The JD is about translating needs into engineering; show that muscle in the first 4 minutes.
Красный флаг №1: прыгать к диаграмме или стеку технологий до уточнения требований. JD про перевод потребностей в инженерное решение; покажи эту мышцу в первые 4 минуты.
Hook: "Before I design anything I'd separate the hard constraints — for economics data that's timeliness and revision correctness — from throughput, which is modest here versus the 3.6B-events/day systems I'm used to."
Зацепка: «Прежде чем проектировать, я бы разделил жёсткие ограничения — для экономических данных это своевременность и корректность ревизий — и пропускную способность, которая здесь скромная по сравнению с системами на 3.6B событий/день, с которыми я работаю.»

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) + консьюмеры.

AxisWhat to askWhy it shapes the design
Volume / cardinalityHow many vendors, series, observations/release? Growth?Macro = thousands–millions of series, tiny per release. Drives "don't over-engineer".
Latency / timelinessWhich 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.
ConsistencyAtomic release visibility, or can a client see partial data?Stage-then-swap publish; ACID table formats.
RevisionsHow are revisions delivered? Need point-in-time / as-of?Append-only vintages, bitemporal grain. The domain differentiator.
ConsumersTerminal (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)?Один источник правды, множество форм чтения.
Interviewer will probe: "What's the hardest constraint?" Answer: revision correctness + timeliness, not scale. Naming that shows domain judgment.
О чём спросит интервьюер: «Какое самое жёсткое ограничение?» Ответ: корректность ревизий + своевременность, а не масштаб. Называние этого показывает доменное суждение.

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 — проговори просто

LayerContractMutability
Bronze (raw)schema-on-readimmutable, append
Silver (conformed)schema-on-write, gatedidempotent rewrite per partition
Gold (served)canonical + vintagesappend-only vintages
СлойКонтрактИзменяемость
Bronze (сырой)schema-on-readimmutable, append
Silver (conformed)schema-on-write, gatedидемпотентная перезапись на партицию
Gold (served)canonical + vintagesappend-only vintages
Hook: "Same shape as the Meta consolidation: profile heterogeneous sources, land immutably, conform to one model, validate before publish. The pivot for econ is that correctness, timeliness, and revision history dominate, not throughput."
Зацепка: «Та же форма, что и консолидация в Meta: профилировать гетерогенные источники, приземлять неизменяемо, conform к одной модели, валидировать перед публикацией. Поворот для econ в том, что доминируют корректность, своевременность и история ревизий, а не пропускная способность.»

4 · Ingestion layer4 · Слой ingestion

Push vs pull — decide per feedPush vs pull — решать на фид
Push (vendor sends)Pull (you fetch)
Transportwebhook, Kafka, SFTP-drop+eventscheduled API poll, SFTP scan
Latencylow, reacts at publishbounded by poll interval
Timing controlvendor controls; you must be readyyou control; risk overshooting SLA
Reliability needidempotent receipt + dedupretry + freshness sensor
Push (поставщик отправляет)Pull (вы забираете)
Транспортwebhook, Kafka, SFTP-drop+eventзапланированный API poll, SFTP scan
Задержканизкая, реагирует при публикацииограничена интервалом poll
Контроль времениконтролирует поставщик; вы должны быть готовыконтролируете вы; риск перестрелить SLA
Требование надёжностиидемпотентный приём + dedupretry + сенсор свежести

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,56 vs 1,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,56 vs 1,234.56), коды единиц, NULL/знаковые конвенции. Причуды поставщика живут ТОЛЬКО в staging.
  • Конфликтующие значения разных поставщиков для одного ряда → явное правило приоритета / tie-break + запись provenance, чтобы объяснить, какой источник победил.
Hook: "Conforming heterogeneous sources to one model is the Meta 10-logging-system consolidation — mapping overlapping fields to one schema cut 47% redundant volume."
Зацепка: «Conform гетерогенных источников к одной модели — это консолидация 10 систем логирования в Meta — маппинг перекрывающихся полей к одной схеме сократил 47% избыточного объёма.»
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 слое (строго типизировано, контракт насаждается перед публикацией). Гейт качества — это граница между ними.

Gotcha: if you enforce schema at ingest and reject a drifted file, you lose the evidence and can't replay. Land it, then gate it.
Подвох: если насаждаешь схему при ingestion и отклоняешь дрейфовавший файл, ты теряешь улику и не можешь replay. Приземли его, затем gate.

5 · Storage & partitioning5 · Хранение и партиционирование

Lakehouse vs warehouse vs time-series DB

Lakehouse vs хранилище vs time-series DB

OptionWhat it isFit for econ time-seriesVerdict
Columnar warehouse
Snowflake / BigQuery
MPP columnar, SQL-nativeGreat for analytics scans, joins to reference data, date pruningPrimary served/analytics store
Lakehouse
object store + Iceberg/Delta
Open table format, ACID, time-travel, cheapIdeal raw landing + history archive; time-travel aids replayLanding + archive layer
Time-series DB
kdb+ / Influx / Timescale
Optimized for high-freq inserts + window queriesOverkill for monthly macro; kdb+ is tick-data worldOnly 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. Использовать оба — это стандартное разделение, а не противоречие.

Hook: "At McMakler I migrated GCP-native → Snowflake for exactly this columnar reason and ran object-storage landing; I'd combine them rather than force one store to do both jobs."
Зацепка: «В McMakler я мигрировал GCP-native → Snowflake именно по этой колоночной причине и запускал landing в object storage; я бы комбинировал их, а не заставлял одно хранилище делать обе работы.»

Partitioning for time-series

Партиционирование для time-series

  • Partition by observation_date (coarser load_date for 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_date partition → 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 партиции, а не дневные.
Interviewer will probe: "Why not partition by 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 точек → пересчитать затронутое производное окно.
Probe: say the word "bitemporal" — valid time vs transaction time. It signals you know revisions are append-only vintages, not updates.
Зондирование: произнеси слово "bitemporal" — valid time vs transaction time. Это сигналит, что ты знаешь, что ревизии — это append-only vintages, а не обновления.
Hook: "At Front Tier on bank financial data I learned point-in-time discipline: a default model trained on after-the-fact numbers looks great and fails in production. Same discipline applies to macro vintages."
Зацепка: «Во Front Tier на банковских финансовых данных я усвоил дисциплину point-in-time: дефолтная модель, обученная на постфактумных числах, выглядит отлично и проваливается в продакшне. Та же дисциплина применима к макро-vintages.»

7 · Serving / query layer7 · Слой отдачи / запросов

ConsumerRead patternServing shape
Terminalinteractive point lookups ("US CPI YoY now / as-of X")low-latency; series_id-clustered; materialized latest-vintage view / cache
Analytics queriesanalytical scans across many series/datescolumnar warehouse; date partition pruning
Enterprise / Data Licensebulk extract / replication to client systemsscheduled 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 Licensebulk-экстракт / репликация в системы клиентазапланированный 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 поверх одной таблицы — никогда не пересчитывай одно число двумя способами (так клиент видит расхождение).

Probe: "Keep Terminal fast without a drifting copy?" → Materialize a latest-vintage view from the same gold table, refresh on publish, never hand-maintain a parallel copy.
Зондирование: «Держать Terminal быстрым без дрейфующей копии?» → Материализовать latest-vintage view из той же gold-таблицы, обновлять при публикации, никогда не поддерживать вручную параллельную копию.

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)
Behavior rule: AI/anomaly flags, deterministic gates decide. Never let a probabilistic step silently publish.
Правило поведения: AI/anomaly флагают, детерминистские gates решают. Никогда не позволяй вероятностному шагу тихо публиковать.
Hook: "At Career.io I institutionalised dbt code-review + testing so quality was a property of the workflow. At Meta I validated the entity-resolution fix against what 100+ downstream consumers saw, not just at the source."
Зацепка: «В Career.io я институционализировал dbt code-review + тестирование, чтобы качество стало свойством workflow. В Meta я валидировал фикс entity-resolution относительно того, что видели 100+ downstream-консьюмеров, а не только у источника.»

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)
CDMP/DMBOK quick win: the live areas are quality-in-pipeline, metadata/lineage, lifecycle (raw→marts→retention), ownership. Vocabulary signals fit.
CDMP/DMBOK быстрый win: живые области — quality-in-pipeline, metadata/lineage, жизненный цикл (raw→marts→retention), ownership. Словарь сигналит fit.

10 · Reliability, failure modes, replay10 · Надёжность, режимы сбоев, replay

Failure modes checklist (name these — strong senior signal)

Чеклист режимов сбоев (называй их — сильный сеньорский сигнал)

FailureDetectRecover
Vendor feed late / missingfreshness SLA breach (deferrable sensor)page + runbook (re-pull, check vendor)
Vendor schema driftcontract check at gatequarantine + alert; do not publish
Malformed rowsparse/validity checkquarantine bad, process good
Bad value / wrong unitrange / anomaly checkgate holds; vendor vs parse bug
Duplicate / replayed deliverycontent-hash dedupidempotent receipt, no double-count
Late-arriving revisionarrives for old observation_dateappend vintage in that partition; recompute derived window
Pipeline bug published bad datamonitor / client reportidempotent reprocess from immutable raw
Partial release visiblestage-then-swap prevents it
СбойОбнаружитьВосстановить
Фид поставщика опоздал / отсутствуетнарушение SLA свежести (deferrable sensor)page + runbook (re-pull, проверить поставщика)
Дрейф схемы поставщикапроверка контракта на gateкарантин + алерт; не публиковать
Некорректные строкиparse/validity checkкарантин плохих, обработать хорошие
Плохое значение / неверный unitrange / anomaly checkgate держит; баг поставщика 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 в инкременталах, чтобы поздние ревизии старых дат не пропустились.
Hook: "Idempotent partition-level reprocessing is what let me fix the Meta entity-resolution defect across 6.2B records safely, without double-counting."
Зацепка: «Идемпотентный reprocessing на уровне партиций — это то, что позволило мне безопасно зафиксить дефект entity-resolution в Meta на 6.2B записях, без двойного счёта.»

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).

Hook: "I'm comfortable at scale — ~3.6B events/day at Meta. The judgment here is recognizing econ's hard constraints are correctness, timeliness, and feed heterogeneity, and not over-building for throughput that isn't there."
Зацепка: «Мне комфортно на масштабе — ~3.6B событий/день в Meta. Суждение здесь — признать, что жёсткие ограничения econ — это корректность, своевременность и гетерогенность фидов, а не избыточное строительство под пропускную способность, которой нет.»

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-всего для месячных данных. Совпадение архитектуры со скромным объёмом — это и ЕСТЬ оптимизация стоимости.
Hook: "At McMakler I saved EUR 1M+ on migrations, including hundreds of thousands/yr in orchestration licensing, by replacing a proprietary orchestrator with Airflow — same instinct as not over-building for absent scale."
Зацепка: «В McMakler я сэкономил EUR 1M+ на миграциях, включая сотни тысяч/год на лицензировании оркестрации, заменив проприетарный оркестратор на Airflow — тот же инстинкт, что и не строить избыточно под отсутствующий масштаб.»

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) не вернулся)
    
Hook: "Exactly the McMakler triple migration — proprietary orchestrator→Airflow, GCP-native→Snowflake, Postgres→dbt — run in parallel and reconciled before cutover, 200+ users served throughout, EUR 1M+ saved."
Зацепка: «Точно тройная миграция в McMakler — проприетарный оркестратор→Airflow, GCP-native→Snowflake, Postgres→dbt — запущены параллельно и сверены перед cutover, 200+ пользователей обслуживались постоянно, EUR 1M+ сэкономлены.»
AI safely: anomaly detection on incoming values, schema/format inference for messy feeds, LLM-assisted rule suggestion. Always human-in-the-loop: AI flags, deterministic gates decide. (Untangler — won Meta EMEA DE Hackathon, adopted internally.)
AI безопасно: обнаружение аномалий на входящих значениях, schema/format inference для грязных фидов, LLM-ассистированное предложение правил. Всегда human-in-the-loop: AI флагует, детерминистские gates решают. (Untangler — победитель Meta EMEA DE Hackathon, принят внутри.)

13 · Self-quiz — tap to reveal13 · Самопроверка — нажми, чтобы открыть

What's the FIRST thing you do when handed an open-ended design prompt?Что ты делаешь ПЕРВЫМ, когда тебе дают открытый запрос на дизайн?
tap to flipнажми, чтобы перевернуть
AnswerОтвет
Clarify, don't draw. Ask V-L-F-C-R: Volume, Latency, Freshness SLA, Consistency, Revisions — plus consumers. Spend the first 3-5 min here.Уточняй, не рисуй. Спроси V-L-F-C-R: Объём, Задержка, SLA свежести, Согласованность, Ревизии — плюс консьюмеры. Потрать первые 3-5 мин здесь.
Why is "the latest value" wrong for economic data?Почему «последнее значение» неверно для экономических данных?
tap to flipнажми, чтобы перевернуть
AnswerОтвет
Macro figures are revised for months. The latest value isn't what a client knew at the time. You need append-only vintages + as-of views to avoid look-ahead bias.Макро-фигуры ревизуются месяцами. Последнее значение — это не то, что клиент знал в тот момент. Нужны append-only vintages + as-of views, чтобы избежать look-ahead bias.
Define bitemporal grain for a series observation.Определи bitemporal grain для наблюдения ряда.
tap to flipнажми, чтобы перевернуть
AnswerОтвет
observation_date (valid time — period data is about) + publish_timestamp (transaction time — when we knew it). Grain: (series_id, observation_date, revision_id, publish_ts, value).observation_date (valid time — период, о котором данные) + publish_timestamp (transaction time — когда мы узнали об этом). Grain: (series_id, observation_date, revision_id, publish_ts, value).
Partition by date or by series_id? Why?Партиционировать по дате или по series_id? Почему?
tap to flipнажми, чтобы перевернуть
AnswerОтвет
Partition by observation_date, cluster by series_id within. A release touches many series for one date; date-partitioning means a release/late-revision rewrites one partition, not thousands.Партиционировать по observation_date, кластеризовать по series_id внутри. Релиз касается многих рядов на одну дату; date-партиционирование означает, что релиз/поздняя ревизия переписывает одну партицию, а не тысячи.
Lakehouse, warehouse, or time-series DB?Lakehouse, хранилище или time-series DB?
tap to flipнажми, чтобы перевернуть
AnswerОтвет
Both lakehouse + warehouse: lakehouse for immutable raw landing + archive (cheap, replay, time-travel); columnar warehouse for served/analytics. Skip a tick-DB — monthly macro doesn't need it.И lakehouse, и хранилище: lakehouse для неизменяемого сырого landing + архива (дёшево, replay, time-travel); колоночное хранилище для served/аналитики. Пропусти tick-DB — месячное макро не нуждается.
Where do schema-on-read and schema-on-write each live?Где живут schema-on-read и schema-on-write соответственно?
tap to flipнажми, чтобы перевернуть
AnswerОтвет
Schema-on-read at landing (capture even malformed files, replayable). Schema-on-write at the conformed/served layer (strict, contract-enforced). The quality gate is the boundary.Schema-on-read при приземлении (захватить даже некорректные файлы, replayable). Schema-on-write в conformed/served слое (строго, контракт насажден). Гейт качества — это граница.
What makes the platform replayable?Что делает платформу replayable?
tap to flipнажми, чтобы перевернуть
AnswerОтвет
Immutable raw landing (the replay source) + idempotent partition-keyed reprocessing. Re-run any date range, any order, in parallel, and converge to the correct state.Неизменяемое сырое landing (источник replay) + идемпотентный partition-keyed reprocessing. Перезапустить любой диапазон дат, в любом порядке, параллельно, и сойтись к правильному состоянию.
How does a release appear atomically to clients?Как релиз появляется атомарно для клиентов?
tap to flipнажми, чтобы перевернуть
AnswerОтвет
Stage-then-swap: build + validate the full release in staging, then make it visible in one atomic op (partition swap / view repoint / Iceberg-Delta commit). Never publish mid-write.Stage-then-swap: собрать + валидировать полный релиз в staging, затем сделать видимым одной атомарной операцией (partition swap / view repoint / Iceberg-Delta commit). Никогда не публикуй посередине записи.
Five golden signals for data observability?Пять золотых сигналов для наблюдаемости данных?
tap to flipнажми, чтобы перевернуть
AnswerОтвет
Freshness, Completeness, Volume, Validity, Schema — surfaced as metrics with SLAs (not log lines), per-feed, tied to lineage for blast radius.Свежесть, Полнота, Объём, Валидность, Схема — представлены как метрики с SLA (не лог-строки), на фид, привязаны к lineage для blast radius.
Speed vs correctness when CPI is late or looks wrong?Скорость vs корректность, когда CPI опаздывает или выглядит неправильно?
tap to flipнажми, чтобы перевернуть
AnswerОтвет
Correctness wins — publish late with a clear signal, never fast-but-wrong. Run minimal critical-path validation, surface the delay, have a documented decision owner. Silent wrong number = huge blast radius.Побеждает корректность — публикуй поздно с чётким сигналом, никогда быстро-но-неправильно. Запусти минимальную валидацию критического пути, поверхностно задержку, имей задокументированного владельца решения. Тихое неправильное число = огромный blast radius.
Where does scale actually bite in econ data?Где масштаб действительно кусает в экон-данных?
tap to flipнажми, чтобы перевернуть
AnswerОтвет
Not row volume. It's: number of feeds (config-driven onboarding), serving concurrency (many clients), and vintage/history growth (every revision kept forever → tiered cheap storage).Не объём строк. Это: количество фидов (config-driven onboarding), конкуренция при отдаче (много клиентов), и рост vintages/истории (каждая ревизия хранится вечно → tier дешёвого хранилища).
Modernize a fragile legacy platform — the sequence?Модернизировать хрупкую легаси-платформу — последовательность?
tap to flipнажми, чтобы перевернуть
AnswerОтвет
Map consumers → strangler-fig new path → parallel-run → reconcile (counts/key-diffs/tolerances) → cut over consumer-by-consumer with fallback → decommission. Embed QC so debt doesn't return.Мапить консьюмеров → strangler-fig новый путь → parallel-run → сверить (counts/key-diffs/tolerances) → cutover консьюмер-за-консьюмером с fallback → списать. Встроить QC, чтобы долг не вернулся.