
상세 설계서가 AI 시대에 필요할까? —— 테스트 패턴을 보물로 만드는 AI 승인 주도 개발
요약
AI 주도 개발 시대에 개발의 병목이 '생성'에서 '승인'으로 이동함에 따라, 인간이 무엇을 옳은 결과로 판단할지 정의하는 'AI 승인 주도 개발' 개념을 제안합니다. 상세 설계서 대신 제약 조건과 기대값을 명확히 정의하는 것이 AI 활용의 핵심임을 강조합니다.
핵심 포인트
- 개발의 중심이 '만드는 것'에서 '승인하는 것'으로 변화
- AI 승인 주도 개발: AI를 통해 인간의 승인을 구동하는 구조
- 상세 설계서보다 제약, 책무, 기대값 정의가 더 중요
- 테스트 코드의 품질은 무엇을 옳다고 할지에 대한 정의에 달려 있음
AI 주도 개발이라는 말에 위화감이 들기 시작했다
최근, **AI 주도 개발 (AI-Driven Development)**이라는 말에 약간의 위화감을 느끼게 되었다.
AI에게 코드를 쓰게 한다.
AI에게 설계안을 내게 한다.
AI 에이전트에게 작업을 진행하게 한다.
모두 중요하다.
하지만 이 말을 들었을 때, AI가 무엇을 만들고 어떻게 움직이는지는 보이지만,
인간은 그 성과물을 무엇을 근거로 옳다고 판단하는가.
라는 점이 중심에 보이지 않았다.
AI가 똑똑해져서 코드, 테스트, 설계 문서를 대량으로 생성할 수 있게 될수록, 개발의 병목 현상(Bottleneck)은 '만드는 것'에서 '승인하는 것'으로 옮겨간다.
AI가 대량으로 생성한다
↓
인간은 모든 것을 처음부터 읽을 수 없다
...
앞으로의 개발에서 중심에 두어야 할 것은 AI의 생성 능력만이 아니다.
인간이 무엇을 옳다고 할지를 판단하고, 그 판단에 책임을 질 수 있는 구조이다.
본고에서 말하는 '승인'은 형식적인 날인이나, 완성된 성과물에 마지막으로 OK를 내는 것이 아니다.
제약, 책무, 기대 결과, 수락 조건을 확인하고,
'이 조건이라면 이것을 옳은 결과로 취급한다'라고 인간이 결정하는 것이다.
그래서 이 구상을 **AI 승인 주도 개발 (AI-Approval-Driven Development)**이라고 부르기로 했다.
AI가 승인하는 것이 아니다.
AI에 의해 인간의 승인을 구동한다.
AI는 구현안을 탐색한다.
테스트 후보를 생성한다.
부족함이나 미연결을 검지한다.
Expected(기대값)와 Actual(실제값)의 차이를 정리한다.
하지만 무엇을 옳다고 할지를 최종적으로 떠맡는 것은 인간이다.
AI 승인 주도 개발 #0
본고는 완성된 이론을 순서대로 설명하는 제1회가 아니다.
현시점에서 생각하고 있는 AI 승인 주도 개발의 전체 구상을 우선 한 번 모두 보이는 곳으로 꺼내놓기 위한 #0이다.
이 #0에서 생겨난 위화감이나 차이를 수집하면서, 향후 #1, #2, #3에서 중요한 논점들을 하나씩 깊이 있게 파고들 것이다.
#0에서는 이 구상의 출발점이 된 질문부터 시작한다.
상세 설계서가 AI 시대에 필요할까?
본고의 전체상
본고에서는 이 하나의 흐름을 중심으로 생각한다.
제약 (Constraints)
= 넘어서는 안 되는 경계
책무 (Responsibilities)
...
AI는 How(방법)를 탐색할 수 있다.
하지만 무엇을 옳다고 할지는 인간이 정의해야만 한다.
AI 시대의 개발에서 인간의 업무는 성과물을 모두 만드는 것이 아니다. 무엇을 옳다고 할지를 정의하고, 그 승인에 책임을 지는 것이다.
상세 설계서가 AI 시대에도 필요할까?
이 구상은 두 가지 작은 경험에서 시작되었다.
첫 번째는 FFT 해석 프로토타입을 GPT에게 만들어 달라고 했을 때의 일이다.
나는 GPT에게 기존 방식과 같은 상세 설계서를 전달하지 않았다.
클래스 구성도, 메서드 구성도, 처리 순서도 쓰지 않았다.
전달한 것은 하고 싶은 것, 입력 데이터, 기대하는 출력, 이용 환경, 지켜줬으면 하는 조건이었다.
그럼에도 GPT는 구현안을 생각하고 동작하는 프로그램을 만들었다.
그때 소박한 의문이 생겼다.
AI에게 프로그램을 만들게 하는 시대에, SE(시스템 엔지니어)에서 PG(프로그래머)로 구현 방법을 인계하는 상세 설계서는 정말로 필요한 것일까.
코드는 만들 수 있었다. 하지만 테스트 코드는 만들 수 없었다
두 번째는 GPT에게 테스트 코드 작성을 의뢰했을 때의 일이다.
나는 가벼운 마음으로,
'이 프로그램의 테스트 코드를 만들어줘'
라고 부탁했다.
그런데 GPT는 기대했던 대로 만들어주지 않았다.
이유는 단순했다.
제약이나 기대값이 부족했다.
무엇을 옳은 결과로 판정해야 할지 알 수 없었던 것이다.
나도 모르게 웃음이 나왔다.
프로그램은 상세 설계서 없이 만들 수 있었다.
하지만 테스트 코드는 '무엇을 옳다고 할지'를 모르면 만들 수 없었다.
이 두 가지 경험은 깔끔한 대칭을 이룬다.
코드 생성
상세한 구현 방법을 전달하지 않아도 만들 수 있었다
↓
...
여기서 기존의 상세 설계서에 대한 관점이 바뀌었다.
기존의 상세 설계서는 AI가 스스로 생각할 수 있는 '어떻게 구현할 것인가(How)'를 자세히 쓰는 반면, AI가 스스로 결정할 수 없는 '무엇을 옳다고 할 것인가'를 충분한 구조로 가지고 있지 않았던 것은 아닐까.
그렇다면 AI 시대의 설계 정보는 기존과는 반대 방향으로 다시 만들어야 할 필요가 있다.
줄여야 할 것
= 구현 절차, 처리 순서, 클래스 구성 등의 How
강화해야 할 것
...
상세 설계서에 섞여 있던 두 가지 역할
단, 여기서 갑자기,
'상세 설계서는 전부 필요 없다'
라고 말하고 싶은 것은 아니다.
기존에 '상세 설계서'라고 불려 왔던 문서에는 적어도 두 가지 역할이 섞여 있었다.
기존의 상세 설계서
├─ 고객에게 내용을 설명하고 승인을 요청하기 위한 문서
└─ SE가 결정한 구현 방법을 PG에게 인계하기 위한 문서
전자는 AI 시대에도 반드시 필요하다.
고객에게는 구현할 업무, 외부 사양, 화면, 인터페이스, 제약 사항, 기대 결과, 수락 조건을 확인받아야 한다.
다만, 이것은 PG에게 내부 구현을 지시하는 문서가 아니다.
본고에서는 임의로, 고객 승인 사양서라고 부른다.
본고에서 불필요하다고 가설을 세우는 것은 후자이다.
AI 협업 개발에서는 「어떻게 구현할 것인가」를 SE가 사전에 세세하게 결정하여 PG에게 인계하기 위한 상세 설계서를 없앤다.
인간이 구현 방법을 상세 설계서에 모두 써서 AI에게 전달하면, AI는 설계자가 아니라 전기 장치(transcription device)가 된다.
더 단순한 구조, 공통화하기 쉬운 설계, 테스트하기 쉬운 구성, 다른 구현안을 탐색할 여지도 인간이 먼저 좁혀버리게 된다.
「어떻게 구현할 것인가」를 너무 많이 쓰는 것은 AI의 사고 여백을 빼앗는 것이기도 하다.
따라서 고정하지 않는 것은 구현 방법, 코드 구조, 처리 순서이다.
그 대신, 인간이 고정하고, 승인하며, 소중히 지켜야 할 것을 다른 형태로 명확히 한다.
그것이 책임(Responsibility), 제약(Constraint), 판단 축, 테스트 패턴(Test Pattern), 기대값(Expected Value)이다.
AI의 사고 여백은 남기는 것이 아니라 설계하는 것이다
여기서 말하는 「AI의 사고 여백」은 AI에게 마음대로 구현하게 하는 것이 아니다.
사고 여백 그 자체가 품질을 보장하는 것은 아니며, 제어되지 않은 여백은 구현의 편차, 리뷰 관점의 증가, 팀 규약으로부터의 이탈, 재현성 저하로 이어진다.
그러한 우려는 옳다.
본고에서 남기고 싶은 것은 무제한적인 자유가 아니라, **경계가 있는 탐색 공간(Bounded Search Space)**이다.
목적
책임
제약
...
각각의 역할은 다음과 같이 생각하고 있다.
제약
= 넘어서는 안 되는 경계
판단 축
...
즉, 상세 설계서를 없애는 목적은 AI를 무제한으로 자유롭게 만드는 것이 아니다.
인간이 탐색 범위와 평가 기준을 설계하고, 그 내부에 남겨진 How(방법)를 AI에게 맡긴다.
이것이 본고에서 말하는 사고 여백이다.
사고 여백은 상황에 따라 바꾼다
모든 업무에서 AI의 사고 여백을 넓게 가져갈 필요는 없다.
필요한 것은 업무의 성격에 맞춰 여백을 개폐(開閉)하는 것이다.
| 상황 | 주로 요구하는 것 | AI의 사고 여백 | 인간이 고정하는 것 |
|---|---|---|---|
| 정해진 CSV 변환 | 매번 동일한 처리 | 거의 불필요 | 입출력 형식, 변환 규칙 |
| ... |
탐색이나 설계에서는 AI가 여러 안을 생각할 수 있도록 여백을 넓게 가져간다.
반면, 품질 확인, 운영 반영, 법령이나 계약에 관련된 처리에서는 여백을 좁히고, 승인된 절차나 기대 결과에 강력하게 구속한다.
설계·탐색
→ 여백을 넓힌다
후보 비교
...
대규모 개발에서 필요한 예측 가능성은 클래스 구성이나 처리 순서를 하나로 고정함으로써만 얻을 수 있는 것이 아니다.
고정하는 것
= 지켜야 할 제약
= 입력에 대한 기대 결과
...
고정하는 것은 기대하는 결과와 지켜야 할 경계이다. 탐색하게 하는 것은 그곳에 도달하는 How이다.
AI 주도 개발(AI-Driven Development)이란 사고 여백을 항상 최대화하는 것이 아니다.
AI 주도 개발이란 업무의 성격에 따라 AI의 사고 여백을 설계하는 것이다.
자율형 AI 에이전트(Autonomous AI Agent)에서는 상황에 따라 계획, 도구, 절차를 선택하게 하는 이상, 일정 수준의 사고 여백이 없으면 자율성 자체가 성립하지 않는다.
다만, 그 자율성 또한 제약, 판단 축, 정지 조건, 인간 승인, TestPattern + Expected에 의해 제어될 필요가 있다.
그런데, 상세 설계서를 없애면 UT가 곤란해진다
여기서 즉시 현장적인 문제가 발생한다.
기존 프로젝트에서는 SE → PG 인계용 상세 설계서를 인풋으로 하여 프로그램별 세세한 체크리스트를 만드는 경우가 많다.
- 정상계
- 이상계
- 경계값
- 한계값
- Null
- 자릿수 초과 (桁あふれ)
- 업데이트 실패
- 롤백 (Rollback)
- 외부 접속 에러
즉, 상세 설계서는 PG로의 인계뿐만 아니라, UT(Unit Test)에서 무엇을 확인할지 도출하는 모체 역할도 하고 있었다.
SE → PG 인계용 상세 설계서
↓
프로그램별 체크리스트
...
이 부분을 대체하지 않고 상세 설계서만 없앤다면 단순한 품질 저하가 된다.
그래서 필요해지는 것이 **책임 정의(Responsibility Definition)**이다.
책임은 「무엇을 하는가」가 아니라 「무엇을 보장하는가」이다
책임 정의는 상세 설계서를 다른 이름으로 다시 만드는 것이 아니다.
당초에는 책임 정의를 다음과 같이 표현했었다.
책임 정의는 구현 방법(Implementation)에 깊이 관여하지 않으면서, 테스트 패턴(Test Pattern)을 도출하고 승인할 수 있는 입도(Granularity)로 정의하는 것이다.
하지만 "구현에 관여하지 않는다"라는 표현은 다소 강한 면이 있다.
책임 또한 설계 정보인 이상, 어떤 조건에서 무엇을 성립시키고, 정상 시와 이상 시에 어떤 상태를 보장할 것인지는 결정해야 한다. 결정하지 않아야 하는 것은 처리 그 자체가 아니라, 그 보장에 도달하기 위한 구체적인 구현 방법이다.
따라서 본고에서는 다음과 같이 정리한다.
책임 정의는 구현 방법을 고정하지 않는다.
그리고 책임의 중심을 다음의 한 문장으로 파악한다.
책임은 무엇을 하는지(What to do)를 쓰는 것이 아니라, 무엇을 보장하는지(What to guarantee)를 쓰는 것이다.
책임 정의로부터 재현되어야 하는 것은 구현이 아니다.
책임 정의로부터 재현되어야 하는 것은 정답 여부의 판정(Correctness judgment)이다.
책임 정의를 읽으면 테스트 담당자는 입력 조건, 정상계, 이상계, 경계 조건, Expected(기대값)를 도출할 수 있다. 반면, 구현 담당자에게는 여러 가지 구현 안이 남겨진다. 이 상태가 책임과 How(구현 방법) 사이의 적절한 경계이다.
책임 정의를 읽는다
↓
TestPattern과 Expected를 도출할 수 있다
...
책임 정의에 쓰는 내용은 예를 들어 다음과 같다.
책임의 목적
테스트 대상
검증 레벨 (UT / CT / AT)
...
반면, 다음과 같은 내용은 원칙적으로 쓰지 않는다.
클래스 구성
메서드 구성
처리 순서
...
너무 거친 책임, 적절한 책임, 너무 상세한 책임
예를 들어 검색 처리를 세 가지 입도로 비교해 보자.
너무 거친 경우
검색한다.
이것만으로는 무엇을 일치로 볼 것인지, 무엇을 결과에 포함할 것인지, 어떤 상태를 유지해야 하는지 알 수 없다. TestPattern과 Expected를 충분히 도출할 수 없다.
적절한 경우
유효한 검색 조건에 일치하는 행만 결과에 포함한다.
검색 결과에는 원 데이터상의 Index를 유지한다.
검색 조건의 평가에 의해 입력 데이터를 변경하지 않는다.
이 정도라면 일치 행, 불일치 행, 문자열 조건, 수치 조건, 원 Index 유지, 부작용(Side effect) 없음과 같은 TestPattern 후보를 도출할 수 있다.
하지만 루프(Loop), 배열 조작, 이용 클래스, 메서드 호출 순서까지는 정해지지 않는다.
너무 상세한 경우
filterRows()에서 첫 번째 행부터 순차적으로 스캔하여,
조건 일치 시 result 배열에 push한다.
문자열 조건에서는 includes()를 이용한다.
이것은 보장이 아니라 구현 방법을 재현하고 있는 것이다.
책임과 How의 경계는 다음 질문으로 확인한다.
- 입력 조건으로부터 Expected를 도출할 수 있는가?
- 결과 또는 상태로서 테스트를 통해 관측할 수 있는가?
- 내부 구현을 다른 방식으로 변경해도 책임 정의는 변하지 않는가?
- 여러 가지 구현 방법이 이 보장을 충족할 수 있는가?
1과 2를 충족하지 못한다면 책임으로서 너무 거칠 가능성이 있다.
3과 4를 충족하지 못한다면 How를 너무 많이 쓰고 있을 가능성이 있다.
또한, 결과의 구체적인 외부 표현이 계약(Contract)으로서 고정되어 있는 경우에는 Interface 측의 정의로 분리한다. 내부 구현에 관한 사항이라 하더라도 보안, 법령, 성능, 트랜잭션 등의 이유로 반드시 지켜야 하는 것은 Constraint(제약 사항)로 분리한다.
Responsibility (책임)
= 무엇을 보장할 것인가
Interface
...
책임 정의의 제1목적은 거창한 설계 모델을 만드는 것이 아니다.
입력 조건으로부터 Expected를 도출할 수 있을 정도의 보장을 쓰고, 그 Expected를 실현하는 How에는 선택지를 남겨둔다.
이것이 책임 정의의 역할이다.
책임의 입도와 완전 방어를 두는 위치
여기서 말하는 책임은 수십 단계(step)의 작은 함수를 하나씩 독립된 UT 대상으로 다루는 것이 아니다.
본고에서는 UT 책임을 품질 보증상 하나의 의미 있는 책임 단위로 파악한다. 구현 규모로는 대략 1KS(1,000 lines of code) 정도가 된다는 것을 초기 가설로 두지만, 코드 양에 따라 책임의 경계를 결정하는 것은 아니다.
UT 책임
= 품질 보증상 하나의 의미 있는 책임 단위
구현 규모
...
언어, 생성된 코드, 프레임워크, 업무 특성에 따라 코드 양은 달라진다. 1KS는 엄격한 규격이 아니라, 책임을 극단적으로 세분화하지 않기 위한 규모감이다.
그리고 책임 정의의 문장량을 구현 규모에 비례시킬 필요도 없다.
1KS의 코드를 1KS만큼 설명하는 것이 책임 정의가 아니다.
1KS의 코드가 담당하는 보장을 몇 개의 검증 가능한 약속으로 압축하는 것이 책임 정의이다.
책임 정의는 구현의 요약서가 아니다.
약 1KS의 구현
↓ 보장으로 압축
몇 개의 검증 가능한 약속
...
책임의 크기는 문장량이 아니라, 독립된 보장(Guarantee)의 집합으로 판단한다. 하나의 책임에 별도의 목적을 가진 상태 변경이나 서로 다른 승인 주체가 섞여 있다면, 코드량이 적더라도 책임을 분리하는 것이 좋다.
여기서 보여주고 싶은 것은, UT(Unit Test)의 Unit을 '최소 함수'가 아니라, 다음과 같은 성질을 가진 **책임 경계 (Responsibility Boundary)**로 파악하는 것이다.
- 하나의 의미 있는 목적을 가진다
- 외부로부터 입력을 받는다
- 입력의 타당성을 스스로 확인한다
- 정상 시·이상 시의 결과를 보장한다
- 부작용(Side Effect)이나 상태 변경의 범위에 책임을 진다
- TestPattern과 Expected를 독립적으로 정의할 수 있다
UT의 Unit은 코드상의 최소 부품이 아니다. 품질 보증상의 최소 책임 단위이다.
완전 방어는 모든 자식 함수에 요구하지 않는다
이 책임 경계에서는 호출 측이 올바른 값을 전달해 줄 것을 전제하지 않는다.
Null, 타입, 자릿수, 범위, 경계, 조합, 권한, 현재 상태 등, 책임을 안전하게 실행하기 위해 필요한 입력 조건을 호출된 책임 측에서 확인한다.
부정확한 입력도 '계약 외(Out of Contract)'라며 배제하지 않고, 정식 테스트 대상에 포함한다.
외부로부터의 입력
↓
UT 책임의 입구
...
반면, 책임 내부에 있는 30단계나 50단계 정도의 자식 함수에 대해 동일한 완전 방어를 반복해서 요구하는 것은 아니다.
부모 책임이 안전을 확립했다면, 자식 함수는 그 검증된 조건을 전제로 자신의 부분 처리에 집중할 수 있다.
부모 책임
= 안전을 확립함
자식 함수
...
자식 함수를 단독으로 직접 테스트하는 것을 금지하는 것은 아니다.
복잡한 수치 계산, 독립된 알고리즘, 다수의 장소에서 이용되는 공통 처리, 과거에 결함이 집중되었던 처리 등은 보조적인 단체 테스트(Unit Test)를 가져도 좋다.
단, 주요 품질 승인 단위는 어디까지나 책임 전체이다.
이 판단 축을 짧게 표현하면 다음과 같다.
입구는 의심한다. 책임 내부에서는 부모가 확립한 안전을 믿는다. 단, 다른 책임 경계를 넘어가면 다시 한번 의심한다.
책임을 「검증 가능한 보장」으로 분해하고, TestPattern과 연결한다
책임을 하나의 긴 문장으로 유지하면, 그 책임의 어느 부분이 테스트되고 있는지 알기 어렵다.
따라서 책임 JSON에서는 하나의 책임을 부모 레코드로 정의하고, 그 책임이 약속하는 내용을 **검증 가능한 보장 (Verifiable Guarantee)**의 명세로서 보유한다.
책임
├─ 책임 CD
├─ 책임명
...
예를 들어, 검색 조건 평가 책임은 다음과 같이 가질 수 있다.
{
"responsibility_cd": "search_filter",
"responsibility_name": "검색 조건 평가 책임",
...
}
TestPattern 측에는 책임 CD뿐만 아니라, 해당 테스트가 검증하는 보장 ID를 보유한다.
{
"test_pattern_id": "search_filter_number_gte_preserves_indexes",
"responsibility_cd": "search_filter",
...
}
TestPattern이 연결되는 상대는 막연한 책임명이 아니다. 그 책임이 약속한 개별적인 검증 가능한 보장이다.
프로토타입 제작 중인 Studio에서 두 개의 JSON을 연결해 보았다
본 구상을 검증하기 위해, 프로토타입 제작 중인 JSON 관리 도구에서 책임 JSON과 TestPattern JSON을 보장 ID를 통해 연결했다.

