Fast-revision cheatsheet for Data Engineering interviews. Tailored for Senior/Lead DE.
Шпаргалка для быстрого повторения перед Data Engineering интервью. Заточена под Senior/Lead DE.
Core theme: embed quality controls directly into pipelines, validation, monitoring, schema-change handling, exception handling, integrity, alerting, observability, remediation.
Ключевая тема: встраивать контроли качества напрямую в пайплайны, валидация, мониторинг, обработка изменений схем, обработка исключений, целостность, алерты, observability, восстановление.
Quality is multi-dimensional. Name them precisely; each maps to a different test. For economics data (rates, CPI prints, GDP revisions, FX), timeliness + accuracy + consistency dominate because downstream terminals trade on it.
Качество — многомерно. Называй их точно; каждое соответствует отдельному тесту. Для экономических данных (ставки, CPI, GDP-ревизии, FX) доминируют свежесть + точность + согласованность, потому что терминалы торгуют на основе этих данных.
| Dimension | Question it answers | Concrete check | Econ-data example |
|---|---|---|---|
| Accuracy | Does the value match reality / source of truth? | Reconcile vs authoritative source; checksum | CPI YoY matches official release |
| Completeness | Are all expected rows/fields present? | Row-count vs expected, NULL ratio, missing partitions | All 50 states present in employment feed |
| Timeliness / Freshness | Did data arrive within the SLA window? | max(event_time) vs now; partition arrival lag | FX tick < 2s old; daily print by 08:31 ET |
| Consistency | Do related sources/copies agree? | Cross-table reconciliation; sum-to-total | Sum of components = headline GDP |
| Validity | Does it conform to format / range / type? | Schema + regex + range/domain constraints | rate ∈ [-5%, 30%]; ISO-4217 currency code |
| Uniqueness | Are there duplicates / broken keys? | PK dedup, distinct-count, no dup grain | One row per (series_id, date) |
| Измерение | На какой вопрос отвечает | Конкретная проверка | Пример (экон. данные) |
|---|---|---|---|
| Точность (Accuracy) | Совпадает ли значение с реальностью / источником истины? | Сверка с авторитетным источником; чексуммы | CPI YoY совпадает с официальным релизом |
| Полнота (Completeness) | Все ли ожидаемые строки/поля присутствуют? | Число строк vs ожидаемое, доля NULL, отсутствующие партиции | Все 50 штатов в фиде по занятости |
| Своевременность / Свежесть (Timeliness / Freshness) | Данные прибыли в пределах SLA-окна? | max(event_time) vs now; задержка партиции | FX-тик < 2s; дневная публикация к 08:31 ET |
| Согласованность (Consistency) | Согласованы ли связанные источники/копии? | Кросс-табличная сверка; сумма по компонентам | Сумма компонентов = headline GDP |
| Корректность (Validity) | Соответствует ли формату / диапазону / типу? | Схема + regex + ограничения по диапазону/домену | rate ∈ [-5%, 30%]; код валюты ISO-4217 |
| Уникальность (Uniqueness) | Есть ли дубликаты / сломанные ключи? | Дедуп PK, distinct-count, отсутствие дублей по grain | Одна строка на (series_id, date) |
Memorize these five — interviewers love the framework (popularized by Monte Carlo). Each is a class of monitored signal on metadata, not on individual values.
Запомни эти пять — интервьюеры любят этот фреймворк (популяризован Monte Carlo). Каждый — это класс отслеживаемого сигнала на метаданных, а не на отдельных значениях.
How recent is the data? Is the table updating on schedule?
Насколько свежие данные? Обновляется ли таблица по расписанию?
Signal: now() - max(updated_at), partition arrival time vs SLA.
Сигнал: now() - max(updated_at), время прибытия партиции vs SLA.
Did the expected number of rows land?
Прибыло ли ожидаемое число строк?
Signal: row counts vs historical baseline / day-of-week seasonality. Catches drops & floods.
Сигнал: число строк vs исторический базис / сезонность по дню недели. Ловит падения и всплески.
Did the structure change? Columns added/removed/retyped?
Изменилась ли структура? Колонки добавлены/удалены/переопределены по типу?
Signal: schema diff vs registered contract; type/order/nullability changes.
Сигнал: schema diff vs зарегистрированный контракт; изменения типа/порядка/nullability.
Are the values still in the expected statistical shape?
Значения всё ещё в ожидаемой статистической форме?
Signal: NULL rate, min/max, mean, cardinality, % in enum, drift (PSI/KS).
Сигнал: доля NULL, min/max, mean, кардинальность, % в enum, дрифт (PSI/KS).
What's upstream/downstream? When something breaks, what's the blast radius and root cause?
Что апстрим/даунстрим? Когда что-то ломается, каков радиус поражения и первопричина?
Signal: column- and table-level dependency graph; map an alert to impacted dashboards/consumers and to the upstream source that changed.
Сигнал: граф зависимостей на уровне колонок и таблиц; сопоставить алерт с затронутыми дашбордами/консьюмерами и с изменившимся апстрим-источником.
Enforce column presence, types, nullability, order before processing. First line of defense; cheap and catches the loudest breakages.
Проверяй наличие колонок, типы, nullability, порядок перед обработкой. Первая линия защиты; дёшево и ловит самые громкие поломки.
# Great Expectations style
expect_table_columns_to_match_ordered_list(["series_id","date","value"])
expect_column_values_to_be_of_type("value", "DOUBLE")
expect_column_values_to_not_be_null("series_id")
# Great Expectations стиль
expect_table_columns_to_match_ordered_list(["series_id","date","value"])
expect_column_values_to_be_of_type("value", "DOUBLE")
expect_column_values_to_not_be_null("series_id")
Domain logic: ranges, enums, conditional rules, cross-field invariants.
Доменная логика: диапазоны, enum, условные правила, кросс-полевые инварианты.
-- dbt-style singular test: rate must be sane and components consistent
SELECT series_id, date
FROM {{ ref('fct_econ_series') }}
WHERE value NOT BETWEEN -5.0 AND 30.0
OR currency_code NOT IN ('USD','EUR','GBP','JPY')
-- dbt-style единичный тест: ставка должна быть вменяемой, компоненты согласованы
SELECT series_id, date
FROM {{ ref('fct_econ_series') }}
WHERE value NOT BETWEEN -5.0 AND 30.0
OR currency_code NOT IN ('USD','EUR','GBP','JPY')
Every FK must resolve to a parent; no orphans. Critical when joining series metadata to facts.
Каждый FK должен разрешаться в родителя; никаких сирот. Критично при джойне метаданных серий к фактам.
-- orphan fact rows = broken integrity
SELECT fact.series_id
FROM fct_econ_series AS fact
LEFT JOIN dim_series AS dim ON fact.series_id = dim.series_id
WHERE dim.series_id IS NULL
-- сиротские факт-строки = сломанная целостность
SELECT fact.series_id
FROM fct_econ_series AS fact
LEFT JOIN dim_series AS dim ON fact.series_id = dim.series_id
WHERE dim.series_id IS NULL
Statistical bounds on metrics over time. Robust methods (MAD, IQR) beat mean±σ for fat-tailed financial data.
Статистические границы на метрики во времени. Робастные методы (MAD, IQR) бьют mean±σ для финансовых данных с «тяжёлыми хвостами».
# robust z-score; flag if today's row count deviates hard
median = np.median(history); mad = np.median(np.abs(history - median))
robust_z = 0.6745 * (today - median) / mad
if abs(robust_z) > 3.5: alert("volume anomaly")
# робастный z-score; флагнуть, если сегодняшнее число строк сильно отклонилось
median = np.median(history); mad = np.median(np.abs(history - median))
robust_z = 0.6745 * (today - median) / mad
if abs(robust_z) > 3.5: alert("volume anomaly")
Compare today's distribution to a baseline. PSI / KS for numeric, chi-square for categorical. Catches silent semantic drift.
Сравнить сегодняшнее распределение с базовой линией. PSI / KS для числовых, хи-квадрат для категориальных. Ловит тихий семантический дрифт.
# Population Stability Index > 0.25 = major shift
psi = Σ (actual%_i - expected%_i) * ln(actual%_i / expected%_i)
# Population Stability Index > 0.25 = крупный сдвиг
psi = Σ (actual%_i - expected%_i) * ln(actual%_i / expected%_i)
Compare your output back to the source-of-truth: row counts, control totals, checksums, sampled value-by-value. The only check that truly proves accuracy.
Сравнить твой вывод обратно с источником истины: число строк, контрольные суммы, чексуммы, выборочная сверка значение-по-значению. Единственная проверка, которая действительно доказывает точность.
-- control-total reconciliation
SELECT ABS(SUM(loaded.value) - source.expected_total) AS drift
FROM loaded, source_control_totals AS source
WHERE drift > 0.01 -- penny tolerance
-- сверка контрольных сумм
SELECT ABS(SUM(loaded.value) - source.expected_total) AS drift
FROM loaded, source_control_totals AS source
WHERE drift > 0.01 -- допуск на копейки
The strong answer is "at three layers, each catching different failures, with cost increasing left-to-right."
Сильный ответ: «на трёх слоях, каждый ловит разные сбои, со стоимостью, растущей слева-направо».
| Layer | What it does | Catches | Trade-off |
|---|---|---|---|
| 1. Ingestion gates fail fast | Validate at the door — schema/contract, type, basic ranges before data enters the warehouse | Malformed feeds, contract breaks, garbage source | Cheapest fix; but limited context (can't check cross-table consistency yet) |
| 2. In-pipeline assertions block bad loads | Checks between transform stages; stop/quarantine if a stage produces bad output | Transform bugs, join fan-out, business-rule violations, referential breaks | Adds runtime + complexity; must not over-block on flaky thresholds |
| 3. Post-load audits verify & observe | Reconciliation, distribution/freshness/volume monitors on the served table | Silent drift, completeness gaps, accuracy vs source, SLA misses | Bad data may already be visible to consumers; pair with rollback/flagging |
| Слой | Что делает | Ловит | Компромисс |
|---|---|---|---|
| 1. Ворота ингеста fail fast | Валидация на входе — схема/контракт, тип, базовые диапазоны до того, как данные попадут в хранилище | Кривые фиды, поломки контракта, мусор из источника | Дешевле всего исправить; но ограниченный контекст (пока нельзя проверить кросс-табличную согласованность) |
| 2. Утверждения в пайплайне блок плохих загрузок | Проверки между этапами трансформации; стоп/карантин, если этап выдаёт плохой вывод | Баги трансформации, join fan-out, нарушения бизнес-правил, поломка ссылочной целостности | Добавляет время выполнения + сложность; нельзя пере-блокировать на зыбких порогах |
| 3. Пост-лоад аудиты проверка & мониторинг | Сверка, мониторы distribution/freshness/volume на выставленной таблице | Тихий дрифт, пробелы в полноте, точность vs источник, пропуски SLA | Плохие данные могут уже быть видны консьюмерам; паровать с rollback/флагированием |
When a critical assertion fails, halt the pipeline / block publish so bad data never reaches consumers. Best for accuracy-critical outputs (market data, control totals).
Когда критическое утверждение проваливается, остановить пайплайн / заблокировать публикацию, чтобы плохие данные никогда не добрались до консьюмеров. Лучше для критичных по точности выводов (рыночные данные, контрольные суммы).
"Better no data than wrong data" for financial feeds.
«Лучше вообще нет данных, чем неправильные данные» для финансовых фидов.
Route failing rows to a side table; let valid rows flow. Keeps the pipeline running while preserving bad records for inspection & backfill.
Направить провалившиеся строки в боковую таблицу; пустить валидные строки дальше. Держит пайплайн работающим, сохраняя плохие записи для инспекции и backfill.
Good when partial delivery is acceptable.
Хорошо, когда частичная доставка приемлема.
Streaming pattern: messages that fail parse/validation go to a DLQ topic instead of crashing the consumer. Reprocess after fix.
Стриминг-паттерн: сообщения, которые провалили parse/валидацию, идут в DLQ-топик вместо краша консьюмера. Переобработать после фикса.
Standard for Kafka/Kinesis ingestion.
Стандарт для Kafka/Kinesis ingestion.
def process_partition(rows):
valid, bad = [], []
for r in rows:
(valid if passes_validation(r) else bad).append(r)
bad_ratio = len(bad) / max(len(rows), 1)
if bad_ratio > 0.02: # circuit breaker: too much rot
raise PipelineHalt("bad-row ratio > 2%, blocking publish")
write_quarantine(bad) # quarantine the rest
return valid
def process_partition(rows):
valid, bad = [], []
for r in rows:
(valid if passes_validation(r) else bad).append(r)
bad_ratio = len(bad) / max(len(rows), 1)
if bad_ratio > 0.02: # circuit breaker: слишком много гнили
raise PipelineHalt("bad-row ratio > 2%, блокируем публикацию")
write_quarantine(bad) # остальное в карантин
return valid
| Change type | Examples | Compatibility | Default reaction |
|---|---|---|---|
| Backward-compatible | Add nullable column, widen type, add enum value | safe | Auto-evolve + log; notify |
| Breaking | Drop/rename column, narrow type, change PK, NOT-NULL on existing | breaks consumers | Circuit-break / require contract version bump |
| Semantic (sneaky) | Same schema, units change (% → bps), meaning shifts | silent | Only distribution observability catches it |
| Тип изменения | Примеры | Совместимость | Реакция по умолчанию |
|---|---|---|---|
| Обратно совместимое | Добавить nullable колонку, расширить тип, добавить enum-значение | безопасно | Авто-эволюция + лог; уведомить |
| Ломающее | Удалить/переименовать колонку, сузить тип, поменять PK, NOT-NULL на существующей | ломает консьюмеров | Circuit-break / требовать бамп версии контракта |
| Семантическое (скрытное) | Та же схема, единицы изменились (% → bps), смысл сдвинулся | тихое | Только мониторинг распределения его ловит |
Let schemas change gracefully over time without breaking readers. Columnar formats (Parquet/Avro/Iceberg/Delta) support additive evolution. Always make new columns nullable with defaults; never reuse a column name with new meaning.
Позволить схемам изменяться плавно во времени без поломки читателей. Колоночные форматы (Parquet/Avro/Iceberg/Delta) поддерживают аддитивную эволюцию. Всегда делать новые колонки nullable со значениями по умолчанию; никогда не переиспользовать имя колонки с новым смыслом.
is_stale=true rather than nothing.is_stale=true вместо ничего.| Severity | Trigger | Route | Action |
|---|---|---|---|
| P0 / Critical | Published market data wrong/missing; SLA breach on a traded series | Page on-call now | Circuit-break; incident channel |
| P1 / High | Freshness/volume anomaly, contract break upstream | Page during hours / ticket | Triage via lineage; remediate |
| P2 / Warn | Soft drift, rising NULL rate, slow trend | Dashboard + digest | Investigate proactively |
| Severity | Триггер | Маршрутизация | Действие |
|---|---|---|---|
| P0 / Critical | Публикуемые рыночные данные неправильные/отсутствуют; нарушение SLA на торгуемом ряде | Пейджить on-call сейчас | Circuit-break; канал инцидента |
| P1 / High | Аномалия freshness/volume, поломка контракта апстрима | Пейджить в часы работы / тикет | Триаж через lineage; восстановить |
| P2 / Warn | Мягкий дрифт, растущая доля NULL, медленный тренд | Дашборд + дайджест | Расследовать проактивно |
| Tool | Category | Strengths | Watch-outs |
|---|---|---|---|
| Great Expectations | DQ assertions | Rich expectation library, data docs, profiling | Config-heavy; can be slow at very large scale |
| dbt tests | DQ in transform layer | Generic + singular tests in CI, version-controlled, free | Warehouse-only; runs at build, not continuous monitoring |
| Soda | DQ checks (SodaCL) | Simple YAML checks, in-pipeline + scheduled | Less ecosystem than GE |
| Monte Carlo | Observability (ML) | Auto 5-pillar monitors, lineage, low setup | Commercial; can be a black box; cost |
| Anomalo | Observability (ML) | Unsupervised anomaly detection on tables | Commercial; tuning false positives |
| Custom framework | Both | Fits warehouse/scale exactly; metrics → ODS/Scuba dashboards | You own maintenance; reinvention risk |
| Инструмент | Категория | Сильные стороны | Что учитывать |
|---|---|---|---|
| Great Expectations | DQ-утверждения | Богатая библиотека ожиданий, data docs, профилирование | Тяжёлая конфигурация; может быть медленным на очень больших масштабах |
| dbt tests | DQ в слое трансформации | Generic + singular тесты в CI, версионируемые, бесплатные | Только хранилище; запуск на билде, а не непрерывный мониторинг |
| Soda | DQ-проверки (SodaCL) | Простые YAML-проверки, в пайплайне + по расписанию | Меньше экосистемы, чем GE |
| Monte Carlo | Observability (ML) | Авто-мониторы 5 столпов, lineage, мало настройки | Коммерческий; может быть чёрным ящиком; стоимость |
| Anomalo | Observability (ML) | Без-учительное обнаружение аномалий на таблицах | Коммерческий; настройка ложных срабатываний |
| Кастомный фреймворк | Оба | Подходит под хранилище/масштаб точно; метрики → ODS/Scuba дашборды | Ты владелец обслуживания; риск переизобретения |
This is where the 3.6B-events/day and 6.2B-record anchors earn their keep. Full-table validation on every run is infeasible at that scale; you trade exactness for cost.
Здесь якоря «3.6B событий/день» и «6.2B записей» окупаются. Полная валидация таблицы на каждый ран невозможна на таком масштабе; ты обмениваешь точность на стоимость.
SOURCE FEEDS INGEST TRANSFORM SERVE / CONSUME
(BLS, FX, GDP, ┌──────────────┐ ┌──────────────────┐ ┌──────────────────┐
vendor APIs) ─────────▶│ [1] INGEST │──────▶│ [2] IN-PIPELINE │──────▶│ [3] POST-LOAD │──▶ Terminal /
│ GATES │ │ ASSERTIONS │ │ AUDITS + OBS │ dashboards /
└──────┬───────┘ └────────┬─────────┘ └────────┬─────────┘ downstream
│ fail │ fail │ drift/SLA
schema/contract biz-rules / ref-integ reconcile vs source
type / range join fan-out / dedup freshness · volume
│ │ schema · dist · lineage
▼ ▼ ▼
┌────────────┐ bad rows ┌──────────┐ ┌──────────────────┐
│ DLQ / │◀───────────│QUARANTINE│ │ METRIC STORE │
│ REJECT │ │ TABLE │──backfill─▶│ (time-series) │
└────────────┘ └──────────┘ └────────┬─────────┘
▲ │ anomaly?
CIRCUIT BREAKER: bad-ratio > threshold ──── HALT ─────────┤
▼
┌──────────────────────┐
│ ALERTING (P0/P1/P2) │
│ severity · SLO/SLA │
│ lineage-grouped │
└──────────┬───────────┘
▼
REMEDIATION LADDER:
retry → re-fetch → last-good
→ rollback → page human
ФИДЫ-ИСТОЧНИКИ INGEST TRANSFORM SERVE / CONSUME
(BLS, FX, GDP, ┌──────────────┐ ┌──────────────────┐ ┌──────────────────┐
vendor API) ─────────▶│ [1] ВОРОТА │──────▶│ [2] УТВЕРЖДЕНИЯ │──────▶│ [3] ПОСТ-ЛОАД │──▶ Терминал /
│ ИНГЕСТА │ │ В ПАЙПЛАЙНЕ │ │ АУДИТ + МОНИТ. │ дашборды /
└──────┬───────┘ └────────┬─────────┘ └────────┬─────────┘ даунстрим
│ провал │ провал │ дрифт/SLA
схема/контракт бизн-правила / реф-целост. сверка с источником
тип / диапазон join fan-out / дедуп freshness · volume
│ │ schema · dist · lineage
▼ ▼ ▼
┌────────────┐ плохие ┌──────────┐ ┌──────────────────┐
│ DLQ / │ строки │ КАРАНТИН │ │ МЕТРИК-СТОР │
│ REJECT │◀───────────│ ТАБЛИЦА │──backfill─▶│ (time-series) │
└────────────┘ └──────────┘ └────────┬─────────┘
▲ │ аномалия?
CIRCUIT BREAKER: bad-ratio > порог ────── HALT ───────────┤
▼
┌──────────────────────┐
│ АЛЕРТЫ (P0/P1/P2) │
│ severity · SLO/SLA │
│ группировка lineage │
└──────────┬───────────┘
▼
ЛЕСТНИЦА ВОССТАНОВЛЕНИЯ:
retry → перезагрузка → last-good
→ rollback → пейджить человека
Three control layers (cheapest fix on the left), DLQ/quarantine for bad records, a metric store powering observability + anomaly detection, a circuit breaker that can halt publish, and a severity-tiered alerting path into a remediation ladder.
Три контрольных слоя (дешевле всего чинить слева), DLQ/карантин для плохих записей, метрик-стор, питающий мониторинг + обнаружение аномалий, circuit breaker, способный остановить публикацию, и severity-тирированный путь алертов в лестницу восстановления.
Tap a card to flip. Say the answer out loud first.
Кликни на карту, чтобы перевернуть. Сначала произнеси ответ вслух.
"I think about quality as fitness-for-use across accuracy, completeness, timeliness, consistency, validity and uniqueness, enforced at three layers: ingestion gates, in-pipeline assertions, and post-load audits. On top of that I run observability — freshness, volume, schema, distribution, lineage — to catch the failures I never wrote a rule for. I've done this at scale: I fixed an entity-resolution defect across 6.2 billion records by combining distribution observability with reconciliation, then locked it in with assertions; and I built DQ monitors on a 3.6B-events/day pipeline using partition-scoped aggregate metrics and seasonality-aware alerting so the cost stayed tiny. For economics data, where timeliness and accuracy are non-negotiable, I'd embed circuit breakers on the must-be-correct series, contracts on the schema, and a severity-tiered alerting path into a remediation ladder — so bad data never silently reaches the terminal."
«Я думаю о качестве как о пригодности для использования по точности, полноте, своевременности, согласованности, корректности и уникальности, исполняемой на трёх слоях: ворота ингеста, утверждения в пайплайне и пост-лоад аудиты. Поверх этого я запускаю observability — freshness, volume, schema, distribution, lineage — чтобы ловить сбои, на которые я никогда не писал правила. Я делал это на масштабе: я исправил дефект entity-resolution на 6.2 миллиардах записей комбинируя мониторинг распределения со сверкой, затем зафиксировал это утверждениями; и я построил DQ-мониторы на пайплайне 3.6B событий/день используя партиция-скоупед агрегатные метрики и сезонно-осведомлённые алерты, чтобы стоимость оставалась крошечной. Для экономических данных, где своевременность и точность неотменяемы, я бы встроил circuit breakers на must-be-correct ряды, контракты на схему, и severity-тирированный путь алертов в лестницу восстановления — чтобы плохие данные никогда тихо не добирались до терминала».