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

Spreadsheet 가 무너지는 이유

~10 min · foundation, anti-pattern, history

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

Excel 은 대단한 소프트웨어야. 매일 수억 명이 쓰고, 일의 첫 80% — 인터랙티브 탐색, 빠른 what-if, 즉석 요약 — 에선 여전히 맞는 도구고. 근데 데이터 엔지니어라면 누구나 같은 쓴맛을 한 번은 봐: spreadsheet 는 재현 가능하고 자동화된 진지한 데이터 작업의 기반이 못 돼. 보통 이 순서로 데어 봐:

일곱 가지 실패 모드

  • Reproducibility 가 없어. Spreadsheet 는 누가 저장을 누른 그 순간의 스냅샷이야. 다음 달 데이터로 같은 로직을 다시 돌리려면 같은 클릭을 같은 순서로 손으로 반복해야 하는데 — 순서가 맞았기를 비는 수밖에 없어. Pandas 코드는 설계부터 재현 가능해 — git checkout + python pipeline.py = 같은 결과.
  • Scale. Excel 의 row 한계는 1,048,576. 실제론 그 한참 전부터 느려져. Pandas 는 노트북에서 수천만 행, Polars 와 DuckDB 는 수억, Spark / BigQuery 는 수십억을 다뤄. 데이터가 커지면 옮기는 건 선택이 아니야.
  • 에러가 숨어. A2:A100 에 row 하나 끼워 넣으면 D5 에 있던 A50 참조 수식이 조용히 깨져. 아무도 안 알려줘. 그냥 숫자가 틀린 채로 굴러가.
  • 수동 단계는 version control 이 안 돼. 드래그-fill, 복붙, 수동 필터 — git diff 에 안 나타나. "이 리포트 지난주랑 뭐가 달라?" 가 답할 수 없는 질문이 돼.
  • 협업. 두 분석가가 같은 sheet 를 각자 고친 걸 머지하는 건 — 아주 너그럽게 말해도 — 악몽이야. Pandas 파이프라인은 그냥 Python diff 로 머지돼.
  • 테스트가 없어. Spreadsheet 의 로직을 단위 테스트할 합리적인 방법이 없어. 그러니 안전한 리팩터링도 없어 — regression 을 잡아 줄 테스트 suite 가 없으니까.
  • 타입 혼동. Excel 의 타입 auto-detect 는 공격적이야. 미국식이 아닌 날짜는 텍스트가 되고, 긴 ID 는 과학 표기로 바뀌며 정밀도를 잃고, 유전자 이름은 날짜로 파싱돼 (이 마지막 건 전설의 괴담이야).

MARCH1 / SEPT4 / DEC1 참사

2016년 Genome Biology 의 한 연구가 표본으로 살펴본 유전체학 논문의 ~20% 에서 Excel 의 유전자 이름 자동 변환 — MARCH1, SEPT4, DEC1 이 날짜로 — 때문에 생긴 에러를 찾아냈어. 문제가 하도 끈질겨서 2020년엔 HUGO Gene Nomenclature Committee (HGNC) 가 유전자 이름을 Excel 이 안 삼키는 심볼로 아예 바꿔 버렸어. 다시 말해 — 인류는 spreadsheet 의 auto-detect 를 못 바꿔서 생물학 어휘를 바꿨어. 두 번 읽어봐.

그어야 할 선

Spreadsheet 는 사람의 탐색, 일회성 요약 공유, 그리고 끝난 분석의 출력 목적지로 써 (임원은 여전히 깔끔한 XLSX 를 원하니까). 분석 자체를 그 위에 올리진 마. 분석이 서는 기반은 Python 코드, version control, 테스트, 스케줄, observability 야.

Code

Excel 을 꼭 읽어야 한다면 — 방어적으로·python
import pandas as pd

# 모든 컬럼 일단 string 으로 읽어서 Excel 의 타입 추측 차단
df = pd.read_excel(
    'sales_2026.xlsx',
    sheet_name='Q1',
    dtype=str,            # 다 텍스트로
    keep_default_na=False  # 빈 칸을 NaN 으로 자동 변환 안 함
)

# 의도적으로 cast — 에러 surface 명시
df['order_date']   = pd.to_datetime(df['order_date'], format='%Y-%m-%d', errors='raise')
df['amount_usd']   = pd.to_numeric(df['amount_usd'].str.replace(',', ''), errors='raise')
df['gene_symbol']  = df['gene_symbol'].astype('string')   # MARCH1 은 MARCH1 으로

# 이상한 거 있으면 지금 raise — 새벽 3시 prod 에서 말고
assert df['order_date'].notna().all(), '깨진 날짜 row 가 통과됨'

External links

Exercise

날짜 컬럼이 있는 아무 Excel 파일이나 하나 골라. Excel 에서 CSV 로 저장하고, 그 CSV 를 텍스트 에디터로 열어 봐. 셀에서 보이던 날짜 포맷이랑 disk 에 실제로 적힌 걸 비교해. Excel 의 표시 포맷과 실제 직렬화가 다른 경우가 자주 있어 — 그 어긋남이 바로 데이터 corruption 이 사는 곳이야.

Progress

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

댓글 0

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

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