메인 콘텐츠로 건너뛰기

AI 시대, 왜 우리를 ‘좋은 코드’로 몰아붙이는가 (개발자 필독)

“AI가 코드를 다 짜준다는데, 굳이 내가 코드를 잘 써야 하나요?”

요즘 정말 많이 듣는 질문입니다. 그런데 실제로 AI 에이전트를 제대로 써본 팀들은 정반대 이야기를 합니다.

AI를 많이 쓸수록, 좋은 코드의 기준은 더 높아지고, 안 좋은 코드의 비용은 훨씬 더 커집니다.

이 글에서는 왜 AI가 우리에게 좋은 코드를 “강요”하는지, 그리고 지금 코드베이스를 어떻게 바꿔야 AI 에이전트와 제대로 협업할 수 있는지 정리해 보겠습니다.

테스트, 문서, 타입, 디렉토리 구조 같은 고전적인 주제들이지만, AI와 함께 쓸 때 완전히 다른 의미를 갖게 됩니다.


AI와 함께 일한다는 건 무엇을 의미할까

요즘 AI 코딩 에이전트는 단순 자동 완성을 넘어서, 저장소를 통째로 읽고, 테스트를 돌리고, 파일을 수정하고, 몇 시간 동안 혼자 프로젝트를 진행하기도 합니다.1

겉으로 보면 “개발자 대신 일해주는 마법사”처럼 보이지만, 실제로는 생각보다 단순한 메커니즘으로 움직입니다.

AI 에이전트는 대략 이런 식으로 일합니다.

  1. 인간이 목표를 텍스트로 설명한다.

  2. 에이전트가 코드베이스를 둘러보며 “계획”을 세운다.

  3. 파일을 읽고, 수정하고, 테스트를 실행한다.

  4. 결과를 보고 다시 계획을 조정한다.

  5. 이 과정을 여러 번 반복한다.12

여기서 핵심은 두 가지입니다.

첫째, 에이전트는 코드의 의미를 “통계적 패턴”으로 이해한다는 점입니다.
둘째, 한 번에 인식할 수 있는 코드 양(컨텍스트)이 제한적이라는 점입니다.13

즉, 코드가 난잡하고 구조가 뒤엉켜 있으면, 인간도 이해하기 어렵지만 AI에겐 아예 “보이지” 않게 되기 쉽습니다.
반대로 구조가 잘 잡힌 코드, 작은 모듈, 명확한 이름, 일관된 패턴이 있는 코드베이스는 AI가 다루기 훨씬 쉽습니다.

그래서 나오는 결론이 하나입니다.

“AI를 많이 쓸수록, 좋은 코드의 기준은 더 엄격해진다.”


1. 테스트: AI가 믿을 수 있는 유일한 ‘진실의 기준’

AI 에이전트의 가장 큰 약점은 비정상적인 상황, 엣지 케이스에서 자신이 틀렸다는 걸 스스로 잘 모른다는 점입니다.1

그래서 에이전트에게는 사람이 코드 리뷰로 잡아주기 전에 미리 “이건 맞고, 이건 틀렸다”를 알려주는 자동 기준이 꼭 필요합니다. 그게 바로 테스트입니다.

100% 코드 커버리지는 왜 갑자기 진지한 옵션이 되었나

과거에는 “100% 커버리지”라는 말을 꺼내면, 대부분 “그건 이론적으로만 멋있지, 실무에선 시간 낭비”라고 했습니다.

하지만 AI 에이전트가 저장소 전반을 돌아다니며 코드를 생성·수정하는 시대에는 얘기가 달라집니다.

  • 에이전트가 새로 작성한 모든 코드 라인에 대해
    “이 라인이 실제로 실행돼서, 예상한 대로 동작하는지”를 자동으로 확인해야 합니다.

  • 그렇지 않으면, 에이전트가 만든 코드가 조용히 빠져나가 버그와 기술 부채를 쌓는 일이 아주 쉽게 발생합니다.

즉, 100% 커버리지는 개발자 양심을 위한 목표가 아니라, AI 에이전트를 위한 안전장치에 가깝습니다.

물론 현실적으로는 다음과 같이 접근하는 편이 좋습니다.

  • 도메인 핵심 로직, 복잡한 비즈니스 규칙:
    커버리지 100%에 가깝게 가져가고, 실패 시 빌드 차단.

  • 외부 연동, UI, 로그성 코드:
    중요도에 따라 커버리지 기준을 나누되, 최소한 스모크 테스트는 유지.

  • 에이전트가 손대는 범위:
    “테스트 없는 코드 변경은 금지”를 파이프라인 규칙으로 강제.

