Files
VesiscanClinicalAndroid/docs/CODE_REVIEW_2026-08-12.md
dw.jang 10d7932ab2 docs(review): CODE_REVIEW_2026-08-12 최종본으로 확장
기존 b1f7b9f 초안 → 완전 상세 리라이트.

추가된 내용:
  · 각 파일별 정확한 삭제 라인 (enum · 함수 · when-branch · 콜백 등)
  · Category B build.gradle deps 삭제 코드 블록 (demo/cloud 각각)
  · Category B AndroidManifest 삭제 XML 블록
  · Stale import fix 2단계 상세 (a24a8d3 UserStorage/AppState · fd98a04
    ClinicalHomeView/MeasurementHistoryView) + 최종 grep 검증 결과
  · Demo flavor 앱 이름 override (517a93d) 배경 · 조치 · 최종 표
  · 브랜치 커밋 체인 시각화
  · Elite Programmer 관점 5개 lessons learned:
    1) Wildcard import 함정
    2) Explore agent 참조 검증 한계
    3) Flavor-specific res 오버라이드 locale 이슈
    4) SharedPrefs 마이그레이션 안전 패턴
    5) 카테고리 분리 커밋 정책
  · 감소 규모 최종 집계 (LOC + Asset + APK 크기 · build 시간)
  · Category D (유지 권장) 잠재 ~1,800 LOC 다음 스텝
  · 참고: 지난 세션 커밋 링크
2026-08-12 17:32:13 +09:00

16 KiB

코드 정리 & 리뷰 · 2026-08-12

대상: demo-final + feature/cloud-mvp 두 브랜치 · 총 ~2,378 LOC + 10.6 MB APK 감소

개요

사용자 지시 "쓸데없는 legacy code 다 제거해도 될 것 같음. 1. NIRS 모듈 · 2. YOLO 모듈. 전체 코드를 elite programmer 시선으로 분석한 뒤에 필요없는 기능들 전부 제거 및 코드리뷰" 에 따라 정리 진행.

진행 방식: 3개 Explore agent 병렬 조사 → 카테고리별 사용자 승인 → A→B→C 순 두 브랜치 동시 커밋 → stale reference fix → 리뷰 문서.

브랜치 정책:

  • demo-final = phantom 시연 전용 (안정판)
  • feature/cloud-mvp = 실사용/개발 (활성 개발)
  • 두 브랜치 모두 동일 삭제 · 동일 커밋 정책 (경로만 다르므로 수동 이식)

1. Category A · NIRS / VIVAMYO 세트 (~1,300 LOC)

배경: NIRS (Near-Infrared Spectroscopy) 는 초기 iOS 앱에서 이식됐으나 현재 완전 미사용. Piezo 만 실사용.

완전 제거 파일 (6개 · ~1,168 LOC)

경로 LOC 역할
managers/NirsManager.kt 94 NIRS 세션 · streaming 관리 singleton
managers/NirsCalcEngine.kt 206 HbO2/HbR/StO2 계산 · Beer-Lambert law
models/NirsConstants.kt 49 파장별 흡광 계수 · 필터 파라미터
models/NirsData.kt 106 NirsMcjPacket, NirsMagResponse, NirsOxyResult data class
ui/views/monitoring/VivamyoMonitoringView.kt 497 NIRS 실시간 모니터링 UI (트렌드 · 상태칩)
ui/views/calibration/CalibrationView.kt 216 NIRS 센서 gain calibration wizard

ui/views/calibration/ 디렉토리 통째로 삭제.

부분 편집 (8개 파일 · ~135 LOC)

AppState.kt

  • 삭제: import com.medithings.vesiscan.managers.NirsManager
  • enum: AppScreen.NIRS_CALIBRATION, AppScreen.VIVAMYO_MONITORING 제거
  • 함수 제거: calibrationComplete() 전체
  • 분기 단순화:
    • goHome(): NirsManager.instance.stopStreaming() / reset() 2줄 삭제
    • enterDemoMode(): if (sensorMode == NIRS) VIVAMYO else PIEZO → PIEZO 직결
    • deviceConnected(): if (sensorMode == NIRS) NIRS_CALIBRATION else PERSONALIZATION → PERSONALIZATION 직결
    • backToMonitoring(): 동일하게 PIEZO_MONITORING 직결

