DEV Community

schema drift를 fail이 아니라 warn으로 둔 이유

schema drift를 fail이 아니라 warn으로 둔 이유

데이터 파이프라인에서 source schema가 바뀌는 순간은 애매하다. 무조건 무시하면 운영자는 입력 구조가 바뀐 사실을 모른다. 반대로 모든 schema 변화를 실패로 처리하면, 정상적인 컬럼 추가까지 daily run을 막아버린다.

manufacturing-data-platform-mini 에서는 이 문제를 작게 다뤘다. synthetic manufacturing CSV의 실제 header를 기준으로 schema_hash 를 만들고, previous successful run과 비교해 달라졌으면 schema_drift quality check를 warn 으로 남긴다. 단, required column이 빠져 silver/gold contract를 만들 수 없는 경우는 현재 ValueError 로 빠르게 실패한다.

1. Scenario

어느 날 source CSV에 새 컬럼이 추가된다.

기존 header:

event_time,plant_id,line_id,work_order_id,machine_id,product_code, operation,units_produced,defect_count,cycle_time_ms,business_date

새 header:

event_time,plant_id,line_id,work_order_id,machine_id,product_code, operation,units_produced,defect_count,cycle_time_ms,business_date,operator_id

operator_id 는 아직 silver/gold mart에서 쓰지 않는다. 하지만 source 구조가 바뀐 사실은 기록되어야 한다.

2. Decision Pressure

schema drift에서 중요한 질문은 단순히 "바뀌었나?"가 아니다.

  • 바뀐 것을 운영자가 알 수 있는가?
  • 정상적인 컬럼 추가 때문에 pipeline을 멈춰야 하는가?
  • downstream gold mart contract가 조용히 바뀌지는 않는가?
  • 이전 successful run과 지금 run의 schema identity를 비교할 수 있는가?

초기 구현에서는 한 가지 실제 버그가 있었다. schema_hash 가 고정된 required column 목록에 너무 묶여 있어서, 추가 컬럼이 들어와도 hash가 바뀌지 않았다. 즉 operator_id 가 추가되어도 drift가 보이지 않았다. 이 문제를 고치기 위해 read_rows 가 실제 CSV header를 반환하고, 그 실제 header 기준으로 schema_hash 를 계산하도록 바꿨다.

3. Options

option result risk
ignore drift pipeline은 계속 돈다 source 변화가 보이지 않음
fail every drift 변화에 강하게 반응 정상적인 컬럼 추가도 막음
warn and continue 변화가 보이고 run도 계속됨 warning을 inspect해야 함
auto-evolve silver/gold 새 컬럼을 바로 사용 가능 downstream contract가 조용히 바뀔 수 있음
full schema registry production에 가까움 mini slice에는 무거움

이 프로젝트의 선택은 warn and continue 다.

4. Decision

현재 contract는 이렇다.

  • previous successful run이 없으면: schema_drift = pass (baseline schema established)
  • current schema_hash == previous successful schema_hash: schema_drift = pass
  • current schema_hash != previous successful schema_hash: schema_drift = warn
  • quality_passedtrue 유지
  • run/lineage record에 previous/current schema_hash 저장
  • required column missing: ValueError fast fail

중요한 구분:

  • schema_drift warn: source shape이 바뀌었다. 하지만 현재 silver/gold contract는 만들 수 있다.
  • missing required column failure: 현재 mart contract를 만들 수 없다.

이 선택은 "schema registry를 만들었다"는 뜻이 아니다. schema change를 invisible하게 두지 않고, quality/check result와 run metadata에 남긴다는 작은 contract다.

비슷한 방향의 외부 기준도 있다.

  • dbt data tests는 unique, not_null, accepted_values 같은 generic test로 data contract를 드러낸다.
  • dbt severity config는 test 결과를 error 또는 warn으로 다룰 수 있게 한다.
  • Great Expectations는 Expectation을 데이터에 대한 검증 가능한 assertion으로 본다.
  • Apache Iceberg schema evolution은 schema 변화를 table metadata 차원에서 다루는 더 큰 방향이다.

이 프로젝트는 그 도구들을 구현한 것이 아니라, 같은 운영 질문을 mini pipeline의 schema_hashschema_drift warning으로 작게 연습한다.

5. Evidence

관련 코드와 문서:

  • src/manufacturing_data_platform/pipeline/lakehouse.py
  • learn/reference-decisions/schema-drift.md
  • VERIFICATION_LOG.md
  • README.md

핵심 테스트:

  • tests/test_lakehouse_pipeline.py
    • test_schema_drift_helper_states
    • test_schema_drift_warns_against_previous_successful_run
    • test_schema_stable_when_schema_unchanged_across_dates
    • test_schema_drift_warns_on_added_column

특히 test_schema_drift_warns_on_added_columnoperator_id 컬럼이 추가됐을 때:

  • schema_drift.status == "warn"
  • previous schema hash != current schema hash
  • quality_passed is True

를 확인한다.

검증 로그에도 이 버그 수정이 남아 있다.

2026-06-30 pre-Codex self-audit: schema_hash was computed from fixed REQUIRED_COLUMNS, not the actual CSV header. Fix: read_rows now returns the actual header; schema_hash uses that actual header.

그리고 최신 local verification에서도 전체 테스트와 CLI가 통과했다.

2026-07-10: pytest: 35 passed
lakehouse JSON CLI: passed

6. Limitations

정직한 한계:

  • full schema registry는 없다.
  • column-level diff UI도 없다.
  • Iceberg/Delta schema evolution은 아직 구현되지 않았다.
  • schema_drift는 hash 중심이라 어떤 컬럼이 바뀌었는지 사람이 바로 보기엔 제한이 있다.
  • warning을 운영자가 inspect하지 않으면 놓칠 수 있다.
  • missing required column은 아직 structured quality report가 아니라 ValueError fast fail이다.

그래서 이 글의 claim은 작게 둔다. actual CSV header 기준 schema_hash를 만들고, previous successful run과 비교해 schema drift를 warn으로 드러내는 mini contract를 구현했다.

7. Why This Connects To Iceberg Later

Slice1은 schema drift를 detect하고 warn으로 남긴다. Iceberg로 가면 질문이 바뀐다.

  • 새 컬럼을 Iceberg table에 add column으로 반영할 것인가?
  • 어떤 변화는 허용하고 어떤 변화는 금지할 것인가?
  • 과거 snapshot은 어떤 schema로 읽히는가?
  • downstream gold mart contract가 조용히 바뀌지 않게 어떻게 막을 것인가?

즉 Slice1의 schema_hash + warn 은 나중에 Iceberg schema evolution으로 이어지는 출발점이다. 하지만 현재 repo에서 Iceberg schema evolution은 design-only이며 구현 evidence가 아니다.

8. 정리

schema drift를 전부 failure로 처리하면 정상적인 source 확장을 막을 수 있다. 반대로 아무 기록 없이 통과시키면 downstream contract가 조용히 흔들릴 수 있다. 이 slice에서는 실제 CSV header 기준 schema_hash 를 남기고, previous successful run과 달라진 header를 warn 으로 드러낸다. run은 계속되지만 운영자는 source 구조 변화를 inspect할 수 있다. required column이 빠져 silver/gold contract를 만들 수 없는 경우는 빠르게 실패시킨다.

Comments

No comments yet. Start the discussion.