실제 대형 조직에서도 AI 도입 후 테스트와 검증 파이프라인이 가장 큰 병목이 되자, 테스트 자동화와 커버리지 확보를 AI로 보강하는 방향으로 움직이고 있습니다.4

테스트는 버그 잡기용이 아니다

테스트를 “버그 예방 도구” 정도로만 보면 AI 시대에 반쯤밖에 활용하지 못하는 겁니다.

AI에게 테스트는 사실상 “계약서” 역할을 합니다.

  • 이 API는 이런 입력에 이런 출력을 내야 한다.

  • 이 함수는 이 상태에서 이 예외를 던지면 안 된다.

  • 이 모듈은 이 시퀀스로 호출될 때만 유효하다.

에이전트는 이 계약서를 보고 움직입니다.

계약이 잘 정의되어 있으면, 에이전트는 그 안에서 활발하게 실험하고 리팩터링할 수 있지만,
계약이 허술하면, 에이전트는 “겉보기엔 돌아가지만 은근히 잘못된 코드”를 양산하게 됩니다.


2. 디렉토리와 파일 구조: AI에게 보여주는 ‘지도’ 만들기

AI 에이전트가 한 번에 읽을 수 있는 코드 양은 제한적입니다.
그래서 코드베이스 전체를 몽땅 보여주기보다는, 필요한 부분만 정확히 집어서 보여주는 게 중요합니다.13

여기서 디렉토리 구조와 파일 크기가 결정적인 역할을 합니다.

작은 파일, 명확한 모듈이 AI에게 유리한 이유

에이전트는 보통 다음 정보를 조합해 컨텍스트를 구성합니다.

  • 내가 수정 중인 파일

  • 연관된 다른 파일들 (import/require, 타입, 인터페이스)

  • 테스트 코드

  • 과거 커밋 히스토리와 문서 일부2

이때 한 파일이 1,000줄을 넘어가고, 서로 다른 역할이 뒤섞여 있으면 이런 일이 벌어집니다.

  • 에이전트가 한 파일만 읽어도 컨텍스트 용량을 상당 부분 소비한다.

  • 그 파일과 연관된 다른 파일들을 충분히 불러오지 못한다.

  • 결과적으로 “부분 맥락”만 이해한 채로 코드를 수정한다.

반대로, 파일이 작고 역할이 명확하면 상황이 완전히 달라집니다.

  • 에이전트가 여러 파일을 동시에 안전하게 컨텍스트에 올릴 수 있다.

  • 특정 책임을 가진 모듈만 집중해서 읽고 수정할 수 있다.

  • 검색과 참조가 쉬워져, 에이전트가 올바른 파일을 찾기 쉽다.

요약하면, “작고 잘 잘린 파일”은 인간만을 위한 게 아니라 AI를 위한 최적화이기도 합니다.

좋은 파일 이름과 디렉토리 구조는 최고의 프롬프트다

에이전트는 코드를 읽기 전에 먼저 “어떤 파일을 읽을까?”를 결정해야 합니다.
이때 가장 처음 보는 힌트가 바로 파일명과 디렉토리명입니다.23

예를 들어 이런 구조를 생각해 볼 수 있습니다.

  • src/billing/domain/Invoice.ts

  • src/billing/application/GenerateInvoiceService.ts

  • src/billing/infrastructure/StripeInvoiceClient.ts

  • tests/billing/GenerateInvoiceService.spec.ts

이런 식으로 의미가 드러나는 구조를 갖고 있으면, 에이전트는 다음 같은 추론을 자연스럽게 합니다.

  • “결제 관련 로직이니까 billing 아래를 보면 되겠군.”

  • “도메인 개념은 domain에, 외부 연동은 infrastructure에 있겠지.”

  • “테스트는 tests/billing 쪽에 찾으면 되겠다.”

반대로 utils.js, common.ts, new.ts 같은 애매한 이름이 많으면 에이전트는 파일을 “찍어보면서” 탐색해야 합니다. 그만큼 쓸데없는 컨텍스트가 쌓이고, 실수 확률도 높아집니다.

결국 파일명과 디렉토리 구조는 AI에게 주는 암묵적인 프롬프트입니다.
“우리 프로젝트는 이렇게 생각하고, 이렇게 나눴다”라는 신호를 코드 구조 자체로 전달하는 셈이죠.


3. 정적 타이핑과 타입스크립트: AI의 혼란을 줄이는 최강 무기

