What DataOps Actually IsЧто такое DataOps на самом деле
▼One-line definitionОпределение одной строкой
DataOps = applying DevOps + Agile + Lean manufacturing ideas to the data lifecycle so that analytics and data products ship fast, repeatably, and with quality guarantees. It is the union of four pillars applied to data:
DataOps = применение идей DevOps + Agile + Lean manufacturing к жизненному циклу данных, чтобы аналитика и дата-продукты выкатывались быстро, воспроизводимо и с гарантиями качества. Это объединение четырёх столпов, примененных к данным:
- CI/CD — automated build, test and deploy of pipelines, transforms and infra.
- Automated testing — code tests and data tests (freshness, volume, schema, business rules).
- Observability / monitoring — freshness, volume, distribution, lineage and incident alerting (the "data downtime" idea).
- Collaboration & governance — version control, code review, environments, catalog, documentation, ownership.
- CI/CD — автоматизированные сборка, тестирование и деплой пайплайнов, трансформаций и инфраструктуры.
- Автоматизированное тестирование — тесты кода и тесты данных (свежесть, объём, схема, бизнес-правила).
- Наблюдаемость / мониторинг — свежесть, объём, распределение, lineage и алертинг при инцидентах (концепция «data downtime»).
- Коллаборация & governance — контроль версий, code review, окружения, каталог, документация, ownership.
Why it matters for an econ-data team
Почему это важно для команды экономических данных
Economic indicators (CPI, payrolls, GDP) are high-trust, point-in-time series consumed by clients and trading systems. A bad revision, a late landing, or a silent schema change is a credibility incident. DataOps is how you make correctness and timeliness systematic rather than heroic.
Экономические индикаторы (CPI, payrolls, GDP) — это высокодоверенные, точечные во времени серии, которые потребляются клиентами и торговыми системами. Плохая ревизия, задержка поступления или тихое изменение схемы — это инцидент доверия. DataOps — это способ сделать корректность и своевременность систематическими, а не героическими.
At McMakler/Career.io I treated dbt as the unit of change: every transform was version-controlled, reviewed against a standard I authored, and tested in CI before it could reach prod. That is DataOps in practice — not a tool, a discipline enforced by the pipeline.
В McMakler/Career.io я относился к dbt как к единице изменений: каждая трансформация была под контролем версий, проходила ревью по стандарту, который я написал, и тестировалась в CI перед тем как попасть в прод. Это DataOps на практике — не инструмент, а дисциплина, обеспечиваемая пайплайном.
DevOps vs DataOps — the key differenceDevOps vs DataOps — ключевое отличие
| Dimension | DevOps | DataOps |
|---|---|---|
| Artifact under test | Code + binaries | Code and the data flowing through it |
| Failure mode | Service crashes / bug | Silent wrong numbers ("data downtime") |
| State | Mostly stateless deploys | Stateful: history, backfills, revisions |
| Tests | Unit/integration of code | + data quality, contracts, freshness, anomaly |
| Rollback | Redeploy old binary | Redeploy + possibly reprocess/restate data |
| Аспект | DevOps | DataOps |
|---|---|---|
| Тестируемый артефакт | Код + бинарники | Код и данные, которые через него текут |
| Режим сбоя | Падение сервиса / баг | Тихие неправильные цифры («data downtime») |
| Состояние | В основном stateless-деплои | Stateful: история, backfill-ы, ревизии |
| Тесты | Unit/integration кода | + качество данных, контракты, свежесть, аномалии |
| Откат | Передеплой старого бинарника | Передеплой + возможная переобработка/restate данных |
"How is testing data different from testing code?" → Code tests are deterministic given input; data tests assert on values you don't control (the data is the variable). You test properties (not-null, unique, ranges, referential integrity, row-count deltas), not exact outputs.
«Чем тестирование данных отличается от тестирования кода?» → Тесты кода детерминированы при заданном вводе; тесты данных проверяют значения, которые ты не контролируешь (данные — это переменная). Проверяешь свойства (not-null, unique, диапазоны, референциальную целостность, дельты числа строк), а не точные выводы.
Version Control for Data & CodeКонтроль версий для данных и кода
▼Git workflow for data teamsGit-процесс для дата-команд
Everything that defines the pipeline lives in git: dbt models, SQL, Airflow DAGs, Terraform, schema/contract files, tests, docs. Common lightweight flow:
Всё, что определяет пайплайн, живёт в git: dbt-модели, SQL, Airflow DAG-и, Terraform, файлы схем/контрактов, тесты, доки. Типичный лёгкий процесс:
# trunk-based with short-lived feature branches git checkout -b feat/cpi-seasonal-adjust # ... edit dbt model + add tests ... git commit -m "[econ_de] Add seasonally adjusted CPI model + freshness test" git push origin feat/cpi-seasonal-adjust # open PR -> CI runs lint + unit + data tests on a sandbox/CI schema # review (enforced standard) -> squash merge to main -> auto-deploy to stage
Environments: dev / stage / prod
Окружения: dev / stage / prod
- dev — engineer's sandbox; dbt builds into a personal schema (
dbt_amal), cheap, fast, dirty. - stage — production-shaped, fed by main branch, full test suite, used for validation and integration tests.
- prod — only reached by promoted, tested, reviewed code. No manual edits.
- dev — песочница инженера; dbt строит в личную схему (
dbt_amal), дёшево, быстро, грязно. - stage — как продакшн, питается из main-ветки, полный набор тестов, используется для валидации и интеграционных тестов.
- prod — доступен только для промоушен-кода, протестированного и пройденного ревью. Никаких ручных правок.
"Version control for data" — three flavours«Контроль версий для данных» — три вкуса
| What you version | How | Tooling examples |
|---|---|---|
| Transform logic | Git on SQL/dbt/DAGs | git, dbt, Airflow |
| Schema / contracts | Versioned schema files, contract checks in CI | dbt contracts, JSON Schema, Avro/Protobuf |
| Data itself | Snapshots, time-travel, table cloning, data versioning | Snowflake Time Travel + Zero-Copy Clone, BigQuery snapshots/time-travel, dbt snapshots, lakeFS / Iceberg branches |
| Что версионируешь | Как | Примеры инструментов |
|---|---|---|
| Логика трансформаций | Git на SQL/dbt/DAG-ах | git, dbt, Airflow |
| Схемы / контракты | Версионированные файлы схем, проверки контрактов в CI | dbt contracts, JSON Schema, Avro/Protobuf |
| Сами данные | Снапшоты, time-travel, клонирование таблиц, data versioning | Snowflake Time Travel + Zero-Copy Clone, BigQuery snapshots/time-travel, dbt snapshots, lakeFS / Iceberg branches |
For econ series specifically, dbt snapshots are how you version data: they capture slowly-changing dimensions / revisions as type-2 history, so you can reconstruct "what did CPI look like as published on 2026-03-10?" — point-in-time correctness, which is everything in economic data.
Для экономических серий в частности, dbt snapshots — это способ версионирования данных: они захватывают медленно меняющиеся измерения / ревизии как type-2 историю, так что можно восстановить «как выглядел CPI на момент публикации 2026-03-10?» — точность на момент времени, что является всем в экономических данных.
Branching for data
Ветвление для данных
Modern pattern: each feature branch gets an isolated data environment. In Snowflake you zero-copy clone prod into a branch schema (instant, cheap, no storage duplication) so CI tests run against realistic data without touching prod. Iceberg/lakeFS expose git-like branch/merge on the data itself.
Современный паттерн: каждая feature-ветка получает изолированное окружение данных. В Snowflake ты делаешь zero-copy clone прода в ветку-схему (мгновенно, дёшево, без дублирования хранилища), так что тесты CI идут на реалистичных данных без касания прода. Iceberg/lakeFS предоставляют git-подобное ветвление/слияние на самих данных.
Never commit credentials, service-account keys, or large data files to git. Data belongs in the warehouse/object store; git holds code and config. Use a .gitignore + secret scanning.
Никогда не коммить credentials, ключи сервисных аккаунтов или большие файлы данных в git. Данные принадлежат хранилищу/object store; git хранит код и конфиг. Использовать .gitignore + сканирование секретов.
CI/CD for Data PipelinesCI/CD для дата-пайплайнов
▼CI/CD-for-data pipeline (ASCII)CI/CD-пайплайн для данных (ASCII)
DEV CI (on Pull Request) CD (on merge)
┌───────┐ git push ┌──────────────────────────────────┐ merge ┌──────────────────────┐
│ branch│ ────────────► │ 1. LINT sqlfluff / dbt parse │ ─────────► │ build artifacts │
│ +tests│ │ 2. UNIT macro / py unit tests│ │ (dbt manifest, DAG, │
└───────┘ │ 3. BUILD dbt build --select │ │ docker image) │
▲ │ state:modified+ │ └──────────┬───────────┘
│ fix │ 4. DATA dbt test (not_null, │ │ deploy
│ │ unique, accepted_*, │ ▼
│ │ relationships, fresh)│ ┌──────────────────────┐
│ FAIL ◄─────────│ 5. CONTRACT schema/contract check│ │ STAGE full run + │
│ │ 6. INTEG e2e on cloned prod │ │ full test suite │
└──────────────────│ schema (zero-copy) │ └──────────┬───────────┘
└──────────────────────────────────┘ │ promote (green)
▼
┌──────────────────────┐
│ PROD blue/green or │
│ canary; auto-rollback│
│ on data-quality gate │
└──────────────────────┘
DEV CI (при Pull Request) CD (при merge)
┌───────┐ git push ┌──────────────────────────────────┐ merge ┌──────────────────────┐
│ branch│ ────────────► │ 1. LINT sqlfluff / dbt parse │ ─────────► │ сборка артефактов │
│ +tests│ │ 2. UNIT macro / py unit tests│ │ (dbt manifest, DAG, │
└───────┘ │ 3. BUILD dbt build --select │ │ docker image) │
▲ │ state:modified+ │ └──────────┬───────────┘
│ fix │ 4. DATA dbt test (not_null, │ │ deploy
│ │ unique, accepted_*, │ ▼
│ │ relationships, fresh)│ ┌──────────────────────┐
│ FAIL ◄─────────│ 5. CONTRACT schema/contract check│ │ STAGE full run + │
│ │ 6. INTEG e2e на клоне прода │ │ полный набор тестов │
└──────────────────│ (zero-copy) │ └──────────┬───────────┘
└──────────────────────────────────┘ │ promote (green)
▼
┌──────────────────────┐
│ PROD blue/green │
│ / canary; auto- │
│ rollback на DQ gate │
└──────────────────────┘
What runs in CI (and why)Что запускается в CI (и зачем)
- Lint / static checks —
sqlfluff,dbt parse, ruff/black for Python DAGs. Catches style + parse errors in seconds, free. - Slim / state-aware builds —
dbt build --select state:modified+only builds models that changed and their downstream. Fast PRs, low compute cost. - Unit tests — dbt unit tests (mock inputs → assert outputs) and Python unit tests for custom logic / operators.
- Data tests — generic + singular dbt tests run against the built models.
- Contract checks — fail the build if output schema/types drift from the declared contract.
- Integration / e2e — full DAG/dbt run on a cloned-prod CI schema to catch cross-model and dependency issues.
- Lint / статические проверки —
sqlfluff,dbt parse, ruff/black для Python DAG-ов. Ловят стиль + parse-ошибки за секунды, бесплатно. - Slim / state-aware сборки —
dbt build --select state:modified+строит только изменённые модели и их downstream. Быстрые PR-ы, низкая стоимость вычислений. - Unit-тесты — dbt unit tests (мок входов → проверка выходов) и Python unit-тесты для кастомной логики / операторов.
- Тесты данных — generic + singular dbt-тесты на построенных моделях.
- Проверки контрактов — фейлить сборку, если выходная схема/типы отклоняются от декларированного контракта.
- Интеграционные / e2e — полный DAG/dbt run на клоне прода CI-схемы для выявления кросс-модельных и dependency-проблем.
Build & deploy of DAGs and dbt models
Сборка & деплой DAG-ов и dbt-моделей
- dbt: CI produces the
manifest.jsonartifact; CD deploys compiled models + runs them in the target env. The manifest also powers slim CI via state comparison. - Airflow: DAG files are version-controlled; CI validates them (
DagBagimport test catches broken DAGs before they hit the scheduler); CD syncs them to the Airflow environment (git-sync / dags volume / image bake).
- dbt: CI производит артефакт
manifest.json; CD деплоит скомпилированные модели + запускает их в целевом окружении. Manifest также питает slim CI через сравнение состояния. - Airflow: файлы DAG-ов под контролем версий; CI валидирует их (тест импорта
DagBagловит битые DAG-и до того как они попадут в планировщик); CD синхронизирует их в Airflow-окружение (git-sync / dags volume / image bake).
I added a CI gate that imports every DAG (DagBag test) plus a cycle/owner/SLA check, so a syntactically broken or owner-less DAG can never reach the scheduler. Combined with dbt slim-CI it cut PR feedback from "wait for the nightly run" to a few minutes.
Я добавил CI-гейт, который импортирует каждый DAG (DagBag-тест) плюс проверку цикла/owner-а/SLA, так что синтаксически битый или без owner-а DAG никогда не дойдёт до планировщика. В сочетании с dbt slim-CI это сократило обратную связь на PR-ах с «жди ночного запуска» до нескольких минут.
Deployment strategies for dataСтратегии деплоя для данных
| Strategy | How it works for data | When to use |
|---|---|---|
| Blue/green | Build new version into a parallel schema/table (green), validate, then atomically swap (rename / view repoint / clone). Old (blue) stays for instant rollback. | Schema or large logic changes to consumed tables |
| Canary | Route a slice (one partition, one market, small % of downstream) to the new logic, compare metrics vs control, then ramp. | Risky transform/model changes |
| Audit-then-swap (WAP) | Write-Audit-Publish: write to staging, run DQ audit, publish only if green. | Default for critical published series |
| Auto-rollback | If a post-deploy DQ gate fails (row count drop, null spike, freshness miss), revert the swap / re-point view to last-good. | Always, as a safety net |
| Стратегия | Как работает для данных | Когда использовать |
|---|---|---|
| Blue/green | Строить новую версию в параллельную схему/таблицу (green), валидировать, затем атомарно переключить (rename / переточить view / clone). Старая (blue) остаётся для мгновенного отката. | Схемные или крупные логические изменения в потребляемых таблицах |
| Canary | Направить кусочек (одна партиция, один рынок, малый % downstream) на новую логику, сравнить метрики с контролем, затем расширять. | Рискованные изменения в трансформ/модели |
| Audit-then-swap (WAP) | Write-Audit-Publish: писать в staging, запускать DQ-аудит, публиковать только если зелёный. | По умолчанию для критических публикуемых серий |
| Auto-rollback | Если пост-деплой DQ-гейт фейлится (падение числа строк, скачок null-ов, пропуск freshness), откатить переключение / переточить view на last-good. | Всегда, как подстраховка |
"How do you do blue/green when the artifact is a table other systems query?" → You don't redeploy a binary, you repoint the consumer abstraction: build into table_v2, validate, then swap the view/alias or atomic RENAME so consumers never see a partial state. Snowflake zero-copy clone makes the "green" copy free.
«Как делать blue/green, когда артефакт — это таблица, которую запрашивают другие системы?» → Ты не передеплоишь бинарник, ты переточишь абстракцию потребителя: строишь в table_v2, валидируешь, затем меняешь view/alias или атомарный RENAME, так что потребители никогда не видят частичное состояние. Snowflake zero-copy clone делает «зелёную» копию бесплатной.
The Testing Pyramid for DataПирамида тестирования для данных
▼
/\ E2E / pipeline (few, slow, expensive)
/ \ full DAG run on cloned prod, output vs golden
/----\
/ \ Integration (cross-model, sources, deps)
/--------\
/ \ Contract (schema/type stability, freshness)
/------------\
/ \ Data-quality tests (not_null, unique, ranges, ref-integ)
/----------------\
/ \ Unit tests (many, fast, cheap)
/____________________\ dbt unit tests + py logic, mocked inputs
/\ E2E / pipeline (мало, медленно, дорого)
/ \ полный запуск DAG на клоне прода, вывод vs эталон
/----\
/ \ Интеграционные (кросс-модельные, sources, deps)
/--------\
/ \ Контракты (стабильность схемы/типов, freshness)
/------------\
/ \ Тесты качества данных (not_null, unique, диапазоны, ref-integ)
/----------------\
/ \ Unit-тесты (много, быстро, дёшево)
/____________________\ dbt unit tests + py-логика, моки входов
| Layer | What it asserts | Example |
|---|---|---|
| Unit | Transform logic given mocked inputs | dbt unit test: a SA-CPI macro returns expected value for fixed fixture rows |
| Data quality | Properties of real data | not_null, unique, accepted_values, custom range test on inflation % |
| Contract | Output shape/types are stable | dbt model contract: column set + types enforced at build |
| Integration | Models fit together; sources behave | relationships test; source freshness; full dbt build |
| E2E | Whole pipeline output correct | Run DAG end-to-end on cloned prod, diff vs golden/reconciliation total |
| Уровень | Что проверяет | Пример |
|---|---|---|
| Unit | Логика трансформации на замоканных входах | dbt unit test: макрос SA-CPI возвращает ожидаемое значение для фиксированных строк-фикстур |
| Качество данных | Свойства реальных данных | not_null, unique, accepted_values, кастомный range-тест на инфляцию % |
| Контракт | Стабильность выходной формы/типов | dbt model contract: набор колонок + типы enforced при сборке |
| Интеграционные | Модели подходят друг другу; sources ведут себя | relationships test; source freshness; полный dbt build |
| E2E | Вывод всего пайплайна корректен | Запустить DAG end-to-end на клоне прода, diff vs эталон/итого сверки |
Data-quality gates in CIГейты качества данных в CI
# dbt schema.yml — declarative data tests + contract models: - name: fct_cpi_monthly config: { contract: { enforced: true } } columns: - name: period data_type: date tests: [not_null, unique] - name: cpi_yoy_pct data_type: numeric tests: - not_null - dbt_utils.accepted_range: { min_value: -20, max_value: 50 } # freshness so a stale upstream feed fails CI/monitoring sources: - name: bls_raw freshness: { warn_after: {count: 26, period: hour}, error_after: {count: 48, period: hour} }
- Block the merge on test failure — a failing data test is a red CI = no deploy.
- Severity:
warnfor soft anomalies,errorfor hard gates. Tune to avoid alert fatigue. - Reconciliation tests — assert totals match the source-of-truth (e.g. sum of components = published headline).
- Блокировать merge при фейле теста — фейлящий тест данных = красный CI = нет деплоя.
- Severity:
warnдля мягких аномалий,errorдля жёстких гейтов. Настраивать, чтобы избегать усталости от алертов. - Тесты сверки — проверять, что итоги совпадают с источником истины (например, сумма компонентов = опубликованный headline).
Don't run heavy data tests on full prod volume in every PR — it's slow and costly. Use slim CI (only changed models + downstream) on a sampled or cloned schema; save full-volume suites for stage / nightly.
Не запускать тяжёлые тесты данных на полном объёме прода в каждом PR — это медленно и дорого. Использовать slim CI (только изменённые модели + downstream) на сэмплированной или клонированной схеме; оставить полнообъёмные наборы для stage / ночных запусков.
"A test fails at 2am for a published series — what happens?" → Pipeline halts at the DQ gate (WAP: never publishes bad data), alert fires to oncall with the failing test + lineage of impacted downstream, last-good version stays served, you triage. Quality gate protects the consumer first.
«Тест фейлится в 2 часа ночи для публикуемой серии — что происходит?» → Пайплайн останавливается на DQ-гейте (WAP: никогда не публикуется плохой датасет), алерт срабатывает на oncall с фейлящим тестом + lineage затронутого downstream, last-good версия остаётся отдаваемой, ты разбираешься. Гейт качества защищает потребителя в первую очередь.
Infrastructure as Code, Docker & OrchestrationInfrastructure as Code, Docker и оркестрация
▼Infrastructure as Code (Terraform basics)Infrastructure as Code (основы Terraform)
IaC = declare infra in version-controlled config so environments are reproducible, reviewable, and diff-able. Terraform is declarative + cloud-agnostic.
IaC = декларировать инфраструктуру в версионированном конфиге, чтобы окружения были воспроизводимыми, reviewable и diff-able. Terraform декларативен + облачно-агностичен.
# declare a warehouse + dataset; plan -> review -> apply resource "snowflake_warehouse" "transform" { name = "WH_TRANSFORM" warehouse_size = "SMALL" auto_suspend = 60 # suspend after 60s idle = cost control auto_resume = true } resource "google_bigquery_dataset" "econ" { dataset_id = "econ_marts" location = "EU" }
- Core verbs:
init→plan(preview diff) →apply.planin CI on every PR = no surprise infra changes. - State lives in a remote backend (GCS/S3) with locking, so the team shares one source of truth.
- Modules = reusable building blocks; workspaces/var files parametrise dev/stage/prod.
- Idempotent & declarative: you describe desired state, Terraform computes the delta.
- Основные команды:
init→plan(preview diff) →apply.planв CI на каждом PR = нет внезапных изменений инфры. - State живёт в remote backend (GCS/S3) с блокировкой, так что команда разделяет один источник истины.
- Модули = переиспользуемые строительные блоки; workspaces/var-файлы параметризуют dev/stage/prod.
- Идемпотентный & декларативный: ты описываешь желаемое состояние, Terraform вычисляет дельту.
Never edit infra in the cloud console by hand once it's under Terraform — that causes state drift. Either import it or change it through code.
Никогда не редактировать инфру в консоли облака вручную, если она под Terraform — это вызывает state drift. Либо импортировать её, либо менять через код.
Containerization + orchestration (high level)Контейнеризация + оркестрация (высокий уровень)
- Docker packages code + dependencies + runtime into one immutable image → "runs the same on my laptop, CI, and prod". For data: a pinned dbt/Python image kills "works on my machine" version drift.
- Image as artifact: CI builds and tags the image; CD deploys that exact tag → reproducible runs and easy rollback (deploy previous tag).
- Orchestration (Kubernetes / managed runners): schedules and scales containers, restarts on failure, handles secrets/config injection. Airflow's
KubernetesPodOperatorruns each task in its own container. - Airflow itself is the workflow orchestrator (dependencies, schedules, retries, backfills, SLAs); Kubernetes is the container orchestrator underneath.
- Docker упаковывает код + зависимости + runtime в один неизменяемый image → «запускается одинаково на моём ноутбуке, CI и проде». Для данных: закреплённый dbt/Python image убивает «работает на моей машине» версионный дрейф.
- Image как артефакт: CI строит и тегирует image; CD деплоит этот точный тег → воспроизводимые запуски и лёгкий откат (деплой предыдущего тега).
- Оркестрация (Kubernetes / managed runners): планирует и масштабирует контейнеры, рестартует при падении, обрабатывает инъекцию секретов/конфига. Airflow
KubernetesPodOperatorзапускает каждую задачу в своём контейнере. - Сам Airflow — это оркестратор workflow (зависимости, расписания, ретраи, backfill-ы, SLA); Kubernetes — оркестратор контейнеров под ним.
"Why containerize a dbt run?" → Pin dbt + adapter + Python deps to an exact, tested version so CI and prod are byte-identical; isolate per-task deps; make rollback = redeploy old image tag. Reproducibility is the whole point.
«Зачем контейнеризировать dbt run?» → Закрепить dbt + adapter + Python deps на точной, протестированной версии, чтобы CI и прод были побайтово идентичны; изолировать зависимости на задачу; сделать откат = передеплой старого image tag. Воспроизводимость — вся суть.
Cloud Data Platform Building BlocksСтроительные блоки облачной дата-платформы
▼The five layersПять слоёв
| Layer | Role | GCP | AWS | Azure |
|---|---|---|---|---|
| Object storage | Cheap durable landing/raw zone | GCS | S3 | ADLS / Blob |
| Warehouse / lakehouse | Query + transform engine | BigQuery | Redshift / Athena | Synapse / Fabric |
| Compute | Elastic processing | Dataproc / BQ slots | EMR / Glue | Databricks / Synapse |
| Orchestration | Schedule + dependencies | Cloud Composer (Airflow) | MWAA | Data Factory |
| Catalog / governance | Metadata, lineage, access | Dataplex / Data Catalog | Glue Catalog / DataZone | Purview |
| Слой | Роль | GCP | AWS | Azure |
|---|---|---|---|---|
| Object storage | Дешёвая надёжная зона landing/raw | GCS | S3 | ADLS / Blob |
| Warehouse / lakehouse | Движок запросов + трансформаций | BigQuery | Redshift / Athena | Synapse / Fabric |
| Compute | Эластичная обработка | Dataproc / BQ slots | EMR / Glue | Databricks / Synapse |
| Оркестрация | Расписания + зависимости | Cloud Composer (Airflow) | MWAA | Data Factory |
| Каталог / governance | Метаданные, lineage, доступ | Dataplex / Data Catalog | Glue Catalog / DataZone | Purview |
Snowflake sits cross-cloud as a managed warehouse/lakehouse that runs on top of GCS/S3/Blob — which is why my GCP→Snowflake migration was about moving the engine, not the storage paradigm.
Snowflake сидит кросс-облачно как управляемый warehouse/lakehouse, который работает поверх GCS/S3/Blob — поэтому моя миграция GCP→Snowflake была о переносе движка, а не парадигмы хранения.
Warehouse vs LakehouseWarehouse vs Lakehouse
| Data Warehouse | Lakehouse | |
|---|---|---|
| Data | Structured, schema-on-write | Structured + semi/unstructured, schema-on-read+write |
| Storage | Proprietary/managed columnar | Open formats on object store (Parquet + Delta/Iceberg/Hudi) |
| Strength | BI/SQL, governance, performance | ML + BI on one copy, open, cheap storage |
| ACID | Native | Via table format (Delta/Iceberg) |
| Examples | BigQuery, Snowflake, Redshift | Databricks, Snowflake (Iceberg), Fabric |
| Data Warehouse | Lakehouse | |
|---|---|---|
| Данные | Структурированные, schema-on-write | Структурированные + полу-/неструктурированные, schema-on-read+write |
| Хранение | Проприетарное/управляемое колоночное | Открытые форматы на object store (Parquet + Delta/Iceberg/Hudi) |
| Сильная сторона | BI/SQL, governance, производительность | ML + BI на одной копии, открыто, дешёвое хранение |
| ACID | Нативный | Через табличный формат (Delta/Iceberg) |
| Примеры | BigQuery, Snowflake, Redshift | Databricks, Snowflake (Iceberg), Fabric |
Snowflake vs BigQuery at a glanceSnowflake vs BigQuery кратко
| Snowflake | BigQuery | |
|---|---|---|
| Compute model | Virtual warehouses (sized, you start/suspend) | Serverless slots (auto / reservations) |
| Pricing | Per-second credits by warehouse size | Per-TB scanned (on-demand) or flat-rate slots |
| Cloud | Multi-cloud (AWS/GCP/Azure) | GCP-native |
| Scaling | Resize / multi-cluster for concurrency | Fully managed, automatic |
| Killer features | Zero-copy clone, Time Travel, data sharing | Serverless, BQML, cheap storage, GIS |
| Cost lever | Right-size + auto-suspend warehouses | Partition/cluster to scan less; cap with reservations |
| Snowflake | BigQuery | |
|---|---|---|
| Модель compute | Виртуальные warehouses (размерные, ты start/suspend) | Serverless slots (авто / резервирования) |
| Ценообразование | По секундам кредитов по размеру warehouse | За TB сканирования (on-demand) или flat-rate slots |
| Облако | Multi-cloud (AWS/GCP/Azure) | GCP-native |
| Масштабирование | Resize / multi-cluster для конкуренции | Полностью управляемо, автоматически |
| Убийственные фичи | Zero-copy clone, Time Travel, data sharing | Serverless, BQML, дешёвое хранилище, GIS |
| Рычаг стоимости | Right-size + auto-suspend warehouses | Partition/cluster, чтобы сканировать меньше; cap с резервированиями |
I led/contributed to migrating transforms from BigQuery to Snowflake. The mindset shift: BigQuery cost = bytes scanned (so partition + cluster aggressively), Snowflake cost = warehouse uptime (so right-size warehouses + auto-suspend, and exploit zero-copy clones for cheap CI/dev environments). Same dbt models, different cost-optimisation playbook.
Я вёл/участвовал в миграции трансформаций с BigQuery на Snowflake. Сдвиг мышления: стоимость BigQuery = сканируемые байты (поэтому партиционируй + кластеризуй агрессивно), стоимость Snowflake = uptime warehouse (поэтому right-size warehouses + auto-suspend, и используй zero-copy clone-ы для дешёвых CI/dev-окружений). Те же dbt-модели, разный плейбук оптимизации стоимости.
Metadata Management, Catalog & LineageУправление метаданными, каталог & Lineage
▼Metadata management & the data catalogУправление метаданными & каталог данных
Metadata = data about the data: schemas, owners, descriptions, freshness, quality scores, classifications (PII/sensitivity), usage. A data catalog is the searchable inventory of all that — so people can find, trust, and understand data without asking the original engineer.
Metadata = данные о данных: схемы, владельцы, описания, свежесть, оценки качества, классификации (PII/чувствительность), использование. Каталог данных — это поисковая инвентаризация всего этого — чтобы люди могли найти, доверять и понимать данные без обращения к исходному инженеру.
| Metadata type | Examples |
|---|---|
| Technical | Schema, types, partitions, row counts, location |
| Operational | Last run, freshness, job status, SLA |
| Business | Definitions, owner, glossary terms, certification |
| Governance | PII tags, access policies, retention, classification |
| Тип метаданных | Примеры |
|---|---|
| Технические | Схема, типы, партиции, число строк, расположение |
| Операционные | Последний запуск, свежесть, статус задачи, SLA |
| Бизнесовые | Определения, владелец, термины глоссария, сертификация |
| Governance | Теги PII, политики доступа, хранение, классификация |
Tools: dbt docs (descriptions + auto DAG), Dataplex/Data Catalog, Snowflake's metadata views + Horizon, DataHub, OpenMetadata, Collibra, Purview.
Инструменты: dbt docs (описания + авто-DAG), Dataplex/Data Catalog, Snowflake metadata views + Horizon, DataHub, OpenMetadata, Collibra, Purview.
Data lineage — technical vs businessData lineage — технический vs бизнесовый
bls_raw.cpi ─┐
├─► stg_cpi ─► int_cpi_seasonal ─► fct_cpi_monthly ─► dashboard / API / client export
fred.weights─┘ │
└─► alert: if this breaks, ALL downstream is impacted
bls_raw.cpi ─┐
├─► stg_cpi ─► int_cpi_seasonal ─► fct_cpi_monthly ─► dashboard / API / клиентский экспорт
fred.weights─┘ │
└─► алерт: если это сломается, ВСЕ downstream затронуты
| Technical lineage | Business lineage | |
|---|---|---|
| Granularity | Table/column-level, system-derived | Concept/report-level, human-readable |
| Answers | "Which columns feed this field?" | "Which business reports use CPI?" |
| Source | Parsed from SQL/dbt/queries | Curated + glossary mapping |
| Primary user | Engineers | Analysts, governance, stakeholders |
| Технический lineage | Бизнесовый lineage | |
|---|---|---|
| Гранулярность | Уровень таблицы/колонки, выводится системой | Уровень концепта/отчёта, читаемый человеком |
| Отвечает на | «Какие колонки питают это поле?» | «Какие бизнес-отчёты используют CPI?» |
| Источник | Парсится из SQL/dbt/запросов | Кураторский + маппинг глоссария |
| Основной пользователь | Инженеры | Аналитики, governance, стейкхолдеры |
Why lineage matters
Почему lineage важен
- Impact analysis — before changing a model, see every downstream table/dashboard/consumer that breaks. (dbt:
dbt ls --select fct_cpi_monthly+.) - Root-cause — when a number looks wrong, walk lineage upstream to find the bad source/transform.
- Governance & compliance — prove provenance of a published figure; trace PII propagation; audit "where did this number come from".
- Trust — column-level lineage + tests + freshness = a data product clients can rely on.
- Анализ влияния — перед изменением модели увидеть каждую downstream-таблицу/дашборд/потребителя, которые сломаются. (dbt:
dbt ls --select fct_cpi_monthly+.) - Root-cause — когда число выглядит неправильно, пройти lineage upstream, чтобы найти плохой source/transform.
- Governance & compliance — доказать происхождение опубликованной цифры; проследить распространение PII; аудит «откуда взялось это число».
- Доверие — lineage на уровне колонок + тесты + свежесть = дата-продукт, на который клиенты могут положиться.
dbt gives column-level lineage for free from the model graph, and my code-review standard required descriptions + tests on every new model — so the catalog/lineage stayed accurate as a side-effect of how we shipped, not as a separate documentation chore.
dbt даёт column-level lineage бесплатно из графа модели, а мой стандарт code-review требовал описания + тесты на каждой новой модели — поэтому каталог/lineage оставались точными как побочный эффект того, как мы выкатывали, а не как отдельная обязанность по документации.
"A client reports a wrong CPI value — walk me through it." → Lineage upstream from fct_cpi_monthly to find which source/transform; check freshness + DQ test history at each hop; reproduce with time-travel/snapshot for the published point-in-time; fix + add a regression test; impact-analyse downstream via lineage to notify affected consumers.
«Клиент сообщает о неправильном значении CPI — пройди меня через это.» → Lineage upstream от fct_cpi_monthly, чтобы найти какой source/transform; проверить freshness + DQ test history на каждом хопе; воспроизвести с time-travel/snapshot для опубликованного момента времени; пофиксить + добавить регрессионный тест; провести impact-анализ downstream через lineage, чтобы уведомить затронутых потребителей.
Cost & Performance in Cloud WarehousesСтоимость & производительность в облачных хранилищах
▼BigQuery (pay per scan)
BigQuery (плата за сканирование)
- Partition on date (e.g.
period) → prune scans. - Cluster on common filter cols (market, series).
- Avoid
SELECT *; select only needed columns (columnar = scan = $). - Materialize heavy repeated subqueries; use incremental models.
- Set bytes-billed limits + cost alerts; flat-rate slots for predictable load.
- Партиционировать по дате (например
period) → прунинг сканов. - Кластеризовать по частым фильтр-колонкам (рынок, серия).
- Избегать
SELECT *; выбирать только нужные колонки (колоночное = скан = $). - Материализовать тяжёлые повторяющиеся подзапросы; использовать инкрементальные модели.
- Ставить лимиты bytes-billed + алерты стоимости; flat-rate slots для предсказуемой нагрузки.
Snowflake (pay per warehouse uptime)
Snowflake (плата за uptime warehouse)
- Right-size warehouses; bigger ≠ always cheaper, but faster can be.
- auto_suspend (e.g. 60s) + auto_resume.
- Multi-cluster only for concurrency, not single big jobs.
- Use result cache + clustering keys on big tables.
- Zero-copy clone for dev/CI = no storage cost.
- Right-size warehouses; больше ≠ всегда дешевле, но быстрее может быть.
- auto_suspend (например 60s) + auto_resume.
- Multi-cluster только для конкуренции, не для одной большой задачи.
- Использовать result cache + clustering keys на больших таблицах.
- Zero-copy clone для dev/CI = нет стоимости хранения.
Universal levers
Универсальные рычаги
- Incremental models (dbt
incremental) — only process new/changed rows, not full refresh. - Slim CI — only build changed + downstream models.
- Tag & attribute compute by team/pipeline for showback/chargeback.
- Monitor query/warehouse cost dashboards; kill runaway queries.
- Инкрементальные модели (dbt
incremental) — обрабатывать только новые/изменённые строки, не full refresh. - Slim CI — строить только изменённые + downstream модели.
- Тегировать & атрибутировать compute по команде/пайплайну для showback/chargeback.
- Мониторить дашборды стоимости запросов/warehouse; убивать убегающие запросы.
"How would you cut warehouse cost without hurting freshness?" → Profile the most expensive queries; switch full-refresh models to incremental; tighten auto_suspend; right-size the warehouse to the workload; move dev/CI to zero-copy clones on a small warehouse; partition/cluster the hot tables. Measure before/after in the cost dashboard.
«Как бы ты сократил стоимость warehouse, не навредив свежести?» → Профилировать самые дорогие запросы; переключить full-refresh модели на инкрементальные; ужесточить auto_suspend; right-size warehouse под workload; перенести dev/CI на zero-copy clone-ы на маленьком warehouse; партиционировать/кластеризовать горячие таблицы. Измерить до/после в дашборде стоимости.
Incremental models drift: a bug in the incremental logic silently accumulates. Schedule periodic full-refresh reconciliation and a row-count/sum reconciliation test to catch silent divergence.
Инкрементальные модели дрейфуют: баг в инкрементальной логике тихо накапливается. Планировать периодическую full-refresh сверку и тест сверки row-count/sum, чтобы ловить тихое расхождение.
Environment Promotion & Secrets ManagementПромоушен окружений & управление секретами
▼Promotion pathПуть промоушена
commit ─► PR (CI: lint+tests on dev/CI clone) ─► merge ─► STAGE (full run+tests)
─► manual/auto gate (green only) ─► PROD (blue/green swap, monitored, rollback-ready)
commit ─► PR (CI: lint+tests на dev/CI clone) ─► merge ─► STAGE (full run+tests)
─► ручной/авто-гейт (только зелёный) ─► PROD (blue/green swap, мониторится, готов к откату)
- Same code, different targets: dbt targets / Airflow connections swap the schema/warehouse/project per env — no code forks.
- Promotion = moving the artifact (manifest/image/DAG), never re-writing logic per env.
- Gate on green: a promotion can only happen if the prior stage's tests passed.
- Immutable artifacts: prod runs the exact image/manifest that passed stage.
- Тот же код, разные таргеты: dbt targets / Airflow connections меняют схему/warehouse/проект на окружение — никаких форков кода.
- Промоушен = перемещение артефакта (manifest/image/DAG), никогда не переписывать логику под окружение.
- Гейт на зелёном: промоушен возможен только если тесты предыдущего stage прошли.
- Неизменяемые артефакты: прод запускает точный image/manifest, прошедший stage.
Secrets managementУправление секретами
- Never in git or code. Use a secrets manager: GCP Secret Manager, AWS Secrets Manager, Azure Key Vault, Vault.
- Inject at runtime as env vars / mounted secrets / Airflow connections+variables (backed by a secrets backend).
- Least privilege service accounts per env; prod creds never reachable from dev.
- Rotation + audit logging; prefer short-lived/federated identity (workload identity, OIDC) over long-lived keys.
- Secret scanning in CI (pre-commit / detect-secrets) to block accidental commits.
- Никогда в git или коде. Использовать менеджер секретов: GCP Secret Manager, AWS Secrets Manager, Azure Key Vault, Vault.
- Инжектить во время выполнения как env vars / mounted secrets / Airflow connections+variables (backed секрет-бэкендом).
- Least privilege сервисные аккаунты на окружение; прод-креды никогда не достижимы из dev.
- Ротация + audit logging; предпочитать short-lived/federated identity (workload identity, OIDC) вместо long-lived ключей.
- Сканирование секретов в CI (pre-commit / detect-secrets) для блокировки случайных коммитов.
# dbt profiles use env vars, not literals prod: type: snowflake account: "{{ env_var('SF_ACCOUNT') }}" user: "{{ env_var('SF_USER') }}" password: "{{ env_var('SF_PASSWORD') }}" # injected from Secret Manager at runtime
Across IU Group's Azure OpenAI work and the GCP/Snowflake stacks, the same rule held: credentials lived in the cloud secret store, were injected at runtime by service identity, and CI failed on any committed secret. Promotion moved code; secrets stayed bound to the environment.
Через работу IU Group с Azure OpenAI и GCP/Snowflake-стеки действовало одно правило: credentials жили в облачном хранилище секретов, инжектились во время выполнения сервисной идентичностью, и CI фейлился на любом закоммиченном секрете. Промоушен перемещал код; секреты оставались привязаны к окружению.
"How do you stop a dev job from touching prod data?" → Separate service accounts/roles per env with least privilege; prod credentials only in the prod secret store; env-scoped connections in Airflow; network/role isolation so dev identity literally cannot authenticate to prod.
«Как остановить dev-задачу от касания прод-данных?» → Отдельные сервисные аккаунты/роли на окружение с least privilege; прод-креды только в прод-хранилище секретов; env-scoped connections в Airflow; сетевая/ролевая изоляция, чтобы dev-идентичность буквально не могла аутентифицироваться в прод.
Self-Quiz — Flip to RevealСамопроверка — Нажми чтобы открыть
▼Tap any card to reveal the answer.
Нажми на любую карточку, чтобы открыть ответ.
--select state:modified+). Gives fast PR feedback and low compute cost instead of rebuilding the whole project on every commit. Full-volume suites move to stage/nightly.
Использование предыдущего manifest.json как состояния для сборки/тестирования только изменённых моделей + их downstream (--select state:modified+). Даёт быструю обратную связь на PR и низкую стоимость вычислений вместо пересборки всего проекта на каждом коммите. Полнообъёмные наборы переходят на stage/ночные запуски.
table_v2), validate with DQ tests, then atomically repoint the consumer abstraction — swap the view/alias or RENAME — so consumers never see a partial state. Old version stays for instant rollback. Snowflake zero-copy clone makes the green copy effectively free.
Построить новую версию в параллельную таблицу (table_v2), валидировать DQ-тестами, затем атомарно переточить абстракцию потребителя — поменять view/alias или RENAME — чтобы потребители никогда не видели частичное состояние. Старая версия остаётся для мгновенного отката. Snowflake zero-copy clone делает зелёную копию эффективно бесплатной.
auto_suspend + zero-copy clones for dev/CI. Same dbt models, different optimisation playbook — the core of my GCP→Snowflake migration.
BigQuery билит за сканируемые байты → партиционировать + кластеризовать + выбирать-только-нужные-колонки + инкрементальные модели, чтобы сканировать меньше. Snowflake билит за uptime warehouse → right-size warehouses + агрессивный auto_suspend + zero-copy clone-ы для dev/CI. Те же dbt-модели, разный плейбук оптимизации — ядро моей миграции GCP→Snowflake.
30-second framing for the interview30-секундный фрейминг для интервью
"I think of DataOps as DevOps for data products: version control + CI/CD + automated testing + observability + a catalog/lineage layer, all enforced by the pipeline rather than by discipline. Concretely, at McMakler/Career.io I version-controlled every dbt model, ran lint + unit + data tests in CI (with slim CI and a DagBag gate for Airflow), promoted immutable artifacts dev→stage→prod, and used a code-review standard I authored to keep tests, contracts and lineage accurate as a side-effect of shipping. On the platform side I migrated transforms GCP/BigQuery→Snowflake and re-tuned the cost model from bytes-scanned to warehouse-uptime."
«Я думаю о DataOps как о DevOps для дата-продуктов: контроль версий + CI/CD + автоматизированное тестирование + наблюдаемость + слой каталога/lineage, всё обеспечиваемое пайплайном, а не дисциплиной. Конкретно, в McMakler/Career.io я держал каждую dbt-модель под контролем версий, запускал lint + unit + data tests в CI (с slim CI и DagBag-гейтом для Airflow), промоутил неизменяемые артефакты dev→stage→prod и использовал стандарт code-review, который я написал, чтобы тесты, контракты и lineage оставались точными как побочный эффект выката. Со стороны платформы я мигрировал трансформы GCP/BigQuery→Snowflake и перенастроил модель стоимости с bytes-scanned на warehouse-uptime.»