[AI가 읽을 수 있는 코드베이스 2/5] 빌드 피드백이 AI를 가르친다

기술 블로그
페이스북링크드인트위터

빌드 에러는 모두 같지 않다

1화에서 빌드 가드레일이 자연어 가이드라인보다 AI 에이전트에게 효과적이라는 것을 이야기했습니다. 하지만 "빌드가 실패한다"는 말 안에는 다양한 피드백 유형이 숨어 있습니다. 컴파일 에러, 의존성 미해결, ktlint 위반, 테스트 실패 — 각각은 에이전트에게 완전히 다른 품질의 정보를 전달합니다.

AI 코딩 에이전트의 관점에서, 빌드 피드백의 품질은 세 가지 차원으로 평가할 수 있습니다.

차원 설명
위치 특정성 에러가 발생한 파일과 라인을 정확히 가리키는가
원인 명확성 "왜" 에러인지가 메시지에 담겨 있는가
수정 방향 유추 가능성 에러 메시지만으로 올바른 수정 방향을 추론할 수 있는가

이 세 차원에서 각 빌드 피드백 유형을 분석해보겠습니다.


피드백 유형 1: 컴파일 에러 — 가장 이상적인 피드백

Kotlin
e: file:///issue/model/src/main/kotlin/com/example/issue/model/Issue.kt:3:8
  Unresolved reference: springframework

> Task :issue:model:compileKotlin FAILED
차원 평가
위치 특정성 최고. 파일 경로, 라인 번호, 컬럼까지 지정
원인 명확성 높음. "Unresolved reference"는 해당 심볼이 이 모듈에서 접근 불가하다는 것을 의미
수정 방향 유추 높음. 해당 import를 제거하거나, 의존성을 추가하거나, 다른 모듈로 코드를 옮기는 세 가지 선택지가 명확

컴파일 에러는 AI 에이전트에게 가장 이상적인 피드백입니다. 위치가 정확하고, 원인이 명확하고, 수정 방향이 유추 가능합니다. flex의 Gradle 멀티모듈 구조에서 이 유형의 피드백이 자주 발생하는 이유는, 모듈 간 의존성이 build.gradle.kts에 명시적으로 선언되기 때문입니다. 허용되지 않은 모듈의 클래스를 import하면 컴파일 자체가 불가능합니다.

에이전트가 이 에러를 만나면 일반적으로 다음과 같은 수정 패턴을 보입니다.

핵심은 "아키텍처 위반" 분기입니다. 에이전트가 issue:model에서 issue:infrastructure의 클래스를 참조하려 할 때, 의존성을 추가하면 컴파일은 되겠지만 아키텍처를 깨뜨립니다. flex의 Convention Plugin은 이런 추가 자체를 빌드 시점에 차단합니다. 에이전트는 "의존성 추가도 안 되네?"라는 두 번째 피드백을 받고, 결국 코드를 올바른 모듈로 이동하는 방향을 선택합니다.


피드백 유형 2: 의존성 미해결 — 구조적 가드레일

Kotlin
> Could not resolve all files for configuration ':issue:standalone-app:compileClasspath'.
   > Could not find com.example.permission:protocol.

> Task :issue:standalone-app:compileKotlin FAILED

실제로 standalone-app의 빌드 설정에는 이 모듈들이 명시적으로 제외되어 있습니다. 전이 의존성으로 들어올 수 있는 프로덕션 전용 모듈을 차단하는 구조적 결정입니다. 에이전트가 permission 관련 코드를 standalone-app에 넣으려 하면, 의존성 해석 자체가 실패합니다.

이 유형의 피드백은 "네가 사용하려는 것이 이 맥락에서는 존재하지 않는다"를 전달합니다. 에이전트에게는 "이 모듈의 경계 밖에 있는 것을 쓰려 하고 있다"는 구조적 신호입니다.


피드백 유형 3: ktlint / detekt 위반 — 스타일 가드레일

Kotlin
/issue/service/src/main/kotlin/IssueService.kt:15:1: 
  Unexpected blank line(s) before "}" (no-blank-line-before-rbrace)

> Task :issue:service:ktlintCheck FAILED
차원 평가
위치 특정성 중간. 어떤 configuration에서 실패했는지는 알 수 있지만, 코드의 어느 줄이 트리거인지는 직접적으로 알려주지 않음
원인 명확성 높음. "Could not find X" — 어떤 아티팩트가 없는지 명확
수정 방향 유추
차원 평가
위치 특정성 최고. 파일, 라인, 규칙 이름까지 제공
원인 명확성 최고. 규칙 이름이 곧 설명
수정 방향 유추 최고. 대부분 ktlintFormat으로 자동 수정 가능

