Skip to content

refactor: 한계에 걸친 함수·파일 분할 (makeStatusMenu, 테스트 하네스)#105

Closed
pignuante wants to merge 2 commits into
fix/ax-outcome-consistencyfrom
refactor/split-oversized-units
Closed

refactor: 한계에 걸친 함수·파일 분할 (makeStatusMenu, 테스트 하네스)#105
pignuante wants to merge 2 commits into
fix/ax-outcome-consistencyfrom
refactor/split-oversized-units

Conversation

@pignuante

Copy link
Copy Markdown
Contributor

스택 PR — base가 fix/ax-outcome-consistency(#103)입니다. #103 머지 후 자동으로 main 기준이 됩니다.

Summary

전체 코드베이스를 SwiftLint의 실제 기준(주석·빈 줄 제외, 선언줄/닫는 괄호 제외)으로 측정해
한계를 넘거나 한계에 걸친 두 곳만 분할했다. 동작 변경 0.

측정 결과 — 나머지는 전부 여유가 있다

대상 실코드 한계 판정
StatusBarController.makeStatusMenu 60줄 60 (error) 🟠 정확히 한계
Tests/CommandEngineTests.swift 595줄 400 (warn) 🟠 초과 (단, Tests/는 lint 대상 아님)
그 외 프로덕션 함수 최대 52줄 60
그 외 프로덕션 파일 최대 234줄 400
프로덕션 타입 최대 274줄 400

Azimuth/ 49개 파일 중 위 한 곳 외에는 분할이 필요한 함수·파일·타입이 없다.

1. makeStatusMenu (60 → 8줄)

한 함수가 권한 상태(진단) · DEBUG 전용 도구 · 일반 앱 동작 세 가지를 조립하고 있었고,
실코드 60줄로 function_body_length 한계에 정확히 걸쳐 있었다 — 상태바에 항목을 하나만
추가해도 make lint가 깨지는 상태였다.

구획별 빌더로 분리: addPermissionSection / addDebugSection / addAppSection.
DEBUG 명령 서브메뉴 조립(중첩 루프)은 makeDebugCommandsItem으로 한 번 더 뺐다.
가장 큰 헬퍼가 24줄이다.

메뉴 항목 순서와 구분선 위치는 그대로다. Release에서는 addDebugSection이 통째로 비어
기존과 동일한 메뉴가 나온다 — Debug/Release 양쪽 구성으로 빌드해 확인했다(#if DEBUG
분기가 구성별로 다르므로 한쪽만 빌드하면 검증이 안 된다).

2. 테스트 하네스 분할 (595 → 최대 185줄)

Tests/included: [Azimuth]라 SwiftLint가 보지 않는다. 그래서 프로덕션이라면 warn을
넘겼을 크기로 계속 자라고 있었다(이번 세션에도 60줄 늘었다).

CommandEngineTests.swift     @main · 공유 상태 · expect* 헬퍼        80줄
├── +Frames.swift            기하 배치 · 이동 · 상대 축소           114줄
├── +Displays.swift          스냅 · 던지기 · 디스플레이 선택        130줄
├── +Apply.swift             앵커 · 적용 판정 · 결과 커밋 정책      185줄
└── +Model.swift             명령 모델 · 그룹 · 식별자              102줄

Swift의 private파일 스코프라 다른 파일의 extension에서 보이지 않는다. 옮긴 함수와
공유 헬퍼의 private을 뗐다(단일 실행 파일로 컴파일되는 하네스라 캡슐화 손실 없음).

Type

  • refactor — no behavior change

Checklist

  • make lint clean — 0 violations / 49 files
  • make test203 checks (분할 전과 동일)
  • make coverage — 100% 유지
  • Debug + Release 양쪽 격리 빌드 BUILD SUCCEEDED
  • 새 테스트 파일 4개를 scripts/test.sh·scripts/coverage.sh 양쪽에 추가
  • .docs/ not staged

Notes / risk

테스트 손실이 없다는 근거: 검사 수가 분할 전후 모두 203개로 동일하다. 추가로
정의된 테스트 함수 25개 / main() 호출 25개 / 중복 정의 0 / 미호출(고아) 0을 확인했다.

리뷰어가 볼 곳: 테스트 파일이 1개 → 5개가 되면서 "새 파일을 두 스크립트에 손으로 추가"
해야 하는 기존 함정의 노출면이 커졌다(CLAUDE.md에 기록된 규칙). 이번 PR에서는 4개 모두
추가했고 make test/make coverage로 확인했지만, 앞으로 테스트 파일을 늘릴 때 같은 실수가
나기 쉽다는 점은 남는다.

한 함수가 권한 상태(진단) · DEBUG 전용 도구 · 일반 앱 동작 세 가지를 조립하고 있었고,
실코드 60줄로 function_body_length 한계(60)에 정확히 걸쳐 있었다. 상태바 메뉴에 항목을
하나만 추가해도 make lint가 깨지는 상태였다.

구획별 빌더로 나눈다: addPermissionSection / addDebugSection / addAppSection.
DEBUG 명령 서브메뉴 조립(중첩 루프)은 makeDebugCommandsItem으로 한 번 더 뺐다.
makeStatusMenu는 8줄이 되고 가장 큰 헬퍼도 24줄이다.

메뉴 항목 순서와 구분선 위치는 그대로다. Release에서는 addDebugSection이 통째로
비어 기존과 동일한 메뉴가 나온다 — Debug/Release 양쪽 빌드로 확인했다.
단일 파일이 실코드 595줄에 테스트 함수 25개였다. Tests/는 SwiftLint 대상이 아니라
(included: [Azimuth]) 프로덕션에 적용되는 file_length 한계(warn 400)를 넘긴 채로 계속
자라고 있었다.

@main·공유 상태·expect* 헬퍼만 CommandEngineTests.swift에 남기고, 테스트는 도메인별
확장 파일로 나눈다: +Frames(기하 배치·이동·상대 축소), +Displays(스냅·던지기·디스플레이
선택), +Apply(앵커·적용 판정·결과 커밋 정책), +Model(명령 모델·그룹·식별자).
가장 큰 파일이 185줄이 된다.

Swift의 private은 파일 스코프라 다른 파일의 extension에서 안 보이므로, 옮긴 함수와
공유 헬퍼의 private을 뗐다(단일 실행 파일로 컴파일되는 테스트 하네스라 영향 없음).

새 파일 4개를 scripts/test.sh·coverage.sh 양쪽 소스 목록에 추가했다. 검사 수는 분할
전후 모두 203개로 동일하고(테스트 손실 없음), 순수 로직 커버리지도 100%를 유지한다.
@pignuante pignuante self-assigned this Jul 22, 2026
@pignuante
pignuante deleted the branch fix/ax-outcome-consistency July 22, 2026 17:38
@pignuante pignuante closed this Jul 22, 2026
@pignuante

Copy link
Copy Markdown
Contributor Author

브랜치를 최신 main 위에서 재작성해 #106으로 옮겼습니다. base였던 fix/ax-outcome-consistency#103 머지와 함께 삭제되면서 이 PR이 자동으로 닫혔고, 닫힌 PR은 base를 바꿀 수 없어 재개설이 필요했습니다.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant