메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

AI 코딩에 테스트와 명세가 필요한 이유: “일단 만들어줘”의 함정

AI 코딩 도구를 처음 써보면 누구나 한 번쯤 이런 요청을 하게 됩니다

 

“TODO 앱 하나 만들어줘.”

로그인 기능 붙여줘.”

관리자 페이지도 만들어줘.”

 

놀랍게도 AI는 꽤 그럴듯한 결과물을 만들어냅니다예전 같으면 며칠이 걸렸을 기능이 몇 분 만에 화면으로 나타나고, API가 만들어지고테스트 코드까지 붙기도 합니다개발자는 더 이상 모든 코드를 직접 타이핑하지 않아도 됩니다이제 AI는 단순한 자동완성 도구를 넘어요구사항을 이해하고 코드를 생성하며 테스트와 리팩터링까지 도와주는 개발 파트너에 가까워지고 있습니다아니그런 줄 알았습니다.

 

하지만 바로 이 지점에서 새로운 문제가 시작됩니다. 지난 글에서는 이 변화 속에서 개발자의 역할이 어떻게 달라지는지 살펴봤습니다. AI 시대의 개발자는 단순 구현자라기보다, AI와 함께 일하는 방식 자체를 설계하는 사람에 가까워지고 있습니다그렇다면 다음 질문은 자연스럽게 이어집니다. AI에게 코드를 맡길 수 있다면그 결과물은 어떻게 믿을 수 있을까요?

 

결국 AI가 빠르게 코드를 만드는 시대일수록개발자는 더 명확하게 명세를 쓰고 더 철저하게 테스트해야 합니다명세는 AI에게 무엇을 만들 것인가를 알려주는 기준이고테스트는 AI가 만든 코드가 그 기준을 제대로 만족하는지 확인하는 안전장치입니다. 이번 글에서는 일단 만들어줘” 방식이 왜 위험할 수 있는지그리고 AI 코딩에 왜 테스트와 명세가 필요한지 살펴보겠습니다.

 

 

AI는 빠르지만방향을 보장하지 않는다

 

AI 코딩 도구의 가장 큰 매력은 속도입니다예전에는 코드를 한 줄씩 직접 작성해야 했기 때문에개발자는 자연스럽게 어떻게 만들 것인가를 먼저 고민했습니다코드 한 줄에도 시간이 들었고잘못 만든 구조는 나중에 더 큰 비용으로 돌아왔기 때문입니다.

 

그런데 AI가 코드를 순식간에 만들어주기 시작하면서 상황이 달라졌습니다이제는 고민보다 생성이 먼저가 되기 쉽습니다. “일단 만들어보고아니면 다시 만들면 되지라는 접근이 가능해진 것입니다실제로 클로드 코드 같은 AI 코딩 도구에게 “TODO 앱 만들어줘라고 요청하면 몇 분 안에 동작하는 코드가 나옵니다화면이 뜨고버튼이 동작하고데이터가 저장되는 모습을 보면 설계 없이 바로 구현에 들어가고 싶어집니다.

 

하지만 이것이 바로 일단 만들어줘” 방식의 함정입니다. AI는 코드를 빠르게 만들 수 있지만그 코드가 올바른 방향인지까지 보장해주지는 않습니다처음에는 그럴듯하게 동작하던 코드도 요구사항이 구체화될수록 쉽게 흔들릴 수 있습니다개인용으로 쓸 TODO 앱인지팀 단위로 공유하는 업무 관리 도구인지, SaaS로 서비스할 제품인지고객사 내부망에 설치해야 하는 온프레미스 솔루션인지에 따라 필요한 구조는 완전히 달라집니다.

 

 

예를 들어 처음에는 단순히 “TODO 웹 애플리케이션 만들어줘라고 요청했다고 해봅시다. AI는 개인용 CRUD 앱을 만들어줄 수 있습니다그런데 며칠 뒤 팀 공유 기능도 추가해줘라고 요청하면 인증과 권한 시스템이 필요해집니다다시 “SaaS처럼 조직별로 사용할 수 있게 해줘라고 하면 멀티테넌시 구조가 필요해지고, “온프레미스 설치 옵션도 필요해라고 하면 환경 설정과 배포 구조까지 다시 설계해야 합니다.

 

