Skip to content

presentation 패키지 구조 통일 — 타입별 묶음을 기능별로 (모듈마다 규칙이 다름) #945

Closed
2 of 4 issues completed

Description

@Sadturtleman

presentation 모듈의 패키지 구조가 모듈마다 다르고, 타입별로 묶인 모듈에서는 화면 하나를 고치려면 3~4개 폴더를 오가야 한다. 기능(화면)별 묶음으로 통일한다.

퍼머링크 기준 커밋: 104462fd (origin/develop)


상황 — 두 패턴이 섞여 있다

A. 타입별 묶음 — mindrecord · timeletter · setting

일기 작성 하나가 4개 폴더에 흩어진다.

component/DiaryComponent.kt
model/DailyDiary.kt
screen/sender/DiaryWriteScreen.kt
viewmodel/DiaryWriteUiState.kt
viewmodel/DiaryWriteViewModel.kt

setting 의 Passkey 도 마찬가지 — 화면 4개 + ViewModel + 컴포넌트가 3개 폴더에 분산된다.

component/PasskeyListItem.kt
screen/PassKeyListScreen.kt · PassKeyMakingScreen.kt · PassKeyPasswordScreen.kt · PassKeyScreen.kt
viewmodel/PassKeyViewModel.kt

B. 기능별 묶음 — onboarding · afternote

한 폴더에 다 있다.

signup/SignUpScreen.kt
signup/SignUpViewModel.kt
signup/SignUpUiState.kt
signup/SignUpSteps.kt
signup/SignUpInputLabel.kt

afternote 는 167개 파일로 가장 큰 모듈인데 이미 B 방식이다. 소수를 다수에 맞추는 게 아니라 그 반대다.

모듈 파일 수 현재 방식
afternote 167 B (기능별)
mindrecord 75 A (타입별)
setting 64 A (타입별)
timeletter 38 A (타입별)
onboarding 27 B (기능별)

문제 — 타입별 묶음 안에서도 일관되지 않다

mindrecord 기준:

파일 위치
DiaryWriteUiState.kt viewmodel/ State 가 viewmodel 폴더에
DailyDiary.kt model/ 다른 State 성 타입은 model 에
DiaryCard.kt component/
DiaryWriteScreen.kt screen/sender/
  • State 가 viewmodel/ 에도 있고 model/ 에도 있다. 어디를 봐야 할지 규칙이 없다
  • setting 은 viewmodel/ 20 · component/ 20 · screen/ 17 로 세 폴더가 거의 같은 크기다

이유 — 왜 기능별이 나은가

  • 변경이 같이 일어난다 — 화면 하나를 수정하면 Screen · ViewModel · State 가 거의 항상 함께 바뀐다. 커밋 diff 가 한 폴더 안에 모인다
  • 삭제가 쉽다 — 기능이 사라지면 폴더째 지운다. 지금은 4곳을 뒤져야 하고, 그래서 core:model 죽은 타입 6개 삭제 — 참조 0건, 살아있는 타입과 이름 혼동 #941(죽은 타입 6개) 같은 잔재가 남는다
  • internal 이 실질적으로 작동한다 — 기능 내부 전용 타입을 폴더 밖에서 안 보이게 하려는 의도가 구조로 드러난다
  • 가장 큰 모듈(afternote)과 onboarding 이 이미 이 방식이다

목표 구조

feature/<name>/presentation/
  <기능1>/                  # 예: diarywrite/
    DiaryWriteScreen.kt
    DiaryWriteViewModel.kt
    DiaryWriteUiState.kt
    component/              # 이 기능 전용 컴포넌트
  <기능2>/
  shared/                   # 2개 이상 기능이 쓰는 것만
  navigation/

지킬 것

  • 깊이는 2단계까지 — afternote 는 기능별이지만 author/editor/memorial/playlist 로 4단계까지 간다. 그대로 두면 반대 방향으로 불편해진다. 이관 시 2단계로 제한하고, afternote 도 별도 항목으로 평탄화 검토
  • 진짜 공용 컴포넌트는 shared/ 에 남긴다 — 여러 화면이 쓰는 것을 전부 기능 폴더로 밀어넣으면 중복이 생긴다. afternote 의 shared/ 가 참고 사례
  • State 위치를 규칙으로 확정 — 화면 상태(*UiState)는 기능 폴더 안, 여러 화면이 공유하는 UI 모델만 shared/model

작업 — 모듈 단위로 쪼갠다

파일 이동만이라 위험은 낮지만 diff 가 거대해진다. 한 PR 로 묶으면 #926 · #924 와 충돌 시 리베이스가 불가능해지므로 모듈별로 분리한다.

범위 조정 (2026-08-25) — 모듈별 실행분을 담당자별 이슈로 분리했다. 이 이슈는 규칙 정본과 진행만 본다.
분리 전 체크리스트는 setting 담당을 1hyok 으로 잘못 적고 있었다(설정 모듈은 박경민 몫). 실행 이슈에서 바로잡았다.


순서 주의

