[번외편] 짜파게티 코드를 피하려면 — 리팩토링을 언제, 어떻게, 누가 검토하게 할지

221.131.***.***
6

tunaFlow 개발기 시리즈 외전입니다. 이번에는 "에이전트랑 같이 쓰는 코드의 유지보수를 어떻게 하는가"에 대한 이야기입니다. 반박시 님들 말이 또 모두 맞습니다. 😁

저는 다른 사람이 에이전트로 만든 프로젝트를 볼 때 솔직히 코드부터 까봅니다. 그리고 보자마자 "또 짜파게티 코드겠지" 하고 시작합니다. 이 편견은 사실 자주 맞습니다. 대체적으로 소프트웨어 개발 경험이 없거나(꼭 개발자가 아니어도요), 아이디어 하나만 가지고 시작했는데 "되니까 한다!" 라는 마음으로 코드가 점점 눈덩이처럼 불어가는데 리팩토링 한번 안하고 그냥 쭉쭉 만들면 보통 app.js 같은 파일하나가 1000줄이 넘어가면 에이전트도 코드 중간에 하나 고치는데도 모든 파일을 처음부터 다 읽으니 컨텍스트에 한계가 오고 이상한 곳을 고치기 시작합니다. 그래서 생기는 일이구요.


"짜파게티 코드"가 뭔가요

제가 쓰는 말입니다. 정의는 이렇습니다.

  • 겉은 멀쩡합니다 — 함수 이름도 나쁘지 않고, 타입도 맞고, 테스트도 있을 수 있습니다

  • 한 파일이 2,000줄 넘어갑니다 — 원래 200줄짜리로 시작했는데 에이전트가 "여기에 추가할게요" 를 반복한 결과입니다

  • 같은 로직이 세 군데에 있습니다 — 에이전트는 기존 코드를 읽지 않고 새로 쓰는 쪽을 자주 선택합니다

  • 경계가 무너져 있습니다 — UI 컴포넌트에 DB 호출이 있고, 스토어에 HTTP 요청이 있고, 그게 "돌기는" 합니다

  • 1개월 후 유지보수 불가입니다 — 그런데 1개월 후에 건드릴 일이 정말 없으면 상관없습니다

LLM이 깔끔한 함수 하나를 쓰는 건 정말 잘합니다. 하지만 모듈 경계책임 분리는 사람이 의식적으로 끌어주지 않으면 무너집니다. 이게 짜파게티가 되는 지점입니다.


언제 리팩토링을 하나요

저는 세 가지 시점을 신호로 씁니다.

1. 새 기능 추가 직전

이게 제일 중요합니다. 에이전트한테 "X 기능 추가해줘" 를 하기 전에, 관련 코드를 훑어보고 이렇게 결정합니다:

  • 지금 기능을 추가할 파일이 1,000줄 넘는 god-file이면, 먼저 쪼개고 시작

  • 비슷한 로직이 이미 있는데 위치가 애매하면, 먼저 한 군데로 모으고 시작

  • 기존 코드가 일관성 있으면, 그대로 진행

에이전트는 깨끗한 코드 위에서 훨씬 더 정확하게 일합니다. 쓰레기 옆에 쓰레기 하나 더 놓는 건 에이전트한테 공짜지만, 제가 그걸 읽고 맥락을 유지하는 건 공짜가 아닙니다.

tunaFlow 실제 기록으로 s26~s29 세션에서 5개 거대 파일(god-file)을 18개 모듈로 쪼갰습니다. 그 다음에야 새 기능 추가가 들어갔습니다. 당시 저는 이게 "낭비처럼 보여도 낭비가 아니다" 라고 계속 스스로 설득했는데, 지금 보니 그때 쪼개놓은 덕에 오늘 세션에서 30+ PR을 머지하면서도 어디에 뭐가 있는지 추적이 가능했습니다.

2. 같은 결함이 두 번 연속

리뷰 단계에서 같은 유형의 finding이 반복되면, 그건 구현 버그가 아니라 설계 문제입니다. 에이전트 탓이 아니라 제가 잘못된 구조 위에서 시키고 있는 겁니다.

tunaFlow의 Review 워크플로우에는 이걸 감지하는 로직이 있습니다. 같은 파일에서 연속 fail 이 나면 design_review_suggested 이벤트를 찍고, 3회 넘으면 doom loop warning 을 띄웁니다. 에이전트가 혼자 고치려다가 같은 자리에서 계속 넘어지는 상황이 가장 위험합니다.

3. "Rule of three"

같은 패턴이 세 번째 복제되는 순간이 임계점입니다. 두 번째까지는 우연일 수 있습니다. 세 번째는 구조 신호입니다.

이때 중요한 건 세 번째가 나오기 직전에 잡는 게 아니라 세 번째가 나온 뒤에 추상화하는 겁니다. 아직 두 번밖에 안 나왔는데 미리 추상화하는 걸 저는 "투기적 추상화"라고 부르는데, 이건 에이전트가 특히 잘 저지릅니다. "미래 확장성을 위해..." 로 시작하는 코드를 보면 지금 당장은 쓸데없이 복잡합니다. 세 번째가 나오기 전까진 그냥 복붙이 낫습니다.