왼쪽에서는 책임 안에 있는 「검증 가능한 보장」에 보장 ID를 부여한다. 오른쪽에서는 TestPattern이 검증하는 보장 ID를 명시한다.
이 연결을 통해 적어도 다음과 같은 상태를 기계적으로 감지할 수 있다.
보장 있음 + TestPattern 있음
= 검증 관계 있음
보장 있음 + TestPattern 없음
...
이것은 단순한 링크 관리가 아니다.
책임
= 무엇을 보장할 것인가
TestPattern + Expected
...
이라는 두 가지 품질 자산을 연결하여, 책임의 보장이 테스트되고 있는지를 횡단적으로 확인하는 구조이다.
책임 JSON과 TestPattern JSON이 보장 ID로 연결되었을 때, 책임 정의는 문서에서 품질 관리 구조로 변화한다.
기존 기술과의 관계 —— 대체하는 것이 아니라, 힘을 빌린다
지금까지의 구상은 기존의 테스트·설계 기술을 부정하고 새로운 이름으로 대체하려는 것이 아니다.
오히려 이미 존재하는 강력한 기술로부터 필요한 힘을 빌리고자 한다.
특히 관계가 깊은 것은 다음 세 가지이다.
- BDD (Gherkin / Cucumber)
- Model-Based Testing
- Design by Contract
비교표
| 관점 | BDD (Gherkin / Cucumber) | Model-Based Testing | Design by Contract | AI 승인 주도 개발 |
|---|---|---|---|---|
| 중심 | 구체적인 사례를 통한 동작의 공통 이해 | 모델을 사용한 테스트 분석·설계 | 부품 간의 요구사항과 보증의 명시 | TestPattern + Expected의 인간 승인 |
| ... |
BDD에서 빌려오고 싶은 것
BDD는 시스템이 어떻게 만들어지는가가 아니라, 사용자나 업무 관점에서 어떻게 동작해야 하는지를 구체적인 사례를 통해 공유한다.
Gherkin에서는 예를 들어 다음과 같이 표현할 수 있다.
Scenario: 상한을 초과한 주문을 거부한다
Given 등록 가능한 고객이 존재한다
When 상한을 초과하는 수량으로 주문한다
...
이는 기대값(Expected)을 포함하는 테스트 패턴을 인간이 이해하기 쉬운 형태로 승인하는 뷰(View)로서 유효하다.
본 구상에서는 JSON을 의미 구조의 원본으로 삼고, Gherkin을 인간을 위한 승인 뷰로 생성하는 것도 고려할 수 있다.
JSON
= 승인 자산의 원본
Gherkin
...
BDD와 Cucumber에 대해서는 Cucumber 공식 문서의 [Behaviour-Driven Development]와 [Gherkin Reference]를 참조하고 있다.
Model-Based Testing에서 빌려오고 싶은 것
Model-Based Testing에서는 시스템의 동작이나 조건을 모델링하고, 테스트 선택 기준을 사용하여 목적에 맞는 테스트 케이스를 생성하거나 선택한다.
책임·제약
↓
동작 모델
...
이는 책임 정의로부터 정상계, 이상계, 경계값, 상태 전이, 조합 등의 테스트 후보를 만들어내는 부분에서 큰 도움을 받을 수 있다.
단, 본 구상에서는 생성된 것만으로 완성을 의미하지 않는다.
생성된 TestPattern과 Expected에 대하여,
- 근거가 되는 책임이나 제약에 연결되어 있는가
- 필요한 관점이 부족하지 않은가
- Expected를 인간이 승인할 수 있는가
- 변경이나 상속에 의해 재승인이 필요한가
까지를 다룬다.
Model-Based Testing에 대해서는 ISTQB의 [Certified Tester Model-Based Tester]와 [CT-MBT Syllabus]를 참조하고 있다.
Design by Contract에서 빌려올 것과 빌려오지 않을 것
Design by Contract의 Precondition, Postcondition, Invariant는 책임이 무엇을 요구하고 무엇을 보증하는지를 정리하는 골격으로서 강력하다.
Precondition
= 처리 전에 성립되어 있는 조건
Postcondition
...
이 세 가지는 책임 정의로부터 테스트 패턴을 도출하기 위해 이용할 수 있다.
하지만 고전적인 Design by Contract에서는 Precondition을 만족하는 것을 호출 측의 의무로 취급한다.
본 구상은 외부에서 호출되는 UT(Unit Test) 책임에 대해 여기에 다른 판단 축을 둔다.
호출 측에는 입력의 타당성을 기대하지 않는다. 호출된 책임이 입력을 검증하고, 성공 또는 제어된 실패를 보증한다.
따라서 외부 책임에서는 다음 내용을 정의한다.
유효 입력 시의 보증
무효 입력 시의 보증
경계·한계 시의 보증
...
한편, 책임 내부의 하위 함수는 부모가 확립한 검증된 조건을 전제로 할 수 있다.
즉, Design by Contract를 그대로 채택하는 것이 아니라,
- 조건과 보증을 명시하는 골격은 빌려온다
- 외부 입력의 책임 분담은 채택하지 않는다
- 검증된 상태가 된 책임 내부에서는 계약적인 전제를 이용한다
라는 입장이다.
Design by Contract에 대해서는 Eiffel의 공식 자료인 [Design by Contract and Assertions]와 [Design by Contract, Assertions and Exceptions]를 참조하고 있다.
세 가지 기술을 어떻게 연결할 것인가
현시점에서는 다음과 같은 역할 분담을 상정하고 있다.
Design by Contract의 지견
= 책임의 조건과 보증을 정리한다
Model-Based Testing의 지견
...
AI 승인 주도 개발의 독자성을 기존 기술과의 차이점을 과장함으로써 만들 필요는 없다.
기존 기술이 가진 강점을 연결하여, 인간이 품질을 승인하기 쉬운 구조로 재구성한다.
그것이 이 구상의 위치이다.
보물은 기대값(Expected)을 포함하는 테스트 패턴
지금까지의 이야기에서 무엇이 주인공인지 명확히 해두고 싶다.
책임 정의(Responsibility Definition)가 주인공이 아니다.
관계(Relation) 승인도 주인공이 아니다.
JSON화도 상속도, 그 자체가 목적은 아니다.
보물은 기대값(Expected)을 포함하는 테스트 패턴(Test Pattern)이다.

