AI 코딩 도구를 처음 써보면 누구나 한 번쯤 이런 요청을 하게 됩니다.
“TODO 앱 하나 만들어줘.”
“로그인 기능 붙여줘.”
“관리자 페이지도 만들어줘.”
놀랍게도 AI는 꽤 그럴듯한 결과물을 만들어냅니다. 예전 같으면 며칠이 걸렸을 기능이 몇 분 만에 화면으로 나타나고, API가 만들어지고, 테스트 코드까지 붙기도 합니다. 개발자는 더 이상 모든 코드를 직접 타이핑하지 않아도 됩니다. 이제 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 코딩 환경에서 TDD, 즉 테스트 주도 개발은 더 중요해집니다. TDD에서는 구현보다 테스트를 먼저 작성합니다. 이는 단순히 버그를 줄이기 위한 절차가 아닙니다. “이 기능은 이렇게 동작해야 한다”라는 요구사항을 실행 가능한 코드로 고정하는 과정입니다. 다시 말해 테스트는 코드의 품질을 확인하는 도구이면서, 동시에 AI가 따라야 할 명세가 됩니다.
예를 들어 TODO 앱에서 “새로운 할 일을 추가하면 목록에 나타나야 한다”, “완료된 할 일의 개수를 정확히 계산해야 한다”와 같은 테스트를 먼저 작성해두면, AI는 그 테스트를 통과하는 방향으로 코드를 구현해야 합니다. 이때 개발자는 구현 세부 사항을 모두 직접 작성하지 않더라도, 원하는 동작의 기준은 분명히 정할 수 있습니다.
반대로 테스트 없이 AI에게 “TODO 기능 만들어줘”라고 요청하면 AI가 기능의 범위와 동작 방식을 스스로 해석하게 됩니다. 처음에는 그럴듯해 보일 수 있지만, 나중에 요구사항과 어긋난 부분을 발견하면 어디서부터 잘못됐는지 추적하기 어려워집니다.
결국 테스트는 AI를 믿기 위한 장치라기보다, AI가 만든 결과를 확인하기 위한 객관적인 검문소입니다. AI가 빠르게 코드를 만들수록 개발자는 더 빠르게 확인할 수 있는 기준을 준비해야 합니다. 그 기준이 없으면 우리는 AI가 만든 코드를 “좋아 보인다”는 감각으로 판단하게 됩니다. 하지만 운영 가능한 소프트웨어에는 감각이 아니라 검증이 필요합니다.
테스트가 중요하다는 사실을 안다고 해서 AI가 자동으로 TDD 방식에 맞춰 개발해주는 것은 아닙니다. 오히려 AI 코딩 도구는 사용자의 요청을 빠르게 완성하려는 방향으로 움직이기 때문에, 테스트 주도 개발의 순서를 건너뛰는 경우가 많습니다.
예를 들어 “로그인 기능을 TDD로 만들어줘”라고 요청해도 AI는 테스트와 구현을 한 번에 작성하려 할 수 있습니다. 더 심하면 구현 코드를 먼저 만든 뒤, 그 코드에 맞춰 테스트를 끼워 넣기도 합니다. 겉으로 보기에는 테스트가 있는 코드처럼 보이지만, 이런 방식의 테스트는 요구사항을 검증하는 기준이라기보다 이미 작성된 구현을 정당화하는 문서에 가까워집니다.
TDD의 핵심은 순서에 있습니다. 먼저 실패하는 테스트를 작성하고, 그 테스트를 통과시키는 최소한의 구현을 만든 뒤, 테스트가 통과하는 상태를 유지하면서 코드를 정리해야 합니다. 이 흐름을 흔히 Red → Green → Refactor라고 부릅니다. 실패하는 테스트를 통해 요구사항을 먼저 고정하고, 그다음 구현이 그 기준을 만족하는지 확인하는 방식입니다.
AI와 함께 TDD를 할 때는 이 순서를 더 명확하게 지시해야 합니다. “기능을 구현하고 테스트도 작성해줘”가 아니라, 단계별로 요청을 나눠야 합니다.
첫 번째 단계에서는 구현을 금지하고 테스트만 작성하게 합니다.
“아직 구현하지 마. 먼저 테스트만 작성해줘.”
두 번째 단계에서는 테스트를 통과시키는 최소한의 코드만 요청합니다.
“방금 작성한 테스트를 통과시키는 최소한의 구현만 해줘.”
세 번째 단계에서는 테스트가 통과하는 상태를 유지한 채 리팩터링을 요청합니다.
“테스트가 통과하는 상태를 유지하면서 중복을 제거하고 코드를 정리해줘.”
이렇게 요청을 나누면 AI가 한 번에 모든 것을 해결하려고 하면서 생기는 문제를 줄일 수 있습니다. 테스트와 구현이 뒤섞이지 않고, 각 단계에서 무엇을 검증해야 하는지도 분명해집니다. 실패하는 테스트가 먼저 존재하기 때문에 AI는 그 테스트를 통과해야 하는 방향으로 구현을 조정하게 됩니다.

주의할 점도 있습니다. AI가 테스트를 통과시키기 위해 테스트 자체를 느슨하게 바꾸거나, 실패하는 테스트를 건너뛰기 위해 skip 처리할 수 있습니다. 그래서 “테스트를 수정하지 말고 구현 코드만 수정해”, “실패한 테스트를 삭제하거나 건너뛰지 마”, “모든 테스트가 통과한 로그를 보여줘”처럼 금지 조건도 함께 명시하는 것이 좋습니다.
AI와 TDD를 함께할 때 중요한 것은 AI에게 “알아서 TDD로 해줘”라고 맡기는 것이 아닙니다. 테스트 작성, 최소 구현, 리팩터링이라는 단계를 개발자가 나누고, 각 단계의 완료 조건을 명확히 제시해야 합니다. 그래야 테스트는 형식적인 산출물이 아니라 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와 함께 개발할 때의 흐름은 다음과 같습니다.
이 흐름에서 명세는 AI가 따라갈 지도이고, 테스트는 목적지에 제대로 도착했는지 확인하는 검문소입니다. AI는 빠르게 코드를 만들 수 있지만, 어디로 가야 하는지와 제대로 도착했는지는 개발자가 정해야 합니다.
그래서 “일단 만들어줘” 방식에서 벗어나려면 순서를 바꿔야 합니다. 먼저 명세로 방향을 정하고, 테스트로 기준을 세운 다음, AI에게 구현을 맡겨야 합니다. AI가 코드를 빠르게 만드는 시대일수록 개발자는 더 명확하게 명세를 쓰고 더 철저하게 테스트해야 합니다. 그것이 AI 코딩을 빠른 데모가 아니라 운영 가능한 개발 방식으로 바꾸는 출발점입니다.
위 콘텐츠는 『클로드 코드 마스터』내용을 토대로 재구성하였습니다.

댓글