이 과정에서 처음 만든 코드는 더 이상 버티기 어려워집니다기능을 하나씩 덧붙일수록 반복 수정과 리팩터링이 늘어나고코드 일관성은 떨어지며예상하지 못한 오류가 생깁니다심하면 지금까지 만든 코드를 밀어내고 처음부터 다시 작성해야 할 수도 있습니다.

 

문제는 AI TODO 앱을 못 만들어서가 아닙니다처음에 우리가 어떤 TODO 앱을 만들 것인지” 정의하지 않았기 때문입니다.

 

AI어떻게 구현할지에는 강합니다하지만 무엇을 만들어야 하는지”, “어떤 구조가 이 제품에 맞는지”, “지금 만들지 않아야 할 것은 무엇인지는 개발자가 먼저 정해야 합니다설계는 거창한 문서를 만드는 일이 아닙니다요구사항을 정리하고필요한 기능과 필요하지 않은 기능을 구분하고데이터와 API의 흐름을 미리 결정하는 일입니다.

 

AI가 빠르게 코드를 만드는 시대일수록 설계는 더 중요해집니다. 생성 속도가 빨라졌다는 것은 잘못된 방향으로도 더 빨리 달려갈 수 있다는 뜻이기 때문입니다그래서 일단 만들어줘” 다음에 필요한 것은 더 많은 프롬프트가 아니라, AI가 따라갈 수 있는 명확한 기준입니다.

 

 

AI가 만든 코드는 왜 테스트로 검증해야 할까?

 

설계를 통해 AI가 나아갈 방향을 정했다면다음으로 필요한 것은 그 결과를 확인하는 기준입니다. AI가 코드를 빠르게 만들어준다고 해서그 코드가 항상 같은 방식으로 만들어지는 것은 아니기 때문입니다.

 

전통적인 프로그래밍은 비교적 결정적입니다. 같은 소스 코드를 컴파일하면 같은 결과가 나오고같은 입력을 넣으면 같은 로직을 따라 같은 출력이 나옵니다하지만 AI 코딩 도구는 다릅니다같은 요청을 하더라도 매번 조금씩 다른 구현을 제안할 수 있습니다

 

사용자 입력을 검증하는 함수를 만들어줘라고 요청했을 때어떤 때는 정규식을 사용하고어떤 때는 조건문을 나열하고또 어떤 때는 외부 라이브러리를 가져올 수 있습니다모두 그럴듯해 보일 수 있지만구현 방식과 세부 동작은 달라질 수 있습니다.

 

문제는 여기서 끝나지 않습니다기존 코드의 일부만 수정해달라고 했는데 관련 없는 파일이나 로직까지 함께 바꾸는 경우도 있습니다빌드와 테스트가 성공했다고 말하지만실제로 확인해보면 그렇지 않은 경우도 있습니다, AI의 답변은 그럴듯할 수는 있지만 그것만으로 충분한 검증이 되지는 않습니다.

 

이때 필요한 것이 테스트입니다.

 

테스트는 AI의 비결정성에 대응하는 결정적인 기준이 됩니다. AI가 어떤 방식으로 코드를 구현했는지는 중요하지 않습니다중요한 것은 그 코드가 우리가 기대한 동작을 만족하느냐입니다테스트를 통과하면 최소한 정의한 요구사항은 충족한 것이고통과하지 못하면 아직 요구사항을 만족하지 못한 것입니다.

 

특히 AI 코딩 환경에서 TDD, 즉 테스트 주도 개발은 더 중요해집니다. TDD에서는 구현보다 테스트를 먼저 작성합니다이는 단순히 버그를 줄이기 위한 절차가 아닙니다. “이 기능은 이렇게 동작해야 한다라는 요구사항을 실행 가능한 코드로 고정하는 과정입니다. 다시 말해 테스트는 코드의 품질을 확인하는 도구이면서동시에 AI가 따라야 할 명세가 됩니다.

 