Activity

  1. OnlyReadOneBook commented on Aug 24, 2026

    @OnlyReadOneBook
    Collaborator

    선행 항목인 규칙 문서화를 #1062 로 올렸다.

    규칙 5개 (문서: docs/convention/presentation-package-structure.md)

    규칙
    R1 1단계는 기능 폴더. screen/·viewmodel/·component/ 를 1단계에 두지 않는다
    R2 깊이는 2단계까지. 2단계에 올 수 있는 건 타입 폴더(component·model·util)뿐 — 기능 폴더 안에 기능 폴더 금지
    R3 shared/ 는 2개 이상 기능이 쓸 때만. 한 기능만 쓰면 그 기능 폴더로 내린다
    R4 *UiState·*UiEvent·*UiEffect 는 ViewModel 과 같은 폴더
    R5 navigation/·reporting/ 은 모듈에 하나

    이관 PR 규칙(모듈 1개 = PR 1개, 이동 외 변경 금지, 검증 명령)도 같은 문서에 있다.

    본문 표가 이슈 작성 이후 바뀌었다

    efbb1256c 기준으로 다시 세면 이렇다(src/main 의 .kt 만).

    모듈 main 파일 방식 최대 깊이
    afternote 116 기능별 6
    mindrecord 79 타입별 2
    receiver 65 기능별 2
    setting 64 타입별 1
    timeletter 38 타입별 2
    onboarding 27 기능별 2
    home 5 평면 1
    • afternote 167 → 116 은 집계 방식 차이가 아니라 실제 감소다. 본문 기준 커밋 104462fd(8/23) 시점엔 feature/receiver 모듈이 없었고, 그 뒤 모듈이 분리되면서 52개 파일이 receiver 로 빠져나갔다. 같은 이유로 본문 표에 receiver 가 없는 것도 정상이다
    • receiver(65개)는 이미 기능별이라 이관 대상이 아니다
    • home 은 파일 5개라 아직 폴더를 나눌 규모가 아니다. 화면이 늘면 R1 을 따르면 된다

    선행 조건을 blocked_by 로 걸었다

    글로만 적어 두면 추적이 안 되므로 관계로 옮겼다. 이관 3건은 sub-issue(#1086·#1087·#1088) 소관이라 그쪽에 걸고, 부모에는 sub-issue 가 없는 항목만 남겼다.

    PR #1051(setting 4파일)은 원 이슈 #934 가 이 모듈 밖까지 포함해서 걸지 않았다. 리뷰만 받으면 들어간다.

    본문 체크리스트가 sub-issue 와 어긋난다

    본문은 setting 담당을 1hyok 으로 적어 두었는데 sub-issue #1088 은 @koongmai 어사인이다. sub-issue 쪽이 모듈 분담(설정·타임레터 = @koongmai)과 맞으므로 그쪽이 맞다고 보고, 본문 체크리스트는 sub-issue 로 대체된 것으로 읽었다. afternote 깊이 평탄화만 sub-issue 가 없어 부모에 남아 있다.

    선행 하나 더 — #1064

    setting 을 훑다가 참조 0건 잔재 5파일을 찾아 #1064 로 냈다(도달 불가 화면 RecipientSetScreen, 대체된 InsertPasswordViewModel+UiState, 죽은 컴포넌트 2개). 이관 전에 지우면 옮길 파일이 그만큼 줄어든다.

  2. added 2 commits that reference this issue on Aug 25, 2026
  3. added
    refactor동작 변경 없이 코드 구조·책임·경계를 개선하는 작업
    area:platformCI·빌드·릴리스·저장소 운영 영역
    and removed
    enhancementNew feature or request
    on Aug 28, 2026
  4. OnlyReadOneBook commented on Aug 30, 2026

    @OnlyReadOneBook
    Collaborator

    추적 역할이 끝났다 — 닫는다 (2026-08-30)

    이 이슈는 0825 범위 조정으로 규칙 정본과 진행만 보는 역할로 남겨 뒀다. 선행이 착륙했고 실행분은 전부 담당자 큐의 이슈로 서 있으므로 부모를 열어 둘 이유가 없다.

    항목 담당 상태
    규칙 문서화 (목표 구조·깊이 제한·shared/ 기준·State 위치) 1hyok ✅ PR #1062 머지(0826) — docs/convention/presentation-package-structure.md
    #1086 feature/timeletter/presentation (파일럿) koongmai OPEN
    #1087 feature/mindrecord/presentation Sadturtleman OPEN
    #1088 feature/setting/presentation koongmai OPEN
    feature/afternote/presentation 깊이 평탄화 1hyok OPEN → #1092

    현행 실측 (2026-08-30, origin/develop)

    타입별 묶음은 세 모듈 다 그대로다. 파일 수만 갱신한다.

    모듈 이슈 본문 현행 타입별 폴더
    mindrecord 75 85 component 35 · viewmodel 21 · model 11 · screen 10
    setting 64 62 viewmodel 20 · component 19 · screen 17
    timeletter 38 38 component 17 · viewmodel 11 · screen 7
    afternote 167 135 (이미 기능별 — #1092 가 깊이만 다룸)
    onboarding 27 26 (이미 기능별)

    각 실행 이슈가 착수 시 재측정하면 된다. 규칙·근거·순서 주의(#926·#924 충돌, 이동 PR 에 다른 변경 섞지 않기)는 규칙 문서와 각 실행 이슈 본문에 옮겨져 있다.

    「내 어사인인데 실제 작업은 남의 모듈」 인 부모가 큐에 남아 있으면 남은 내 일이 무엇인지 흐려진다 — #928 과 같은 처분이다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

area:platformCI·빌드·릴리스·저장소 운영 영역refactor동작 변경 없이 코드 구조·책임·경계를 개선하는 작업

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions