정제 로직 계층화로 여러 서비스 수렴
목차
금액 포맷팅(money 패턴)에서 성공한 '1층 enrichment + 2층 presentation' 구조를 텍스트 정제(humanizer) 전반으로 확대했다. 블로그, 정부 데이터, ssul 세 서비스에 동일한 패턴을 적용하는 작업이었다.
왜 계층을 나눌 필요가 있었나
데이터 처리 파이프라인을 보면 보통 두 개의 결정 지점이 생긴다. 첫 번째(1층)는 데이터 정제: 원본 입력을 받아 이상을 제거하고 구조를 정리하는 단계다. 두 번째(2층)는 표현 포맷팅: 정제된 데이터를 사용자가 읽을 형태로 변환하는 단계다.
금액의 경우, 이 구분이 명확했다. enrichment 단계에서는 "1234567" 이라는 숫자를 수정하고, publish 단계에서는 "1,234,567원" 처럼 세자리 구분과 통화 기호를 붙인다. 이 둘을 섞으면 어디서 포맷팅이 일어나는지 불명확해지고, 같은 데이터를 여러 채널로 출력할 때마다 로직을 반복하게 된다.
텍스트 정제도 똑같은 패턴을 반복하고 있었다. enrich 단계에서 HTML 태그를 제거하고, publish 단계에서 문장 부호를 정규화하는 식인데, 서비스마다 구현이 뒤섞여 있었다.
기존 money 패턴에서 배운 점
| 단계 | money 예시 | 역할 | 파일 |
|---|---|---|---|
| 1층 (enrichment) | int(amount_str) |
원본 데이터 타입 확정, 유효성 검사 | gov/enrich.py |
| 2층 (publish) | f"{amount:,}원" |
로케일/형식 적용, 출력 최적화 | gov/publish.py |
money 패턴이 먹혔던 이유는 단순했다. 계층이 명확하면 테스트와 수정이 쉬워진다. enrichment 에서 버그가 나면 숫자 변환 로직만 고쳤고, publish 에서 문제가 있으면 포맷 문자열만 건드렸다. 또한 같은 기본 데이터를 여러 채널로 내보낼 때(웹, API, 메시지)도 1층 로직은 공유하고 2층만 바꿀 수 있었다.
humanizer 확대 적용
이번 커밋은 이 성공 사례를 텍스트 정제 전반으로 펼쳤다:
- blog/post_news.py: 뉴스 포스트의 본문/요약 정제
- gov/enrich.py, gov/publish.py: 정부 공시 데이터 (1층: 구조 정리 → 2층: 읽기 좋게 포맷)
- ssul/generate.py, ssul/publish_crawl.py: 커뮤니티 콘텐츠 정제 및 발행
각 서비스는 자신만의 텍스트 특성이 있다. 뉴스는 링크 제거와 문단 단정이 중요하고, 정부 데이터는 약자 확장이 중요하고, ssul 은 욕설 필터링이 중요할 수도 있다. 그런데도 기본 구조는 같다: 먼저 깨끗하게 정제(1층)한 뒤, 각 채널/맥락에 맞게 포맷(2층)한다.
# 1층: enrichment - 원본 텍스트를 깔끔하게
def enrich_text(raw):
text = remove_html_tags(raw)
text = normalize_whitespace(text)
return text
# 2층: publish - enriched 텍스트를 사용자가 볼 형태로
def humanize_text(enriched, locale='ko'):
text = truncate_long_sentences(enriched)
text = add_emphasis_marks(text)
return text
여러 서비스 동시 변경의 무게
한 번에 5개 파일을 건드린 건 의도적이었다. 왜냐하면 이 세 서비스가 사용자 입장에선 별개지만, 아키텍처 입장에선 같은 문제를 푸는 비슷한 파이프라인이기 때문이다. 각각을 따로 수정하면 나중에 누군가 "어? blog 는 왜 다르게 구현했지?" 라는 불일치를 발견하게 된다.
물론 트레이드오프가 있다. 이 변경이 모든 서비스에 영향을 주므로, 한 곳의 버그는 세 곳에 퍼질 수 있다. 따라서 코드 리뷰와 테스트가 더 촘촘해야 한다. 또한 나중에 humanizer 로직을 수정할 때, 모든 서비스의 맥락을 고려해야 한다. "정부 데이터 때문에 이 옵션을 봤는데, ssul 에서는 원하지 않는 건 아닐까?" 같은 고민이 생긴다.
다음은 추상화 과정
현재는 money 패턴을 각 서비스 내에서 복제한 것이다. 이건 빠른 적용과 서비스별 맞춤의 장점이 있지만, 장기적으로는 공통 humanizer 라이브러리 로 수렴할 가능성이 높다. 그때쯤이면 "1층과 2층을 공통 모듈로 분리하고, 각 서비스는 설정만 다르게" 하는 구조가 될 것 같다.
지금 이 커밋은 그 과정의 중간 지점이다. 구체적 서비스 코드에서 패턴을 확인하고, 추상화할 가치를 입증하는 단계. "모든 서비스가 같은 문제를 겪고 있고, money 처럼 계층화하면 해결된다"는 증거를 모으는 것이다.
회고해보면, 세 곳을 동시에 건드린 건 리스크가 있지만, 불일치를 방치하는 게 더 큰 리스크라고 판단했다. 나중에 새로운 서비스가 생기면 여기서 패턴을 따라가면 되고, 이번 경험이 그 과정을 수월하게 해줄 것 같다.
🛒 이 글과 어울리는 추천 상품
*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
댓글 0
첫 댓글 달아줘.