본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 05. 21. 02:06

AI 에이전트가 지루한 코드를 선호하는 이유

요약

AI 코딩 에이전트의 성능을 높이기 위해서는 더 똑똑한 모델보다 일관된 패턴을 가진 '지루한 코드베이스'를 구축하는 것이 더 중요합니다. 에이전트는 패턴 매칭을 통해 코드를 작성하므로, 코드베이스의 일관성이 낮으면 에이전트가 잘못된 패턴을 선택하거나 예외적인 구조를 인식하지 못해 오류를 발생시킬 확률이 높아집니다.

핵심 포인트

  • 지루한 코드란 동일한 패턴, 명명 규칙, 에러 처리 및 파일 구조를 가진 일관된 코드를 의미함
  • AI 에이전트는 코드베이스를 사전 확률(prior)로 활용하여 패턴 매칭 방식으로 동작함
  • 코드베이스 내의 특이한 요소나 맞춤형 라이브러리는 에이전트가 처리해야 할 '세금'과 같음
  • 일관되지 않은 코드베이스는 에이전트의 추측을 유도하여 런타임 오류나 중복 코드를 생성함

당신의 코딩 에이전트(coding agent)를 위해 할 수 있는 가장 유용한 일은 더 나은 프롬프트(prompt)나 더 똑똑한 모델(model)을 제공하는 것이 아닙니다. 그것은 바로 더 지루한 코드베이스(codebase)를 만드는 것입니다. 이것은 농담처럼 들리겠지만, 농담이 아닙니다.

"지루함"이 의미하는 것

지루한 코드(Boring code)는 나쁜 코드가 아닙니다. 지루한 코드는 동일한 상황에 있는 다른 모든 코드 조각이 수행하는 것과 정확히 똑같은 일을 하는 코드입니다. 동일한 패턴(patterns), 동일한 명명 규칙(naming), 동일한 에러 처리(error handling), 동일한 파일 구조(file structure)를 사용합니다. 하나의 모듈을 읽었다면, 대략 모든 모듈을 읽은 것이나 다름없습니다. 놀라움도 없고, 특별한 사례도 없으며, 오직 원작자만이 이해할 수 있는 영리한 지름길(shortcuts)도 없습니다. 지루한 코드는 팀이 소수의 컨벤션(conventions)을 준수하기로 약속하고 그것에서 벗어나기를 거부할 때 얻을 수 있는 결과물입니다. 이는 "모든 엔지니어가 자신을 표현하는 것"의 반대 개념입니다. 이는 일련의 개별적인 공연이라기보다 조율된 활동으로서의 엔지니어링입니다. 시니어 엔지니어들은 항상 조용히 지루한 코드를 선호해 왔습니다. 왜냐하면 그들은 코드를 쓰는 시간보다 읽는 데 더 많은 시간을 소비하며, 지루하지 않은 코드가 어떤 대가를 치르게 하는지 알고 있기 때문입니다. 에이전트(Agents)는 이러한 선호도를 경제적으로 피할 수 없게 만듭니다.

에이전트가 이를 보상하는 이유

당신의 코드베이스에서 작업하는 에이전트는 자신이 훈련받은 모든 것과 방금 컨텍스트(context)로 로드한 저장소(repo)의 모든 것에 대하여, 고도의 패턴 매칭(pattern-matching)에 가까운 작업을 수행하고 있습니다. 그 컨텍스트가 일관될수록 매칭은 더 신뢰할 수 있게 됩니다. 만약 코드베이스의 모든 컨트롤러(controller)가 동일한 방식으로 입력을 검증한다면, 에이전트는 별도의 지시 없이도 그 방식으로 입력을 검증할 것입니다. 만약 절반은 하나의 패턴을 사용하고 나머지 절반은 다른 패턴을 사용한다면, 에이전트는 그중 하나를 선택할 것이며(편집 중인 파일에는 잘못된 패턴일 수도 있습니다), 당신은 코드 리뷰(code review) 단계에서, 혹은 더 나쁘게는 런타임(runtime)에 이를 발견하게 될 것입니다. 이것은 특정 모델의 기이한 특성이 아닙니다. 패턴 매칭 도구에 일관되지 않은 패턴을 제공했을 때 발생하는 현상입니다. 코드베이스는 사전 확률(prior)입니다. 일관되지 않은 사전 확률은 일관되지 않은 출력(outputs)을 만들어냅니다.

새로움에 대한 세금

당신의 코드베이스에 있는 모든 특이한 요소는 에이전트가 지불해야 하는 세금입니다.