AI가 코드를 생성할 때 가장 많이 실수하는 지점 중 하나가 데이터 흐름과 상태입니다.
“여기서 이 객체에 이런 필드가 있던가?” 같은 것을 헷갈리기 쉬운 거죠.

이 문제를 줄이는 가장 확실한 방법이 정적 타이핑입니다.

타입이 강한 언어가 AI에게 좋은 이유

타입 시스템은 인간에게도 친절하지만, AI에게는 거의 치트키에 가깝습니다.

  • 어떤 함수가 어떤 타입을 받고 무엇을 반환하는지 명시적으로 알 수 있습니다.

  • 상태(state)가 어떤 형태를 가지는지, 어떤 상태 전이가 합법적인지 제한할 수 있습니다.

  • 컴파일러 에러를 통해 AI가 만든 코드의 잘못된 부분을 빠르게 피드백할 수 있습니다.

정적 타입이 없는 코드에서는 에이전트가 이런 것들을 다 추측해야 합니다.
반면 타입 정보가 잘 정리되어 있으면, 에이전트는 타입 정의만 훑어봐도 전체 시스템의 경계를 금방 파악할 수 있습니다.

그래서 많은 팀이 AI와 함께 쓸 전용 스택으로 타입스크립트 같은 타이핑이 강한 언어를 선택합니다.2

  • 프런트엔드/백엔드 모두 TypeScript로 통일

  • 상태 머신, 비즈니스 규칙, API 스펙을 타입으로 표현

  • 에이전트에게 타입 정의 파일부터 읽게 해서 전체 구조를 파악하도록 유도

이렇게 하면 에이전트가 “마구잡이로” 코드를 건드리는 게 아니라, 타입이 허용하는 범위 안에서만 움직이게 만들 수 있습니다.

타입은 AI에게 줄 수 있는 가장 싸고 강력한 가이드라인

에이전트에게 “이 값은 여기서 절대 null이면 안 돼” 같은 걸 문서로 장황히 설명하는 것보다,
타입 시스템으로 NonNullable, Union, Discriminated Union 등을 활용해 표현하는 편이 훨씬 명확합니다.

인간은 문서를 대충 읽고 실수할 수 있지만, AI는 타입 에러를 보고 즉시 수정을 시도합니다.
즉, 타입은 AI에게 줄 수 있는 가장 저렴하면서도 강력한 가이드라인입니다.


4. 실시간 테스트 환경과 다중 개발 환경 자동화

AI 에이전트의 생산성을 높이려면, “시도 → 실행 → 피드백” 루프가 최대한 빠르게 돌아가야 합니다.

그래서 중요한 두 가지 인프라 요소가 등장합니다.

  1. 빠른 실시간 테스트 환경

  2. 여러 개발 환경의 자동 구성 및 운영

에이전트에게 빠른 피드백 루프를 제공하라

에이전트가 코드를 수정할 때마다 테스트를 직접 실행해 보고, 실패하면 다시 코드를 고치고, 또 테스트를 돌리는 패턴이 일반적입니다.13

이 루프가 느리면 다음과 같은 일이 벌어집니다.

  • 에이전트가 오래 기다리다 타임아웃

  • 테스트 한 번 돌릴 때마다 토큰/비용 소모 증가

  • 결국 사람도 AI도 테스트 돌리기를 기피하게 됨

반대로, 테스트 실행이 빠르면 상황이 완전히 달라집니다.

  • 에이전트가 작은 단위로 자주 테스트를 돌린다.

  • 실패 → 수정 → 재실행을 자동으로 여러 번 반복한다.

  • 사람은 “테스트가 전부 초록인 상태의 결과물”만 검토하면 된다.

이를 위해 많은 팀이 다음을 고민합니다.

  • 테스트를 단위 테스트/통합 테스트/엔드 투 엔드로 나누고, 에이전트에게는 주로 단위 테스트만 자주 돌리게 설정.

  • DB, 외부 서비스는 최대한 테스트 더블/로컬 환경으로 대체.

  • 변경된 파일과 직접 관련된 테스트만 우선 실행하는 전략 도입.

“환경 세팅”을 자동화해야 에이전트가 빛난다

에이전트는 로컬 또는 샌드박스 컨테이너에서 커맨드를 직접 실행할 수 있습니다.1
문제는, 환경 세팅이 복잡하면 에이전트도 똑같이 고생한다는 점입니다.

  • OS, 런타임, 패키지 매니저 버전이 제각각

  • .env 설정이 수동으로 이루어짐

  • 특정 서비스는 팀장만 알고 있는 비공개 스크립트를 사용