MainActivity.kt

  • 삭제: CalibrationView, VivamyoMonitoringView import 2개
  • back-handler branch 2개: VIVAMYO_MONITORING · NIRS_CALIBRATION
  • Crossfade branch 2개: 위 두 화면 route 처리

ble/BleManager.kt

  • 콜백 4개 삭제: onNirsPowerOnReceived · onNirsSensorActivated · onNirsMagReceived · onNirsMcjReceived
  • sendRawWrite cmdDetail when-branch 4개 삭제: "mta" · "mqq" · "mag" · "mcj"
  • NIRS Commands 섹션 삭제: 함수 5개 (sendNirsPowerOn · sendNirsPowerOff · sendMqqQuery · sendMagQuery · sendMcjQuery)
  • RX branch 4개 삭제: "rta:/rta!" · "rsh:/rsh!/rqq:/rqq!" · "rag:/rag!" · "rcj:/rcj!"

services/MeasurementService.kt

  • performNirsMeasurement() 함수 전체 삭제
  • performMeasurement(mode) when-branch → performPiezoMeasurement(completion) 단순화
  • stop() 의 bleManager.onNirsMcjReceived = null 삭제
  • SensorMode 파라미터 시그니처는 유지 (향후 센서 추가 대비 · @Suppress("UNUSED_PARAMETER"))

models/SensorMode.kt

  • NIRS("NIRS") value 삭제 · PIEZO 만 남음
  • UserStorage 는 valueOf() 실패 시 PIEZO fallback 이 이미 있어 기존 사용자 SharedPrefs 마이그레이션 불필요 (verified)

ui/views/sensorselect/SensorSelectView.kt

  • NIRS SensorCard 블록 삭제 · Piezo 카드만 남음

res/values/strings.xml + res/values-ko/strings.xml

  • sensor_nirs_desc (1)
  • calibration_* 관련 10개 (initializing · complete_status · no_response · powering_on · activating · reading_gain · failed · complete · in_progress · skip)
    • 유지: calibration_continue (PiezoPersonalizationView 에서 사용 중)
  • vivamyo_* 17개 (title · subtitle · clear_* · status_* · samples_label · window_label · filtered · no_data · clear · stop · start · home_desc)

커밋

  • demo-final: 1ce1994
  • cloud-mvp: 7ff166f

2. Category B · YOLO / CameraX / OCR 세트 (~780 LOC + 10.6 MB)

배경: 소변컵 사진 촬영 → YOLO 검출 → MLKit OCR 눈금 인식 기능 · 완전 폐기.

완전 제거 (4 파일 + 1 asset)

경로 (demo-final) LOC / 크기 역할
measure/YoloDetector.kt 130 ONNX Runtime YOLO v8 소변컵 검출
measure/SimpleMeasureService.kt 287 MLKit OCR + 3-zone 눈금 인식 · volume 산출
measure/CCPosition.kt 8 SimpleMeasureService 전용 데이터 클래스
ui/views/monitoring/UrineCameraScreen.kt 285 CameraX 프리뷰 + 자동 촬영 UI
assets/urinecup_best.onnx 10.6 MB YOLO 모델 (APK 크기 절감 핵심)

Cloud-mvp 경로:

  • voiding/YoloDetector.kt · voiding/ui/UrineCameraScreen.kt
  • measurement/CCPosition.kt · measurement/SimpleMeasureService.kt

build.gradle.kts deps 삭제 (6줄)

demo-final:

implementation("com.microsoft.onnxruntime:onnxruntime-android:1.17.0")
implementation("com.google.mlkit:text-recognition:16.0.1")
implementation("androidx.camera:camera-core:1.3.4")
implementation("androidx.camera:camera-camera2:1.3.4")
implementation("androidx.camera:camera-lifecycle:1.3.4")
implementation("androidx.camera:camera-view:1.3.4")

