Repository navigation
refactor: Home State를 4축으로 재설계 — 불법 조합을 표현 불가능하게 (Phase E5) - #374
Merged
Merged
Conversation
HomeViewModel.State의 저장 필드가 10개라 표현 가능 조합이 1,536개였고,
그중 상당수가 화면으로 말이 되지 않는 상태였다. 아래가 전부 타입상
표현 가능했다:
- 등록이 없는데 배너가 있다
- 카드가 없는데 selectedRouteId가 있다 (버튼이 "해제"로 남는다)
- 등록이 없는데 syncedAt이 있다 ("HH:mm 확인 기준"이 떠 있다)
- 아무것도 없는데 isAlarmBusy가 true다 (버튼이 영영 비활성)
- 숨겨진 칩이 진행 중이다
그래서 cancelAlarmTapped가 다섯 필드를 한 번에 고쳐야 했다 — 하나씩
고치면 didSet이 중간 상태를 VC로 내보내기 때문이다. 실제로 이 방식이
버그를 만든 적도 있다(selectedRoute = nil의 didSet이 뒤이은
state = newState에 덮여, 지난 막차에 등록 버튼이 남았다).
저장 필드를 4축으로 묶는다: departure / arrivalText / chip / session.
- HomeChipState — 텍스트 없이 busy일 수 없다
- HomeSessionState — empty / card / past / armed 4케이스.
배너·확인 시각은 Registration 안에 살아서 등록 없이 존재할 수 없고,
경로 id는 Card가 들고 있어 카드와 갈라질 수 없다.
전이는 이제 case 하나를 고르는 일이다(selecting / arming / disarmed /
withBanner / settingBusy).
**읽기 이름은 계산 프로퍼티로 그대로 유지했다** — routeCard·banner·
alarmButton·isAlarmBusy·recentRouteChipText·freshnessText. 저장 구조를
고치는 일이 VC(444줄)·테스트 81개 참조의 전면 개명으로 번지지 않게 하려는
의도적 선택이고, 덕분에 기존 테스트 66개가 **한 줄도 바뀌지 않고** 통과한다.
표 테스트 14개 신설(스텁 0개, ViewModel 0개) — "배너는 등록 없이 존재할
수 없다", "아무것도 없는데 진행 중일 수 없다" 같은 성질을 고정한다.
부수: 쓰이지 않게 된 alarmButtonMode static 제거(로직은
HomeSessionState.alarmButton으로), 앞 Phase에서 남은 고아 주석 1줄 제거.
검증: 3구성 빌드 + Domain 112 · CoreStorage 44 · AtchaData 64 · AtchaV2 39
· DesignSystem 73 · HomeFeature 80(+14) · SearchFeature 26 · SettingsFeature 18.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
무엇이 문제였나
HomeViewModel.State의 저장 필드가 10개라 표현 가능 조합이 1,536개였고, 그중 상당수는 화면으로 말이 되지 않았다. 아래가 전부 타입상 표현 가능했다.banner있음selectedRouteId있음syncedAt있음isAlarmBusyisChipBusy그래서
cancelAlarmTapped가 다섯 필드를 한 번에 고쳐야 했다 — 하나씩 고치면didSet이 중간 상태를 VC로 내보내기 때문이다.이 방식은 실제로 버그를 만들었다.
selectedRoute = nil의didSet이 뒤이은state = newState에 덮여, 지난 막차 카드에 등록 버튼이 남았다(누르면tooLate로 실패). 고칠 때 "지역 사본에도 함께 반영하라"는 주석을 다는 것 말고는 방법이 없었다.어떻게 바꿨나
저장 필드를 4축으로 묶는다:
departure/arrivalText/chip/session.Registration안에 산다 → 등록 없이 존재할 수 없다Card가 들고 있다 → 카드와 갈라질 수 없다 (위 버그의 구조적 원인 제거)busy는 카드나 등록이 있는 case 안에만 있다 → 빈 상태의 영구 비활성이 불가능HomeChipState→ 텍스트 없이 busy일 수 없다전이는 이제 case 하나를 고르는 일이다:
selecting/arming/disarmed/withBanner/settingBusy.블라스트 반경을 한 파일로 막았다
읽기 이름은 계산 프로퍼티로 그대로 유지했다 —
routeCard·banner·alarmButton·isAlarmBusy·recentRouteChipText·selectedRouteId·registeredRouteId·syncedAt·freshnessText.저장 구조를 고치는 일이
HomeViewController(444줄)와 테스트 81개 참조의 전면 개명으로 번지지 않게 하려는 의도적 선택이다. 덕분에 기존 테스트 66개가 한 줄도 바뀌지 않고 통과한다 — 리팩토링이 동작을 바꾸지 않았다는 가장 강한 증거다.신설 테스트
표 테스트 14개, 스텁 0개 · ViewModel 0개. "배너는 등록 없이 존재할 수 없다", "아무것도 없는데 진행 중일 수 없다", "등록된 채 다른 경로를 고르면 버튼은 등록이다" 같은 성질을 직접 고정한다.
검증
이것으로 리팩토링 계획의 Phase A~F가 전부 완료된다.
🤖 Generated with Claude Code