C.W.K.
Stream
Lesson 04 of 06 · published

DE Mental Model — Schema, Lineage, Idempotency, Contract

~14 min · foundation, mental-model, principles

Level 0구경꾼
0 XP0/47 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

네 가지 아이디어가 한 번 돌아간 스크립트와 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 는 사회적 — 팀 사이에, 우리가 약속하는 것. 진지한 파이프라인은 넷 다 가져. 일회성 스크립트는 하나도 안 가져.

Code

Idempotent partition write — canonical 패턴·python
from pathlib import Path
import shutil
import pandas as pd

def write_partition(df: pd.DataFrame, root: Path, partition: str) -> Path:
    '''Partition 을 atomic 하게 교체. 다시 돌려도 안전 — 같은 결과.'''
    target = root / f'date={partition}'
    staging = root / f'.tmp_{partition}'

    # 1. 아무도 안 읽는 staging 디렉토리에 쓰기
    staging.mkdir(parents=True, exist_ok=True)
    df.to_parquet(staging / 'data.parquet', index=False)

    # 2. staging → target atomic swap. 위에서 뭔가 실패했으면 target 은 그대로
    if target.exists():
        shutil.rmtree(target)
    staging.rename(target)
    return target

# 같은 partition 에 다시 돌려? 같은 결과. Double-count 도 orphan row 도 없음
write_partition(today_df, Path('warehouse/orders'), '2026-04-30')

External links

Exercise

과거에 작성한 데이터 생산 스크립트 — CSV exporter, daily 리포트, 뭐든 — 하나 골라. 네 아이디어 (explicit schema, traceable lineage, idempotent rerun, declared contract) 에서 0–4 점 매겨. 일회성 스크립트는 보통 0/4 — 그게 정상. 근데 이제 타겟이 생긴 거야.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.