네 가지 아이디어가 한 번 돌아간 스크립트와 2년간 매일 밤 도는 파이프라인을 가르는 거야. 지금 외워 — 다음 모든 트랙에서 보일 테니까.
1. Schema
Schema 는 데이터가 어떤 모양이어야 하는지의 선언적 기술 — 컬럼 이름, 타입, 제약 ("unique", "non-negative", "이 정규식 매칭"). Auto-detect 는 탐색용으론 OK. 무인으로 도는 파이프라인에선 schema 가 명시적, version-controlled, 그리고 도구 경계마다 검증돼야 해.
2. Lineage
Lineage 는 "이 숫자 어디서 왔어?" 에 답해 — 테이블 수준, 컬럼 수준, 이상적으론 row 수준에서. CFO 가 Q1 매출이 0.3% 움직인 이유 물으면, 거꾸로 걸어갈 수 있어야 해: 대시보드 → 최종 mart → 중간 join → 소스 extract. Modern 도구 (dbt, Dagster, OpenLineage) 가 그래프를 자동 생성할 수 있어 — 그쪽 결만 따르면.
3. Idempotency
Idempotent 파이프라인은 같은 입력 window 에 대해 한 번 돌리든, 두 번이든, 스무 번이든 같은 결과를 내. 이게 사소해 보이지만 안 사소해. 순진한 append-style write 는 retry 시 row 두 배. 순진한 incremental load 는 backfill 후 sync 깨짐. 규율은 write 단계를 partition 다시 돌리면 깔끔히 교체되도록 설계하는 거야. 한번 이거 내재화하면, 디버깅이 더는 무섭지 않아 — "그냥 다시 돌려" 가 진짜 답이 돼.
4. Contract
Data contract 는 데이터 만드는 팀과 쓰는 팀 사이의 공유된, 지속적인 합의야: schema, freshness, 소유권, breaking change 정책. Contract 없으면 모든 upstream 변경이 outage 대기. 있으면 producer 는 깨면 안 되는 게 뭔지 알고, consumer 는 의존해도 되는 게 뭔지 알아.
네 개가 어떻게 맞물리는지
Schema 는 지역적 — 단계마다, 이게 사실이어야 함. Lineage 는 전역적 — 전 단계 걸쳐, 데이터가 어떻게 흘렀나. Idempotency 는 시간적 — 재실행 걸쳐, 결과가 안정. Contract 는 사회적 — 팀 사이에, 우리가 약속하는 것. 진지한 파이프라인은 넷 다 가져. 일회성 스크립트는 하나도 안 가져.