이 세금이 실제로 어떤 모습인지에 대한 몇 가지 예시는 다음과 같습니다: 표준 라이브러리(standard library)가 하는 일과 거의 비슷하지만 완전히 같지는 않은 맞춤형 로깅 래퍼(logging wrapper)가 있는 경우입니다. 에이전트는 대부분의 코드가 사용하는 방식에 따라 표준 라이브러리를 선택하게 되고, 그 결과 생성된 로그는 다른 모든 로그와 다른 곳에 쌓이게 됩니다. 아무도 기억하지 못하는 역사적인 이유로 시스템의 나머지 부분과는 다른 ORM을 사용하는 단일 서비스가 있는 경우입니다. 에이전트는 다수의 스타일로 코드를 작성하며, 소수의 스타일을 조용히 깨뜨립니다. 어노테이션(annotations)으로부터 핸들러(handlers)를 자동 생성하는 모듈 내의 영리한 메타프로그래밍(metaprogramming) 기법이 있는 경우입니다. 에이전트는 이 트릭을 인식하지 못하고 핸들러를 수동으로 추가하며, 이제 동일한 경로(route)에 두 개의 핸들러가 존재하게 됩니다. 이 중 그 어떤 것도 에이전트의 버그가 아닙니다. 이것들은 코드베이스의 버그이며, 여기서

이러한 규칙들이 없는 팀은 에이전트에게 매번 추측 게임을 강요하는 것과 같습니다. 선의보다는 기계적인 강제가 더 효과적입니다. 제대로 작동하는 컨벤션(Convention, 관례)은 누군가가 그것을 기억해야 하는 것에 의존하지 않는 것입니다. 린터(Linters), 포매터(Formatters), 타입 시스템(Type systems), 그리고 CI 체크(CI checks)는 컨벤션을 "우리는 이런 식으로 하기로 합의했습니다"라는 영역에서 "하지 않으면 빌드가 실패합니다"라는 영역으로 옮겨주는 방법입니다. Prettier와 gofmt는 지루한 도구들이지만, 수천 개의 스타일 가이드보다 코드베이스의 일관성을 유지하는 데 더 큰 역할을 해왔습니다. 자동 수정(Autofix) 기능이 있는 ESLint 규칙은 논쟁을 커밋(Commit)으로 바꿔줍니다. 강력한 타입 시스템은 에이전트가 생성할 수도 있었던 코드의 범주 전체를 기계적으로 배제합니다. 이것이 에이전트에게 특히 중요한 이유는 에이전트가 피드백에 반응하기 때문입니다. 린터를 실행하고 에러를 확인한 에이전트는 그 에러를 수정합니다. 첫 시도에 린터에 부합하는 코드를 생성하는 에이전트는, 당신의 코드베이스로부터 학습한 패턴이 이미 그 방향을 가리키고 있기 때문에 그렇게 생성하는 것입니다. 어느 쪽이든, 도구는 인간 리뷰어가 수행해야 했을 작업을 수행하고 있습니다. 에이전트의 처리량(Throughput)에 맞서 인간의 속도로 작업하는 것이 아니라 말입니다. 디스크에 기록된 컨벤션(Conventions on disk). 투자할 가치가 있는 또 다른 관행은 지루한 것입니다. 바로 당신의 컨벤션을 에이전트가 읽을 수 있는 파일로 리포지토리(Repo) 내에 기록하는 것입니다. 정확한 파일명은 다양합니다 (AGENTS.md, CLAUDE.md, CONTRIBUTING.md, 또는 트리 최상단의 README). 중요한 것은 당신의 팀이 암묵적으로 알고 있는 것들이 명시적으로 변하여, 에이전트가 매 세션 시작 시 컨텍스트(Context)로 불러올 수 있는 장소에 위치하게 하는 것입니다. "클래스(Classes)가 아닌 함수형 컴포넌트(Functional components)를 사용합니다." "에러는 라우트 핸들러(Route handler)로 전파됩니다. 서비스 레이어(Service layer)에서 에러를 잡지 마세요." "데이터베이스 접근은 리포지토리 모듈(Repository module)을 통해 이루어집니다. 생 쿼리(Raw queries)를 사용하지 마세요." 이것들은 새로운 인간 엔지니어가 일주일간의 코드 리뷰와 몇 번의 불편한 PR(Pull Request)을 통해 배우게 될 내용들입니다. 에이전트에게는 일주일이라는 시간이 주어지지 않습니다. 에이전트에게는 단 하나의 파일이 주어집니다. 파일에 코드가 이미 암시하고 있는 내용을 명시하여, 에이전트의 사전 지식(Priors)이 당신의 현실과 일치하도록 만드세요. 하네스(Harness) 사용하기. 컨벤션을 글로 적는 것은 시작 단계일 뿐입니다.