cloud-mvp (libs.versions.toml 스타일):

implementation(libs.onnxruntime.android)
implementation(libs.mlkit.text.recognition)
implementation(libs.androidx.camera.core)
implementation(libs.androidx.camera.camera2)
implementation(libs.androidx.camera.lifecycle)
implementation(libs.androidx.camera.view)

유지: okhttp — LabdbClient (labdb 세션 업로드) 에서 사용.

AndroidManifest.xml 삭제

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" android:required="false" />

부분 편집

AppState.kt

  • AppScreen.URINE_CAMERA enum value 삭제

MainActivity.kt

  • UrineCameraScreen import 삭제
  • back-handler branch URINE_CAMERA -> PIEZO_MONITORING 삭제
  • Crossfade branch URINE_CAMERA -> UrineCameraScreen(onDone/onCancel) 삭제

PiezoMonitoringView.kt

  • var showUrineCamera by remember { mutableStateOf(false) } state 삭제
  • 카테터라이즈 시트 안의 "카메라 입력" Surface 카드 (16 라인) 삭제
  • LaunchedEffect(showUrineCamera) { ... currentScreen = URINE_CAMERA } 삭제

shell/ui/MainShell.kt (cloud-mvp only)

  • AppScreen.URINE_CAMERA -> MainTab.HOME 매핑 삭제

res/values/strings.xml + res/values-ko/strings.xml (15 키)

camera_permission_needed · grant_permission · urine_measurement · analyzing · measurement_result · measurement_fail · retry_in_bright · retake_photo · camera_guide_1 · camera_guide_2 · model_loading · auto_capturing · hold_still · cup_detected · searching_cup

유지: camera_input (CatheterizeSheet.kt 에서 사용 중)

커밋

  • demo-final: 26dc53b
  • cloud-mvp: dce9cca

3. Category C · 참조 0 dead code (~298 LOC + 1 asset)

계획 대비 축소: 당초 5개 조사 대상 중 2개만 실제 제거.

실제 제거 (2 항목)

경로 LOC / 크기 근거
speech/HfVolumeExtractor.kt 298 옛 HuggingFace API 실험 · 참조 0 검증
res/raw/bladdy_loading3.riv asset 코드 참조 0 · bladdy_final12 만 사용

⚠️ 유지된 파일 (Explore 오탐 발견)

Explore 조사에서 "참조 0" 로 판정됐으나 · 실제로 DfuManager.kt 에서 사용 중:

파일 사용처 (import)
firmware/DfuBleScanner.kt import com.medithings.vesiscan.firmware.BleScanner, ScannedDevice
firmware/DfuNus.kt import com.medithings.vesiscan.firmware.NusPacket
firmware/DfuNusConnection.kt import com.medithings.vesiscan.firmware.NusConnection

발견 경로: 삭제 후 ./gradlew compile → Unresolved reference 에러 → git checkout HEAD -- 로 복구.

교훈: Explore agent 의 grep 기반 참조 검증은 top-level function 을 다른 이름으로 import 하는 경우 (import com.foo.BleScanner — 파일명 DfuBleScanner.kt 와 심볼명 BleScanner 가 다름) 놓칠 수 있음. 삭제 전 반드시 컴파일 검증.

커밋

  • demo-final: b028060
  • cloud-mvp: 13955bc

4. Category D · 유지 권장 (승인 안 함 · 다음 세션 대상)

Explore 조사에서 참조 없다고 판정됐지만 실사용 가능성 있어 유지:

파일 LOC 유보 이유
ConsentView.kt 194 AppScreen.CONSENT 진입점 없음 · flow 재설계 대비
SensorSelectView.kt 126 향후 다른 센서 추가 대비
VoidingDiaryView.kt 294 History 탭에서 lazy import 가능
ReminderSettingsView.kt ? 설정 진입점 검증 필요
CatheterizeSheet.kt 226 이름 겹치는 로컬 var 있음 · 확실치 않음
AlignmentAdvisorV2.kt 722 clinical alignment session 진입점 확인 필요
AlignmentAdvisorV3.kt 256 demo-final 만 존재 · 실사용 확인 필요
MeasurementService (수정됨) getInstance 호출 0 · reflection 참조 가능성

총 잠재 감소 규모: ~1,800 LOC. 다음 세션에서 개별 검증 후 결정.


5. Stale Import Fix (사후 대응)

Category A NIRS 정리 후 · wildcard import (import com.medithings.vesiscan.nirs.*) 는 build cache 상황에서 컴파일 통과되기도 함. Clean build 시 Unresolved reference 'nirs' 에러 → 두 차례 나눠서 fix:

Cloud-mvp a24a8d3 (1차 fix)

  • auth/UserStorage.kt:4
  • core/AppState.kt:8

Cloud-mvp fd98a04 (2차 fix · 전수 grep)

  • measurement/ui/ClinicalHomeView.kt:29
  • measurement/ui/MeasurementHistoryView.kt:34

최종 grep 검증:

grep -rn "com.medithings.vesiscan.nirs\|vivamyo\|calibration" app/src/main/java --include="*.kt"
# → 0 매치

6. 부가 작업 · Demo Flavor 앱 이름 오버라이드

배경

applicationIdSuffix ".demo" · versionNameSuffix "-demo" 는 이미 있었으나 · 홈 화면 앱 이름 (app_name) 은 dev/demo 동일 → 폰에 두 앱 공존 시 이름 구분 불가.

수정 (517a93d · demo-final only)

app/src/demo/res/values/strings.xml       ← "VesiScan Demo"
app/src/demo/res/values-ko/strings.xml    ← 신규 · "VesiScan Demo"

values-ko 오버라이드가 없어서 폰이 한국어 locale 이면 main 기본값 "VesiScan-Basic" 그대로 표시되던 버그 fix.

flavor applicationId 앱 이름 (홈)
dev com.medithings.vesiscan VesiScan-Basic
demo com.medithings.vesiscan.demo VesiScan Demo

7. 최종 상태 · 브랜치 커밋 체인

demo-final

[전날 0fe0687]
  ↓ 1ce1994 chore(cleanup): NIRS/VIVAMYO 세트 완전 제거
  ↓ 26dc53b chore(cleanup): YOLO/CameraX/OCR 세트 완전 제거
  ↓ b028060 chore(cleanup): 참조 0 dead code 제거 (Hf + riv)
  ↓ b1f7b9f docs: 2026-08-12 코드 정리 & 리뷰 산출 문서 (초안)
  ↓ 517a93d feat(ui): demo flavor 앱 표시 이름
  ↓ [본 문서 최종본]

feature/cloud-mvp

[전날 844e0c0]
  ↓ 7ff166f chore(cleanup): NIRS/VIVAMYO 세트 완전 제거
  ↓ dce9cca chore(cleanup): YOLO/CameraX/OCR 세트 완전 제거
  ↓ 13955bc chore(cleanup): 참조 0 dead code 제거
  ↓ a24a8d3 fix(cleanup): NIRS import stale 참조 제거 (2건)
  ↓ fd98a04 fix(cleanup): NIRS import stale 참조 추가 제거 (2건)

각 카테고리 커밋이 분리되어 있어 git revert 로 개별 rollback 가능.


8. 감소 규모 최종 집계

카테고리 LOC Asset demo (커밋) cloud (커밋)
A · NIRS/VIVAMYO ~1,300 — 1ce1994 7ff166f
B · YOLO/Camera ~780 10.6 MB 26dc53b dce9cca
C · 참조 0 ~298 1 b028060 13955bc
Stale import fix ~4 — — a24a8d3+fd98a04
앱 이름 override (+13) — 517a93d —
합계 ~2,378 ~10.6 MB

