데이터 계약 설계
사용 시점
- 상류(서비스, 이벤트, API, 파일)가 하류 파이프라인에 데이터를 공급하며, 변경이 조용히 하류를 손상시킬 수 있는 경우
- 데이터를 생산하는 팀/시스템과 웨어하우스 간의 인터페이스를 정의하는 경우
- 수집 경계에서 스키마/품질 제약을 추가하는 경우
- 하나의 dbt 프로젝트 내에서 모델 간 변경에는 사용하지 마십시오(대신 테스트 +
handling-schema-evolution을 사용).
계약이 명시하는 사항
- 스키마: 필드, 타입, 널 허용 여부, 허용 값
- 의미: 각 필드가 의미하는 것과 단위/세분성
- 보장 사항: 신선도/SLA, 볼륨 예상치, 키의 고유성
- 소유권: 누가 생산하는지와 연락처
- 버전 관리 + 변경 정책: 호환을 깨는 변경이 어떻게 전달되는지
워크플로
- [ ] 계약을 버전 관리되고 체크인된 스키마로 작성(구전 지식 금지)
- [ ] 수집 경계에서 강제 실행(도착 시 검증)
- [ ] 변경 분류: 추가(안전) 대 호환 깨짐(새 버전 필요)
- [ ] 위반 시 거부/격리하고 프로듀서에게 경고
- [ ] 호환을 깨는 변경을 사전에 버전 관리하고 전달
- 명시적으로 만들고 버전 관리하세요. 계약을 코드(JSON Schema, Avro/Protobuf 스키마 또는 YAML 명세)로 파이프라인 옆에 저장하고, API처럼 리뷰합니다.
- 경계에서 강제하세요. 들어오는 데이터가 도착 시 계약에 부합하는지 검증하고, 위반 사항은 로드하지 말고 거부하거나 격리합니다.
- 변경을 분류하세요. 추가/선택적 필드 = 하위 호환 가능. 필드 제거, 이름 변경, 타입/널 허용 여부 강화 = 호환 깨짐 → 새 버전.
- 조용히 하류에 전파하지 말고 프로듀서에게 즉시 알리세요.
패턴
수집 시 적용되는 JSON Schema 계약:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"required": ["order_id", "amount", "ordered_at"],
"properties": {
"order_id": { "type": "string" },
"amount": { "type": "number", "minimum": 0 },
"ordered_at": { "type": "string", "format": "date-time" },
"coupon": { "type": ["string", "null"] }
},
"additionalProperties": false
}
강제 지점 — 수집 시 각 레코드를 검증하고, 실패한 레코드는 사유와 함께 격리(quarantine) 위치로 보내고 프로듀싱 팀에 알립니다. 이렇게 하면 조용한 하류 손상이 즉각적이고 소스에서 소유권이 명확한 신호로 바뀝니다.
스키마 레지스트리 (Kafka/Avro) — 게시 시점에 호환성(BACKWARD)을 강제하여 프로듀서가 호환되지 않는 스키마를 배포할 수 없도록 합니다.
일반적인 함정
- 문서로만 존재하는 계약 — 코드로 강제되지 않으면 시간이 지나면서 어긋나고 조용히 손상됩니다.
- 웨어하우스 깊숙한 곳에서 강제 — 경계에서 위반을 잡아내야 합니다, 나쁜 데이터가 퍼지기 전에요.
- 버전 관리 없음 — 모든 변경이 비상 상황이 됩니다; 버전을 관리하고 우아하게 폐기하세요.
- 엄격함이 필요할 때
additionalProperties제한 없음 — 예상치 못한 필드가 통과합니다; 적절한 곳에서 false로 설정하세요. - 소유자 없음 — 거부된 배치에 연락할 사람이 없으면 파이프라인이 멈춥니다.
- 리드 타임 없는 호환 깨짐 변경 — 버전 관리된 스키마와 폐기 기간을 통해 프로듀서/컨슈머 간 조정하세요.