에이전틱 코딩 추천사항

ko생성일: 2025. 6. 12.갱신일: 2025. 6. 15.

에이전틱 코딩 경험과 권장사항을 실제 활용 사례와 함께 소개합니다. 효율적인 워크플로우, 툴 선택, 언어 선정, 최적화 팁 등 에이전틱 개발에 집중한 실용적인 조언을 제공합니다.

에이전틱 코딩 추천사항

2025년 6월 12일 목요일 작성

현재 에이전틱 코딩에 관한 경험을 공유하는 사람들이 폭발적으로 늘어나고 있습니다. 제가 이 주제에 대해 최근 두 번의 글을 올린 이후로, 제 실전 활용법에 대한 질문도 꽤 받게 되었습니다. 그래서 이 글을 남깁니다.

서문

제가 어떤 방식으로 작업하는지 간단히 정리하자면, 주로 Claude Code를 저렴한 Max 구독(월 $100)으로 사용합니다[1]. 이 방식이 좋은 이유는 몇 가지 있습니다:

  • 항상 더 저렴한 Sonnet 모델만 씁니다. 제 작업에는 충분하고, 실제로는 더 비싼 Opus 모델보다 결과물이 더 마음에 듭니다.
  • 토큰 효율을 극대화하기 위해 툴 사용을 최적화합니다. 캡처 화면, 브라우저 상호작용은 가급적 피하고 있습니다. 이 부분은 아래에서 더 다룹니다.

저의 기본 워크플로우는, 에이전트에게 작업을 지정하고(실질적으로 모든 권한을 줍니다) 완료를 기다리는 방식입니다. 중간에 작업을 끊는 일은 거의 없고, 아주 작은 작업에만 예외가 있을 뿐입니다. 그 결과, IDE에서 AI가 차지하는 역할이 크게 줄었고, 대부분 마지막 편집 용도로만 씁니다. 이 덕에 오히려 AI가 없는 Vim으로 코딩하는 빈도도 높아졌습니다.

참고: 이 글은 금방 낡을 수 있습니다. 혁신의 속도가 매우 빠릅니다. 그래서 단기적인 팁이 아니라, 앞으로도 변하지 않을 것 같은 원칙 위주로 정리합니다.

제가 이 방식으로 오픈소스 라이브러리를 작업하는 녹화 영상을 여기에서 보실 수 있습니다.

기본 원칙

저는 모든 권한 확인을 끕니다. 즉, claude --dangerously-skip-permissions로 실행합니다. 좀 더 구체적으로는 claude-yolo라는 alias를 만들어서 쓰고 있습니다. 이게 무책임하다고 보실 수 있지만, 위험성은 Docker로 개발 환경을 격리해 관리할 수 있습니다. 사실 Docker 없이도 잠시 지켜보면 꽤 잘 굴러갑니다. 경험은 다를 수 있습니다(YMMV).

MCP는 이 분야에서 피해갈 수 없는 용어입니다. MCP는 실질적으로 에이전트가 더 많은 툴에 접근할 수 있도록 하는 표준 프로토콜입니다. 사실 저는 거의 MCP를 사용하지 않지만, 꼭 써야 할 상황(예: 브라우저 자동화에 playwright-mcp 필요 등)엔 씁니다. 대신, 데이터베이스를 살펴봐야 할 때는, 에이전트가 사용할 수 있는 도구(예: psql)를 그냥 씁니다. 다른 방법이 너무 불안정한 경우에만 MCP를 고려합니다. 이유는 MCP 서버 자체가 꽤 불안정할 때가 많고, 추가 장애 포인트가 되기 때문입니다. 가능하면 간단하게 가는 게 낫죠. 커스텀 툴은 별도 스크립트 파일로 만들어서 돌립니다.

언어 선택

