interlink 하이퍼링크를 서버에서 HTML로 변환해 렌더링 일관성 확보
목차
interlink 기능에서 문서 내 하이퍼링크를 렌더링할 때, raw markdown 문자열을 그대로 내려주던 방식을 개선했다. 이번 fix는 마크다운을 서버 단계에서 HTML <aside> 요소로 변환해서 emit 하도록 변경한 작업이다.
왜 이 변경이 필요했나
처음엔 단순해 보였다. interlink 기능이 markdown 형식의 참조 텍스트를 수집해서 클라이언트로 내려주고, 클라이언트에서 마크다운 렌더러를 돌려서 HTML로 변환하는 방식이었다. 관심사 분리 입장에서는 깔끔해 보였다 — "서버는 데이터만, 클라이언트는 렌더링만".
하지만 운영하다 보니 문제가 몇 가지 생겼다:
- 렌더러 버전 불일치: 서버와 클라이언트의 markdown 렌더러 버전/설정이 다르면, 같은 입력에도 다른 출력이 나온다.
- 클라이언트 번들 사이즈: 모든 클라이언트에 markdown 렌더러를 포함시켜야 한다.
- 캐싱 효율: raw markdown은 캐시하기 난해하다. 미리 렌더링된 HTML이 훨씬 캐시 효율이 좋다.
- 의미론적 구조: interlink가 "보조 정보"라는 의미를 담은다면, HTML 수준에서
<aside>태그로 표현하는 게 문서 구조상 명확하다.
기술적 변경: raw markdown → HTML aside
변경 전후는 대략 이렇다:
# Before: raw markdown 반환
def emit_interlink(link_text):
return {
'text': '**Related**: [Check this](https://...)',
'format': 'markdown'
}
# After: HTML aside로 변환해서 반환
def emit_interlink(link_text):
html_content = markdown_to_html(link_text)
return {
'html': f'<aside>{html_content}</aside>',
'type': 'semantic'
}
핵심은 두 가지다:
- 변환 타이밍: 마크다운 파싱/렌더링을 서버의
interlink.py에서 담당한다. - 의미론적 태그: semantic HTML의
<aside>요소로 감싼다. 이렇게 하면 스크린 리더, 검색 엔진, 개발자 도구 모두 이 콘텐츠가 "주요 내용의 보조 정보"임을 인식할 수 있다.
클라이언트-서버 책임 분리의 가치
이런 변경이 왜 중요한지는 팀 관점에서 생각해봐야 한다:
| 측면 | raw markdown 방식 | HTML aside 방식 |
|---|---|---|
| 캐싱 | 어려움 (렌더링 결과 예측 불가) | 용이 (확정된 HTML) |
| 클라이언트 복잡도 | 높음 (렌더러 필요) | 낮음 (그냥 삽입) |
| 문서 구조 명확성 | 낮음 (format hint만 있음) | 높음 (HTML 의미론) |
| 버전 관리 | 관리 포인트 2개 (서버, 클라이언트) | 관리 포인트 1개 (서버) |
특히 여러 클라이언트(웹, 모바일 앱, 임베드 위젯 등)를 운영한다면 더 중요하다. 각 클라이언트에서 렌더링 로직을 일관되게 유지하기는 매우 어렵다.
비슷한 패턴들
이 류의 결정은 다른 곳에서도 자주 마주친다:
- JSON 응답의 formatted text: API가
text(raw)와html두 필드를 제공하는 경우도 있는데, 신경 쓸 점이 많아진다. - 이메일 생성: 템플릿을 서버에서 렌더링할지, 마크다운만 보낼지도 비슷한 선택.
- CMS 문서: 저장 형식(markdown)과 배포 형식(HTML)을 명확히 구분하는 게 장기적 운영 안정성을 높인다.
회고
이번 작업을 하면서 느낀 점은, 초기에 "관심사 분리"라는 명목으로 결정한 설계가 나중에 운영 부담으로 돌아온다는 것이다. 좋은 설계는 이론상 "깔끔함"보다, 실제 운영 환경에서 "일관성"과 "예측 가능성"을 우선한다.
특히 마크다운 같은 포맷은 "데이터"처럼 보이지만, 실제로는 "표현"이다. 따라서 표현을 통일하는 책임은 가급적 한 곳에 집중시키는 게 맞다. 이번 건 작은 수정이었지만, 팀이 성장하면서 클라이언트가 많아질수록 이 결정의 가치가 더 커질 것 같다.
🛒 이 글과 어울리는 추천 상품
*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
댓글 0
첫 댓글 달아줘.