예를 들어 TODO 앱에서 새로운 할 일을 추가하면 목록에 나타나야 한다”, “완료된 할 일의 개수를 정확히 계산해야 한다와 같은 테스트를 먼저 작성해두면, AI는 그 테스트를 통과하는 방향으로 코드를 구현해야 합니다이때 개발자는 구현 세부 사항을 모두 직접 작성하지 않더라도원하는 동작의 기준은 분명히 정할 수 있습니다.

 

반대로 테스트 없이 AI에게 “TODO 기능 만들어줘라고 요청하면 AI가 기능의 범위와 동작 방식을 스스로 해석하게 됩니다처음에는 그럴듯해 보일 수 있지만나중에 요구사항과 어긋난 부분을 발견하면 어디서부터 잘못됐는지 추적하기 어려워집니다.

 

결국 테스트는 AI를 믿기 위한 장치라기보다, AI가 만든 결과를 확인하기 위한 객관적인 검문소입니다. AI가 빠르게 코드를 만들수록 개발자는 더 빠르게 확인할 수 있는 기준을 준비해야 합니다그 기준이 없으면 우리는 AI가 만든 코드를 좋아 보인다는 감각으로 판단하게 됩니다하지만 운영 가능한 소프트웨어에는 감각이 아니라 검증이 필요합니다.

 

 

AI에게도 TDD 순서를 알려줘야 한다

 

테스트가 중요하다는 사실을 안다고 해서 AI가 자동으로 TDD 방식에 맞춰 개발해주는 것은 아닙니다오히려 AI 코딩 도구는 사용자의 요청을 빠르게 완성하려는 방향으로 움직이기 때문에, 테스트 주도 개발의 순서를 건너뛰는 경우가 많습니다.

 

예를 들어 로그인 기능을 TDD로 만들어줘라고 요청해도 AI는 테스트와 구현을 한 번에 작성하려 할 수 있습니다더 심하면 구현 코드를 먼저 만든 뒤그 코드에 맞춰 테스트를 끼워 넣기도 합니다겉으로 보기에는 테스트가 있는 코드처럼 보이지만이런 방식의 테스트는 요구사항을 검증하는 기준이라기보다 이미 작성된 구현을 정당화하는 문서에 가까워집니다.

 

TDD의 핵심은 순서에 있습니다먼저 실패하는 테스트를 작성하고그 테스트를 통과시키는 최소한의 구현을 만든 뒤테스트가 통과하는 상태를 유지하면서 코드를 정리해야 합니다이 흐름을 흔히 Red → Green → Refactor라고 부릅니다실패하는 테스트를 통해 요구사항을 먼저 고정하고그다음 구현이 그 기준을 만족하는지 확인하는 방식입니다.

 

AI와 함께 TDD를 할 때는 이 순서를 더 명확하게 지시해야 합니다. “기능을 구현하고 테스트도 작성해줘가 아니라단계별로 요청을 나눠야 합니다.

 

첫 번째 단계에서는 구현을 금지하고 테스트만 작성하게 합니다.

아직 구현하지 마먼저 테스트만 작성해줘.”

 

두 번째 단계에서는 테스트를 통과시키는 최소한의 코드만 요청합니다.

방금 작성한 테스트를 통과시키는 최소한의 구현만 해줘.”

 

세 번째 단계에서는 테스트가 통과하는 상태를 유지한 채 리팩터링을 요청합니다.

테스트가 통과하는 상태를 유지하면서 중복을 제거하고 코드를 정리해줘.”

 

이렇게 요청을 나누면 AI가 한 번에 모든 것을 해결하려고 하면서 생기는 문제를 줄일 수 있습니다테스트와 구현이 뒤섞이지 않고각 단계에서 무엇을 검증해야 하는지도 분명해집니다실패하는 테스트가 먼저 존재하기 때문에 AI는 그 테스트를 통과해야 하는 방향으로 구현을 조정하게 됩니다.

 

 

