한 번 돌아간 스크립트와 2년째 매일 밤 도는 파이프라인을 가르는 건 아이디어 네 개야. 지금 외워 둬 — 앞으로 모든 트랙에서 계속 마주칠 테니까.
1. Schema
Schema 는 데이터가 어떤 모양이어야 하는지를 선언해 둔 기술이야 — 컬럼 이름, 타입, 제약 ("unique", "음수 금지", "이 정규식에 맞을 것"). 탐색할 땐 auto-detect 도 괜찮아. 하지만 사람 없이 도는 파이프라인에선 schema 가 명시적이어야 하고, version control 에 있어야 하고, 도구 경계를 넘을 때마다 검증돼야 해.
2. Lineage
Lineage 는 "이 숫자 어디서 왔어?" 에 답해 줘 — 테이블 수준에서, 컬럼 수준에서, 이상적으론 row 수준에서. CFO 가 Q1 매출이 0.3% 움직인 이유를 물으면 거꾸로 걸어갈 수 있어야 해: 대시보드 → 최종 mart → 중간 join → 소스 extract. Modern 도구 (dbt, Dagster, OpenLineage) 는 이 그래프를 자동으로 그려 줘 — 도구가 깔아 준 길을 따라 쌓았다면.
3. Idempotency
Idempotent 파이프라인은 같은 입력 window 에 대해 한 번을 돌리든, 두 번이든, 스무 번이든 같은 결과를 내. 사소해 보이지? 안 사소해. 순진한 append 는 retry 한 번에 row 가 두 배가 되고, 순진한 incremental load 는 backfill 뒤에 sync 가 어긋나. 규율은 write 단계를 이렇게 설계하는 거야: partition 을 다시 돌리면 깔끔하게 통째로 교체되도록. 이걸 한번 몸에 익히면 디버깅이 더는 무섭지 않아 — "그냥 다시 돌려" 가 진짜 답이 되거든.
한 가지는 조심해. 아래 stage-and-swap 패턴을 두고 atomic 이라고들 하는데 정확히는 아냐. 파일시스템이 한 번에 원자적으로 갈아 주는 건 경로 하나뿐이고, 이미 내용물이 있는 디렉토리를 한 걸음에 바꿔 끼우진 못해. 이 패턴이 실제로 주는 건 다시 돌려도 안전한 write, 그리고 partition 이 잠깐 공중에 떠 있는 아주 짧은 구간이야. 그 정도면 충분해 — 거기서 죽어도 되돌릴 수 있게 순서만 잡아 두면. Track 4 에서 제대로 뜯어볼 거야.
4. Contract
Data contract 는 데이터를 만드는 팀과 쓰는 팀 사이의 살아 있는 합의야: schema, freshness, 소유권, breaking change 정책. Contract 가 없으면 모든 upstream 변경이 장애 예약이야. 있으면 producer 는 뭘 깨면 안 되는지 알고, consumer 는 뭘 믿어도 되는지 알아.
네 개가 어떻게 맞물리는지
Schema 는 지역적이야 — 단계마다, 여기서 이게 참이어야 해. Lineage 는 전역적이고 — 전 단계에 걸쳐, 데이터가 어떻게 흘렀나. Idempotency 는 시간적이야 — 재실행을 거듭해도 결과가 흔들리지 않나. Contract 는 사회적이고 — 팀 사이에, 우리가 서로 뭘 약속했나. 진지한 파이프라인은 넷 다 갖고 있어. 일회성 스크립트는 하나도 없고.