2026. 8. 15. 09:43ㆍPROJECT/Toy Project
[Live Event Stream #3] Playback Gate 회고를 반영한 바이브 코딩 전략
1. 시작하며
이전 Playback Gate 프로젝트에서도 대부분의 코드를 AI Coding Assistant와 함께 작성했다.
당시에는 단순히
"이 기능 만들어줘"
↓
AI 구현
방식으로 개발하지 않고,
요구사항
↓
설계
↓
Task
↓
AI 구현
↓
Test
↓
성능 측정
↓
문제 분석
↓
설계 변경
이라는 흐름을 만들었다.
결과적으로 이 방식 자체는 꽤 괜찮았다.
특히 처음에는 Redis나 Index가 당연히 필요할 것처럼 생각했지만 실제 측정 결과에서는 그렇지 않았다.
Playback Gate의 최종 구조에서는 Redis가 빠졌고, Cache는 Caffeine을 사용했으며, 동시성 문제는 Redis Lock이 아니라 DB FOR UPDATE로 해결했다.
반대로 아쉬웠던 부분도 있었다.
- REQUIREMENTS.md와 DESIGN.md의 파일명이 실제 역할과 반대로 만들어졌다.
- 처음 실험 파일명에 redis, index처럼 정답을 미리 넣으려 했다.
- Phase 전체를 로컬에서 완료한 뒤 GitHub에 한 번에 올려 변화 과정이 Commit History에 남지 않았다.
- 프로젝트 중간에 ROADMAP.md의 필요성을 뒤늦게 느꼈다.
- 여러 Cursor Skill을 만들려고 했지만 실제로는 하나의 Skill과 문서만으로 충분했다.
- 성능 개선이라고 생각했던 변경이 실제로는 처리량을 개선하지 않는 경우도 있었다.
그래서 Live Event Stream에서는 기존 전략을 그대로 복사하지 않고, Playback Gate에서 실제로 개발해본 결과를 반영해 Harness를 조금 더 단순하고 명확하게 구성하려고 한다.
2. 이번에도 기본 원칙은 같다
Live Event Stream에서도 AI가 기술적 판단을 대신하도록 두지는 않는다.
AI의 역할은 다음과 같다.
정해진 요구사항과 현재 설계를 코드로 빠르게 옮기고, 테스트와 실험을 보조하는 역할
반대로 다음 부분은 개발자가 직접 통제한다.
무엇을 만들 것인가
→ REQUIREMENTS
어떤 순서로 실험할 것인가
→ ROADMAP
현재 구조는 무엇인가
→ DESIGN
어떤 기술을 선택할 것인가
→ ADR
실제로 문제가 해결됐는가
→ TEST + EXPERIMENT
이번 프로젝트에서도 AI가
Kafka에는 DLQ가 필요하니까 넣겠습니다.
중복 처리를 막기 위해 Unique Constraint를 미리 추가하겠습니다.
운영 환경을 고려해 Schema Registry를 추가하겠습니다.
라고 제안하더라도 바로 적용하지 않는다.
Live Event Stream의 목적은 이런 문제를 먼저 직접 발생시키는 것이기 때문이다.
3. Playback Gate와 달라진 Harness
이번에는 프로젝트를 시작할 때부터 문서 역할을 정확하게 고정한다.
docs/
├── REQUIREMENTS.md
├── DESIGN.md
├── ROADMAP.md
├── TASKS.md
│
├── adr/
│ └── ...
│
└── experiments/
└── ...
그리고 Cursor에는 프로젝트 전체 규칙을 관리하는 하나의 Skill만 둔다.
.cursor/
└── skills/
└── live-event-stream/
└── SKILL.md
Playback Gate에서는 기능별 Skill까지 나눌 생각을 했지만 실제로는 필요하지 않았다.
이번에는 문서는 Context를 제공하고 Skill은 작업 규칙만 강제하는 역할로 단순하게 나눈다.
4. 문서의 역할을 처음부터 고정한다
Playback Gate에서는 문서 파일명과 실제 역할이 뒤바뀌는 실수가 있었다.
이번에는 다음 규칙을 변경하지 않는다.
REQUIREMENTS.md
무엇을 만들어야 하는가?
기능 요구사항과 비기능 요구사항을 관리한다.
예:
Event API가 Event를 받을 수 있어야 한다.
Kafka에 Event를 발행해야 한다.
Consumer가 Event를 처리해야 한다.
최종적으로 중복 Event가 결과를 중복시키지 않아야 한다.
여기에는 구현 방법을 넣지 않는다.
DESIGN.md
현재 시스템은 어떻게 동작하는가?
현재 코드의 실제 구조만 기록한다.
초기에는:
Event API
↓
Producer
↓
Kafka
↓
Consumer
↓
MySQL
정도로 시작한다.
나중에 Retry Topic이나 DLQ를 실제로 도입했다면 그때 DESIGN을 수정한다.
Main Topic
↓
Consumer
↓
Retry
↓
DLQ
ROADMAP에 등장한다는 이유만으로 미리 DESIGN에 추가하지 않는다.
ROADMAP.md
어떤 문제를 어떤 순서로 확인할 것인가?
Live Event Stream의 전체 Phase와 각 Phase의 완료 조건을 관리한다.
Baseline Pipeline
↓
Baseline 측정
↓
Consumer Lag
↓
Partition / Consumer 실험
↓
중복 처리
↓
실패 / Retry / DLQ
↓
Replay / Recovery
↓
Schema 변경
↓
최종 비교
중요한 점은 ROADMAP도 기술 도입 순서가 아니라 문제 확인 순서라는 것이다.
TASKS.md
현재 Phase에서 지금 무엇을 해야 하는가?
예를 들어 Phase 1이라면:
- Event DTO 구현
- Event API 구현
- Kafka Producer 구현
- Consumer 구현
- Event 저장
- Integration Test
만 기록한다.
Phase 4의 DLQ 작업을 미리 TASKS에 넣지 않는다.
현재 Phase가 끝난 뒤 다음 Phase의 TASK로 교체한다.
5. 이번에는 Git도 Harness에 포함한다
Playback Gate에서는 전체 프로젝트를 로컬에서 완료한 뒤 한 번에 GitHub에 올렸다.
그래서 최종 결과는 남았지만,
Race Condition이 존재하던 상태
↓
Race를 재현한 상태
↓
Lock을 적용한 상태
같은 변화 과정이 Commit History에서는 잘 보이지 않았다.
Live Event Stream에서는 이 부분을 바꾼다.
모든 작은 수정마다 Commit할 필요는 없지만 실험의 기준점이 되는 상태는 Commit으로 남긴다.
예를 들어:
feat: implement baseline event pipeline
experiment: reproduce consumer lag
experiment: reproduce duplicate event processing
fix: add idempotent event handling
experiment: reproduce poison message blocking
feat: add retry and dlq handling
처럼 남긴다.
특히 문제를 해결하기 전 상태를 Commit으로 남긴다.
문제 존재
↓
Commit
↓
실험으로 재현
↓
해결
↓
Commit
이렇게 하면 README나 블로그에서 결과만 설명하는 것이 아니라 실제 코드 변화도 함께 보여줄 수 있다.
6. 실험 파일명에는 답을 넣지 않는다
Playback Gate를 시작할 때는 다음과 같은 파일명을 생각했다.
002-db-index.md
003-redis-cache.md
하지만 실제 결과는 Index가 아니었고 Redis도 아니었다.
파일 이름에 기술을 넣는 순간 이미 실험의 결론을 정해놓은 셈이 된다.
Live Event Stream에서는 실험 이름을 문제 중심으로 작성한다.
예를 들어:
001-baseline.md
002-throughput-analysis.md
003-consumer-lag.md
004-partition-consumer-scaling.md
005-duplicate-processing.md
006-failure-handling.md
007-recovery-replay.md
008-schema-evolution.md
009-final-comparison.md
처럼 작성한다.
잘못된 예:
004-add-partitions.md
005-redis-deduplication.md
006-add-dlq.md
좋은 예:
004-partition-consumer-scaling.md
005-duplicate-processing.md
006-failure-handling.md
실험 결과에 따라 Partition을 늘리지 않을 수도 있고 Redis를 사용하지 않을 수도 있기 때문이다.
7. 문제는 해결하기 전에 먼저 재현한다
Playback Gate에서 가장 잘 작동했던 방식 중 하나가 Race Condition을 먼저 재현했던 것이다.
BASIC 동시 재생 제한 = 1
40개 동시 요청
↓
ACTIVE Session = 40
이 상태를 확인한 뒤 Lock을 비교했다.
Live Event Stream에서도 같은 방식을 사용한다.
예를 들어 중복 처리를 학습하고 싶다면 처음부터 eventId UNIQUE를 넣지 않는다.
먼저:
Event 처리
↓
DB INSERT
↓
Offset Commit 전 Consumer 종료
↓
Consumer 재시작
↓
같은 Event 재처리
↓
DB 중복 저장
상황을 만든다.
그리고 실제 중복 데이터를 확인한 뒤 해결 방법을 비교한다.
Consumer Lag 역시 마찬가지다.
처음부터 Consumer Thread와 Partition을 많이 만들지 않는다.
Producer
5,000 events/sec
↓
Consumer
1,000 events/sec
↓
Lag 증가
상태를 먼저 만들어본다.
즉 이번 프로젝트에서는 다음 규칙을 강하게 적용한다.
학습 대상으로 정한 문제는 AI가 예방하지 않는다. 먼저 재현한 뒤 해결한다.
8. Kafka의 'Best Practice'도 정답으로 취급하지 않는다
Playback Gate에서는 Redis가 대표적인 예였다.
처음에는 당연히 필요할 것 같았지만 실제로는 그렇지 않았다.
Kafka에서도 비슷한 일이 발생할 수 있다.
예를 들어:
Partition은 많을수록 좋다.
Consumer는 많을수록 좋다.
Batch Consumer가 항상 빠르다.
Retry Topic이 항상 필요하다.
Redis Deduplication이 좋다.
같은 문장을 그대로 적용하지 않는다.
예를 들어 Partition을 3개에서 12개로 늘렸다고 가정한다.
Partition 3
→ 10,000 events/sec
Partition 12
→ 10,100 events/sec
라면 Partition이 병목이 아닐 가능성이 있다.
DB INSERT가 병목일 수도 있고 Consumer 로직 자체가 느릴 수도 있다.
따라서 AI에게:
Partition을 늘려서 성능을 개선해줘.
라고 요청하지 않는다.
대신:
현재 측정 결과
Producer: 8,000 events/sec
Consumer: 2,100 events/sec
Lag: 지속 증가
Partition: 3
Consumer: 3
DB Connection Pool: 포화
이 결과를 기준으로 병목 후보를 분석하고
가능한 해결 방법을 비교하라.
아직 코드는 변경하지 마라.
와 같이 요청한다.
9. AI에게는 항상 Plan을 먼저 요청한다
Playback Gate에서도 사용했던 규칙이지만 이번에는 더 엄격하게 적용한다.
특히 Kafka 설정은 작은 설정 하나가 Offset Commit이나 Retry 동작을 바꿀 수 있기 때문이다.
AI에게 바로 코드를 수정하게 하지 않는다.
현재 REQUIREMENTS.md
DESIGN.md
ROADMAP.md
TASKS.md
Experiment 결과
를 기준으로 이번 Task의 변경 계획을 작성하라.
수정할 파일,
설정 변경,
예상되는 Kafka 동작,
검증 방법을 설명하라.
아직 코드는 수정하지 마라.
먼저 계획을 확인한다.
그 후 다음 질문을 확인한다.
왜 이 설정이 필요한가?
Offset Commit 시점이 바뀌는가?
중복 가능성이 바뀌는가?
Ordering에 영향을 주는가?
실험하려던 문제를 미리 없애지는 않는가?
문제가 없다면 구현하게 한다.
10. Kafka 설정은 코드보다 더 주의해서 검토한다
Playback Gate에서는 주로 Java 코드와 SQL을 확인했다.
Live Event Stream에서는 Kafka Consumer 설정 역시 설계의 일부다.
예를 들어 다음 설정들은 단순한 옵션이 아니다.
enable.auto.commit
auto.offset.reset
ack-mode
max.poll.records
max.poll.interval.ms
session.timeout.ms
이 값에 따라:
- Event가 언제 처리 완료로 판단되는지
- Event가 다시 전달될 수 있는지
- Consumer가 Group에서 빠지는 시점
- 한 번에 몇 개의 Event를 처리하는지
가 달라질 수 있다.
따라서 AI가 설정을 추가하면 최소한 다음을 확인한다.
설정 이름
기본값
현재 설정값
왜 변경했는가
어떤 동작이 달라지는가
현재 실험 결과와 어떤 관계가 있는가
단순히
Kafka 권장 설정입니다.
라는 이유로 변경하지 않는다.
11. 완료 조건을 기능과 실험으로 나눈다
Playback Gate에서는 테스트를 구현 완료 조건으로 사용했다.
Live Event Stream에서는 이를 조금 더 세분화한다.
기능 Task 완료 조건
예:
Task
Kafka Producer 구현
완료 조건
- 정상 Event 발행
- 잘못된 Event 거절
- memberId가 Key로 사용됨
- Integration Test 통과
실험 Task 완료 조건
예:
Task
Consumer Lag 재현
완료 조건
- Producer Events/sec 기록
- Consumer Events/sec 기록
- Lag 증가 확인
- 최대 Lag 기록
- 부하 종료 후 회복 시간 기록
- 실험 문서 작성
AI가 코드를 작성했다고 실험이 끝난 것이 아니다.
측정 결과가 문서에 남아야 Experiment가 완료된 것으로 판단한다.
12. ADR은 Phase가 아니라 결정에 대해 작성한다
Playback Gate를 진행하면서 가장 헷갈렸던 부분 중 하나가 Phase와 ADR의 관계였다.
이번에는 처음부터 명확하게 정한다.
Phase 변경
≠
ADR 작성
ADR은 중요한 설계 결정을 했을 때만 작성한다.
예를 들어:
Phase 2
Baseline 측정 완료
↓
Phase 3 이동
은 ADR이 필요 없다.
반면:
중복 처리 문제 발생
↓
Unique Constraint
DB 처리 Event Table
Redis Deduplication
비교
↓
DB Unique Constraint 선택
처럼 중요한 정합성 전략을 선택했다면 ADR을 작성한다.
adr/
001-event-idempotency.md
Retry 전략을 선택했다면:
002-retry-dlq-strategy.md
처럼 작성한다.
13. DESIGN은 결과만 반영한다
ROADMAP에는 앞으로 검증할 후보가 많이 등장한다.
예:
Retry
DLQ
Partition 증가
Batch Consumer
Redis Deduplication
Schema Registry
하지만 이것들이 DESIGN에 있다는 의미는 아니다.
DESIGN에는 실제로 현재 코드에 존재하는 것만 기록한다.
예를 들어 Phase 1의 DESIGN이:
Event API
↓
Kafka
↓
Consumer
↓
MySQL
이라면,
Phase 4에서 Retry/DLQ를 실제로 선택한 이후에만:
Event API
↓
Kafka
↓
Consumer
│
├─ 성공 → MySQL
│
└─ 실패
↓
Retry
↓
DLQ
로 수정한다.
DESIGN은 미래 계획 문서가 아니라 현재 시스템의 Snapshot으로 유지한다.
14. 측정값이 기대와 다르더라도 그대로 남긴다
Playback Gate에서는 Hikari Pool을 10에서 40으로 늘리면 처리량이 크게 올라갈 것으로 예상했다.
실제로는 Pending은 줄었지만 RPS는 거의 증가하지 않았다.
최종 시스템 역시 Baseline보다 RPS가 낮았다.
그 결과도 그대로 기록했다.
Live Event Stream에서도 동일하게 적용한다.
예를 들어:
Consumer 1개
= 2,000 events/sec
Consumer 3개
= 4,800 events/sec
Consumer 6개
= 4,900 events/sec
가 나왔다면
Consumer를 확장해서 성능을 개선했다.
로 끝내지 않는다.
대신:
1 → 3에서는 증가
3 → 6에서는 거의 증가하지 않음
↓
다른 병목이 존재
라고 기록한다.
가설이 틀린 것도 실험 결과다.
15. README도 처음부터 Harness로 본다
Playback Gate에서는 프로젝트를 끝낸 뒤 README를 테스트 방법 중심으로 수정했다.
이번에는 처음부터 README 역할을 명확하게 정한다.
README는 아키텍처 설명을 길게 복사하는 문서가 아니다.
GitHub를 처음 보는 사람이 다음 질문에 바로 답할 수 있도록 작성한다.
이 프로젝트가 무엇인가?
어떻게 실행하는가?
Event를 어떻게 보내는가?
Kafka에서 Event가 들어왔는지 어떻게 확인하는가?
테스트는 어떻게 실행하는가?
부하 테스트는 어떻게 실행하는가?
Consumer Lag은 어디서 보는가?
실험 결과는 어디에 있는가?
즉 README는 사람을 위한 문서이면서 동시에 프로젝트를 검증하기 위한 Harness의 진입점으로 사용한다.
16. 이번 프로젝트의 Loop
Live Event Stream에서는 다음 Loop를 기본 개발 절차로 사용한다.
ROADMAP
현재 Phase 확인
↓
TASK
현재 작업 선택
↓
PLAN
AI 변경 계획
↓
HUMAN REVIEW
계획 확인
↓
IMPLEMENT
AI 구현
↓
TEST
기능 검증
↓
EXPERIMENT
문제 재현 / 측정
↓
ANALYZE
결과 분석
↓
DECIDE
설계 변경 여부 결정
↓
ADR
필요한 경우 의사결정 기록
↓
DESIGN
현재 구조 갱신
↓
COMMIT
실험 기준점 저장
↓
NEXT TASK
Playback Gate보다 한 단계 추가된 부분은 COMMIT이다.
Git History까지 실험 과정의 일부로 남긴다.
17. Human Gate를 두는 지점
모든 단계에서 사람이 승인할 필요는 없다.
단순 DTO 작성이나 테스트 코드 생성까지 매번 확인하면 바이브 코딩의 장점이 줄어든다.
대신 결과가 시스템의 의미를 바꾸는 지점에만 Human Gate를 둔다.
예를 들어 다음 변경은 반드시 확인한다.
Kafka 전달 보장 변경
Ack 방식 변경
Offset Commit 방식 변경
데이터 정합성 변경
Idempotency 방식 결정
Unique Constraint 추가
Deduplication Store 추가
Event Ordering 변경
Kafka Key 변경
Partition 전략 변경
장애 처리 변경
Retry 전략
DLQ
Retry 횟수 / Backoff
구조 변경
Redis 추가
Schema Registry 추가
새 Consumer Group 추가
반대로 단순 리팩터링이나 반복 코드 작성은 AI에게 더 많이 맡긴다.
즉 Playback Gate보다 Human Gate의 위치를 명확하게 정의한다.
18. Graph Engineering은 이번에도 목표가 아니다
Live Event Stream이 Playback Gate보다 구조는 복잡하지만 처음부터 여러 Agent를 연결하지 않는다.
예를 들어:
Planner Agent
↓
Coding Agent
↓
Kafka Test Agent
↓
Performance Agent
↓
Review Agent
같은 Graph를 만드는 것은 이번 프로젝트의 목적이 아니다.
우선:
Harness
+
Human-controlled Loop
를 유지한다.
다만 반복 실험이 많아지면 일부 과정은 자동화할 수 있다.
예를 들어:
부하 테스트 실행
↓
Metric 수집
↓
결과 Markdown 생성
정도는 자동화 후보가 될 수 있다.
Graph는 여러 Agent가 실제로 필요한 문제가 생겼을 때만 고려한다.
19. Playback Gate에서 Live Event Stream으로 바뀐 전략
두 프로젝트의 전략을 비교하면 다음과 같다.
항목Playback GateLive Event Stream
| 문서 구조 | 진행 중 정리 | 시작부터 이름과 역할 고정 |
| ROADMAP | 중간에 중요성 확인 | 시작부터 핵심 Harness |
| Skill | 여러 하위 Skill도 고려 | 하나의 프로젝트 Skill만 유지 |
| Experiment 이름 | 기술명이 들어갈 뻔함 | 문제 중심으로만 작성 |
| 문제 재현 | Race에서 적극 적용 | 모든 핵심 문제에 적용 |
| Git | 완료 후 한 번에 Push | 실험 기준점마다 Commit |
| README | 마지막에 테스트 안내 강화 | 처음부터 실행/검증 진입점 |
| AI Plan | 변경 전 확인 | Kafka 설정까지 반드시 확인 |
| Human Gate | 일반적인 설계 변경 | Offset·Ordering·정합성·장애 전략에 집중 |
| Graph | 사용하지 않음 | 이번에도 필요할 때만 |
20. 이번 프로젝트의 최종 바이브 코딩 전략
Live Event Stream에서는 다음 구조로 개발한다.
REQUIREMENTS
│
▼
ROADMAP
│
▼
TASKS
│
▼
AI PLAN
│
▼
HUMAN GATE
│
▼
IMPLEMENT
│
▼
TEST
│
▼
EXPERIMENT
│
▼
MEASURE
│
▼
ANALYZE
│
┌────────┴────────┐
│ │
변경 불필요 설계 변경
│ │
│ ADR
│ ↓
│ DESIGN
│ │
└────────┬────────┘
↓
COMMIT
↓
NEXT TASK
Playback Gate에서 배운 가장 큰 점은 처음 예상한 기술이 최종 답이 아닐 수 있다는 것이었다.
그래서 Live Event Stream에서도 Kafka를 사용하는 것 외에는 가능한 한 답을 미리 정하지 않는다.
Partition을 늘리지 않을 수도 있다.
Redis를 끝까지 사용하지 않을 수도 있다.
Batch 처리가 효과가 없을 수도 있다.
Retry Topic보다 다른 방식이 더 단순할 수도 있다.
중요한 것은 특정 기술을 사용하는 것이 아니다.
문제를 직접 재현하고, 측정하고, 후보를 비교한 뒤 현재 상황에 맞는 선택을 하고 그 결과를 다시 검증하는 것
이 이번 Live Event Stream에서도 유지할 바이브 코딩의 기본 원칙이다.
그리고 Playback Gate와 달라진 점은 여기에 문서 구조, Phase Gate, 실험 기록, Git History까지 Harness의 일부로 관리한다는 것이다.
다음 단계에서는 이 전략을 실제 개발에 적용할 수 있도록 Live Event Stream의 ROADMAP과 초기 DESIGN을 작성해보려고 한다.
'PROJECT > Toy Project' 카테고리의 다른 글
| [ContentOps Agent #1] 프로젝트 소개와 학습 목표 (0) | 2026.08.15 |
|---|---|
| [Live Event Stream #4] 회고 (0) | 2026.08.15 |
| [Live Event Stream #2] 요구사항 정의 (0) | 2026.08.15 |
| [Live Event Stream #1] 프로젝트 소개와 학습 목표 (0) | 2026.08.15 |
| [Playback Gate #4] 회고 (0) | 2026.08.14 |