|
| 1 | +# HaapyProcess 프로젝트 작업 가이드 |
| 2 | + |
| 3 | +## 작업 워크플로우 |
| 4 | + |
| 5 | +리팩토링/기능 작업 시 아래 순서를 따른다. |
| 6 | + |
| 7 | +1. **브랜치 생성**: `git checkout -b <type>/<description>` |
| 8 | +2. **테스트 먼저 작성 (TDD)**: 구현 전에 실패하는 단위 테스트부터 작성한다 (아래 TDD 원칙 참고) |
| 9 | +3. **코드 작업**: 테스트를 통과시키는 최소 구현 → 리팩토링 |
| 10 | +4. **빌드 + 테스트 검증**: `./gradlew test` (또는 `./gradlew compileJava`로 컴파일만; DB 없는 환경에서는 통합 테스트 실패는 무시하되 단위 테스트는 통과해야 한다) |
| 11 | +5. **커밋**: 변경사항 커밋 (테스트 코드 포함) |
| 12 | +6. **푸시 및 PR**: `git push -u origin <branch>` → `gh pr create --base main` |
| 13 | + |
| 14 | +## TDD / 단위 테스트 원칙 |
| 15 | + |
| 16 | +이 프로젝트는 **테스트 주도 개발(TDD)** 을 기본 개발 방식으로 삼는다. 기능을 먼저 짜고 |
| 17 | +테스트를 나중에 붙이는 게 아니라, **테스트가 설계를 이끈다**. |
| 18 | + |
| 19 | +### Red → Green → Refactor |
| 20 | + |
| 21 | +1. **Red** — 구현하려는 동작을 검증하는 **실패하는 테스트**를 먼저 작성한다. 테스트가 |
| 22 | + 실패하는 것을 눈으로 확인한다(테스트 자체가 맞는지 검증하는 단계). |
| 23 | +2. **Green** — 테스트를 통과시키는 **최소한의 코드**만 작성한다. 과한 일반화는 하지 않는다. |
| 24 | +3. **Refactor** — 테스트가 초록불인 상태에서 중복 제거·구조 개선. 테스트가 안전망이 된다. |
| 25 | + |
| 26 | +### 무엇을, 어떻게 테스트하나 |
| 27 | + |
| 28 | +- **단위 테스트 우선** — 서비스/도메인 로직은 외부 의존성(DB, 외부 API)을 Mock으로 |
| 29 | + 분리해 **순수 단위 테스트**로 검증한다. JUnit5 + Mockito 기준. |
| 30 | +- **경계·예외부터** — happy path만이 아니라 null/빈 값/경계 조건/예외 흐름을 반드시 덮는다. |
| 31 | + 버그는 대부분 경계에서 난다. |
| 32 | +- **테스트는 하나의 행위만** — 테스트 이름은 "무엇을 검증하는지" 한국어로 명확히 쓴다 |
| 33 | + (예: `가족이_없으면_빈_리스트를_반환한다`). given-when-then 구조를 권장한다. |
| 34 | +- **외부 호출 금지** — 단위 테스트는 실제 DB·네트워크에 접근하지 않는다. 통합이 필요한 |
| 35 | + 검증은 별도 통합 테스트로 분리한다. |
| 36 | +- **회귀 테스트** — 버그를 고칠 때는 그 버그를 재현하는 테스트를 먼저 추가한 뒤 고친다. |
| 37 | + |
| 38 | +### 강제 원칙 |
| 39 | + |
| 40 | +- 새 로직(서비스 메서드, 도메인 규칙)에는 **반드시 단위 테스트가 동반**되어야 한다. |
| 41 | + 테스트 없는 기능 코드는 미완성으로 본다. |
| 42 | +- 커밋 전에 `./gradlew test`로 단위 테스트가 **모두 통과**하는지 확인한다. |
| 43 | +- 리팩토링 PR이라도 기존 테스트가 깨지지 않아야 하며, 동작 변경이면 테스트도 함께 수정한다. |
| 44 | + |
| 45 | +## 코드 스타일 — 관심사의 분리 |
| 46 | + |
| 47 | +이 프로젝트는 **도메인 기반 패키지 구조(package-by-feature)** 를 따른다. |
| 48 | +`domain/<도메인>/{controller, service, repository, entity, dto}` + 공통은 `global/`. |
| 49 | +핵심은 **도메인끼리, 계층끼리 책임이 섞이지 않게 하는 것**이다. 의존성이 꼬이면 |
| 50 | +변경 한 곳이 엉뚱한 곳을 깨뜨리고, 테스트도 어려워진다. |
| 51 | + |
| 52 | +### 계층별 책임 (Layered Architecture) |
| 53 | + |
| 54 | +각 계층은 자기 일만 한다. 책임을 넘나들지 않는다. |
| 55 | + |
| 56 | +- **Controller** — HTTP 요청/응답 처리만. 파라미터 검증, DTO 매핑, 서비스 호출. |
| 57 | + **비즈니스 로직을 넣지 않는다.** 엔티티를 직접 반환하지 말고 응답 DTO로 변환한다. |
| 58 | +- **Service** — 비즈니스 로직과 트랜잭션 경계(`@Transactional`)를 담당. 도메인 규칙은 |
| 59 | + 여기 또는 엔티티에 둔다. 컨트롤러나 웹 관심사(HttpServletRequest 등)를 알지 못한다. |
| 60 | +- **Repository** — 데이터 접근만. JPA 쿼리. 비즈니스 판단을 넣지 않는다. |
| 61 | +- **Entity** — 도메인 상태와 그에 직접 속한 규칙. 외부 계층(DTO, 웹)을 의존하지 않는다. |
| 62 | +- **DTO** — 계층 간 데이터 전달. 엔티티를 API 경계 밖으로 노출하지 않기 위한 방어막. |
| 63 | + |
| 64 | +### 도메인 간 의존성 규칙 |
| 65 | + |
| 66 | +- **도메인은 서로 느슨하게.** `family`가 `member`를 알아야 한다면, 상대 도메인의 |
| 67 | + **Service(공개 API)를 통해서만** 협력한다. 남의 도메인 Repository·Entity 내부에 |
| 68 | + 직접 손대지 않는다. |
| 69 | +- **순환 의존 금지.** A 도메인이 B를, B가 다시 A를 의존하는 구조를 만들지 않는다. |
| 70 | + 순환이 생기면 도메인 경계가 잘못 그어진 신호다 — 책임을 재배치하거나 공통 부분을 |
| 71 | + 분리한다. |
| 72 | +- **양방향 결합 주의.** 꼭 필요한 방향으로만 의존한다. 의존 방향은 한쪽으로 흐르게 한다. |
| 73 | +- **공통 관심사는 `global/`로.** 보안·예외·설정·JWT 등 여러 도메인이 공유하는 것은 |
| 74 | + 특정 도메인에 두지 말고 `global/`에 둔다. 반대로 특정 도메인 전용 로직을 `global/`에 |
| 75 | + 올리지 않는다. |
| 76 | + |
| 77 | +### 실천 지침 |
| 78 | + |
| 79 | +- 새 기능은 **해당 도메인 패키지 안에서** 완결되게 짠다. 다른 도메인 패키지를 수정해야 |
| 80 | + 한다면, 경계가 맞는지 먼저 의심한다. |
| 81 | +- "이 클래스가 왜 이걸 알아야 하지?"를 자문한다. 답이 군색하면 책임이 잘못 배치된 것이다. |
| 82 | +- 엔티티를 컨트롤러/외부로 그대로 흘려보내지 않는다 (DTO 변환). |
| 83 | +- 한 메서드·클래스가 여러 이유로 바뀐다면 분리를 고려한다 (단일 책임). |
| 84 | + |
| 85 | +## 주의사항 |
| 86 | + |
| 87 | +- 커밋 메시지, PR 본문에 AI 작성 티를 내지 않는다 (Co-Authored-By, Generated with 등 금지) |
0 commit comments