2교시 · 문제 정의와 구현 전략
1일차 11:00–12:00 · 이론/실습 선행: 1교시(환경 구축 완료)
🎯 학습 목표
- 모호한 한 줄 요구("매출 분석해 줘")를 검증 가능한 작은 기능 단위로 분해할 수 있다.
- 각 기능을 클린 아키텍처의 어느 계층에 둘지 1차로 매핑할 수 있다.
- "어디부터 만들고 테스트할지" TDD 진입 순서를 근거를 들어 정한다.
📖 개념 1 — 모호한 요구가 실패하는 진짜 이유
소프트웨어 개발에서 가장 흔한 실패는 이렇게 시작합니다.
❌ 요구: "매출 분석 앱 만들어 줘" ❌ 결과물: (그럴듯한 200줄이 한 덩어리로) ❌ 문제: 무엇이 맞고 틀린지 아무도 모름. 고치려 해도 어디를 건드릴지 모름.
문제의 뿌리는 요구가 모호하다는 것입니다. 모호한 요구는 "가장 흔한 방식"으로 대충 채워지고, 그 결과가 우리가 원한 것과 다를 뿐입니다. 이것은 사람이 직접 짜든, 나중에(12·13교시) AI에게 맡기든 똑같이 적용됩니다 — 오히려 AI는 모호함을 더 빠르게 잘못된 코드로 바꿔 놓습니다.
그래서 구현에 앞서 사람이 먼저 정해야 할 것은 다음 세 가지입니다.
- 무엇을 만들 것인가 (기능을 또렷하게 정의)
- 왜 그렇게 만드는가 (제약·우선순위)
- 어떤 순서로 만들 것인가 (검증하기 쉬운 것부터)
이 교시에서 그 "설계 도면"을 만듭니다. 도면이 정확할수록 직접 구현하기도 쉽고, 12·13교시에서 Copilot에게 정확히 시키기도 쉬워집니다.
📖 개념 2 — "검증 가능한 단위"란 무엇인가
기능을 쪼갤 때의 기준은 "입력 → 출력이 한 문장으로 떨어지는가" 입니다.
- ❌ "데이터를 처리한다" — 너무 큼. 입력도 출력도 불분명.
- ✅ "CSV 파일 경로를 받아 → 유효한 매출 레코드 목록을 돌려준다" — 입력/출력이 명확. 그래서 테스트할 수 있음.
입력과 출력이 분명하면, "이 입력을 주면 이 출력이 나와야 한다"는 테스트를 쓸 수 있습니다. 즉, 검증 가능한 단위 = 테스트 가능한 단위입니다. 기능을 이 수준까지 쪼개는 것이 이 교시의 핵심 작업입니다.
💻 실습 1 — 요구사항을 사용자 시나리오로 쓰기
docs 폴더를 만들고 requirements.md를 작성합니다.
New-Item -ItemType Directory -Force -Path docs
VS Code에서 docs/requirements.md를 만들고 다음을 작성합니다.
# 매출 인사이트 에이전트 — 요구사항
## 한 줄 정의
영업 담당자가 매출 CSV를 올리면, 핵심 지표·차트·AI 요약이 담긴
리포트를 1분 안에 받아볼 수 있다.
## 사용자 시나리오 (사용자가 겪는 순서대로)
1. 사용자가 매출 CSV 파일을 업로드한다.
2. 시스템이 데이터 형식을 검증하고 정리한다(잘못된 행은 건너뛴다).
3. 시스템이 총매출·기간·상위 상품·지역별 매출·월별 추이를 계산한다.
4. 시스템이 차트(상위 상품, 월별 추이)를 그린다.
5. AI가 분석 결과를 자연어 인사이트로 요약한다.
6. 사용자가 리포트(요약+지표+차트)를 다운로드한다.
## 입력 데이터 형식 (CSV)
| 컬럼 | 타입 | 예시 |
|---|---|---|
| date | 날짜(YYYY-MM-DD) | 2024-01-05 |
| product | 문자열 | 노트북 |
| region | 문자열 | 서울 |
| quantity | 정수(>0) | 3 |
| unit_price | 실수(>0) | 1200000 |
> 매출액(revenue) = quantity × unit_price 로 계산한다.
> 이 값은 저장하지 않고 필요할 때마다 계산한다. (이유는 아래 관찰 포인트)
## 제약/비기능 요구
- API 키는 .env 파일로만 다룬다 (코드/깃에 노출 금지).
- 잘못된 행은 분석을 멈추지 않고 "제외 사유"와 함께 건너뛴다.
- 모든 핵심 로직은 테스트로 검증한다.
🔍 관찰 포인트 1 — 명사와 동사를 구분해 읽으세요. 요구사항 문장에는 명사와 동사가 섞여 있습니다.
- 명사("매출 레코드", "분석 결과", "리포트") → 나중에 데이터 구조(엔티티) 가 됩니다.
- 동사("검증한다", "계산한다", "요약한다") → 나중에 기능(유스케이스/어댑터) 이 됩니다. 다음 실습에서 이 둘을 분리합니다.
🔍 관찰 포인트 2 — 매출액을 "저장하지 않고 계산"하는 이유. 매출액을 별도 컬럼으로 저장하면, 수량이나 단가가 바뀔 때 매출액도 따로 고쳐야 하고, 깜빡하면 데이터가 어긋납니다(불일치). 대신 "수량 × 단가"로 항상 계산하면, 원본(수량·단가) 하나만 관리하면 됩니다. 이를 단일 진실 원천(Single Source of Truth) 이라 합니다.
💻 실습 2 — 기능 단위로 분해하기
시나리오의 동사를 뽑아, 독립적으로 테스트 가능한 기능으로 쪼갭니다. 각 기능에 식별자(F1~F7)를 붙입니다.
| # | 기능 | 입력 → 출력 | 1차 계층 |
| F1 | 매출 한 건을 표현·검증 | 값들 → SalesRecord(또는 오류) | domain |
| F2 | CSV에서 매출 레코드 목록 적재 | 파일 경로 → SalesRecord 목록 + 제외 목록 | adapter |
| F3 | 매출 지표 분석 | SalesRecord 목록 → AnalysisResult | usecase |
| F4 | 차트 생성 | AnalysisResult → 이미지 파일 | adapter |
| F5 | AI 인사이트 요약 | AnalysisResult → 요약 텍스트 | adapter(LLM) |
| F6 | 리포트 조립·저장 | 결과+요약+차트 → Report 파일 | usecase |
| F7 | 웹 화면 연결 | 업로드 → 위 흐름 → 다운로드 | infra/UI |
🔍 관찰 포인트 — F1과 F3은 "순수"하다. F1(레코드 검증)과 F3(지표 분석)을 보세요. 둘 다 파일·네트워크·화면이 전혀 필요 없습니다. 값을 받아 계산하거나 검증할 뿐입니다. 이런 "순수한" 기능은:
- 테스트하기 가장 쉽고 (외부 도구 없이 입력만 주면 됨),
- 통과/실패가 가장 명확하며,
- 다른 모든 기능이 의존하는 핵심입니다. 그래서 가장 먼저 만들 후보입니다.
📖 개념 3 — TDD: Red → Green → Refactor
테스트 주도 개발(TDD)은 테스트를 먼저 쓰는 개발 방식입니다. 세 단계를 반복합니다.
🔴 Red : 아직 구현이 없어서 "실패하는" 테스트를 먼저 쓴다
→ 이 테스트가 곧 "무엇을 만들지"의 명세가 된다
🟢 Green : 그 테스트를 통과시키는 "최소한"의 코드를 쓴다
→ 더도 말고 덜도 말고, 통과에 필요한 만큼만
🔵 Refactor : 테스트를 통과한 상태를 유지하며 코드를 다듬는다
→ 동작은 그대로, 코드 품질만 향상
왜 테스트를 먼저 쓰나요? 세 가지 이득이 있습니다.
- 테스트가 곧 "이 기능이 무엇을 해야 하는가"의 실행 가능한 명세가 됩니다. 말로 된 요구가 코드로 된 기준으로 바뀝니다.
- 명세(테스트)가 있으면 구현이 맞는지 즉시 자동 검증할 수 있습니다. 직접 짠 코드든, 나중에 Copilot이 짠 코드든 마찬가지입니다.
- 나중에 코드를 고쳐도, 테스트가 "기존 기능이 망가졌는지"를 즉시 알려 줍니다(회귀 방지).
이 TDD 습관은 12·13교시에서 빛을 발합니다. TDD가 "정답지(테스트)"를 만들어 두면, 바이브 코딩이 "그 정답을 맞히는 코드"를 빠르게 생성해도 안심할 수 있기 때문입니다.
💻 실습 3 — TDD 진입 순서 정하기
원칙: "바깥(파일·LLM·웹)이 필요 없는 것부터, 안쪽에서 바깥쪽으로" 진행합니다.
1순위) F1 SalesRecord ← 순수 검증. 가장 안쪽. (5교시 첫 TDD 사이클)
2순위) F3 분석 로직 ← 순수 계산. 안쪽. (7교시)
3순위) F2 CSV 적재 ← 파일 입출력 필요. (6교시)
4순위) F4 차트 / F5 LLM 요약 ← 외부 도구·네트워크 필요. (8·9교시)
5순위) F6 리포트 / F7 웹 ← 위의 것들을 조립. 가장 바깥. (9·10교시)
🔍 관찰 포인트 — 교시 번호와 TDD 우선순위가 일부러 다릅니다. 개념적 난이도(테스트 쉬움)로만 보면 F3(분석)이 F2(CSV)보다 안쪽이라 먼저 할 수도 있습니다. 하지만 수업 흐름상 "데이터가 들어와야 분석이 의미 있다"는 직관을 따라 6교시에서 CSV(F2)를 먼저 다룹니다. 핵심은 이것입니다 — 개념적 난이도와 수업 진행 순서는 다를 수 있으며, 그 이유를 알고 진행하면 됩니다. (5교시에서는 가장 순수한 F1로 TDD 리듬 자체를 익힙니다.)
✏️ 미니 실습 — 테스트 목록(Test List) 쓰기
docs/test-list.md에 F1에 대해 "검증하고 싶은 것"을 문장으로 나열합니다. (아직 코드가 아닙니다. 한국어 문장이면 됩니다.)
# F1 SalesRecord 테스트 목록
- [ ] 정상 값으로 레코드를 만들면 revenue가 quantity × unit_price로 계산된다
- [ ] quantity가 0 이하이면 오류가 발생한다
- [ ] unit_price가 0 이하이면 오류가 발생한다
- [ ] product가 빈 문자열이면 오류가 발생한다
🔍 관찰 포인트: 이 문장 목록이 5교시에서 그대로 테스트 코드로 옮겨집니다. "무엇을 검증할지"를 한국어로 먼저 정리해 두면, 코드로 옮기는 일은 기계적이고 쉬워집니다.
🔒 진행 게이트
- 제출물(기록): docs/test-list.md — F1~F7을 검증 가능한 단위로 쪼개고 우선순위를 매긴 목록.
- 이 결과가 있어야 다음 교시로 넘어갑니다.
- 정답·해설(별도 파일): solutions/미니실습정답_02.md
✅ 체크포인트
- [ ] docs/requirements.md에 시나리오와 CSV 형식이 정의됐다
- [ ] 기능을 F1~F7로 분해하고 각각 계층을 1차 매핑했다
- [ ] "입력→출력이 한 문장으로 떨어지는 단위"의 의미를 설명할 수 있다
- [ ] Red→Green→Refactor 각각의 의미를 말할 수 있다
- [ ] docs/test-list.md에 F1 테스트 목록을 적었다
🛠️ 트러블슈팅 / 자주 하는 실수
| 실수 | 왜 문제인가 | 교정 |
| 기능을 너무 크게 잡음 ("분석 기능") | 입력/출력이 불분명해 테스트 불가 | 한 문장으로 떨어질 때까지 쪼갠다 |
| 화면(UI)부터 만들고 싶어함 | 검증 안 된 핵심 위에 UI를 얹게 됨 | UI는 가장 바깥. 핵심 검증 후 붙인다 |
| revenue를 컬럼으로 저장하려 함 | 수량·단가 변경 시 불일치 발생 | 저장하지 않고 계산(단일 진실 원천) |
| 테스트 목록을 코드로 먼저 씀 | 무엇을 검증할지 흐려짐 | 먼저 한국어 문장으로 정리 |
🔑 핵심 정리
- 구현(직접이든 AI든)의 성패는 요구를 얼마나 또렷한 단위로 쪼개느냐에 달렸다.
- 모호한 요구를 F1~F7의 검증 가능한 단위로 나누고 계층을 매핑했다.
- "안쪽(순수 로직)부터" TDD로 진입한다 — 첫 타자는 F1 SalesRecord다.
다음 교시: 방금 나눈 계층이 왜 그렇게 나뉘는지, 클린 아키텍처의 원리를 제대로 이해합니다.
'AI System > 클린 아키텍처와 바이브 코딩을 활용한 AI Agent 시스템의 설계와 구' 카테고리의 다른 글
| d01 - 6. 데이터 처리 로직 구현 (0) | 2026.06.22 |
|---|---|
| d01 - 5. 첫번째 TDD 사이클 (0) | 2026.06.22 |
| d01 - 4. AI Agent 구조 설계 (0) | 2026.06.22 |
| d01 - 3. 클린 아키텍처 핵심 이해 (0) | 2026.06.22 |
| d01 - 1. 개발환경 구축 (0) | 2026.06.22 |