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

정제가 품질의 지렛대야

~12 min · curation, conversion-seam, clean-at-adapter, garbage-in-garbage-out

Level 0꺼진 심지
0 XP0/33 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"엔진이 틀린 게 아니었어. 코퍼스에 들어 있던 HTML 부스러기를 충실하게 이어준 것뿐이야."

자동완성에 태그 조각이 나타난 사건

웹사이트 콘텐츠를 색인한 뒤 자동완성에 data emotion playful img class 같은 조각이 나타났어. 사람이 쓴 문장 대신 HTML 속성이 이어졌지. 처음에는 자동완성 기능이 고장 난 듯 보였고, 결과에서 태그 모양을 걸러내는 조건을 넣고 싶어졌어.

검색기는 입력받은 것을 정직하게 보여줬어

자동완성은 코퍼스에서 어떤 문구 뒤에 실제로 무엇이 나왔는지 세어. 색인한 텍스트가 HTML 태그와 속성으로 가득하면 그 부스러기가 정답으로 나오는 게 맞아. 잘못은 조회 알고리즘이 아니라 그 알고리즘에 넣은 데이터에 있었어. 더러운 입력에서 깨끗한 결과만 기대할 수는 없어.

사용 지점이 아니라 변환 경계에서 고쳐

해결책은 자동완성 API에 예외를 붙이는 것이 아니라 웹 콘텐츠를 다시 캡처하는 어댑터였어. frontmatter에서 제목을 꺼내고, HTML 마크업을 지우며, 식별자처럼 생긴 키를 제외하고, 너무 짧은 조각은 버려 깨끗한 본문만 만들었지. 이 텍스트를 스냅샷하자 검색과 자동완성 등 모든 하류 기능이 함께 깨끗해졌어.

품질 문제는 데이터가 들어오는 경계에서 고쳐. 결과를 쓰는 곳마다 필터를 달면 증상 하나만 가리고 같은 오염이 다른 기능으로 계속 흘러. adapter에서 한 번 정제하면 그 코퍼스를 쓰는 모든 기능이 같은 혜택을 얻어.

원본은 그대로 두고 정제된 읽기를 보존해

정제한다고 웹사이트 원본 파일을 직접 고치지는 않아. adapter가 지저분한 소스를 읽어 깨끗한 본문을 만들고, 그 결과를 captured 스냅샷으로 보존해. chunk의 문자 위치와 해시는 모두 이 스냅샷을 기준으로 삼아. 원본은 제자리에서 자기 역할을 계속하고, Lantern은 검색에 적합한 읽기를 별도로 지키는 거야. 원본 불변과 데이터 정제가 충돌하지 않는 이유가 바로 이 변환 경계에 있어.

쿼리 경로의 필터가 늘어나는 것은 상류 데이터가 잘못 들어왔다는 냄새일 수 있어. 검색과 자동완성, 요약에서 같은 쓰레기를 각각 걸러내고 있다면 세 기능을 고칠 일이 아니라 adapter 하나를 고칠 일이야. 소비자 수만큼 반복되는 예외를 입력 경계의 단일 규칙으로 되돌려야 해.

Code

adapter에서 정제: 깨끗한 본문을 스냅샷으로 남기고 소스는 그대로 둬·python
def extract_prose(raw_html_ish: str) -> str:
    """A site-extract-style adapter: turn tag-polluted content into clean prose."""
    title = frontmatter_title(raw_html_ish)          # pull a heading from metadata
    body = strip_html_tags(raw_html_ish)             # remove <div class=...> soup
    prose_parts = []
    for key, value in mine_structured_text(raw_html_ish):
        if is_identifier_key(key):
            continue                                  # block 'class', 'data-emotion', etc.
        if len(value) >= 20:                          # prose floor: no fragment survives
            prose_parts.append(value)
    text = join_prose([title, body, *prose_parts])
    return text
    # This text is what gets snapshotted and chunked. The messy original on disk
    # is never edited — cleaning lands in the captured snapshot, not the source.

External links

Exercise

시스템이 엉뚱한 결과를 낸 사례를 하나 떠올려. 처리 로직이 틀렸는지, 들어온 데이터에 문제가 있었는지 먼저 구분해. 입력이 원인이었다면 사용 지점에서 결과를 걸러낼지, 입력 경계에서 데이터를 정제할지 결정해 봐. 입력을 그대로 둔 채 출력마다 필터를 붙였을 때 생길 실패도 함께 적어.
Hint
출력 단계의 필터는 소비자 하나만 가리고, 같은 나쁜 데이터를 쓰는 다른 소비자마다 다시 만들어야 해. 입력 경계에서 한 번 정제하면 모든 소비자가 함께 나아져. 같은 오염이 여러 출력에 반복된다면 해결책을 상류의 입력 경계에 둘 증거야.

Progress

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

댓글 0

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

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