리팩토링을 어떻게 하나요

작은 PR로 자르기

에이전트에게 "이 god-file 18개 모듈로 쪼개줘" 라고 한 방에 시키면 대부분 무너집니다. 저는 이렇게 합니다:

  1. 먼저 분해 지도를 손으로 그립니다 (어느 모듈에 뭐가 들어갈지)

  2. 각 모듈을 한 PR씩 뽑아냅니다

  3. 각 PR 은 테스트 유지가 조건입니다 (기능 변화 없음, 타입/테스트 전부 통과)

  4. 중간에 꼬이면 바로 롤백 가능하게 PR이 작을수록 좋습니다

오늘 세션에 머지된 30개 PR 중 가장 큰 게 800줄, 대부분 50~200줄 수준입니다. 이게 의도적인 설계입니다. 큰 PR 한 방이 빠를 것 같지만, 중간에 꼬이면 전체를 되돌려야 해서 결국 느립니다.

기존 코드를 먼저 읽게 하기

에이전트에게 수정을 시킬 때 제가 거의 항상 하는 건 "먼저 관련 파일 전부 읽고 구조 파악한 뒤에 말해봐" 입니다. 에이전트는 읽기를 건너뛰고 바로 쓰기로 넘어가는 경향이 있는데, 이걸 명시적으로 막지 않으면 바로 전에 누군가 이미 해결한 걸 다른 방식으로 또 만듭니다.

"확인만, 수정 금지" 모드

리팩토링 진입 전에 에이전트한테 종종 쓰는 지시입니다. "코드 상태만 확인하고 수정은 하지 마. 내가 결정한 뒤에 수정해." 이 한 줄이 짜파게티 방지에 생각보다 효과적입니다. 에이전트가 자기 판단으로 중간 단계에서 마음대로 정리해버리면 의도가 섞여서 리뷰가 어려워집니다.


긴 코드에서 에이전트가 방향을 잃지 않게 하려면

tunaFlow가 지금 Rust 25k줄 + TypeScript 24k줄 규모입니다. 이 정도 되면 에이전트 하나가 한 번에 전체를 알 수 없습니다. 방향을 잃지 않게 하려면 세 축의 맥락 주입이 필요합니다.

축 1: 프로젝트 맥락 (ContextPack)

매 요청마다 에이전트에게 다음을 조립해서 넘깁니다:

  • 프로젝트 정체성 (CLAUDE.md 수준의 문서)

  • 현재 작업 plan 과 직전 findings

  • 관련 파일 인덱스 (임베딩 + 그래프)

  • 최근 대화 압축본 (장기 메모리)

이걸 매번 손으로 복사해서 넘기는 게 사실상 불가능해서, 아예 도구(tunaFlow)를 만들었습니다. "모델 품질보다 컨텍스트 품질이 더 중요하다" 는 말이 여기서 실감 납니다. tunaFlow를 만들때는 기획하는 오퍼스, 코드 만들거나 고치는 오퍼스를 따로 다른 세션(창)에 두고 기획 오퍼스(아키텍트)랑 충분히 분석하고 문서를 만들게 시킨 다음, 코더 오퍼스에게 그냥 복붙해서 넘기는 식이었습니다.

축 2: 역할 분리

같은 에이전트라도 역할별로 persona 를 다르게 주면 행동이 다릅니다:

  • Architect: "설계 결정. 구현에 바로 들어가지 말 것. 승인 후 실행."

  • Developer: "Plan 범위 밖은 건드리지 말 것. 요청된 부분만 수정."

  • Reviewer: "객관적 결함만 지적. 확인되지 않은 문제를 단정하지 말 것. 의견은 recommendations 로 분리."

세 persona 가 전부 같은 모델(예: Claude Sonnet)이어도, 역할별 프롬프트 제약 덕에 행동이 분리됩니다. 특히 Developer persona 에 "plan 범위 밖 수정 금지" 같은 제약을 걸어두면 에이전트가 "이 김에 이것도..." 로 뻗어나가는 걸 막을 수 있습니다.

축 3: 과정의 구획화

한 번에 한 가지만 시키는 습관입니다. 구체적으로:

  • plan → dev → review 흐름을 강제 (tunaFlow의 워크플로우 파이프라인)

  • 각 단계마다 사용자 승인 게이트

  • 하나의 PR에 한 주제만 (두 가지 이상 섞이면 리뷰 품질 떨어짐)

에이전트한테 "A 하면서 B 도 하고 C 도 해줘" 를 해본 분은 알 겁니다. 결과가 셋 다 애매합니다. A 끝나고 승인, B 끝나고 승인, C 끝나고 승인이 결국 빠릅니다.


리뷰어 에이전트를 어떻게 쓰는가

이게 오늘 제가 제일 하고 싶던 얘기입니다.

자기 코드를 자기가 리뷰하면 망합니다

