본문 바로가기
C.W.K.
Stream
Lesson 06 of 06 · published

Production Mindset — Rerunnable, Observable, Reviewable

~12 min · foundation, production, mindset

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

"데이터 wrangle 할 줄 아는 사람" 이 "데이터 엔지니어" 가 되는 순간이 있어. 지금 돌아가나를 붙잡던 눈이 월요일 아침에도 살아 있나로 옮겨가는 순간. 그 둘을 가르는 속성이 세 가지야.

Rerunnable (다시 돌릴 수 있다)

아무나 — 6개월 후의 너, 내일 입사한 동료, 새벽 3시의 on-call 엔지니어 — clean checkout 에서 아무 historical window 나 골라 돌려도 같은 결과가 나와야 해. 그러니까 hard-coded 경로도 없고, "화요일 upstream feed 다음에만 돌아가요" 같은 숨은 약속도 없고, "step 4 는 원래 손으로 하는 거야" 도 없어. 설정은 명시적이고, 입력은 주소로 가리킬 수 있고, 진입점은 명령어 하나야.

Observable (들여다볼 수 있다)

파이프라인이 성공하면 성공했다는 증거가 있어 — row count, freshness, 분포 metric, lineage. 실패하면 어느 단계가 어떤 입력으로, 무슨 에러로 죽었는지 바로 알 수 있어 — 손을 쓸 수 있을 만큼 빨리. 로그는 구조화돼 있고, metric 은 흘러나오고, 대시보드는 첫 사고가 나기 전부터 있어 — 사고 나고 만드는 게 아니라.

Reviewable (리뷰할 수 있다)

모든 변경이 코드 리뷰를 거쳐. Diff 는 리뷰어한테 어떤 코드가 아니라 어떤 비즈니스 의미가 바뀌는지 말해 줘. 테스트는 새 동작이 새 기대와 맞는다는 걸 증명하고. Migration 은 명시적이야. "4년 전에 누가 대시보드 SQL 을 바꿨는데 왜인진 아무도 몰라" — 그 무덤엔 리뷰 없이 들어간 변경들이 줄줄이 묻혀 있어.

이건 문화 얘기야

도구 고르는 문제가 아니야 — 자세 문제지. 똑같은 Pandas 스크립트가 rerunnable + observable + reviewable 한 시스템일 수도 있고, 누군가의 home directory 에 굴러다니는 notebook 일 수도 있어. Disk 위 byte 는 비슷해 — 시스템과 유리 세공품을 가르는 건 그걸 둘러싼 규율이야. 좋은 소식: 규율은 배울 수 있고, 이 quest 의 대부분이 바로 그 수업이야.

Code

Rerunnable + observable 한 파이프라인 진입점·python
import argparse, logging, sys, time
from datetime import date
from pathlib import Path

log = logging.getLogger('orders_pipeline')
logging.basicConfig(level=logging.INFO,
    format='%(asctime)s %(levelname)s %(name)s %(message)s')

def run(window: str, root: Path) -> None:
    t0 = time.monotonic()
    log.info('start window=%s root=%s', window, root)

    df = extract(window, root)
    log.info('extract.rows=%d', len(df))

    clean = transform(df)
    log.info('transform.rows=%d', len(clean))

    written = load(clean, root, window)
    log.info('load.path=%s rows=%d', written, len(clean))

    log.info('done elapsed=%.2fs', time.monotonic() - t0)

if __name__ == '__main__':
    p = argparse.ArgumentParser()
    p.add_argument('--window', default=str(date.today().isoformat()))
    p.add_argument('--root',   default=Path('warehouse'), type=Path)
    args = p.parse_args()
    try:
        run(args.window, args.root)
    except Exception:
        log.exception('pipeline failed')
        sys.exit(1)

External links

Exercise

본인이 쓴 스크립트 하나 골라. 30분 타이머 걸고 세 가지를 추가해: (1) 아무 날짜나 지정해서 돌릴 수 있는 --window CLI argument, (2) 각 stage 시작/끝에 row count 가 찍히는 구조화된 log.info(), (3) 실패하면 non-zero exit. "production" 까진 못 가도 — 방향이 꺾이는 감각은 올 거야.

Progress

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

댓글 0

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

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