왜 테스트 패턴이 보물이 되는가
이 생각은 원래 내가 AI 주도 개발(AI-Driven Development)의 기본 이념으로 두고 있는 세 가지 요소에서 비롯되었다.
제약 (Constraint)
= 무엇을 지켜야 하는가
재현성 (Reproducibility)
...
제약만으로는 아직 실행할 수 없다.
재현성을 갖추기 위해서는 입력 조건이나 사전 상태를 고정할 필요가 있다.
차이(Difference)를 관측하기 위해서는 기대값(Expected)을 명시할 필요가 있다.
그 세 가지를 실행 가능한 단위로 묶으면, 테스트 패턴(Test Pattern) + 기대값(Expected)에 도달한다.
제약
↓
실행 조건·입력
...
즉, 테스트 패턴(Test Pattern) + 기대값(Expected)은,
제약을 재현 가능한 조건으로 떨어뜨려, 구현(Implementation)과의 차이를 반복해서 관측할 수 있는 형태로 만든 품질 자산
이다.
코드는 AI가 다시 만들 수 있다.
구현 방식도 기술이나 AI의 진화에 따라 바뀔 수 있다.
하지만,
- 무엇을 정상으로 볼 것인가
- 어디가 경계(Boundary)인가
- 무엇을 이상(Abnormal)으로 볼 것인가
- 실패 시 무엇을 남기지 말아야 하는가
- 고객에게 무엇을 보증하는가
- 과거의 결함을 어떻게 재발 방지할 것인가
라는 "인간이 승인한 기대"는 쉽게 다시 만들 수 없다.
그것은 고객과의 합의, 설계 판단, 장애 대응, 리뷰, 현장 경험으로부터 쌓아 올린 판단의 자산이다.
그 기대를 재현 가능하고 실행 가능한 형태로 남긴 것이 기대값(Expected)을 포함하는 테스트 패턴(Test Pattern)이다.
책임 정의
↓
테스트 관점
...
테스트 패턴은 옳음 그 자체는 아니다
다만, 본고에서 테스트 패턴을 "보물"이라고 부르는 것은 그것만으로 프로그램의 완전한 옳음을 증명할 수 있기 때문이 아니다.
유한한 개수의 테스트를 통과하더라도, 모든 입력과 상태에 결함이 존재하지 않는다는 것까지는 증명할 수 없다.
게다가 바탕이 되는 책임 정의나 제약이 틀렸다면, 거기서 생성되는 테스트 패턴도 올바르지 않게 된다.
잘못된 책임 정의
↓
정합적으로 생성된 Test Pattern
...
AI는 잘못된 전제로부터도 문서, 테스트, 코드를 매우 정합적으로 만들어 버릴 수 있다.
그렇기 때문에 승인 대상은 테스트 패턴뿐만이 아니다.
고객 승인 사양·제약
↓ 승인
책임 정의
...
그리고 각각의 명세뿐만 아니라,
제약 → 책임
책임 → Test Pattern
판단 축·판단 로그 → Expected
이라는 관계(Relation) 또한 인간에 의한 승인 대상으로 한다.
책임의 올바름은 검증 레벨에 따라 고객, 업무 책임자, 설계 책임자, 개발 책임자, 품질 담당자 등이 승인한다.
누가, 무엇을 근거로 그 책임을 승인했는지를 남긴다.
그렇다고 해서 처음부터 완전한 옳음을 증명할 수 있는 것은 아니다.
현실과의 불일치나 새로운 차이가 발견되면,
현실과의 차이
↓
판단 로그를 추가
...
와 같이 옳음의 정의 그 자체를 키워 나간다.
AI 승인 주도 개발은 완전한 옳음을 한 번에 증명하는 메커니즘이 아니다. 인간이 승인한 기대를 구조화하고, 현실과의 차이를 통해 그 기대를 계속해서 키워 나가는 메커니즘이다.
왜 테스트 코드(Test Code)가 아니라 JSON의 테스트 패턴(Test Pattern)인가
자동 테스트를 품질 자산으로서 중시하는 개발 문화는 이미 널리 존재한다.
다만, 테스트 코드는 프로그래머에게는 뛰어난 실행 가능 자산일지라도, 고객, 업무 담당자, 관리자 등 코드를 읽지 않는 승인자에게는 확인하기 쉬운 표현이라고 단정할 수 없다.
그래서 승인하는 품질 사양과 실행하는 메커니즘을 분리한다.
Test Pattern + Expected
= 인간이 승인하는 품질 사양
Test Pattern JSON 군
...
테스트 코드 자체에 기대값을 가두지 않고, 테스트 패턴(Test Pattern)과 기대값(Expected)을 구조화된 데이터로 분리한다.
그렇게 하면 코드를 읽지 않는 사람도 품질 사양을 승인하기 쉬워지며, 테스트 실행 측은 품질 확인이 완료된 범용 프로그램으로서 고정하기 쉬워진다.
통합하여 관리하는 것
= Test Pattern / Expected / 근거 / 승인 상태 / 실행 방식 / 결과 참조
테스트마다 달라도 되는 것
...
따라서 본고에서 말하는 "보물"은 테스트 코드 그 자체에 한정되지 않는다.
보물(Treasure)이란, 제약(Constraint)에 기반한 기대치(Expectation)를 인간이 승인할 수 있고, 몇 번이고 재현할 수 있으며, 구현(Implementation)과의 차이(Difference)를 관측할 수 있는 형태로 구조화한 TestPattern + Expected이다.
AI 승인 주도 개발(AI-Approval-Driven Development)의 모든 것은 이 보물을 정확하게 생성하고, 소중히 지키고, 육성하며, 재사용하기 위해 존재한다.
Expected는 반드시 TestPattern에 구체적인 값으로 직접 작성하지 않는다
모든 TestPattern에 구체적인 Expected를 중복해서 기술할 필요는 없다.
Expected를 보유하는 방식에는 적어도 다음의 세 가지 종류가 있다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기