17장. 운영: 살아있는 서비스 다루기
제품은 출시하는 날보다, 출시한 다음 날부터 진짜 실력이 드러난다. 가입은 되는데 결제가 가끔 실패하고, 대시보드는 열리는데 저녁마다 느려지고, 사용자는 "좋아요"라고 말하면서도 이탈한다. 만드는 단계에서는 열정이 차이를 만들지만, 운영 단계에서는 관찰력과 루프가 차이를 만든다.
솔로 빌더에게 운영은 특히 어렵다. 팀이 없으니 새벽 장애를 함께 볼 사람도 없고, 백엔드 담당과 프론트 담당에게 핑퐁할 수도 없다. 대신 좋은 소식도 있다. 클로드 코드가 있으면 혼자서도 "관찰 → 진단 → 수정 → 검증 → 배포" 루프를 꽤 짧게 만들 수 있다. 핵심은 AI에게 마법을 기대하는 것이 아니라, 로그와 지표와 사용자 목소리를 잘 먹이는 것이다.
![[5부] 운영: 살아있는 서비스 다루기](https://images.tilnote.io/pages/c93be706-bfc7-4f9f-ba72-a7af3aaf3499.webp)
운영은 기능 추가가 아니라 피드백 시스템이다
운영을 잘하는 사람은 서버를 한 번도 안 터뜨린 사람이 아니다. 터졌을 때 원인을 빨리 좁히고, 같은 문제가 다시 생기지 않게 시스템을 바꾸는 사람이다. 이 장에서 말하는 운영 루프도 딱 그 방향이다.
첫째, 장애가 나면 로그를 읽을 수 있어야 한다. 둘째, 느린 쿼리와 메모리 누수 같은 성능 문제를 "감"이 아니라 증거로 다뤄야 한다. 셋째, 분석 데이터와 사용자 피드백이 코드 변경으로 이어져야 한다. 대시보드에서 끝나는 데이터는 장식품이고, 이슈로만 쌓이는 피드백은 죄책감 저장소다.
운영에서 특히 중요한 것은 메트릭, 로그, 트레이스를 따로따로 보지 않는 습관이다. 숫자는 "어디가 이상한지" 알려주고, 로그는 "무슨 일이 있었는지" 보여주며, 트레이스는 "어디서 막혔는지" 드러낸다.1
17.1 장애 대응: 로그를 클로드 코드에 던지는 법
장애가 나면 많은 사람이 제일 먼저 하는 실수는 로그를 많이 보는 것이다. 사실 더 중요한 것은 로그를 잘 묶어 보는 것이다. 로그 500줄보다, 같은 요청의 흐름이 이어진 20줄이 훨씬 유용하다.
좋은 운영 로그는 소설처럼 읽힌다. 요청이 언제 들어왔는지, 어떤 사용자였는지, 어떤 라우트였는지, 어느 외부 API를 불렀는지, 어디서 예외가 났는지, 응답 시간은 얼마였는지가 이어져야 한다. 반대로 Error: something went wrong만 남는 로그는 미래의 나를 괴롭히는 저주다.
클로드 코드에 로그를 던질 때도 요령이 있다. 로그를 무작정 붙여넣기보다, 다음 맥락을 같이 주면 진단 품질이 급상승한다.
장애가 시작된 시각과 끝난 시각
관련 요청 ID, 사용자 ID, 배포 SHA
최근 바뀐 코드나 설정
정상 로그 1개와 실패 로그 1개
예를 들어 이렇게 요청할 수 있다.
21:03~21:10 사이 결제 콜백에서 500 에러가 급증했다. 아래 로그 두 묶음은 같은 request_id 기준으로 정리했다. 최근 변경은
payment/webhook.ts와 Redis 키 네이밍 수정이다. 실패의 최초 지점을 찾고, 재현 가능한 가설 3개와 확인 순서를 제안해줘.
이 프롬프트가 좋은 이유는 AI에게 "답"이 아니라 "수사 방향"을 요청하기 때문이다. 운영에서는 첫 추측이 맞는 것보다, 잘못된 추측을 빨리 버리는 것이 더 중요하다.
여기서 한 단계 더 나가면, 클로드 코드가 단순히 정적 로그만 읽는 것이 아니라 실행 중인 애플리케이션의 상태를 같이 보게 만들 수 있다. 예를 들어 runtime-mcp 같은 서버를 붙이면 메모리 사용량, 이벤트 루프 상태, 최근 요청, 에러, DB 연결, 슬로 쿼리 같은 런타임 정보를 MCP 리소스로 노출할 수 있다.2 "지금 이 프로세스가 뭘 하고 있지?"라는 질문에 코드 추측이 아니라 실제 상태로 답하게 되는 셈이다.
직접 진단 도구를 심는 방법도 있다. Spring 기반 서비스라면 읽기 전용 MCP 도구를 애플리케이션 안에 넣어, 고객 상태 조회나 할인 조건 검증 같은 진단용 함수를 Claude가 호출하게 만들 수 있다. 중요한 원칙은 단 하나다. 운영용 도구는 반드시 read-only여야 한다.3
이렇게 되면 장애 대응 방식이 바뀐다. 예전에는 "로그를 보고, 코드 추측을 하고, 임시 로그를 심고, 다시 배포"였다. 이제는 "로그를 보고, 현재 상태를 조회하고, 관련 코드와 함께 가설을 세우고, 작은 수정으로 검증"이 된다. 혼자 운영하는 사람에게 이 차이는 체감상 엄청 크다.
17.2 슬로 쿼리, 메모리 누수, 캐시 미스 디버깅
운영 문제의 절반은 결국 성능 문제다. 그리고 성능 문제의 무서운 점은, 대부분 "아예 안 된다"가 아니라 "가끔 이상하게 느리다"는 형태로 온다는 데 있다. 이런 문제는 재현이 어렵고, 그래서 더 비싸다.
느린 쿼리: SQL을 보기 전에 호출 맥락부터 본다
느린 쿼리를 만나면 많은 개발자가 곧바로 쿼리문부터 뜯어본다. 물론 중요하다. 하지만 솔로 빌더는 먼저 이 질문부터 해야 한다.
이 쿼리가 원래 느린가, 갑자기 느려졌는가? 모든 사용자에게 느린가, 특정 조건에서만 느린가? 한 번 느린가, 같은 요청 안에서 여러 번 반복되는가?
클로드 코드에 쿼리 로그와 관련 코드, 그리고 가능하다면 트레이스를 함께 주면 N+1 패턴, 불필요한 조인, 인덱스 누락 의심 구간을 꽤 잘 좁혀준다. runtime-mcp처럼 최근 쿼리와 슬로 쿼리를 노출하는 도구가 있으면 더 좋다.2 이때 AI에게 "이 쿼리 최적화해줘"보다 "왜 이 쿼리가 이 요청에서 27번 실행됐는지 설명해줘"라고 물어보는 편이 더 실전적이다.
문제의 본질은 쿼리 속도가 아니라 호출 구조인 경우가 많기 때문이다. 쿼리 하나를 30ms에서 10ms로 줄이는 것보다, 같은 쿼리를 20번 부르는 코드를 1번으로 바꾸는 쪽이 훨씬 크다.
메모리 누수: 스냅샷보다 증가 패턴을 본다
메모리 누수는 "메모리가 높다"보다 "메모리가 계속 안 내려온다"가 핵심이다. 트래픽이 늘 때 올라가는 것은 정상이다. 요청이 끝난 뒤에도 내려오지 않고, 배포 후 시간이 갈수록 계단처럼 오르면 냄새가 난다.
이때 클로드 코드에게 도움이 되는 자료는 세 가지다. 첫째, 메모리 사용량의 시간대별 변화. 둘째, 최근 배포에서 바뀐 캐시, 이벤트 리스너, 스트림, 전역 배열 관련 코드. 셋째, 가능하다면 힙 스냅샷 전후 비교다. runtime-mcp는 힙 스냅샷과 이벤트 구독 같은 런타임 관찰 도구도 제공하므로, "어떤 객체가 계속 살아남는지"를 추적하는 데 유리하다.2
AI가 메모리 누수를 잡아주는 마술사는 아니다. 하지만 "이벤트 리스너 해제가 없다", "맵에 키가 계속 쌓인다", "요청 스코프여야 할 객체가 모듈 전역에 남는다" 같은 패턴을 코드와 런타임 증거를 함께 볼 때 꽤 안정적으로 짚어낸다.
캐시 미스: 캐시가 없는 것과, 틀린 캐시를 쓰는 것은 다르다
캐시 문제는 의외로 자주 오해된다. 캐시 히트율이 낮다고 무조건 Redis 용량 문제는 아니다. 실제로는 키 설계가 들쭉날쭉하거나, 무효화 시점이 꼬였거나, 사용자별로 분리해야 할 값을 공용 키로 저장해서 캐시를 꺼버리는 경우가 많다.
이럴 때는 클로드 코드에 캐시 키 생성 코드, 읽기/쓰기 조건, 만료 정책, 장애 시점의 로그를 같이 보여주자. 그러면 "콜드 스타트"인지, "키 불일치"인지, "무효화 과잉"인지 분류하는 데 도움이 된다. 솔로 빌더 입장에서 중요한 것은 캐시를 멋지게 설계하는 것이 아니라, 왜 캐시가 기대한 만큼 돈을 못 벌고 있는지 이해하는 것이다.
운영에서 성능 문제를 다룰 때 기억할 문장은 하나면 충분하다. 코드만 보면 추측이고, 지표만 보면 현상이다. 둘을 함께 봐야 원인이 된다.
17.3 분석 데이터를 코드 개선으로 이어가기
서비스를 운영하다 보면 대시보드가 점점 예뻐진다. 가입 전환율, 활성 사용자, 이탈 구간, API 에러율, 페이지별 체류 시간까지 다 나온다. 그런데 제품은 그대로인 경우가 많다. 데이터가 쌓이는 것과 제품이 좋아지는 것은 별개다.
솔로 빌더에게 필요한 것은 거대한 분석 체계가 아니라, 데이터를 코드 변경으로 바꾸는 짧은 루프다. 저는 다음 네 단계면 충분하다고 본다.
이상 징후를 하나 고른다. 예를 들어 가입 완료율 하락, 특정 페이지 이탈 급증, 결제 성공률 감소 같은 것.
그 현상과 연결된 로그, 세션 리플레이, API 응답 시간, 배포 이력을 한 묶음으로 만든다.
클로드 코드에게 "무슨 코드가 원인일 가능성이 높은지"와 "가장 싼 실험이 무엇인지"를 묻는다.
큰 리뉴얼 대신 작은 PR 하나로 가설을 검증한다.
핵심은 한 번에 많이 고치지 않는 것이다. 운영 데이터는 늘 여러 해석이 가능하다. 예를 들어 팀 초대 화면에서 이탈이 늘었다고 하자. 문구가 어려운 것일 수도 있고, 이메일 전송 API가 느린 것일 수도 있고, 모바일 뷰에서 버튼이 화면 아래로 밀린 것일 수도 있다. 이때 클로드 코드에게 화면 코드, 이벤트 로그, 네트워크 지연, 최근 커밋을 같이 보여주면 "UX 문제인지, 성능 문제인지, 순서 문제인지"를 꽤 빠르게 분해해준다.
좋은 운영자는 매주 묻는다. "이번 주에 가장 많이 본 숫자는 무엇인가?"가 아니라, "이번 주에 어떤 숫자가 실제 코드 변경을 만들었는가?"
이 질문이 중요하다. 왜냐하면 솔로 빌더의 시간은 가장 비싼 자원이기 때문이다. 분석은 통찰처럼 보이지만, 실제로는 우선순위 도구다. 데이터를 많이 보는 것보다, 어떤 한 줄의 코드가 매출과 이탈을 바꾸는지 찾는 것이 더 중요하다.
17.4 사용자 피드백을 기능 PR로 자동 변환하기
사용자 피드백은 대개 세 군데에서 온다. 메일함, 채팅, 그리고 머릿속 죄책감이다.
"모바일에서 저장이 안 돼요." "CSV 다운로드가 있었으면 좋겠어요." "결제는 했는데 영수증 메일이 안 왔어요."
이런 말들은 하나하나 작아 보여도, 쌓이면 제품의 방향을 바꾼다. 문제는 솔로 빌더가 이 피드백을 읽고만 끝내기 쉽다는 것이다. 읽는 순간에는 중요한데, 다음 버그를 잡고 나면 증발한다.
이 흐름을 바꾸려면 피드백을 문장이 아니라 작업 단위로 바꿔야 한다. MCP는 GitHub, Slack, Notion, 데이터베이스 같은 외부 시스템을 클로드 코드와 연결하는 표준 인터페이스라서, 피드백을 모으고 분류하고 다음 액션으로 넘기는 통로로 쓰기 좋다.4
실전에서는 피드백 항목마다 최소한 다음 세 가지를 붙이면 충분하다.
어떤 사용자가 어떤 상황에서 겪었는가
매출, 유지율, 신뢰에 어떤 영향을 주는가
버그 수정인지, UX 개선인지, 신규 기능인지
이 정보만 있으면 클로드 코드는 중복 피드백을 묶고, 문제 정의를 다시 쓰고, GitHub 이슈 초안을 만들고, 작은 구현 계획까지 제안할 수 있다. 예를 들어 "영수증 메일이 자주 늦는다"는 피드백 다섯 개가 쌓이면, 그냥 메일 버그가 아니라 비동기 큐 지연 문제일 수 있다. 반대로 "CSV 다운로드" 요청 열두 개는 단순 기능 요청이 아니라, 사용자가 제품 안에서 데이터를 분석할 수 없다는 신호일 수 있다.
여기서 추천하는 자동화 흐름은 이렇다.
피드백이 들어오면 Claude가 먼저 요약한다. 그다음 같은 주제의 피드백을 묶어 하나의 문제 정의로 만든다. 이후 영향도와 구현 난이도를 기준으로 우선순위를 매긴다. 마지막으로 "문제 설명 → 재현 조건 → 기대 동작 → 수용 기준"까지 채운 이슈나 PRD 초안을 만든다. 그러면 솔로 빌더는 빈 페이지에서 시작하지 않고, 바로 구현과 판단으로 들어갈 수 있다.
그리고 가능하다면 마지막 게이트도 붙이자. PR가 만들어진 뒤에는 자동 리뷰를 통해 회귀 버그를 한 번 더 걸러내는 편이 좋다. Claude Code Review는 PR 변경 사항을 여러 에이전트가 병렬 분석하고, 검증 단계를 거쳐 인라인 코멘트를 남기는 방식으로 동작한다.5 혼자 만드는 제품일수록 "내가 짠 코드"를 "남의 눈"으로 다시 보는 장치가 더 필요하다.
운영 루프를 가진 솔로 빌더가 결국 이긴다
제품을 한 번 만드는 사람은 많다. 하지만 제품을 계속 돌리면서 더 좋아지게 만드는 사람은 많지 않다. 격차는 여기서 벌어진다.
운영은 멋진 대시보드가 아니다. 장애가 났을 때 로그를 제대로 읽는 능력이고, 느린 쿼리를 구조 문제로 보는 시선이고, 사용자 불만을 다음 PR의 재료로 바꾸는 습관이다. 클로드 코드는 그 과정을 대신 살아주는 비서가 아니라, 그 과정을 훨씬 짧고 덜 외롭게 만들어주는 도구다.
혼자 만드는 제품일수록 더더욱 그렇다. 당신에게 필요한 것은 더 많은 기능이 아니라, 더 빠른 피드백 루프다. 로그가 코드로 이어지고, 데이터가 실험으로 이어지고, 피드백이 PR로 이어질 때 제품은 비로소 살아 움직인다.
그리고 살아 움직이는 제품은, 대개 살아남는다.
참고
1Claude Code 모니터링: AI 개발자 도구 사용량 추적 가이드
3Debugging Spring Boot with Claude Code and MCP: A Developer's Guide
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.