루프: 의도 → 생성 → 검토 → 개선
이 책의 모든 것은 하나의 사이클로 귀결된다. 이것을 체화하라.
루프는 출력이 당신의 기준을 충족할 때까지 돈다 — 그리고 검토는 매번 통과해야 하는 관문이다:
┌──────────────────────────────────────────────┐
│ │
▼ │
┌────────┐ ┌──────────┐ ┌────────┐ ┌──────────┐
│ 의도 │ ─▶ │ 생성 │ ─▶ │ 검토 │ ─▶ │ 개선 │
│ 명세 │ │ (AI) │ │ 당신 │ │ 당신 │
└────────┘ └──────────┘ └───┬────┘ └──────────┘
│
통과? ▼
┌──────────┐
│ 출시 │
└──────────┘
- 의도(Intent). 원하는 것과 중요한 제약을 진술하라 — 입력, 출력, 엣지 케이스, 스택, 스타일. 모호한 의도는 모호한 코드를 낳는다.
- 생성(Generate). 모델이 구현을 작성하게 하라. 문법을 일일이 붙잡지 말고, 동작을 설명하라.
- 검토(Review). 돌아온 결과를 읽어라. 실제로 그 일을 하는가? 빈 리스트, null, 실패한 네트워크 호출을 처리하는가? 작동하는 것 중 가장 단순한 버전인가?
- 개선(Refine). 무엇이 잘못됐는지 가리키고, 구체적인 수정을 제시하고, 다시 생성하라. 기준을 충족할 때까지 반복하라.
대부분의 초보자는 3단계를 건너뛴다. 생성하고, 돌아가고, 넘어간다. 그러다 설명한 적 없는 케이스에서 프로덕션이 깨진다. 검토 단계가 바로 엔지니어링이 일어나는 곳이다.
이 루프에서 좋은 첫 프롬프트는 다음과 같은 모습이다:
TypeScript 함수 `parseDuration(input: string): number` 를 작성해줘.
"1h30m", "45s", "2d" 같은 문자열을 총 초(seconds)로 변환한다.
요구사항:
- 단위 지원: d (일), h (시간), m (분), s (초).
- 여러 단위 조합 가능: "1h30m" = 5400.
- 잘못된 입력(빈 값, 알 수 없는 단위, 음수)은 명확한 메시지와 함께
Error 를 throw 해서 거부한다.
- 외부 라이브러리 금지. 엣지 케이스를 다루는 단위 테스트 5개 포함.
함수와 테스트만 보여줘.
구조에 주목하라: 정확한 시그니처, 명시적인 규칙, 명시된 엣지 케이스, 진술된 제약, 그리고 테스트 요청. 당신은 모델이 알아서 맞추기를 바라는 게 아니다 — 잘못된 추측을 만들어내는 모호함을 제거하는 것이다.
개선 단계도 첫 프롬프트만큼이나 하나의 기술이다. 모호한 피드백은 모호한 수정을 낳는다. 이 두 가지 수정 요청을 비교해보라:
나쁜 예: "이거 틀렸어, 고쳐줘"
좋은 예: "parseDuration('1h30m') 가 5400 대신 90 을 반환해 — 숫자는
더하면서 단위 배수를 무시하고 있어. 더하기 전에 각 값에
해당 단위의 초(d=86400, h=3600, m=60, s=1)를 곱해야 해.
그리고 조합 케이스 '2d3h' 에 대한 테스트도 추가해줘."
좋은 쪽은 증상, 원인, 그리고 수정 방법을 명시한다. 당신은 동료의 풀 리퀘스트를 검토하듯 검토하고 있는 것이다 — 그리고 더 정밀하게 가리킬수록 더 적은 라운드를 쓴다. 각 루프는 수렴해야 한다. 제자리를 맴돌고 있다는 느낌이 든다면, 그것은 의도가 명세 부족이었다는 신호다. 다시 생성하기를 멈추고 명세를 다시 써라.