Skip to content

refactor(afternote): 저장 흐름 예외 3종을 AfternoteFailure sealed 루트로 압축 (#934 4-B) [base: develop] - #1056

Merged
1hyok merged 1 commit into
developfrom
refactor/934-3-afternote
Aug 25, 2026
Merged

1hyok merged 1 commit into
developfrom
refactor/934-3-afternote

Conversation

@1hyok

@1hyok 1hyok commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

#934 의 4-B 단계. 1·2단계는 #1051, 4-A(수신자)는 #1054 — 세 PR 이 다 머지되면 이슈를 닫는다. 파일이 겹치지 않아 머지 순서 제약은 없다.

무엇을

AfternoteAuthoringValidationException 과, UseCase 파일에 얹혀 있던 MemorialVideoSaveException·MemorialPhotoSaveException → AfternoteFailure 루트 아래 AuthoringValidation·MediaSave 둘로.

sealed class AfternoteFailure(message: String?, cause: Throwable?) : Exception(message, cause) {
    class AuthoringValidation(val kind: AfternoteAuthoringValidationKind) : AfternoteFailure(...)
    class MediaSave(val media: MediaKind, cause: Throwable) : AfternoteFailure(...)
}

매체별로 타입을 나눌 이유가 없었다 — 화면은 둘을 갈라 보지 않고 handleSaveFailure 의 generic 폴백으로 같이 처리하며, 갈라 보던 코드도 없다. 매체는 MediaKind 필드로 구분한다(#938 이 도입한 enum).

이슈 본문이 못박은 두 제약을 지켰다

  • cause 보존 — 원본 예외를 cause 로 나르는 게 계약이고 ResolveMemorialMediaForSaveUseCaseTest 가 단언한다.
  • data class 금지 — 생성된 equals/hashCode 가 선언 프로퍼티만 덮어 cause 를 무시한다. 일반 class 로 뒀다.

묶기만 하지 않았다

handleSaveFailure 의 when 이 else -> null 로 뭉개고 있어 sealed 이득이 0 이었다. 루트로 좁혀 MediaSave 가 "검증 실패 아님(null)"으로 명시되게 했고, 실패 유형이 늘면 그 자리가 컴파일 에러로 잡힌다. 그 null 이 곧 "텔레메트리 기록 대상" 이라 분류를 빠뜨리면 조용히 기록에서 빠진다.

판단해서 정한 것

message 를 진단 문구(영문)로 통일했다. 기존 한국어 문구("영상 업로드에 실패했습니다.")는 화면에 닿지 않는 값이다 — handleSaveFailure 가 검증 실패가 아닌 실패를 전부 afternote_editor_save_failed_generic 리소스로 폴백시키므로, 이 문구는 Crashlytics 에만 남는다. 나머지 도메인 예외의 정책(표시 문구는 리소스, message 는 진단)과 맞췄다.

AfternoteAuthoringValidationKind 는 값이 하나(RECEIVERS_REQUIRED)뿐이지만 유지했다 — 서버 코드 475 에 대응하는 도메인 어휘라 AuthoringValidation 자체를 없애면 그 번역 지점이 사라진다.

검증

게이트 결과
:app:compileDebugUnitTestKotlin green
:app:compileDebugAndroidTestKotlin (#949 신설) green
전 모듈 ktlintCheck green
:feature:afternote:domain · :data · :presentation testDebugUnitTest green

시각 검증 해당 없음 — 리소스·Compose 변경 0. baseline 사이클 미실행.

리뷰어에게

AfternoteAuthoringValidationException 과 UseCase 파일에 얹혀 있던
MemorialVideoSaveException·MemorialPhotoSaveException 을 AfternoteFailure sealed
루트 아래 AuthoringValidation·MediaSave 둘로 줄인다.

매체별로 예외 타입을 나눌 이유가 없었다 — 화면은 둘을 갈라 보지 않고
handleSaveFailure 의 generic 폴백으로 같이 처리하며, 갈라 보던 코드도 없다. 매체는
MediaKind 필드로 구분한다.

MediaSave 에 data class 를 쓰지 않은 건 생성된 equals/hashCode 가 선언 프로퍼티만 덮어
cause 를 무시하기 때문이다. 원본 예외를 cause 로 나르는 것이 이 타입의 계약이고
ResolveMemorialMediaForSaveUseCaseTest 가 그것을 단언한다.

message 는 진단 문구(영문)로 통일했다. 기존 한국어 문구("영상 업로드에 실패했습니다.")는
handleSaveFailure 가 검증 실패가 아닌 실패를 전부 generic 리소스로 폴백시켜 화면에 닿지
않는 값이었다 — Crashlytics 에만 남으므로 나머지 도메인 예외와 정책을 맞췄다.

소비처는 루트로 좁혀 when 을 exhaustive 하게 만들었다. handleSaveFailure 가 검증 실패를
가려낼 때 MediaSave 가 "검증 실패 아님(null)" 으로 명시되고, 실패 유형이 늘면 그 자리가
컴파일 에러로 잡힌다. 기존 else -> null 은 그 구분을 삼켰다.
@1hyok
1hyok merged commit d2f9ebc into develop Aug 25, 2026
13 checks passed
@1hyok
1hyok deleted the refactor/934-3-afternote branch August 25, 2026 03:36
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.

2 participants