여러 프로그래밍 언어에서 에이전트 성능을 비교해보니, 새 백엔드 프로젝트에는 Go를 강력히 추천합니다:

  • Context 시스템: Go의 context는 명시적으로 함수 경로를 따라 전달되는 복사-on-write 데이터 백입니다. 이는 Python의 contextvars나 .NET의 execution context와 유사하나 명확해서 AI가 작업하기에 아주 좋습니다.
  • 테스트 캐싱: Rust에서는 cargo test 문법 오용 등으로 에이전트가 종종 실패합니다. Go는 테스트가 빠르고 누적 실행되어 매우 효율적인 에이전틱 코딩이 가능합니다.
  • Go는 단순하다: Go의 단순함은 LLM이 코드를 이해하는 데 큰 도움이 됩니다.
  • 구조적 인터페이스: Go의 인터페이스는 구조적 방식이라, 필요한 메소드만 구현하면 자동적으로 부합합니다. LLM이 이해하기에도 쉽습니다.
  • 에코시스템 변동이 적다: Go 환경은 호환성과 버전 전환에 매우 보수적이어서, AI가 구식 코드를 작성할 가능성이 낮습니다. 이는 빠르게 변하는 자바스크립트와 크게 대비됩니다.

반면, 초기엔 Python을 썼는데 여러가지 문제점이 있습니다. 예시로 Pytest의 fixture injection 등 마법 같은 구조나, 비동기 코딩에서 이벤트루프 착오, 느린 실행 속도 등이 있습니다. 에이전트가 테스트 스크립트나 프로세스를 자꾸 새로 띄우고, Python 해석기가 뜨고 초기화되는 시간이 오래 걸립니다.

프론트엔드는 tailwind, React (tanstack query/router), vite를 정착적으로 씁니다. 완전히 만족스럽진 않지만 대안보다 낫다고 느꼈습니다. tailwind와 vite는 좋고, tanstack의 파일 기반 라우터의 경우, 파일명에 $ 기호가 포함되어 에이전트가 shell 해석 문제로 종종 혼동합니다. 예: $param.tsx를 수정해야 하는데 .tsx 파일만 건드는 식입니다. 사소하지만 꽤 귀찮습니다.

툴, 툴, 툴

언어와 무관하게 중요한 건 강력한 툴링입니다. 몇 가지 핵심 규칙:

  • 무엇이든 툴이 될 수 있다. 셸 스크립트, MCP 서버, 로그 파일 등 에이전트가 접근/관찰할 수 있으면 모두 툴입니다.
  • 툴은 빠르게 동작해야 한다. 응답이 빠르고 불필요한 출력이 적을수록 좋습니다. 충돌(crash)은 참을 수 있으나, 멈춤(hang)은 치명적입니다.
  • 툴은 사용자 친화적이어야 한다. 잘못 사용시 명확하게 에러를 알려 앞으로 나아갈 수 있어야 합니다.
  • 툴은 LLM 카오스몽키에 의해 엉뚱하게 사용되더라도 방어할 수 있어야 함. 사용자 실수나 정의되지 않은 동작은 있어서는 안 됩니다!
  • 툴은 올바른 디버깅 및 관찰 기능을 제공해야 합니다.

실례로, 중요한 툴은 Makefile에 넣습니다. make dev로 프로세스 관리자가 서비스를 시작합니다. 여기서 두 가지를 변경했습니다:

  1. 프로세스 관리자가 이미 실행 중일 때 중복으로 실행되지 않도록 방어 로직을 넣었습니다. shoreman 포크로 pidfile을 작성하게 했고, 두 번째 실행이면 “services already running” 메시지를 출력하며 에러 처리합니다. 왜 중요할까요? 에이전트는 서비스가 이미 실행 중인지 판단 못하고 중복 띄워 같은 포트 충돌이 종종 발생합니다.
  2. 터미널뿐 아니라 로그 파일로도 항상 출력을 남겨, 에이전트가 로그를 읽어 문제를 진단할 수 있도록 했습니다.

에이전틱 상호작용 예시:

⏺ "포맷이 좋아보이네요. 이제 개발 서버를 띄워 다이나믹 온보딩을 테스트할게요."

⏺ Bash(make dev) ⎿  Error: error: services are already running make: *** [dev] Error 1

⏺ "개발 서버가 이미 돌아가고 있습니다. 로그를 확인해 프론트엔드 URL을 알아내 볼게요."

⏺ Bash(make tail-log) ⎿ 01:06:55 backend | Starting server on localhost:8080 01:07:39 backend | [Running: sh -c 'cd backend && go run cmd/server/main.go serve'] 01:07:39 backend | Starting server on localhost:8080 08:45:34 backend | "GET http://localhost:8080/api/users/me HTTP/1.1" from 127.0.0.1:61804 - 200 39.252666ms … +96 lines (ctrl+r to expand)