스타일/포맷 영역에서 ktlint 위반은 피드백 품질이 가장 높은 유형입니다. 하지만 아키텍처적으로는 가장 덜 중요합니다. ktlint 포맷 위반은 ./gradlew ktlintFormat으로 자동 수정이 가능하고, detekt 규칙 위반은 코드 구조 판단이 필요한 경우가 많습니다. 흥미로운 점은 ktlint가 에이전트의 "무의식적 패턴"을 교정한다는 것입니다. 에이전트는 학습 데이터에 있는 다양한 코딩 스타일을 섞어서 코드를 생성합니다. 프로젝트의 일관된 스타일은 ktlint가 강제합니다. 몇 번의 피드백 루프를 거치면, 에이전트도 해당 프로젝트의 스타일에 맞는 코드를 처음부터 생성하는 경향을 보입니다.


피드백 유형 4: 테스트 실패 — 가장 풍부하지만 가장 어려운 피드백

Kotlin
IssueCreateUseCaseTest > should create issue with generated code FAILED
    org.opentest4j.AssertionFailedError: 
    expected: "ISS-0001"
    but was: null

    at com.example.issue.service.IssueCreateUseCaseTest.should create issue(IssueCreateUseCaseTest.kt:45)

> Task :issue:service:test FAILED
차원 평가
위치 특정성 높음. 실패한 테스트 클래스와 라인 번호 제공
원인 명확성 중간. "expected vs actual"은 보여주지만, "왜 null인지"는 추론 필요
수정 방향 유추 낮음~중간. 테스트 코드와 프로덕션 코드, 양쪽을 분석해야 원인 파악 가능

테스트 실패는 가장 풍부한 정보를 담고 있지만, 에이전트가 처리하기 가장 어려운 유형이기도 합니다. "expected ISS-0001 but was null"이라는 메시지를 보고, 에이전트는 다음을 추론해야 합니다.

  1. issueCode가 어디에서 생성되는가? (SequenceGenerator)
  2. 테스트에서 SequenceGenerator가 제대로 주입되었는가?
  3. Mock이 올바르게 설정되었는가?

이 추론 체인이 길어질수록 에이전트의 수정 정확도는 떨어집니다. 그래서 테스트의 설계 자체가 AI 접근성에 영향을 줍니다. 좋은 테스트는 실패 메시지만으로 수정 방향을 유추할 수 있게 작성되어야 합니다.


피드백 유형별 비교 매트릭스

이 매트릭스에서 가장 주목할 영역은 오른쪽 위 사분면 — 아키텍처를 보호하면서 수정도 용이한 피드백입니다. 컴파일 에러가 이 영역에 위치합니다. 이것이 flex가 "빌드가 지킨다"를 반복하는 이유입니다. 가장 중요한 규칙을 가장 효과적인 피드백 유형으로 강제하고 있기 때문입니다.


IaC(Pulumi)에서의 빌드 피드백

빌드 피드백의 위력은 백엔드 코드에만 한정되지 않습니다. 본편 6화에서 언급한 것처럼, 인프라 코드베이스의 Pulumi 프로젝트도 Kotlin으로 IaC를 작성합니다. 이는 인프라 코드에서도 동일한 빌드 피드백 체계가 작동한다는 뜻입니다.

HCL(Terraform) vs Kotlin(Pulumi)의 피드백 비교

Kotlin
// Kotlin + Pulumi: 리소스 간 참조가 타입 안전
val vpc = Vpc("main-vpc", ...)
val subnet = Subnet("public", SubnetArgs.builder()
    .vpcId(vpc.id())  // vpc가 삭제되면 컴파일 에러
    .build()
)
비교 항목 HCL (Terraform) Kotlin (Pulumi)
피드백 시점 terraform validate 또는 plan (검증 범위에 따라 다름) ./gradlew build (로컬, 즉시)
Credential 필요 여부 validate 는 불필요, plan 은 필요 컴파일에는 불필요
타입 안전성 선언/런타임 단계 검증 컴파일 타임 검증
리팩토링 지원 문자열 기반 참조 IDE 리팩토링, 참조 추적
AI 에이전트 피드백 루프 느림 (API 호출 대기) 빠름 (로컬 컴파일)