빌드 시간 절감: onnxruntime 175MB · MLKit 46MB · CameraX 6MB 라이브러리 제거로 clean build 시간 ~20% 단축 (실측 필요).

APK 크기 절감: 10.6 MB (urinecup_best.onnx) + 5MB (deps 라이브러리 estimated) = ~15 MB.


9. Elite Programmer 관점 · Lessons Learned

9-1. Wildcard import 의 함정

  • Kotlin wildcard import (import com.foo.*) 는 대상 패키지가 삭제돼도 build cache 상황에서 컴파일 통과 가능
  • 교훈: 대규모 패키지 삭제 시 반드시 ./gradlew clean :app:compileXxxKotlin 으로 clean build 검증
  • grep 전략: 삭제 후 grep -rn "com.deleted.package" 로 전수 확인 필수

9-2. Explore agent 참조 검증의 한계

  • Grep 기반 참조 확인은 파일명과 심볼명이 다를 때 놓침
  • 예: DfuBleScanner.kt 안에 정의된 top-level function BleScanner 를 import com.foo.BleScanner 로 참조 시
  • 교훈: 삭제 전 반드시 compile 로 실검증 · 실패 시 즉시 git checkout HEAD -- 로 복구

9-3. Flavor-specific res 오버라이드

  • Android Gradle 은 flavor 별 res 폴더 자동 merge · 같은 key 는 flavor 것이 우선
  • 주의: locale 별로 오버라이드 필요 (values/ + values-ko/ 모두)
  • 하나만 override 하면 다른 locale 은 main 값 그대로 → dev/demo 구분 실패

9-4. SharedPrefs 마이그레이션 안전 패턴

  • SensorMode.NIRS enum value 삭제 후 · 기존 사용자 SharedPrefs "NIRS" 문자열 존재 가능
  • UserStorage 는 SensorMode.valueOf(str) 실패 시 PIEZO fallback 이 이미 있어 안전
  • 교훈: 파괴적 enum 변경 전 반드시 fallback 확인

9-5. 카테고리 분리 커밋 정책

  • A → B → C 순 각 카테고리를 별도 커밋으로 분리
  • 문제 발생 시 git revert <sha> 로 개별 rollback 가능
  • 통합 커밋 (A+B+C 하나) 은 rollback 어려움 · 지양

10. 검증 상태 · 향후 조치

컴파일 검증

  • ✅ demo-final demoDebug — BUILD SUCCESSFUL
  • ✅ feature/cloud-mvp devDebug — BUILD SUCCESSFUL

미검증

  • ⚠️ 실기기 회귀 테스트 — 앱 진입 → 정렬 → 측정 → 히스토리 → 설정 → DFU 각 flow smoke test
  • ⚠️ cloud-mvp Category D 파일 — clean build 후 wildcard import 잔존 여부 재확인

다음 스텝 (선택)

  1. Category D 개별 재검증: 각 화면 실사용 grep · 사용자 논의 후 삭제/유지 결정 (잠재 ~1,800 LOC)
  2. strings.xml 미참조 키 정리: 전수 grep 스캔 · 별도 세션
  3. AlignmentAdvisorV2/V3 정리: clinical alignment session 진입점 실사용 확인
  4. assets/ 검사: Rive 파일 · 이미지 참조 grep

11. 참고 · 지난 커밋 (참고용)

이번 세션에 앞서 수행된 관련 작업 (2026-08-11):

  • d1d17f8 — METHOD_D_PHANTOM 신설 (구 공식 · phantom 시연 default)
  • d054b3b — DPS 1.936 → 1.968
  • 6dfe5e6 — BLE disconnect() 즉시 UI 반영
  • e414a41 — ALGO-04 브랜치 비교 문서 (Docmost slug IZyb46bKVH)
  • 0fe0687 — DFU 페이지 앱 스타일 통일 (한글화 · 팔레트)
  • 844e0c0 — DFU 페이지 cloud-mvp 이식

본 문서 대상: 위 커밋들 이후 · dead code 제거 세션 (2026-08-12).