⏺ "좋아요! 프론트엔드가 http://localhost:3000/ 에서 동작하며 최신 변경사항도 핫리로드 됐습니다. 이제 playwright로 온보딩 기능을 테스트합니다."

일반적으로 로깅이 매우 중요합니다. 예시로, 제 앱의 로그인/회원가입 플로우는 이메일을 보내는데, 디버그 모드(에이전트가 실행)에선 이메일이 stdout에 기록됩니다. 이는 아주 중요합니다! 에이전트가 원격 브라우저를 제어하며 회원가입을 완료할 수 있고, 이메일 링크도 로그에서 추출해 클릭해야 할 곳을 정확히 알 수 있습니다. CLAUDE.md에 이를 명시해 두었기 때문에 로그를 자연스럽게 봅니다.

이것도 툴인가요? 제 기준에서는 툴입니다.

속도가 생명이다

에이전틱 코딩의 비효율성 대부분은 추론(inference) 비용과 비효율적인 툴 사용에서 발생합니다. 반복하지만, 빠르고 명확한 툴의 응답이 매우 중요합니다. 때로는 에이전트가 직접 "임시 툴"을 생성해서 사용하기도 합니다. 이때 컴파일 및 실행이 빠르면 작업 속도가 크게 향상됩니다. 이를 어떻게 도울 수 있을까요?

적절한 지침만 있다면, AI에게 기존 컨벤션을 따르는 새 툴을 빠르게 만들도록 할 수 있습니다. 이것은 곧 AI가 새 코드를 써서 바로 실행할 수 있어야 함을 의미합니다. 만일 이 툴의 실행시간이 3ms와 5초 컴파일/1분 초기화+불필요한 로그의 차이라고 생각해보세요. 어마어마한 생산성 차이가 생깁니다.

혹시라도 실행이 너무 느리면, "vibe-coding a demon"(파일 시스템에 새 모듈을 동적으로 로드/실행하는 방식)으로 보완하는 것도 방법입니다. 예로 Sentry가 코드 reload나 재시작에 너무 오래 걸려서, 저는 파일시스템을 감시해 새로운 Python 모듈을 자동 실행하고, 결과를 로그에 남기게 했고, 이를 cat 명령으로 에이전트에 피드백했습니다. 완벽하진 않지만, 기본 코드를 빠르게 시험해보는 데 있어 큰 도움이 됐습니다.

로그 출력의 간결함과 정보성 균형도 중요합니다. 토큰 사용량 및 추론 속도를 좌우하므로, 불필요한 로그는 줄이고, 정보성은 유지해야 비용/속도를 잡을 수 있습니다. 균형을 못 맞추면, AI가 조정할 수 있는 쉬운 옵션(로그 레벨 등)을 주면 됩니다.

궁극적으로는 에이전트가 코드를 작성할 때, 그 자체로 필요한 로그가 남겨져 첫 실행에서 바로 관찰되는 게 이상적입니다. 디버그 정보를 추가하는 반복작업을 줄이고, 생산성을 크게 높일 수 있습니다.

안정성과 복사/붙여넣기

안정적인 에코시스템은 곧 성공의 열쇠입니다. LLM(대형언어모델)은 Go, Flask 처럼 변화가 적은 환경을 좋아합니다. 여러분의 코드베이스도 마찬가지입니다. AI는 코드를 작성하면서 결정 근거 등에 주석을 남기는데, 무심코 라이브러리 버전을 올리며 그런 결정들이 무의미해지면 혼란에 휩싸일 수 있습니다.

원칙적으로 인간이나 AI나 동일하게 적용되어야 하지만, 현실에서 에이전트가 너무 쉽게 업그레이드하니 확인없이 맡겨버리는 유혹이 생깁니다. 저는 테스트 통과만으로 만족하지 않고, 실제로는 더 보수적으로 업그레이드 해야 한다고 생각합니다.