실제로 인프라 코드베이스 Pulumi 프로젝트의 모든 코드 변경이 AI 에이전트(Claude Code)와의 대화로 생성되었다는 경험은, Kotlin 기반 IaC의 빌드 피드백이 에이전트에게 충분히 실용적인 피드백이 될 수 있음을 보여줍니다.

에이전트가 리소스 빌더에 타입이 맞지 않는 값을 넘기거나, 코드에서 제거된 VPC 객체를 계속 참조하면 ./gradlew build가 즉시 잡아냅니다. HCL에서도 일부 참조 오류는 terraform validate에서 잡히지만, provider 상태와 결합된 검증은 terraform plan까지 가야 합니다. 그 순간 실제 AWS credential이 필요해지고, AI 에이전트의 피드백 루프 속도에서 결정적인 차이가 생깁니다.


빌드 피드백 품질을 높이는 설계 원칙

지금까지의 분석을 종합하면, AI 에이전트를 위한 빌드 피드백 품질을 높이려면 다음 원칙이 필요합니다.

원칙 1: 가능한 한 컴파일 타임으로 옮겨라

런타임 검증보다 컴파일 타임 검증이, 컴파일 타임 검증보다 타입 시스템 강제가 에이전트에게 더 좋은 피드백입니다. flex의 모듈 간 의존성 제한이 이 원칙의 전형적 사례입니다.

원칙 2: 에러 메시지에 맥락을 담아라

Kotlin
// 나쁜 에러 메시지
BUILD FAILED

// 좋은 에러 메시지
> Task :issue:model:compileKotlin FAILED
e: file:///issue/model/src/main/kotlin/Issue.kt:3:8
  Unresolved reference: springframework

원칙 3: 빌드 실패는 빠르게, 성공은 정확하게

./gradlew build가 10분 걸린다면, 에이전트의 피드백 루프도 10분이 됩니다. 모듈 단위 빌드(./gradlew :issue:model:compileKotlin)가 가능한 구조에서, 에이전트는 변경한 모듈만 빠르게 빌드하고 피드백을 받을 수 있습니다.

원칙 4: 테스트 실패 메시지를 피드백으로 설계하라

테스트는 "통과/실패" 바이너리가 아니라, 실패 시 수정 방향을 유추할 수 있는 메시지를 제공하도록 설계되어야 합니다. expected: "ISS-0001" but was: null보다 Issue code generation failed: SequenceGenerator returned null for tenant=CUSTOMER:1이 에이전트에게 더 나은 피드백입니다.


빌드 피드백 계층 구조

이 네 가지 피드백 유형은 하나의 계층을 형성합니다.

위로 갈수록 피드백이 빠르고 명확합니다. 아래로 갈수록 검증 범위가 넓지만 원인 추적이 어렵습니다. flex의 아키텍처가 효과적인 이유는, 가장 중요한 아키텍처 규칙을 가장 위 계층(컴파일 에러)에서 잡기 때문입니다.

이것이 1화에서 소개한 "빌드가 지킨다"의 구체적인 메커니즘입니다. 모든 빌드 에러가 동등한 것이 아니라, 에러의 유형에 따라 AI 에이전트에 대한 교육 효과가 달라집니다. 그리고 flex는 가장 교육 효과가 높은 유형 — 컴파일 에러 — 으로 가장 중요한 규칙을 강제하고 있습니다.


빌드 피드백이 빠르게 작동하려면, 에이전트가 수정한 코드를 전체 시스템 없이도 즉시 실행해볼 수 있는 환경이 전제되어야 합니다.

다음 화 — Standalone App — 도메인을 꺼내 독립 실행한다. issue:standalone-app의 실제 코드를 열어보고, Hexagonal Architecture의 Adapter 교체가 어떻게 독립 실행 가능한 도메인 슬라이스를 만드는지 상세 분석합니다. (2축 프레임워크의 A축: 빌드 피드백 품질, 모듈 경계 예측 가능성)

🚀플렉스팀 채용페이지 바로가기☕flex Private Talk 신청하기
글이 마음에 드셨나요?
공유하기
페이스북링크드인트위터
flex가 궁금하다면? 지금 무료로 체험해 보세요
flex가 궁금하다면? 지금 무료체험하기
  • 기술 블로그
    2026. 5. 20
    [AI가 읽을 수 있는 코드베이스 1/5] 프롬프트보다 구조가 먼저다
    프롬프트 엔지니어링보다 코드베이스 구조가 AI 활용의 하한선을 결정한다
  • 아티클
    2020. 5. 25
    근태관리, 유연근무제, 그리고 코로나 시대
    코로나, 뉴노멀, 유연근무제, 그리고 근태관리