주의할 점도 있습니다. AI가 테스트를 통과시키기 위해 테스트 자체를 느슨하게 바꾸거나실패하는 테스트를 건너뛰기 위해 skip 처리할 수 있습니다그래서 테스트를 수정하지 말고 구현 코드만 수정해”, “실패한 테스트를 삭제하거나 건너뛰지 마”, “모든 테스트가 통과한 로그를 보여줘처럼 금지 조건도 함께 명시하는 것이 좋습니다.

 

AI TDD를 함께할 때 중요한 것은 AI에게 알아서 TDD로 해줘라고 맡기는 것이 아닙니다테스트 작성최소 구현리팩터링이라는 단계를 개발자가 나누고각 단계의 완료 조건을 명확히 제시해야 합니다. 그래야 테스트는 형식적인 산출물이 아니라 AI가 따라야 할 실제 기준이 됩니다.

 

 

명세는 AI에게 무엇을 만들지” 알려주는 기준이다

 

TDD AI가 만든 코드의 동작을 검증하는 장치라면, SDD AI가 무엇을 만들어야 하는지 알려주는 기준입니다. 테스트가 제대로 만들었는가를 확인한다면명세는 그보다 앞서 무엇을 만들어야 하는가를 정의합니다.

 

SDD Specification-Driven Development, 명세 주도 개발을 뜻합니다코드를 먼저 작성한 뒤 나중에 문서를 맞추는 방식이 아니라코드를 작성하기 전에 명세를 먼저 정의하고 그 명세를 기준으로 개발을 진행하는 방식입니다여기서 명세는 단순한 참고 문서가 아닙니다개발의 출발점이자구현 과정에서 계속 돌아와 확인해야 하는 기준점입니다.

 

AI 코딩 환경에서 명세가 중요한 이유는 분명합니다. AI는 모호한 요청에도 그럴듯한 답을 내놓습니다. “TODO 앱 만들어줘라고 요청하면 AI는 나름의 판단으로 화면을 만들고데이터 구조를 정하고, API를 설계합니다하지만 그 판단이 우리가 원하는 제품의 방향과 일치한다는 보장은 없습니다개인용 앱인지팀 협업 도구인지, SaaS 서비스인지에 따라 필요한 구조는 달라지지만명세가 없다면 AI는 그 차이를 알 수 없습니다.

 

명세는 이런 모호함을 줄이는 역할을 합니다어떤 사용자를 위한 기능인지어떤 데이터를 다뤄야 하는지어떤 API가 필요한지어떤 예외 상황을 처리해야 하는지이번 범위에서 제외할 것은 무엇인지 미리 정리해두면 AI가 임의로 해석할 여지가 줄어듭니다다시 말해 명세는 AI와 개발자 사이의 공통 언어가 됩니다.

 

물론 SDD라고 해서 수십 페이지짜리 문서를 먼저 만들어야 한다는 뜻은 아닙니다중요한 것은 AI가 구현을 시작하기 전에 판단 기준을 충분히 제공하는 것입니다기능 요구사항비기능 요구사항데이터 모델, API 명세완료 조건처럼 개발에 직접 영향을 주는 정보가 명확히 정리되어 있으면 됩니다.

 

예를 들어 할 일 관리 기능을 만들어줘라고 요청하는 대신다음처럼 명세를 먼저 정의할 수 있습니다.

 

사용자는 할 일을 생성수정삭제할 수 있어야 한다할 일은 제목설명상태담당자마감일을 가진다상태는 TODO, IN_PROGRESS, DONE 중 하나다팀 단위로 데이터를 분리해야 하며삭제된 할 일은 복구할 수 있어야 한다이번 버전에서는 결제 기능과 알림 기능은 구현하지 않는다.”

 

이렇게 명세를 먼저 정리하면 AI의 역할도 분명해집니다. AI는 무엇을 만들지 추측하는 대신주어진 명세를 어떻게 구현할지에 집중할 수 있습니다개발자는 구현의 모든 세부를 직접 작성하지 않더라도제품의 방향과 범위는 명확히 통제할 수 있습니다.

 

