생성된 프로젝트 키워 가기
생성된 프로젝트는 처음 돌았다고 끝나지 않습니다. 에이전트 키트의 Pet Store 벤치마크 (benchmarks/petstore)는 먼저 빈 폴더에서 쇼핑몰을 만들게 하고, 완성된 쇼핑몰마다 변경 요청을 주어, 작업이 어디서 DSL 을 벗어나는지 보았습니다. 측정은 Claude Code 와 ElastiCORE 에이전트 키트로, 구성마다 한 번씩, 작성자들이 Windows PC 한 대에서 했습니다. 결과물은 별도의 Claude Code 에이전트가 체크리스트로 빌드·기동·호출해 채점했습니다.
변경 요청
동작하는 쇼핑몰 위에(task-2.ko.md):
- 재고. 품목에 재고 수량(0 이상, 필수). 주문하면 각 줄의 수량만큼 재고가 줄고, 한 줄이라도 모자라면 주문 전체를 거부(409, 메시지에 품목 이름). 취소하면 재고를 되돌림. 관리자는 재고를 고칠 수 있음.
- 리뷰. 로그인한 회원이 품목에 리뷰: 별점(1
5), 내용(11000자), 작성 시각(서버가 정함). 한 회원은 한 품목에 하나만 (두 번째는 409). 수정·삭제는 쓴 사람만(관리자는 삭제 가능). 누구나 품목별 리뷰를 최신순으로 봄. 응답에는 쓴 사람의 로그인 ID 만 있고 다른 개인정보는 없음. - 택배사 연동. 관리자가 배송 처리하면 택배사 API 를 불러 운송장 번호를 주문에 저장. 택배사 주소는 설정 파일에, 기본은 서버 안의 가짜 택배사. 택배사가 오류를 내면 배송 처리는 실패하고 주문은 PLACED 로 남음(502).
- BI 지표. 매출(취소 제외 total 합), 주문 수(취소 제외), 객단가(매출 / 주문 수), 회원 수를 표준 시맨틱 모델(Apache Ossie) 파일로. 관리자 매출 요약 API 도 객단가를 함께.
- 한국어 오류 메시지.
Accept-Language: ko면 검증 오류의 필드 메시지를 한국어로, 없으면 지금처럼 영어.
결과
세 구성 - Java 헥사고날, Java DDD, Kotlin 헥사고날 - 을 각자 완성된 쇼핑몰의 복사본 위에서, 변경이 diff 로 보이도록 먼저
커밋한 뒤 진행하고 checklist-2.md(20개 항목)로 채점했습니다:
| 구성 | 점수 | 시간 | 비용 | 턴 |
|---|---|---|---|---|
| Java 헥사고날 | 20 / 20 | 13분 24초 | $1.67 | 56 |
| Java DDD | 19.5 / 20 | 14분 11초 | $2.02 | 70 |
| Kotlin 헥사고날 | 20 / 20 | 13분 58초 | $1.77 | 70 |
바뀐 프로젝트를 복사본에서 다시 생성하면 아무 파일도 쓰지 않았고 SKIP(user-modified) 도 없었습니다: 손으로 쓴
코드는 모두 개발자 소유 파일에만 있었습니다.
업무 로직으로 남은 손 코드: 주문 때 재고를 빼고 취소 때 되돌리기, 리뷰에 쓴 사람의 로그인 저장, 택배사 호출 자체.
드러난 것과 바뀐 것
| 보인 것 | 지금 (ElastiCORE 3.0.261022-rc1, 키트 0.4.0) |
|---|---|
세 구성 모두 긴 가이드에서 metrics: 와 ossie-export 를 찾음 | 키트의 빠른 참조에 있음 |
기본 검증 메시지가 서버 머신의 언어로, DSL 메시지는 영어로 섞임. 구성마다 spring.web.locale 을 쓰거나 ValidationMessages.properties 를 씀 | 한 응답은 한 언어: Accept-Language, 아니면 spring.web.locale, 머신의 언어는 쓰지 않음 |
update() override 에 쓴 규칙을 PUT /batch 가 건너뜀 (관리자가 회원의 리뷰를 고침) | batchUpdate 가 update() 를 부름. 쓰기 규칙의 자리는 beforeSave |
| 리뷰를 다른 품목으로 옮길 수 있었음 | 참조의 @updatable(false) 가 동작 |
TypeScript 클라이언트가 처음 모델에 머묾 (elcore3ts 는 별도 태스크) | typescriptClient = true, 클라이언트가 모델보다 오래되면 경고 |
| 택배사 실패를 502 로 답하려고 예외와 처리기를 손으로 씀 | PortCallException, 502 |
| 모르는 enum 값이 Spring 의 기본 본문으로 답함 | 모든 요청 오류가 fieldErrors 가 있는 problem+json |
count(Customer) 가 bare COUNT(*) 로 나감 | 지표가 어느 dataset 인지 말함 |
| 이름 검색이 대소문자를 구분 | v3 번들(헥사고날·DDD·Kotlin·-Pv3)에서 @search(like) 는 대소문자 무시 |
그 전에: 쇼핑몰 만들기
처음 과제(task.ko.md): 카탈로그, 로그인하는 회원, 생명주기와 서버가 계산하는 가격의 주문, 관리자 보고서, 정적 화면 -
24개 항목으로 채점.
1회차(고치기 전, 키트 0.3.0): 세 구성 모두 24 중 23.5. 8분 06초(Java 헥사고날), 8분 40초(Java DDD), 30분 53초
(Kotlin 헥사고날). 모든 구성이 값 객체, @login/@access, states:, @snapshot/@compute 를 가이드에서 찾았고,
런타임 jar 를 javap 로 열었고, 로그인 컨트롤러, 참조한 행의 존재 확인, 거절된 상태 이동의 409, 주문 시각을 손으로
썼습니다. 이것이 ElastiCORE 의 @signin, requireReferences(404), 409, @readonly @default(now) 가 되었고, 키트에는 상점
레시피와 런타임 클래스 표가 생겼습니다. 레시피 를 쓰면서 ElastiCORE 버그 두 개도 찾아 고쳤습니다 - 필수 필드가 있는
선택 임베디드 주소가 주소 없는 주문을 모두 거절한 것, 읽지 못한 모델 파일이 빠진 채 빌드가 성공한 것.
2회차(고친 뒤, 키트 0.4.0):
| 구성 | 점수 | 시간 | 비용 | 턴 |
|---|---|---|---|---|
| Java 헥사고날 | 24 / 24 | 7분 25초 | $0.86 | 28 |
| Java DDD | 23 / 24 | 8분 49초 | $1.01 | 37 |
| Kotlin 헥사고날 | 24 / 24 | 9분 14초 | - | - |
어느 구성도 쇼핑몰 기능을 긴 가이드에서 찾지 않았고, 로그인 컨트롤러나 역할 검사를 쓰지 않았습니다. 남은 손 코드: 시작 데이터, 보고서 엔드포인트, 이벤트 리스너, 개발자 소유 서비스의 VAT·할인.
키트의 상점 레시피는 1회차 뒤에 쓰였고 이 과제와 가깝습니다. 그래서 2회차는 과제의 도메인에 맞는 레시피가 있는 키트를 잰 것입니다. 구성마다 한 번씩 돌렸고, 과제·체크리스트·실행 스크 립트·분석 스크립트는 벤치마크 폴더에 있습니다.
내 프로젝트에서의 순서
- 변경 요청을 업무의 말로 적습니다.
- YAML 을 고치고, 다시 생성·컴파일하고, DSL 경고를 모두 고칩니다.
- DSL 이 말할 수 없는 것만 개발자 소유 파일에 씁니다(
beforeSave, 명령 override, 작은 컨트롤러). - 띄워서 불러 봅니다 - 거절까지.
- 바뀐 것을 업무의 말로 보고하고, 한 번 더 다시 생성해 생성 파일에 손댄 것이 없음을 확인합니다.
에이전트 키트가 AI 도구와 함께 바로 이 일을 합니다: 변경 요청.