사람도 그렇지만 에이전트는 특히 더 심합니다. 본인이 짠 코드를 본인이 리뷰하면 "잘 짠 것 같습니다 ✅" 가 거의 기본값입니다. 자기 맥락이 이미 머리에 있으니 놓칠 리가 없다고 착각합니다.

다른 에이전트(다른 엔진이면 더 좋음)한테 맡기세요

Claude 가 짠 코드를 Codex 나 Gemini 에게 리뷰시키면 훨씬 잘 잡힙니다. 다른 모델 계열일수록 편향이 다르기 때문입니다. 같은 Claude 두 번 돌리는 것보다 Claude + Codex 조합이 실질적인 교차검증에 가깝습니다.

리뷰어에게 실제 실행 결과를 주세요

여기가 핵심입니다. Reviewer 에게 "Developer 가 보고한 테스트 결과를 확인해" 만 시키면, Developer 가 환각으로 "테스트 통과했습니다" 라고 거짓말할 경우 Reviewer 는 그대로 pass 를 내립니다. 이게 실제로 일어납니다.

해결책: Reviewer 호출 전에 실제로 cargo test / vitest 를 돌리고, 그 출력을 Reviewer 프롬프트에 박아서 같이 넘깁니다. tunaFlow 에서는 Review RT 시작 버튼이 이 순서대로 작동합니다:

  1. run_project_tests 실제 실행

  2. stdout/stderr 결과를 testOutput 변수에 담음

  3. startReviewRT(plan, messages, testOutput, engines) 호출

  4. Reviewer 프롬프트에 ## 테스트 결과 섹션으로 주입됨

이러면 Developer 의 자기 보고가 아니라 실행 결과로 판정합니다. 작년에 비슷한 걸 Anthropic 이 "Agent-as-Judge" 논문에서 정리했던데, 핵심은 리뷰어가 텍스트가 아니라 도구 결과를 본다 는 것입니다.

수치 루브릭을 시키세요

자유형식 리뷰("pass / fail / findings: [...]") 는 리뷰어마다 기준이 다릅니다. 저는 5차원 채점으로 강제합니다:

  • plan_coverage (1~5): 계획된 subtask 가 실제로 구현됐나

  • code_quality (1~5): 런타임/논리/보안 결함

  • test_coverage (1~5): 테스트 결과 + 커버리지

  • doc_quality (1~5): 주석/문서 업데이트

  • convention (1~5): 기존 코딩 스타일과 일관성

총점으로 자동 판정(22+ pass / 10 미만 fail / 그 외 conditional). 에이전트가 "느낌상 pass" 같은 걸 못 내립니다. 숫자를 박아야 하니까요.

외부 에이전트에게 리뷰시킬 때는 조심

Gemini 같은 프로젝트 맥락을 모르는 외부 LLM 한테 전체 리뷰를 맡기면 "신랄하게" 같은 단어 하나에 단정 안전벨트가 풀립니다 (ㄹㅇㅋㅋ). 근거 없이 단호한 판정이 튀어나오고, 그걸 믿으면 멀쩡한 코드를 갈아엎는 사고가 납니다.

제가 그제 이걸 한 번 겪었습니다 (다른 글에 상세히 썼습니다). 외부 리뷰는 자극용 으로만 쓰는 게 맞고, 각 지적은 반드시 코드 라인 인용으로 하나씩 검증해야 합니다. 한 번의 외부 리뷰에서 건지는 건 보통 5개 중 1~2개입니다. 나머지는 웃어넘기면 됩니다. 하지만 꽤 크리티컬한 걸 잡아 낼 수 있으므로, 아키텍트와 상의하시면서 하시면 됩니다.


요약

저한테 짜파게티 방지는 결국 세 가지로 수렴합니다.

  1. 새 기능 추가 전에 정리하기. 쓰레기 위에 기능 얹지 않기

  2. 에이전트한테 맥락 주입 + 역할 제약 걸기. persona + ContextPack + 단계별 승인

  3. 리뷰어는 다른 에이전트가 + 실제 실행 결과를 받아서 + 수치 루브릭으로 채점

특별한 비법은 없습니다. 사람 팀에서 시니어가 주니어랑 일할 때 하는 거랑 거의 같습니다. 차이는, 에이전트는 하루 24시간 쉬지 않고 이 패턴을 요구한다는 것뿐입니다. 그래서 도구가 필요하고, 그 도구로 tunaFlow 를 만들고 있습니다.

아직 완성은 멀었습니다. 하지만 적어도 제가 "짜파게티 코드 비웃는 제 자신이 짜파게티 만들고 있더라" 되는 상황은 피하려고 합니다. 😁


레퍼런스 / 관련 글

  • Sebastian Raschka, Components of a Coding Agent (2025) — "model quality = context quality"
  • Addy Osmani, Orchestrating Coding Agents (2025) — 멀티 에이전트 오케스트레이션 패턴
로그인한 회원만 댓글 등록이 가능합니다.

개발한당

KR | ID | EN
  • IDR
  • KOR
8.34 =0.00

2026.07.11 KEB 하나은행 고시회차 1694회

다가오는 한인 행사일정

  • 등록 된 일정이 없어요!