Claude Code 사용기(2): 기존 웹서비스 개인화 - 마크다운 스타일 각주 링크 변환 Chrome 확장프로그램 개발기
대학생 때나 연구개발 엔지니어 시절, python이나 tcl로 짠 코드는 문법은 정말 손에 잘 붙지 않았다. 매뉴얼을 뒤지고, READ.ME와 웹문서를 찾고, 비슷한 증상을 다룬 블로그 글을 뒤지는 과정이 전체 작업시간의 절반은 잡아먹은 것 같았다. 디버깅을 해도 에러 코드가 떠도 무엇이 문제인지 파악하는 데는 한참이 걸렸다.
그러다 Perplexity를 구독하고 처음으로 에러 메시지와 코드를 통째로 붙여 넣어봤을 때, 생산성을 위해 코드를 짜는 사람들의 노동 생산성이 획기적으로 달라지고 있다는 걸 처음 느꼈다. 원인 분석과 수정 제안이 몇 초도 안 되어 나왔다. 이제는 너무 당연하지만, 직접 겪었을 때 내 지난 시간들의 가치가 한 순간에 0으로 수렴함과 동시에, 이제 그 지난한 과정에서의 해방감이 함께 느껴졌다. AI 코딩도구와 처음 마주한 날의 복합적인 감정이었다.
기획의도
AI와 글을 함께 쓰는 시대가 오면서, 내 글 쓰는 루틴도 바뀌었다. 학보사 기자 시절엔 그 주제에 해당하는 개론서를 읽고, 다뤄보고 싶은 세부주제 논문들을 좀 읽어본 후, 취재한 내용과 종합해 흐름을 잡고난 후 기획문건을 작성해간 회의 시간에 동료 기자들에게 혹독한 코멘트를 듣고 난 후 기사를 작성했다. 영화나 책 리뷰도 작품을 먼저 읽고, 다른 리뷰들을 좀 읽어본 후 내가 독창적으로 주장하고 싶은 부분을 주제로 잡고 글을 썼다. Perplexity를 쓰기 시작한 후부터 Claude와 함께 일상을 함께하는 현재에 이르기까지 내 루틴은 크게 다르지 않다. 다만, 글 소재와 내 가설/주장을 설명한 의식의 흐름대로 서술한 글과 대강의 글 흐름을 제시하고, 목차부터 논거, 반론까지 클로드와 입씨름을 하면서 결정 후 Claude에게 초안을 맡긴다. 내게는 퇴고가 가장 중요한 과정이기에, Claude에게 초고를 맡겨야 한다. 글에 욕심 있는 동지들이라면 공감하겠지만, 스스로 쓴 초고는 퇴고하면서 목차부터 갈아 엎는 일이 많기 때문이다. 마지막엔 어김없이 Perplexity로 자리를 옮겨 팩트체크와 코멘트를 한 번 더 받으면 완성이다.
LLM 서비스와 함께 글 짓기를 할 때 내가 가장 만족스러운 점은 인용이다. 예전엔 Mendeley도 불편하게 느꼈기에 웬만하면 각주도 최대한 달지 않으려고 노력하면서 썼다. 하지만 역설적으로 LLM 서비스로 지은 글이 흘러 넘치는 시대엔, 결국 읽을 가치 있는 글의 기준은 출처와 인용이라 생각한다.
여기서 문제가 발생한다. 티스토리에도 footnote를 간단히 구현할 수 있는 기능이 있지만, Claude로 마크다운 파일을 받아 워드 문서로 퇴고하는 나로서는 html이든 기본모드든 각주 링크를 일일이 넣어주기 굉장히 번거롭다. 한 두개면 직접 html 문법에 맞춰서 태그를 넣어주면 그만이지만, 10개가 넘어가는 순간부터는 결코 유쾌하지 않다. Claude가 마크다운으로 작성한 글을 HTML 편집기에 붙여넣으면, 각주 번호 [1], [2]에는 하이퍼링크가 달려 있지만 클릭해도 아무 데도 가지 않는다. 워드 문서에서 복사해도 마찬가지다. 링크처럼 생겼지만 앵커 네비게이션이 작동하지 않는, 독자에게 궁금해서 클릭하게 하지만 실망감이 큰 '텅빈 기표'다. 20개가 넘는 각주에 id와 href를 일일이 손으로 붙이는 것도 마찬가지다.
그래서 Chrome 확장 프로그램을 만들기로 했다. 티스토리 HTML 편집기에서 마크다운 스타일 각주에 양방향 앵커 링크를 자동으로 부여하는 기능만 갖춘 아주 단순한 툴이다. 본문의 [1]을 클릭하면 하단 각주로, 각주의 [1]을 클릭하면 본문으로 돌아오는 기능이다. 먼저 테스트로 마크다운 문서를 html로 변환하고, html 문서 내 각주 태그에 쌍방향 링크를 달아주는 룰로 만들어 몇 개 테스트 해보고, Chrome 확장 프로그램으로 제작하기로 했다. 프로그램 사용 방법까지 설명해주니 정말 이 단계까진 정말 딸깍(그냥 말이 딸깍이지 역시 거짓말이다. 표 등이 깨지고, 마크다운 문서에 익숙하지 않다보니 1, 2번의 대화는 수정 과정을 거쳐야 했다)이었다.
새로 배운 웹 개발자들의 '상식'
격리된 세계에 사는 브라우저 확장 프로그램
첫 번째 벽은 생각보다 일찍 나타났다. 확장 프로그램 팝업에서 스캔 버튼을 누르면 항상 "각주가 없습니다"라고만 표시됐다. 눈에 보이는 에디터에는 분명 각주가 있는데, 의도대로 작동하지 않았다. 상황 설명을 최대한 자세히 해도, 엉뚱한 코드만 바꿀 뿐이었다. 답답한 나머지, Claude Code가 짜준 정규식과 변환 코드를 Claude 웹 확장 프로그램에게 넣어주고 수정하라고 지시하고, 수정이 성공한 후에는 Claude Code에게 test 결과 및 원인 분석을 위한 정보를 제공하게끔 시켰다.
Claude Code가 파악한 원인은 이랬다. Chrome 확장의 content script는 "isolated world"라는 격리된 환경에서 실행된다. 같은 페이지를 보고 있어도, 확장 프로그램의 코드와 페이지의 JavaScript 객체는 서로를 볼 수 없다는 것이다. DOM(Document Object Model)은 공유해서 페이지의 HTML에는 접근할 수 있지만, 에디터의 API는 보이지 않아 JavaScript로 만든 내부 객체에는 접근할 수 없는 상황이었다. 해결책은 페이지 컨텍스트에 별도 스크립트를 주입하고 window.postMessage로 통신하는 방식인 "page bridge" 패턴이었다. 개발자에게는 아마 상식적인 우회로겠지만, 나는 이 개념 자체를 처음 알았다.
티스토리 HTML은 "깨끗하지" 않다
에디터에 접근하는 데에는 성공했지만, 이번엔 정규식이 말을 듣지 않았다. 각주 정의 영역의 <p> 태그를 잡으려 했는데, 티스토리 HTML의 실제 구조는 <p data-ke-size="size16"><a href="#_ftnref1">였다. 티스토리가 자체 속성을 HTML에 자동으로 삽입한다는 걸 몰랐다. <p>를 <p[^>]*>로 바꾸고, 변환 후에도 속성이 보존되도록 수정했다.
그런데 이보다 더 지저분한 게 있었다. 본문에서 <a href="#_ftn1">[1]</a> 패턴을 찾으려 했는데, 실제 HTML을 보니 <a href="#_ftn1"><span><span><span><span>[1]</span></span></span></span></a>였다. 워드나 한글 문서에서 복사-붙여넣기하면 서식 정보가 <span> 태그로 변환되어 중첩된다는 것이다. 모든 case를 찾아서 다 수정하기는 어려웠고, 결국 .docx나 마크다운 문서 그대로 붙여넣었을 경우들만 대처할 수 있도록 했다.
변환이 됐다면서?
팝업은 "변환 완료"라고 뜨는데 에디터 내용은 바뀌지 않는 상황이 한동안 이어졌다. textarea.value = newContent로 값을 바꾸는 코드였는데, 전혀 반영되지 않았다.
CodeMirror는 <textarea>를 뒤에 숨겨두고 자체 DOM으로 렌더링하는 에디터라고 한다. 원래 <textarea>는 숨겨두고 자신이 만든 구조를 렌더링하고 사용자가 입력하면 CodeMirror가 자신의 내부 데이터 모델에 저장한다고 한다. 화면에 보이는 것과 실제 데이터가 따로 놀게 만든다는 것이다. 그래서 textarea 값을 직접 바꿔봤자 에디터는 아무 소용 없고, 반드시 cm.setValue() API를 통해야 한다는 것이다. page bridge를 통해 CM5 인스턴스에 직접 접근하도록 구조를 바꾸고 나서야 변환 내용이 에디터에 반영됐다.
변환까지 됐는데 왜 발행 버튼을 누르고 나면 초기화될까?
마지막 문제는 가장 잡아내기 어려웠다. 의도대로 변환된 후 발행 버튼을 누르려고 해도 였다. 에디터에 아무 글자나 입력했다 지우면 그제야 활성화됐다. 바로 Claude Code에게 현상을 설명하고 원인분석과 해결책 제시를 요구하니 아래와 같은 대답을 내놨다.
cm.setValue()는 편집 히스토리를 초기화하고 markClean()을 호출한다. CodeMirror가 "변경 없음"으로 판단하고, 티스토리 저장 버튼이 이를 감지해 비활성 상태로 유지하는 것이었다. cm.replaceRange()로 바꾸니 해결됐다. 정상적인 편집 동작으로 기록되어 dirty 상태가 되어 "변경을 에디터에 인식시키는" 작업이 필요한 것이었다. 서비스 개발자의 치밀함도 새삼 느끼면서, 남이 만든 서비스에 무언가 얹는 것이 관습을 모르고는 쉽지 않다는 생각이 들었다.
오늘도 느낀 웹 개발자들의 벽
이번에 가장 오래 걸린 구간도, 기능 구현이 아니라 '왜 안 되는지' 테스트 해보며 파악하는 단계였다. isolated world, CodeMirror와 같은 개념을 알았다면, context에 미리 반영해서 지시를 하였을 텐데 그렇게 할 수 없었다. 이번에 새로 배운 건 기존 웹 서비스 연동으로 무언가를 만들 때 클로드 웹 확장 어플리케이션으로 원인 파악해달라고 하고, 테스트 지시 하고, 결과 받아서 다음 지시 내려서 클로드 코드와 협업하게 한다면 좀 더 빠르게 작업할 수 있다는 것이었다. 다음에는 Claude Code에게 계획 짜게 하기 전에, Claude 웹 확장 어플리케이션에게 미리 구조를 파악해달라고 조사를 시키고 결과를 전달한 상태에서 시작할 생각이다.
개발자 유튜버들은 개발자가 설 자리가 점점 없어진다며 걱정하기도 하는데, 한편으로는 비개발자의 생산성 향상 에이전트로서 개발자에 대한 수요는 오히려 늘 수 있다는 생각이 들기도 한다. 아무래도 '딸깍'으로 내가 못하던 영역을 해결해준다고 해도, 비개발자가 Claude Code로 구현한 프로그램을 상품으로 만드는 것은 물론이고 조직의 새로운 표준 업무툴로 배포하기에도 다소 불안한 마음도 있다. '딸깍'으로 해결해주면 그 아낀 시간에 스스로 원리를 학습하고 내 지식으로 흡수를 해야하는데, 이미 쇼츠에 절여진 정신을 체현한 자로서는 습관들이기가 생각보다 어려운 것 같다.
프로그램 사용법
설치법
1) 완성한 프로그램은 아래 링크로 들어가, 녹색 Code 버튼 옆의 아랫방향 화살표를 눌러 다운 받을 수 있다.
https://github.com/heeveloper72/Extension_Markdown_footnotes_converter
GitHub - heeveloper72/Extension_Markdown_footnotes_converter
Contribute to heeveloper72/Extension_Markdown_footnotes_converter development by creating an account on GitHub.
github.com
2) 다운 받은 ZIP 파일의 압축을 풀고, 3) 크롬 브라우저의 확장 프로그램 탭에 들어가 개발자 모드를 켜주고, 4) 압축해제된 확장 프로그램 로드에서 압축해제된 폴더를 선택해주면 설치가 완료된다.
사용 예시
사용법은 더 간단하다. 티스토리 블로그 글쓰기 편집창에서 확장 프로그램을 눌러주면 된다.

1) 글쓰기 편집창에서 Claude로부터 받은 마크다운 문서를 우선 붙여넣고(docx 문서도 기본모드에 붙여넣으면 가능했음)

2) HTML 편집모드에서 각주 스캔을 누르면

3) 대화창이 뜨고 누르면 쌍방향 링크가 구현된다.