다음은 그것들을 하네스(Harness)로 감싸는 것입니다. 하네스는 "우리는 이런 방식으로 일을 한다"라는 정적인 목록을, 에이전트(Agent)가 능동적으로 참조하고, 교정받으며, 유지 관리하도록 돕는 무언가로 변환하는 계층(Layer)입니다. 유용한 작업 정의를 내리자면, 하네스는 에이전트 자체를 제외한 에이전트 주변의 모든 것입니다. 제가 특별히 모델(Model)이라고 말하지 않는 점에 유의하십시오. 용어상 일부 중첩되는 부분이 있기 때문입니다. 어떤 이들은 Claude Code(및 기타 유사한 제품들)를 하네스라고 부르기도 합니다. 어떤 면에서는 그렇습니다. 그것은 모델을 감싸는 하네스입니다. 여기서 저는 에이전트의 결과(이 Claude Code 세션)를 개선하기 위해 코드 내에 정의된 에이전트 하네스(Agent harness)에 대해 구체적으로 이야기하고 있습니다. 에이전트가 로드하는 CLAUDE.md, .claude/ 디렉토리에 있는 규칙(Rules)과 기술(Skills), 팀이 표준화한 슬래시 명령어(Slash commands), 에이전트가 파일을 수정할 때 실행되는 체크(Checks), 그리고 "리뷰어가 잘못된 패턴을 발견했다"를 "다음 에이전트 실행 시에는 그렇게 하지 않는다"로 바꾸는 루프(Loop) 등이 이에 해당합니다. 에이전트(Agent) = 모델(Model) + 하네스(Harness)입니다. 당신은 매주 화요일마다 새로운 모델을 선택할 수는 없지만, 하네스는 매일 엔지니어링할 수 있습니다. 만약 아무것도 없는 상태에서 시작한다면, bridle이 합리적인 기본값입니다. 이는 CLAUDE.md와 규칙, 에이전트, 기술, 명령어가 포함된 .claude/ 디렉토리를 구성(Scaffold)해주는 Claude Code 플러그인이며, 생명주기를 위한 슬래시 명령어를 함께 제공합니다: /bridle:learn은 리뷰 코멘트를 지속 가능한 규칙으로 변환하고, /bridle:audit는 저장소(Repo)를 탐색하며 규칙 위반 사항을 찾아내며, /bridle:harness-health는 오래된 규칙이나 희박해진 커버리지를 표시합니다. 여기서 핵심은 독단적인 견해(Opinionation)를 제공한다는 점입니다. 즉, 디렉토리 레이아웃을 정하느라 한 스프린트(Sprint) 동안 소모적인 논쟁(Bikeshedding)을 하는 대신, 단 한 오후 만에 작동 가능한 기준선(Baseline)에 도달할 수 있게 해줍니다. 하지만 특정 도구가 논점은 아닙니다.

핵심은 작동하는 하네스(Harness)가 필요하다는 것입니다. 이 하네스는 저장소(Repo) 내에 존재하며, 에이전트가 매 세션마다 읽고, 에이전트가 예상치 못한 행동을 할 때 팀이 업데이트하며, "리뷰에서 이 문제를 발견했다"와 "다음 실행 시에는 이 문제가 발생하지 않을 것이다" 사이의 루프를 닫아주는 것이어야 합니다. 세 개의 마크다운(Markdown) 파일과 프리커밋 훅(Pre-commit hook)으로 구성된 자체 제작 설정이, 아무도 건드리지 않는 정교한 하네스보다 훨씬 낫습니다. 중요한 것은 규율(Discipline)입니다. 하네스를 코드베이스의 일부로 취급하고, 버전을 관리하며, 변경 사항을 리뷰하고, 에이전트가 코드 리뷰에서 수정했을 법한 행동을 할 때마다 하네스에 반영하십시오. 에이전트로부터 가장 많은 이득을 얻는 팀은 이러한 계층을 의도적으로 구축한 팀들입니다. 반면 가장 적은 이득을 얻는 팀은 여전히 단 하나의 CLAUDE.md 파일과 강력한 모델만 있으면 충분할 것이라고 희망하고 있습니다. 그렇지 않습니다.

이것이 파이프라인과 어떻게 연결되는가: 이 모든 논의를 관통하는 실타래는 지속적 인도(Continuous Delivery) 및 비난 없는 사후 분석(Blameless post-mortems)을 관통하는 것과 동일합니다. 즉, 개인이 아닌 시스템이 표준을 보유해야 한다는 것입니다. CI에서의 린터(Linter) 체크는 시스템이 강제하는 표준입니다. 빌드 타임에 발견된 타입 에러(Type error)는 시스템이 강제하는 표준입니다. 에이전트가 스택의 잘못된 계층에 접근했을 때 실패하는 회귀 테스트(Regression test)는 시스템이 강제하는 표준입니다. 이 중 그 어느 것도 리뷰어가 디프(Diff)를 읽는 순간에 해당 규칙을 기억하고 있는지에 의존하지 않습니다. 에이전트는 수많은 디프를 생성할 것입니다. 리뷰어는 확장(Scale)될 수 없지만, 표준은 확장되어야 합니다.

레버리지(Leverage): 내일 더 나은 에이전트 활용을 원한다면, 가장 강력한 레버리지는 모델 업그레이드가 아닌 경우가 많습니다. 그것은 코드베이스를 예측 가능하게 만드는, 다소 지루한 작업입니다. 문제당 하나의 패턴을 선택하고, 그 패턴을 문서화하며, 기계적으로 강제하고, 눈에 띄는 예외 사항들이 조용해질 때까지 리팩터링(Refactor)하는 것입니다. 지루한 코드(Boring code)는 승수 효과(Force multiplier)를 가져옵니다. 인간에게도 항상 그랬듯이, 에이전트는 그 효과를 수치로 증명할 뿐입니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0