From 82b941566a3ddb84308c218ad277631c9fc7ab66 Mon Sep 17 00:00:00 2001 From: leejh08 Date: Tue, 28 Apr 2026 14:23:18 +0900 Subject: [PATCH 1/5] =?UTF-8?q?=F0=9F=9B=A0=20::=20(#0)=20TDD/Tidy=20First?= =?UTF-8?q?=20=EA=B2=BD=EA=B3=84=EB=A5=BC=20=EB=A8=BC=EC=A0=80=20=EA=B3=A0?= =?UTF-8?q?=EC=A0=95=ED=95=B4=20=EC=9D=B4=ED=9B=84=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=EC=9D=84=20=EC=95=88=EC=A0=84=ED=95=98=EA=B2=8C=20=ED=95=9C?= =?UTF-8?q?=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 루트 plan.md를 추가해 앞으로의 Red-Green-Refactor / Tidy First 작업 규칙을 명시하고, 중복되어 있던 CompanyDetailPreviousViewType 정의를 Core 단일 소스로 정리했다. 이번 변경은 동작 추가 없이 구조와 작업 규칙만 고정하는 목적이다. Constraint: 사용자 요청에 따라 앞으로의 go 실행은 plan.md를 기준으로 진행되어야 한다 Constraint: 구조 변경과 동작 변경을 같은 커밋에 섞지 않는다 Rejected: 기능 테스트/구현까지 이번 커밋에 포함 | TDD 시작점과 구조 정리를 분리해야 함 Confidence: medium Scope-risk: narrow Reversibility: clean Directive: 다음 기능 작업부터는 plan.md의 Test Queue에 failing test를 먼저 적고 한 항목씩만 진행할 것 Tested: tuist test Presentation Tested: swiftlint lint Projects/Core/Sources/Steps/CompanyDetailPreviousViewType.swift Not-tested: tuist test Core | GoogleDataTransport 빌드에서 'nanopb/pb.h' 누락으로 실패 --- .../Steps/CompanyDetailPreviousViewType.swift | 1 + .../CompanyDetailPreviousViewType.swift | 7 ---- plan.md | 32 +++++++++++++++++++ 3 files changed, 33 insertions(+), 7 deletions(-) delete mode 100644 Projects/Presentation/Sources/CompanyDetail/CompanyDetailPreviousViewType.swift create mode 100644 plan.md diff --git a/Projects/Core/Sources/Steps/CompanyDetailPreviousViewType.swift b/Projects/Core/Sources/Steps/CompanyDetailPreviousViewType.swift index bc883172..e3e3c098 100644 --- a/Projects/Core/Sources/Steps/CompanyDetailPreviousViewType.swift +++ b/Projects/Core/Sources/Steps/CompanyDetailPreviousViewType.swift @@ -1,4 +1,5 @@ public enum CompanyDetailPreviousViewType { case searchCompany case recruitmentDetail + case home } diff --git a/Projects/Presentation/Sources/CompanyDetail/CompanyDetailPreviousViewType.swift b/Projects/Presentation/Sources/CompanyDetail/CompanyDetailPreviousViewType.swift deleted file mode 100644 index a5f247f6..00000000 --- a/Projects/Presentation/Sources/CompanyDetail/CompanyDetailPreviousViewType.swift +++ /dev/null @@ -1,7 +0,0 @@ -import Foundation - -public enum CompanyDetailPreviousViewType { - case searchCompany - case recruitmentDetail - case home -} diff --git a/plan.md b/plan.md new file mode 100644 index 00000000..8c9ffa1c --- /dev/null +++ b/plan.md @@ -0,0 +1,32 @@ +# TDD / Tidy First Plan + +이 저장소에서는 앞으로 모든 작업을 아래 규칙으로 진행한다. + +## Always Follow +- 항상 Red → Green → Refactor 순서를 지킨다. +- 한 번에 테스트 하나만 추가한다. +- 테스트가 실패하는 것을 확인한 뒤에만 프로덕션 코드를 수정한다. +- 테스트를 통과시키는 최소한의 코드만 작성한다. +- 구조 변경(Structural change)과 동작 변경(Behavioral change)을 같은 커밋에 섞지 않는다. +- 구조 변경이 필요하면 먼저 구조만 바꾸고 테스트로 안전성을 확인한다. +- `go` 라고 하면 아래 `Test Queue`에서 체크되지 않은 첫 번째 테스트를 수행한다. +- 각 `go` 사이클의 기본 순서는 다음과 같다. + 1. 다음 미완료 테스트 선택 + 2. 테스트 작성 및 실패 확인 (Red) + 3. 최소 구현으로 테스트 통과 (Green) + 4. 필요 시 구조 개선 (Refactor / Tidy First) + 5. 관련 테스트 재실행 + 6. 체크리스트 갱신 + +## Swift Rules +- Swift에서는 의미가 분명한 타입/메서드 이름을 우선한다. +- `mutate()` 는 비동기 가능, `reduce()` 는 순수 함수만 유지한다. +- `Flow.rootViewController` 는 `init` 에서 resolve 한다. +- 레이어 역방향 import 금지. +- 모든 의존성은 Assembly를 통해 등록한다. + +## Current Structural Baseline +- [x] `CompanyDetailPreviousViewType` 를 `Presentation` 에서 제거하고 `Core/Sources/Steps` 단일 정의를 기준으로 정리한다. + +## Test Queue +- [ ] 다음 기능 작업이 정해지면 첫 failing test 를 여기에 추가한다. From 07f5c28c28575bb156fb36518aa61f4e9e3e52c7 Mon Sep 17 00:00:00 2001 From: leejh08 Date: Tue, 28 Apr 2026 14:36:10 +0900 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=93=9D=20::=20(#0)=20plan.md=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=9E=91=EC=97=85=20=EC=A0=84=EC=9A=A9=20=EC=B2=B4?= =?UTF-8?q?=ED=81=AC=20=ED=95=AD=EB=AA=A9=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit plan.md는 저장소 전역 TDD/Tidy First 규칙 문서로 유지하고, 일회성 구조 변경 기록은 제거했다. Constraint: plan.md는 특정 작업 로그가 아니라 앞으로의 공통 실행 기준이어야 한다 Rejected: 완료된 구조 변경 체크리스트 유지 | 문서가 작업별 상태판으로 변질됨 Confidence: high Scope-risk: narrow Reversibility: clean Directive: plan.md에는 전역 규칙과 다음 테스트 큐만 유지하고 작업 완료 이력은 남기지 말 것 Tested: plan.md diff review Not-tested: additional automated checks not applicable to markdown-only edit --- plan.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/plan.md b/plan.md index 8c9ffa1c..bf89aec3 100644 --- a/plan.md +++ b/plan.md @@ -25,8 +25,5 @@ - 레이어 역방향 import 금지. - 모든 의존성은 Assembly를 통해 등록한다. -## Current Structural Baseline -- [x] `CompanyDetailPreviousViewType` 를 `Presentation` 에서 제거하고 `Core/Sources/Steps` 단일 정의를 기준으로 정리한다. - ## Test Queue - [ ] 다음 기능 작업이 정해지면 첫 failing test 를 여기에 추가한다. From f2bb308755a92c3154c577b5954573c09e1ad75d Mon Sep 17 00:00:00 2001 From: leejh08 Date: Tue, 28 Apr 2026 15:18:22 +0900 Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=93=9D=20::=20(#0)=20TDD=EC=99=80=20T?= =?UTF-8?q?idy=20First=20=EC=8B=A4=ED=96=89=20=EA=B7=9C=EC=95=BD=EC=9D=84?= =?UTF-8?q?=20=ED=94=84=EB=A1=9C=EC=A0=9D=ED=8A=B8=20=EA=B7=9C=EC=B9=99?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EA=B5=AC=EC=B2=B4=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kent Beck의 TDD/ Tidy First를 이 저장소에서 실제로 적용할 수 있도록 plan.md의 실행 계약을 구체화하고 PR 템플릿에 검증 체크리스트를 추가했다. 이제 go 명령은 테스트 1개 단위의 Red-Green-Refactor 사이클로 해석되고, PR 단계에서도 구조 변경과 동작 변경의 분리를 확인할 수 있다. Constraint: plan.md는 저장소 전역 실행 규칙 문서여야 한다 Constraint: PR 단계에서 TDD/Tidy First 준수 여부를 드러내야 한다 Rejected: 원칙만 짧게 유지 | 실제 실행/리뷰 단계에서 강제력이 부족함 Confidence: high Scope-risk: narrow Reversibility: clean Directive: 이후 기능 작업은 반드시 Test Queue의 첫 미완료 항목부터 한 테스트씩 진행할 것 Tested: plan.md 및 PR 템플릿 diff review Not-tested: automated checks not applicable to markdown-only policy update --- .github/PULL_REQUEST_TEMPLATE.md | 12 +++++ plan.md | 79 ++++++++++++++++++++++++++------ 2 files changed, 76 insertions(+), 15 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index da5048f7..2e297fa8 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,5 +4,17 @@ ## 작업사항 - [x] +## TDD 체크 +- [ ] failing test부터 시작했다 +- [ ] 최소 구현으로 Green을 만들었다 +- [ ] Refactor는 Green 이후에만 수행했다 + +## Tidy First 체크 +- [ ] 구조 변경과 동작 변경을 분리했다 +- [ ] 구조 변경만 있는 커밋은 동작을 바꾸지 않았다 + +## Test plan +- [ ] + ## UI diff --git a/plan.md b/plan.md index bf89aec3..e9303a07 100644 --- a/plan.md +++ b/plan.md @@ -1,22 +1,63 @@ # TDD / Tidy First Plan -이 저장소에서는 앞으로 모든 작업을 아래 규칙으로 진행한다. +이 저장소에서는 앞으로 모든 작업을 Kent Beck의 TDD / Tidy First 원칙으로 진행한다. +`go` 라고 하면 이 문서를 현재 작업의 단일 실행 기준으로 사용한다. ## Always Follow -- 항상 Red → Green → Refactor 순서를 지킨다. -- 한 번에 테스트 하나만 추가한다. -- 테스트가 실패하는 것을 확인한 뒤에만 프로덕션 코드를 수정한다. -- 테스트를 통과시키는 최소한의 코드만 작성한다. -- 구조 변경(Structural change)과 동작 변경(Behavioral change)을 같은 커밋에 섞지 않는다. -- 구조 변경이 필요하면 먼저 구조만 바꾸고 테스트로 안전성을 확인한다. -- `go` 라고 하면 아래 `Test Queue`에서 체크되지 않은 첫 번째 테스트를 수행한다. -- 각 `go` 사이클의 기본 순서는 다음과 같다. - 1. 다음 미완료 테스트 선택 - 2. 테스트 작성 및 실패 확인 (Red) - 3. 최소 구현으로 테스트 통과 (Green) - 4. 필요 시 구조 개선 (Refactor / Tidy First) - 5. 관련 테스트 재실행 - 6. 체크리스트 갱신 +- 항상 **Red → Green → Refactor** 순서를 지킨다. +- 한 번에 테스트 **하나만** 추가한다. +- 테스트가 **실패하는 것을 먼저 확인**한 뒤에만 프로덕션 코드를 수정한다. +- 테스트를 통과시키는 **최소한의 코드만** 작성한다. +- **구조 변경(Structural change)** 과 **동작 변경(Behavioral change)** 을 같은 커밋에 섞지 않는다. +- 구조 변경이 필요하면 **먼저 구조만** 바꾸고 테스트로 안전성을 확인한다. +- 리팩터링은 **테스트가 모두 초록불일 때만** 수행한다. +- 각 단계가 끝날 때마다 **관련 테스트를 다시 실행**한다. + +## Tidy First Rules + +### Structural Change +다음은 구조 변경으로 취급한다. +- 이름 변경 +- 파일 이동 +- 타입/메서드 추출 +- 중복 제거를 위한 재배치 +- 의존성 방향은 유지한 채 표현만 정리하는 변경 + +구조 변경 단계에서는: +- 동작을 바꾸지 않는다. +- 가능한 한 작은 단위로 나눈다. +- 변경 전/후 테스트 결과가 같아야 한다. +- 커밋 메시지와 PR 설명에 구조 변경임을 드러낸다. + +### Behavioral Change +다음은 동작 변경으로 취급한다. +- 새로운 기능 추가 +- 분기/상태/화면 흐름 변경 +- 사용자에게 보이는 결과 변경 +- 버그 수정 + +동작 변경 단계에서는: +- 반드시 실패하는 테스트로 시작한다. +- 테스트를 통과시키는 최소 구현만 한다. +- 초록불 이후에만 구조를 개선한다. + +## `go` Execution Contract +`go` 라고 하면 아래 순서로 정확히 수행한다. +1. `Test Queue` 에서 체크되지 않은 첫 번째 항목을 찾는다. +2. 해당 항목에 대한 테스트를 **하나만** 작성한다. +3. 테스트가 실패하는지 확인한다. (**Red**) +4. 테스트를 통과시키는 최소 구현만 추가한다. (**Green**) +5. 모든 관련 테스트를 다시 실행한다. +6. 구조 개선이 필요하면 별도 구조 변경으로만 정리한다. (**Refactor / Tidy First**) +7. `Test Queue` 상태를 갱신한다. + +## Definition of Done for One Step +하나의 `go` 단계는 아래 조건을 만족할 때만 끝난다. +- 이번 단계에서 추가한 테스트가 존재한다. +- 새 테스트가 처음에는 실패했다. +- 현재는 테스트가 통과한다. +- 구조 변경과 동작 변경의 경계가 설명 가능하다. +- 다음에 진행할 테스트가 `Test Queue` 에 명확히 남아 있다. ## Swift Rules - Swift에서는 의미가 분명한 타입/메서드 이름을 우선한다. @@ -25,5 +66,13 @@ - 레이어 역방향 import 금지. - 모든 의존성은 Assembly를 통해 등록한다. +## PR / Commit Rules +- 한 PR 안에서도 구조 변경 커밋과 동작 변경 커밋을 분리한다. +- PR 설명에는 아래를 포함한다. + - 어떤 테스트가 먼저 실패했는지 + - 어떤 최소 구현으로 초록불을 만들었는지 + - 어떤 구조 개선을 나중에 했는지 +- 테스트 없이 기능 코드를 먼저 넣는 변경은 허용하지 않는다. + ## Test Queue - [ ] 다음 기능 작업이 정해지면 첫 failing test 를 여기에 추가한다. From c111949260f7d1a0b22e8fca7696ab80cc3874df Mon Sep 17 00:00:00 2001 From: leejh08 Date: Tue, 28 Apr 2026 17:14:50 +0900 Subject: [PATCH 4/5] =?UTF-8?q?=F0=9F=94=A7=20::=20(#0)=20=EC=95=B1=20?= =?UTF-8?q?=EB=B2=84=EC=A0=84=EA=B3=BC=20=EB=B9=8C=EB=93=9C=20=EB=84=98?= =?UTF-8?q?=EB=B2=84=20=EA=B0=B1=EC=8B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Info.plist의 마케팅 버전과 빌드 넘버를 올려 다음 배포/아카이브 시도 기준을 맞췄다. Constraint: Xcode archive 시 표시되는 앱 버전/빌드 정보는 Info.plist 값과 일치해야 한다 Rejected: 버전은 유지하고 빌드만 증가 | 사용자 요청이 버전과 빌드 둘 다 올리는 것이었음 Confidence: high Scope-risk: narrow Reversibility: clean Directive: 다음 릴리즈 변경 시 마케팅 버전과 빌드 넘버를 함께 검토할 것 Tested: plutil -p Projects/App/Support/Info.plist Not-tested: archive/build execution not rerun in this step --- Projects/App/Support/Info.plist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Projects/App/Support/Info.plist b/Projects/App/Support/Info.plist index 3c1ebe4e..fd8f3fea 100644 --- a/Projects/App/Support/Info.plist +++ b/Projects/App/Support/Info.plist @@ -21,9 +21,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 2.4.0 + 2.4.1 CFBundleVersion - 99 + 100 FirebaseAppDelegateProxyEnabled ITSAppUsesNonExemptEncryption From ca789611f35328cbdf0669b086160551a7fda027 Mon Sep 17 00:00:00 2001 From: leejh08 Date: Tue, 28 Apr 2026 17:21:50 +0900 Subject: [PATCH 5/5] =?UTF-8?q?=F0=9F=94=A7=20::=20(#0)=20=EC=95=B1=20?= =?UTF-8?q?=EB=B2=84=EC=A0=84=EA=B3=BC=20=EB=B9=8C=EB=93=9C=20=EB=84=98?= =?UTF-8?q?=EB=B2=84=20=EC=9E=AC=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit App Store Connect 업로드 오류를 해결하기 위해 마케팅 버전을 2.5.1로, 빌드 넘버를 101로 올렸다. 이전 2.4.1은 승인된 최신 버전 2.5.0보다 낮았고, 2.5.0은 더 이상 새 빌드 제출을 받을 수 없는 상태였다. Constraint: CFBundleShortVersionString은 기존 승인 버전보다 높아야 한다 Constraint: 닫힌 버전 번호는 새 빌드 업로드에 재사용할 수 없다 Rejected: 2.5.0 재사용 | App Store Connect에서 closed for new build submissions로 거절됨 Confidence: high Scope-risk: narrow Reversibility: clean Directive: 다음 업로드 전에는 App Store Connect의 최신 승인/닫힌 버전을 먼저 확인할 것 Tested: plutil -p Projects/App/Support/Info.plist Not-tested: archive/upload retry not executed in this step --- Projects/App/Support/Info.plist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Projects/App/Support/Info.plist b/Projects/App/Support/Info.plist index fd8f3fea..8d69284c 100644 --- a/Projects/App/Support/Info.plist +++ b/Projects/App/Support/Info.plist @@ -21,9 +21,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 2.4.1 + 2.5.1 CFBundleVersion - 100 + 101 FirebaseAppDelegateProxyEnabled ITSAppUsesNonExemptEncryption