결국 SDD AI에게 더 많은 일을 맡기기 위한 방식이 아니라, AI가 엉뚱한 일을 하지 않도록 기준을 세우는 방식입니다. “일단 만들어줘에서 벗어나려면 먼저 무엇을 만들 것인지를 정의해야 합니다그리고 그 정의가 바로 명세입니다.

 

 

 

 

명세가 방향을 잡고테스트가 품질을 지킨다

 

명세와 테스트는 서로 다른 역할을 합니다명세는 무엇을 만들 것인가를 정의하고테스트는 제대로 만들었는가를 확인합니다. SDD가 개발의 방향을 잡는다면, TDD는 그 방향대로 구현되었는지 검증하는 안전장치입니다.

 

이 둘을 따로 생각하면 효과가 반쪽에 그칠 수 있습니다명세만 있고 테스트가 없다면구현이 명세를 제대로 만족하는지 확인하기 어렵습니다. 반대로 테스트만 있고 명세가 없다면테스트가 어떤 제품 방향과 요구사항을 기준으로 만들어졌는지 불분명해질 수 있습니다그래서 AI 코딩 환경에서는 SDD TDD를 함께 사용하는 것이 중요합니다.

 

흐름은 단순합니다

 

먼저 명세를 작성합니다어떤 기능을 만들지어떤 데이터가 필요한지어떤 API가 있어야 하는지성공 조건과 실패 조건은 무엇인지 정리합니다그다음 명세에서 테스트 케이스를 도출합니다사용자가 할 일을 등록할 수 있어야 한다면, “할 일을 생성하면 목록에 나타난다는 테스트가 필요합니다상태를 변경할 수 있어야 한다면, “TODO 상태의 항목을 IN_PROGRESS DONE으로 변경할 수 있다는 테스트가 필요합니다.

 

이렇게 테스트가 준비되면 AI에게 구현을 요청합니다이때 중요한 것은 전체 기능을 알아서 만들어줘가 아니라, “이 명세와 테스트를 기준으로 최소 구현을 해줘라고 요청하는 것입니다그러면 AI는 기능을 임의로 확장하기보다명세와 테스트를 만족하는 방향으로 코드를 작성하게 됩니다.

 

구현이 끝난 뒤에는 테스트를 실행합니다테스트가 실패하면 AI에게 원인을 분석하게 하고실패한 테스트를 통과하도록 수정하게 합니다테스트가 통과하면 리팩터링을 진행하되이때도 테스트가 계속 통과하는지 확인해야 합니다마지막으로 구현 결과가 처음 작성한 명세와 어긋나지 않는지 다시 검토합니다.

 

정리하면 AI와 함께 개발할 때의 흐름은 다음과 같습니다.

 

  1. 명세를 확인한다.
  2. 명세에서 테스트를 작성한다.
  3. 테스트를 통과하는 최소 구현을 요청한다.
  4. 테스트가 통과하는 상태에서 리팩터링한다.
  5. 구현 결과가 명세와 일치하는지 검증한다.

 

이 흐름에서 명세는 AI가 따라갈 지도이고테스트는 목적지에 제대로 도착했는지 확인하는 검문소입니다. AI는 빠르게 코드를 만들 수 있지만어디로 가야 하는지와 제대로 도착했는지는 개발자가 정해야 합니다.

 

그래서 일단 만들어줘” 방식에서 벗어나려면 순서를 바꿔야 합니다먼저 명세로 방향을 정하고테스트로 기준을 세운 다음, AI에게 구현을 맡겨야 합니다. AI가 코드를 빠르게 만드는 시대일수록 개발자는 더 명확하게 명세를 쓰고 더 철저하게 테스트해야 합니다그것이 AI 코딩을 빠른 데모가 아니라 운영 가능한 개발 방식으로 바꾸는 출발점입니다.


위 콘텐츠는 클로드 코드 마스터내용을 토대로 재구성하였습니다. 

 

댓글

댓글 입력