또한, AI 사용시에도 직접 코드를 작성하는 걸 라이브러리 사용보다 더 선호합니다. 직접 구현하는 것이 왜 더 나은지에 대해 예전에도 썼지만, 에이전틱 환경에선 그 진가가 더욱 드러난다고 느낍니다.

단순한 코드를 작성하세요

단순한 코드는 복잡한 코드보다 에이전틱 환경에서 훨씬 나은 성능을 보입니다. 못생긴 코드에 대하여라는 글에 썼으니, 다시 읽어보길 권합니다. "될 수 있는 한 가장 쉬운 방식"으로 하게 하세요.

  • 명확하고 설명적인, 다소 길더라도 함수명 위주로 클래스를 최소화합니다.
  • 상속/트릭/너무 똑똑한 패턴 등은 피하세요.
  • ORM보다는 꼭 필요한 SQL을 직접 쓰게 하세요. 에이전트는 정말 훌륭하게 SQL을 잘 짜고, 로그와 쿼리 결과를 잘 매칭합니다. ORM 이상하게 속성, 로그 등에서 혼동하는 경우가 거의 필연적입니다.
  • 권한 체크는 꼭 근처에! 권한 확인 로직을 엔드포인트 근처나 명확한 위치에 두어 AI가 어떤 함수에 권한 검증이 이뤄지는지 명확히 인식할 수 있게 하세요. 분리/감춰두면 자주 빠뜨리게 됩니다.

병렬화가 핵심

에이전트는 개별적으로는 빠르지 않지만, 병렬 처리를 활용하면 전체 속도를 높일 수 있습니다. 파일시스템, DB, Redis 등 공유 상태를 병렬로 관리할 수 있는 방법을 찾으세요. 피하거나 지능적으로 분할할 수 있는 방법을 고민하세요.

최초엔 단순히 파일시스템을 다른 checkout으로 분리하는 것도 좋습니다. 최근엔 container-use처럼 Docker 컨테이너 내에서 실험하게 하는 MCP 서버도 등장했고, Cursor의 background agents, Codex 등은 CI에 이 기능을 통합하려 하고 있습니다. 저는 아직 직접 업무엔 적용하지 못했지만, 앞으로 주목할 부분입니다.

리팩터링 숙달하기

에이전틱 코딩 환경에서는 리팩터링 우선순위도 달라집니다. 에이전트는 복잡도가 일정 규모 이하에선 업무를 잘 처리하지만, 한계점에 도달하면 전혀 다루지 못합니다. 예를 들어, 몇십 개 파일에 중구난방으로 Tailwind 클래스가 흩어진 시점부턴 반드시 컴포넌트 라이브러리로 묶어야 합니다. 그렇지 않으면 대규모 리디자인/컴포넌트 추출시 에이전트가 무척 힘들어합니다.

에이전틱 워크플로우는 적절한 시점에 코드 정리 및 리팩터링을 격려합니다. 너무 이르거나, 너무 늦게 하지 않는 게 모두에게 이득입니다.

앞으로는?

에이전틱 코딩은 급격히 진화하고 있으며, 내일은 오늘과 또 완전히 달라질 수 있지만, 분명한 점은 에이전트를 개발 프로세스에 통합하면 큰 생산성 향상을 얻을 수 있다는 것입니다. 계속 실험하세요. 도구와 기술은 바뀌어도 단순함, 안정성, 관찰성, 스마트한 병렬화라는 핵심 원칙은 계속 중요할 것입니다.

궁극적으로 목표는, 에이전트를 이용해 단순히 빠르게 코드만 작성하는 것이 아니라 더 견고하고, 유지보수하기 쉬운, 복원력 있는 코드를 만드는 것입니다. 이미 불과 몇 달 전의 엉성했던 output과는 비교할 수 없을 정도로 코드 품질이 좋아졌습니다. 적응력을 유지하며, 즐거운 코딩이 되길 바랍니다!

[1] 이 글은 Claude Code 홍보가 아닙니다. 현재 제가 사용하는 에이전트일 뿐입니다. 비슷한 사용자 경험을 갖는 대안으로는 OpenCode, goose, Codex 등도 있습니다. 클라우드에서 구동되는 Devin이나 Cursor의 background agents도 있으나 구조가 조금 다릅니다.

이 글은 aithoughts 태그가 달려 있습니다.