저는 수학쌤이 코딩 배우는 이야기를 블로그에 올리는데, 글을 쓰는 것과 발행하는 것 사이에 자동화 파이프라인을 하나 두고 있어요. 제가 마크다운으로 초안(blog.md)을 쓰면, 그걸 발행용 HTML로 바꿔주는 과정이죠. 그런데 이 파이프라인을 정비하다, 마크다운을 HTML로 바꾸는 렌더 작업이 두 군데서 따로 돌고 있는 걸 발견했습니다.
오늘은 왜 그게(당장 멀쩡해 보여도) 문제인지, 그리고 그 두 경로를 어떻게 하나로 합쳤는지를 나눌게요. 초보가 자동화를 짜다 보면 자기도 모르게 만드는 함정이라, 알아두면 두고두고 도움이 됩니다.
어쩌다 발견했나 — 터진 게 아니라, 점검하다 보였다
솔직히 이건 뭔가 터져서 알게 된 게 아니에요. 발행 파이프라인을 손보다가, 마크다운을 HTML로 바꾸는 코드가 두 군데에 따로 있는 걸 봤습니다. 한쪽은 발행 직전 검사(게이트)가 쓰고, 다른 쪽은 실제 발행이 쓰고 있었죠.
그래서 둘의 출력을 실제로 맞대어(바이트 단위로) 비교해 봤어요. 결과는 — 당장은 똑같았습니다. 지금 고장 난 건 없었던 거죠. 그런데도 이걸 그냥 둘 수 없었어요. 같은 일을 두 곳에서 따로 하고 있으면, 지금 같아도 언젠가 반드시 갈라지거든요. 터진 뒤에 고치는 것보다, 갈라지기 전에 합치는 게 훨씬 싸다고 봤습니다.
왜 두 곳이 문제인가 — 렌더가 서로 다른 코드였다
핵심은 이 두 곳이 서로 다른 코드로 렌더를 하고 있었다는 점이에요.
- 한 곳: 발행 직전 검사 단계에서 초안을 HTML로 바꿔 본다.
- 다른 곳: 실제 발행 단계에서 초안을 HTML로 바꿔 올린다.
처음엔 둘이 똑같았을지 몰라도, 시간이 지나며 한쪽만 살짝 고치고 다른 쪽은 안 고치는 식으로 얼마든지 갈라질 수 있는 구조였죠. 그러면 같은 blog.md라도 검사가 본 결과와 실제 발행된 결과가 어긋나기 시작합니다 — 검사를 통과했는데 발행본은 깨지거나, 그 반대이거나요.
배운 것 — “한 가지 일을 두 번 구현하면 반드시 갈라진다”
이게 이번 일의 진짜 교훈이었어요. 똑같은 일을 두 곳에서 각자 구현해두면, 언젠가 반드시 갈라집니다. 처음엔 복사-붙여넣기로 똑같이 만들어도, 한쪽만 고치는 순간부터 둘은 다른 물건이 돼요. 그리고 그 미세한 차이가 나중에 “왜 여기선 되고 저기선 안 되지?” 하는 유령 같은 버그로 돌아옵니다.
채점으로 치면, 같은 채점 기준을 두 반에 따로따로 적어두는 것과 같아요. 한 반 기준만 고치면, 같은 답인데 반마다 점수가 달라지죠. 기준은 한 장이어야 합니다.
어떻게 고쳤나 — 렌더를 한 함수로 모았다
해결은 단순했어요. 흩어져 있던 렌더 작업을 딱 하나의 공용 함수로 모았습니다. 마크다운을 HTML로 바꾸는 일(앞머리 메타데이터 떼어내기, 마크다운 변환, 중복 제목 정리)을 한 곳에서만 하도록요. 그리고 검사 단계도, 발행 단계도, 미리보기도 전부 그 한 함수를 불러 쓰게 했어요.
이렇게 하니 “두 결과가 다를” 여지가 아예 사라졌습니다. 렌더가 한 곳에서만 일어나니, 어디서 보든 항상 똑같은 HTML이 나오거든요. 검사가 본 결과와 실제 발행본이 원천적으로 같아지니, 둘이 어긋날 일 자체가 없어졌고요. 덤으로, 마크다운 변환 도구의 버전도 한 곳에 고정해서 “도구가 업데이트되며 결과가 바뀌는” 변수까지 묶어뒀어요.
그래서 뭘 하면 되나
같은 출력을 여러 곳에서 만들고 있다면, 이 표대로 점검하세요.
| 신호 | 판단 | 액션 |
|---|---|---|
| 같은 입력인데 위치마다 결과가 다름 | 🔴 경로가 둘 이상 | 그 일을 하는 함수를 하나로 통합 |
| 지금은 결과가 같아도 경로가 둘 | 🟡 미래에 갈라질 씨앗 | 터지기 전에 단일 함수로 합치기 |
| 복사-붙여넣기로 같은 로직이 두 곳 | 🔴 언젠가 갈라짐 | 공용 함수로 추출(한 곳만 고치게) |
| 외부 도구 버전에 결과가 흔들림 | 🟡 재현성 저하 | 버전을 한 곳에 고정 |
한 문장 요약: 같은 일(여기선 렌더)을 두 곳에서 각자 구현하면 반드시 갈라진다 — 그 일을 단일 공용 함수로 모아 모든 곳이 그것만 부르게 하고, 외부 도구 버전까지 한 곳에 고정해 “어디서 보든 같은 결과”를 보장하라.
돌아보면 이건 거창한 버그가 아니라 구조의 문제였어요. “한 가지 진실은 한 곳에만 둔다”는 건 코딩에서 정말 자주 나오는 원칙인데, 저처럼 초보일 땐 편하다고 여기저기 같은 코드를 흩뿌리기 쉽죠. 그러다 그게 갈라지면 유령 버그가 됩니다. 아직 터지지도 않은 걸 굳이 손봤지만, 갈라질 수 있는 구조를 미리 하나로 모아두는 게 나중의 나를 위한 일이더라고요.