AI의 잠재력을 최대한 활용하기: 에이전트의 성공을 위한 코드베이스 구조화
요약
AI 에이전트의 성능을 극대화하기 위해 코드베이스를 구조화하는 방법을 다룹니다. 모듈 경계 설정, 명확한 타입 정의, 관습적인 파일 구조를 통해 에이전트가 코드를 더 정확하게 이해하고 작업할 수 있는 환경을 구축하는 것이 핵심입니다.
핵심 포인트
- 모듈 경계를 명확히 하여 에이전트가 필요한 파일만 쉽게 찾도록 설계해야 함
- 명시적인 타입(Typed contracts)을 제공하여 에이전트의 추측을 방지해야 함
- 파일당 하나의 컴포넌트와 폴더 구조를 통해 에이전트의 멘탈 모델을 지원해야 함
- 잘 구조화된 코드베이스는 에이전트의 작업 효율을 두 배 이상 높임
Cursor와 Claude Code는 당신이 단 한 줄의 코드도 작성하지 않고도 200개의 컴포넌트로 구성된 디자인 시스템을 가져와 작동하는 관리자 페이지를 출시할 수 있습니다. 이것은 마케팅 수사가 아닙니다. 저는 OTF SaaS 키트에서 실제로 일어나는 것을 목격했습니다. 문제는 에이전트가 무엇을 할 수 있는지가 당신이 건네주는 레포지토리(repo)의 형태에 거의 전적으로 달려 있다는 점입니다. 에이전트가 읽도록 설계된 코드베이스는 대부분의 AI 앱 빌더가 생성하는 4,000줄짜리 단일 파일과는 전혀 다르게 생겼습니다.
그 차이는 프롬프트 마법(prompt magic)에 있지 않습니다. 그것은 다섯 가지 지루한 구조적 속성에 있으며, 각 속성을 추가하는 데 드는 비용은 거의 없으면서 에이전트가 안정적으로 수행할 수 있는 작업량을 대략 두 배로 늘려줍니다. OTF 키트는 의도적으로 이런 방식으로 구축된 작업 예시(worked example)이지만, 이 패턴은 어떤 레포지토리에서도 작동합니다.
1. 모듈 경계(Module boundaries)가 컴포넌트 개수보다 우선한다
에이전트는 신입 사원과 동일한 방식으로 코드베이스를 확장합니다. 즉, 스크롤을 내리지 않고 필요한 파일을 찾는 방식입니다. 모든 관심사(concern)가 각자의 폴더에 있고, 파일당 하나의 컴포넌트가 있으며, 루트에 배럴 수출(barrel export)이 있는 레포지토리는 에이전트에게 지도를 제공합니다. 모든 것이 app/page.tsx에 들어 있는 레포지토리는 에이전트가 전체를 추론해야 하는 하나의 진흙 덩어리(ball of mud)와 같습니다.
효과적인 형태:
src/
components/
Button/
...
각 폴더는 하나의 단위입니다. 에이전트는 Card/Card.tsx를 읽고, Prop(속성) 형태를 이해하며, 다른 곳에 <Card>를 작성할 수 있고, 나머지는 전혀 건드릴 필요가 없습니다. 키트가 이런 방식으로 출시되면 에이전트의 멘탈 모델(mental model)은 파일 트리와 일치하게 됩니다. 샌드박스(sandbox)가 평면적인 파일(flat file)을 제공하면, 에이전트에게 남은 유일한 옵션은 전체를 계속해서 다시 생성하는 것뿐입니다.
이를 잘못 처리했을 때의 비용은 복리로 쌓입니다. 평면 파일 레포지토리에 작성하는 모든 프롬프트는 레이아웃을 다시 설명해야 합니다. 관심사별 폴더 구조 레포지토리에 작성하는 모든 프롬프트는 그저 요청하기만 하면 됩니다.
2. 타입이 지정된 계약(Typed contracts)이 사양(spec)이다
Props는 컴포넌트의 API입니다. 만약 타입이 명시적인 변형(variants)을 가진 ButtonProps라면, 에이전트는 파일을 읽고 어떤 변형이 존재하는지 정확히 확인하여 추측 없이 올바른 것을 선택합니다. 만약 타입이 any라면, 에이전트는 구현부(implementation)를 읽어야 하며, 그 시점에는 다시 수동 코딩(hand-coding) 단계로 돌아가게 됩니다.
정말 유용한 방법은 컴포넌트와 함께 props를 내보내는(exporting) 것입니다:
// components/Card/Card.tsx
export type CardProps = {
title: string
...
이제 에이전트 프롬프트에 "variant='elevated'와 푸터(footer)를 포함하여 Card 컴포넌트를 사용해줘"라고 입력하면, 에이전트는 관습(convention)을 임의로 만들어낼 필요 없이 해당 타입을 임포트(import)하면 됩니다. 동일한 패턴은 서버 함수(server functions), DB 쿼리(DB queries), 그리고 라우트 핸들러(route handlers)에도 적용됩니다. 모든 키트(kit)가 내보내진(exported) prop 타입을 제공하는 바로 이 이유 때문입니다.
3. 에이전트가 실제로 읽는 파일에 관습을 기록하세요
이것은 가장 효과가 큰 변화입니다. Cursor는 .cursorrules를 읽고, Claude Code는 CLAUDE.md를 읽습니다. 대부분의 리포지토리(repo)에는 이 두 파일이 모두 없습니다. 두 파일 모두 실행될 때마다 에이전트의 시스템 컨텍스트(system context)로 로드되는데, 이는 그곳에 작성된 내용이 에이전트가 다시 발견할 필요가 없는 영구적인 컨텍스트가 된다는 것을 의미합니다.
효과적인 .cursorrules는 짧습니다. 다음 세 가지를 수행합니다:
// .cursorrules
- @otfdashkit/ui의 컴포넌트를 사용하고, 새로운 것을 작성하지 마세요
- 토큰(Tokens)은 @otfdashkit/tokens에 있습니다. 색상/간격을 하드코딩(hardcode)하지 마세요
...
위의 각 불렛 포인트(bullet point)는 결과물 — 무엇을 사용할지, 어디에 배치할지 — 이며, 어떤 에이전트라도 이에 따라 행동할 수 있습니다. 30줄짜리 관습 파일이 있는 리포지토리는 문서화되지 않은 30,000줄의 코드가 있는 리포지토리보다 항상 더 나은 성능을 발휘합니다.
피해야 할 실수: 에이전트가 절대 읽지 않는 README에 관습을 작성하는 것입니다. README는 4,000단어짜리 문서를 훑어보고 필요한 부분을 뽑아낼 수 있는 인간을 위한 것입니다. 에이전트는 그렇게 하지 않습니다. 에이전트는 규칙 파일(rules file)을 읽고 나머지는 무시할 것입니다.
4. 테스트된 예시 프롬프트 — 아무도 제공하지 않는 부분
CLAUDE.md가 에이전트에게 규칙을 알려준다면, 테스트된 프롬프트 폴더는 성공적인 결과가 어떤 모습인지를 알려줍니다. 이 둘의 차이는 스타일 가이드(style guide)와 튜토리얼(tutorial)의 차이와 같습니다. 둘 다 유용하지만, 실제로 당신을 앞으로 나아가게 하는 것은 튜토리얼입니다.
효과적인 구조는 다음과 같습니다:
ai/
prompts/
01-add-a-new-page.md # 검증됨: 에이전트가 작동하는 라우트(route)를 생성함
...
각 프롬프트 파일은 세 가지 섹션으로 구성됩니다: 일반적인 영어로 작성된 작업(task), 에이전트가 수정해야 할 파일들, 그리고 검증 단계("렌더링이 되는가?", "테스트를 통과하는가?", "pnpm ship이 성공하는가?")입니다. 키트(kit)가 배포되기 전에, 누군가가 이 모든 프롬프트를 키트에 적용하여 실행해 보았고 출력이 정확함을 확인했습니다. 프롬프트 파일은 소스 파일과 마찬가지로 키트의 일부입니다.
이것은 샌드박스(sandbox) 도구들이 가지고 있지 않으며 쉽게 만들어낼 수 없는 부분입니다. 즉, "에이전트가 이 코드베이스에서 올바르게 수행한 작업의 검증된 예시가 여기 있으니, 다음 프롬프트는 이 선례를 따를 수 있다"라는 점입니다. 20개의 검증된 프롬프트는 하나의 코퍼스(corpus, 말뭉치)가 됩니다. 에이전트는 신입 사원이 PR(Pull Request)을 읽는 것과 같은 방식으로 이를 읽습니다.
5. 명령형 설정(imperative setup)보다 멱등성 스크립트(Idempotent scripts)가 낫다
에이전트는 12단계의 수동 설정을 안정적으로 수행할 수 없습니다. 하지만 하나의 스크립트는 안정적으로 실행할 수 있습니다. 키트에는 pnpm dev, pnpm test, pnpm ship, pnpm preview:mobile이 포함되어 있으며, 각각은 완전하고 결정론적인(deterministic) 작업을 수행합니다. 에이전트는 package.json을 읽고, 스크립트를 확인한 뒤, 이를 사용합니다.
{
"scripts": {
"dev": "vite",
...
pnpm ship은 커스텀 도메인, DNS, 그리고 TLS를 연결합니다. 에이전트는 그 방법을 알 필요가 없습니다. 그저 명령어를 실행할 뿐입니다. 과거에 암묵적 지식(tribal knowledge)이었던 모든 단계는 스크립트가 되며, 모든 스크립트는 에이전트가 호출할 수 있는 단일 호출 지점(single point of invocation)이 됩니다. 설정을 스크립트로 표현할 수 있다면 에이전트가 실행할 수 있습니다. 만약 설정이 Slack 스레드에 있다면, 에이전트는 실행할 수 없습니다.
샌드박스 출력물 vs 에이전트가 읽을 수 있는 저장소(repo)
[[COMPARE: 샌드박스에서 생성된 단일 파일 앱 vs 규칙과 프롬프트가 포함된 폴더 구조의 저장소로 배포된 OTF 키트]]
| 속성 | 샌드박스 출력물 | 에이전트가 읽을 수 있는 저장소 (OTF 키트) |
|---|---|---|
| 파일 레이아웃 | 4000줄짜리 단일 app.tsx | 관심사별 폴더 구분, 각 폴더당 하나의 컴포넌트 |
| ... |
오른쪽 열(column)의 방식이 공짜는 아니지만, 그렇다고 비용이 많이 드는 것도 아닙니다. 키트는 이런 방식으로 한 번 구축되면, 그것으로부터 시작하는 모든 프로젝트에서 재사용됩니다.
이를 통해 얻는 것
저는 지난주에 터미널에 npx otf-kit@latest saas-dashboard를 붙여넣는 것만으로 SaaS 대시보드를 만들기 시작했습니다. 2분 후, 저는 200개의 컴포넌트로 구성된 디자인 시스템, Postgres 스키마 (schema), Stripe 연동, .cursorrules, 그리고 CLAUDE.md가 포함된 폴더를 갖게 되었습니다. 에이전트 (agent)는 컨벤션 (conventions) 파일을 읽고 첫 번째 프롬프트 (prompt)에서 올바른 컴포넌트들을 사용했습니다. 제가 결제 플랜 페이지를 추가해 달라고 요청하자, 에이전트는 페이지를 생성했고, 테스트를 통과했으며, 제가 레이아웃 (layout)을 건드리지 않고도 개발 서버 (dev server)에서 이를 렌더링했습니다.
[[CONCEPT: 기록된 컨벤션, 내보내진 타입 (types), 멱등성이 보장된 스크립트 (idempotent scripts) — 에이전트가 읽을 수 있는 저장소 (repo)는 신입 사원도 온보딩 (onboard)할 수 있는 저장소입니다.]]
이것이 바로 테스트 기준입니다. 만약 시니어 엔지니어가 월요일에 당신의 저장소에 합류하여 README, CLAUDE.md, 그리고 기존 코드만 가지고 금요일에 기능을 배포할 수 있다면, AI 에이전트는 오후 시간 안에 똑같은 일을 해낼 수 있습니다. 만약 시니어 엔지니어가 결제 로직이 어디에 있는지 찾기 위해 30분 동안의 설명을 들어야 한다면, 에이전트에게는 가망이 없습니다.
모델이 바뀌어도 변하지 않는 부분
Cursor와 Claude Code는 6개월 뒤에 지금과는 다른 모습일 것입니다. 그 뒤에 있는 모델 (model)은 두 번 이상 교체될 것입니다. 하지만 위의 다섯 가지 속성은 변하지 않을 것입니다. 그것들은 에이전트의 속성이 아니라 코드베이스 (codebase)의 속성이기 때문입니다. 이번 주에 구축한 저장소는 모든 모델 업그레이드 과정에서도 에이전트가 읽을 수 있는 상태를 유지합니다. 왜냐하면 에이전트는 파일 트리 (file tree), 타입 (types), 컨벤션 파일, 그리고 검증된 프롬프트 (verified prompts)를 읽기 때문입니다. 이 중 그 어느 것도 루프 (loop) 안에 어떤 모델이 있느냐에 의존하지 않습니다.
이것이 바로 샌드박스 (sandbox) 도구들이 제공할 수 없는 계층입니다. 왜냐하면 그들에게는 제공할 저장소가 없기 때문입니다. 그들은 생성된 번들 (bundle)을 제공할 뿐입니다. 번들은 데모 (demo)용으로는 훌륭합니다. 하지만 당신이 그것을 확장하고 싶어지는 순간, 즉 에이전트가 당신을 대신해 확장해주기를 원하는 바로 그 순간부터 번들은 더 이상 훌륭하지 않게 됩니다.
OTF 키트가 존재하는 이유가 바로 이것입니다. 에이전트(그리고 신입 사원)가 읽을 수 있는 방식으로 이미 구조화된 저장소를 제공하며, 첫날부터 컨벤션, 타입, 스크립트, 그리고 검증된 프롬프트가 갖춰져 있기 때문입니다. Cursor를 사용하든, Claude Code를 사용하든, 다음에 출시될 어떤 에이전트를 사용하든 — 그것을 받아들일 준비가 된 코드베이스에서 시작하십시오.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기