이런 환경에서는 사람도 힘들지만, 에이전트는 거의 아무것도 못 합니다.

그래서 AI를 제대로 쓰는 팀들은 개발 환경 자체를 코드로 관리하려고 합니다.

  • Dev 컨테이너, Docker Compose, Infra as Code(Terraform 등)로 개발 환경 통일

  • “이 명령 하나만 실행하면, 테스트 가능한 환경이 자동으로 뜨게” 만드는 스크립트

  • 여러 개의 독립된 개발 환경을 병렬로 띄울 수 있는 인프라

이렇게 해두면, 에이전트 여러 개가 서로 다른 브랜치나 실험을 동시에 돌리는 것도 가능합니다.4

결과적으로 사람은 “환경 세팅”이라는 귀찮고 반복적인 작업에서 완전히 해방되고,
에이전트는 언제나 같은 규칙과 환경에서 안정적으로 코드를 다룰 수 있습니다.


5. AI 에이전트가 강요하는 “장기적인 코드베이스 목표”

AI 시대에 살아남는 팀과 그렇지 못한 팀의 차이는,
“AI를 도입했느냐”가 아니라 “AI가 일하기 좋은 코드베이스를 만들었느냐”입니다.

여기서 장기 목표는 꽤 명확합니다.

  1. 강력한 코드베이스

    • 잘 정의된 모듈 경계

    • 높은 수준의 테스트와 타입 안정성

    • 일관된 패턴과 규칙

  2. 잘 정의된 환경

    • 자동화된 개발 환경 세팅

    • 빠른 테스트 인프라

    • AI 에이전트가 따라야 할 가이드라인과 툴링

  3. 지속적인 툴 개선

    • 에이전트가 남긴 로그와 실패 사례를 수집

    • 자주 틀리는 패턴을 규칙·템플릿·유틸리티 코드로 흡수

    • 에이전트와 코드베이스가 함께 학습하는 “루프” 구축23

이런 상태에 도달하면, AI는 단순한 자동 완성 도구가 아니라
“팀의 일하는 방식을 증폭시키는 시스템”이 됩니다.

반대로 테스트가 부족하고, 구조가 뒤엉켜 있고, 타입이 없고, 환경이 제각각이면,
AI 에이전트는 그 혼란을 그대로 증폭시켜 버립니다.

버그, 기술 부채, 보안 리스크 모두 AI 속도로 늘어나는 셈입니다.


시사점: 지금 당장 바꿔야 할 것들

정리해 보면, AI 에이전트는 우리에게 이렇게 말하고 있습니다.

  • “테스트 좀 더 써줘. 그래야 내가 덜 사고 쳐.”

  • “파일 좀 작게 나눠줘. 그래야 내가 한 번에 이해할 수 있어.”

  • “타입 좀 명확히 써줘. 그래야 내가 덜 헷갈려.”

  • “환경 좀 자동화해줘. 그래야 내가 마음껏 실험해볼 수 있어.”

좋은 코드는 더 이상 “예쁜 코드”가 아닙니다.
이제 좋은 코드는 “기계와 인간이 모두 안전하게 다룰 수 있는 코드”입니다.

그래서 현실적인 실행 계획을 이렇게 제안합니다.

  1. 새로 만드는 기능부터는

    • TypeScript 등 정적 타이핑을 적극 도입하고

    • 모듈 경계를 의식해서 작은 파일로 나누고

    • 테스트와 타입 정의를 “AI에게 줄 사양”이라고 생각하고 작성한다.

  2. 기존 코드베이스는

    • AI 에이전트와 함께 리팩터링하는 작은 실험을 시작하고

    • 그 과정에서 나온 실패·성공 패턴을 팀 규칙과 템플릿으로 승격한다.

  3. 인프라 측면에서는

    • git clone 후 한 줄 명령으로 개발 환경이 준비되도록 만들고

    • 단위 테스트를 빠르게 돌릴 수 있는 파이프라인을 먼저 고친다.

AI가 개발자를 대체할까요?
아마도 “효율적인 시스템을 설계하고 유지할 수 있는 개발자”만 남게 만들 가능성은 큽니다.

그 첫 단계는 거창한 AI 전략이 아니라,
지금 눈앞의 코드 한 줄을 AI가 이해하기 좋은 방향으로 바꾸는 것에서 시작합니다.


참고

1How AI coding agents work—and what to remember if you use them

2Compound Engineering: How Every Codes With Agents

4How AI-Enabled Tooling Boosted Code Output 30% — While Keeping Quality and Deployment Safety Intact

이 노트는 요약·비평·학습 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.