LabHub
배우기 러닝패스 코스

Working With Customer Data

A Validator That Cannot Say "Passed" Is Not a Validator

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

한 줄 요약

검증기의 가치는 무엇을 잡아내느냐가 아니라 정상 파일에 대해 정상이라고 말할 수 있느냐에서 결정된다.

Concept map: 스키마 규칙 · 중복 규칙 · 범위 규칙 · 참조 규칙

왜 이게 필요했나

정제 스크립트는 한 번 쓰고 버립니다. 검증기는 매주 돕니다. 이 차이가 설계를 바꿉니다.

고객사에 데이터 연동을 붙이고 나면, 다음 달부터 매주 같은 형식의 파일이 도착합니다. 그중 어느 주에는 상류 시스템이 바뀌어서 열이 하나 늘거나, 날짜 형식이 달라지거나, 인코딩이 바뀝니다. 그 변화를 사람이 눈으로 발견하는 시점은 대개 집계 숫자가 이상하다는 신고가 들어온 뒤입니다.

검증기는 그 시차를 없애기 위한 것입니다.

어떻게 동작하나

쓸 만한 검증기는 네 종류의 규칙을 가집니다.

스키마 규칙 — 열의 개수와 이름, 필수 값의 존재, 타입. "필드가 5개여야 하고, customer 는 비어 있으면 안 되고, amount 는 정수여야 한다."

중복 규칙 — 키가 유일한가. 여기서 주의할 것은 앞 모듈에서 본 함정입니다. 키에 결측이 있을 수 있으면 결측 행은 별도로 셉니다.

범위 규칙 — 값이 상식적인 구간에 있는가. amount 가 0 이거나 음수이거나 9,900만 원인 행은 형식상 유효한 정수지만 업무상으로는 거의 확실히 잘못된 데이터입니다. 범위 규칙이 없는 검증기는 타입만 맞으면 전부 통과시켜서, 소수점 위치가 하나 밀린 값을 그대로 흘려보냅니다.

참조 규칙 — 다른 데이터와의 정합성. 주문의 고객 번호가 고객 테이블에 실제로 있는가.

그리고 이 네 가지보다 중요한 성질이 하나 있습니다. 정상 파일에 대해 반드시 통과라고 말해야 합니다.

현장에서 만나는 모습

검증기가 실패하는 두 가지 방식이 있고, 둘 다 흔합니다.

과탐지. 규칙이 너무 빡빡해서 정상 파일도 실패합니다. 그러면 사람이 매주 "또 그거겠지" 하며 무시하기 시작하고, 두 달 뒤 진짜 문제가 왔을 때도 똑같이 무시합니다. 그 시점에는 검증기가 있는 것이 없는 것보다 나쁩니다. 있다고 믿게 만들면서 실제로는 아무것도 막지 못하기 때문입니다.

과소탐지. 규칙이 느슨해서 아무것도 못 잡습니다. 대개 "일단 죽지 않게" 만든 검증기가 이렇게 됩니다.

그래서 검증기를 만들면 반드시 두 방향으로 시험합니다. 정상 파일에 돌려 통과하는지, 깨진 파일에 돌려 실패하는지. 둘 중 하나만 확인한 검증기는 절반만 만든 것입니다.

마지막으로 출력 형식입니다. 검증기는 종료 코드로 말해야 합니다. 통과면 0, 실패면 0 이 아닌 값. 그래야 CI 나 배치 파이프라인에 그대로 꽂힙니다. 사람이 읽을 메시지는 그 위에 얹는 것이고, 기계가 읽을 신호가 먼저입니다.

검증기가 갖춰야 할 것

"틀렸다" 만 말하는 검증기는 반쪽입니다. 사람이 고칠 수 있으려면 네 가지가 필요합니다.

요소 없으면
어느 줄·어느 필드인가 100만 행 중 어디인지 찾느라 하루
무엇을 기대했나 무엇으로 고쳐야 할지 모른다
실제 값은 무엇인가 원본을 다시 열어 봐야 한다
몇 건인가 하나짜리 예외인지 구조적 문제인지 모른다
❌ 검증 실패: 잘못된 데이터가 있습니다
✅ 행 4213, 컬럼 order_date: '2026-13-45' 가 날짜 형식이 아닙니다 (기대: YYYY-MM-DD)
   같은 오류 1,842건 — 원본의 8행 이후 전부. 인코딩이나 구분자를 먼저 확인하세요.

마지막 문장이 핵심입니다. 오류가 특정 지점 이후로 몰려 있으면 개별 값의 문제가 아니라 파싱 문제 입니다. 검증기가 그 패턴을 알아채고 알려 주면 조사 방향이 바로 잡힙니다.

어디서 막을 것인가

같은 검사를 여러 층에 두는 것은 낭비가 아닙니다. 각각 다른 것을 막습니다.

1. 수집 경계   형식·필수 필드·인코딩       → 나쁜 데이터가 들어오지 못하게
2. 변환 중     비즈니스 규칙·참조 무결성    → 조용히 잘못된 결과를 만들지 못하게
3. 적재 후     행 수·합계·분포 대조         → 옮기다 잃어버린 것을 잡게

3번을 자주 빠뜨립니다. 원본 12,043행이 적재 후 12,041행이면 2행이 어디선가 사라진 것입니다. 행 수와 금액 합계를 대조하는 한 줄 이 이런 것을 잡습니다.

-- 적재 후 대조
select
  (select count(*) from staging_orders) as src,
  (select count(*) from orders where load_id = :id) as dst,
  (select sum(amount) from staging_orders) as src_amt,
  (select sum(amount) from orders where load_id = :id) as dst_amt;

나쁜 행을 어떻게 다루나

전부 실패시키면 좋은 데이터까지 못 씁니다. 하나도 안 막으면 오염됩니다. 실무의 답은 격리 입니다.

읽은 행 12,043
 ├ 통과   11,998 → 적재
 └ 격리       45 → quarantine 표 + 사유

격리된 행은 사유와 함께 남기고, 격리 건수에 임계를 겁니다. 평소 0.1% 이던 것이 5% 로 뛰면 원본 쪽에 무언가 바뀐 것이므로 그 자체가 경보입니다. 조용히 버리면 이 신호가 사라집니다.

다음 실습에서 할 것

의도적으로 서로 다른 방식으로 깨진 파일 세 개와 멀쩡한 파일 하나를 놓고, 각각 몇 행이 규칙을 어기는지 세고, 마지막에 통과와 실패를 둘 다 판정할 수 있는 검증 스크립트를 만듭니다.