Feature를 구현할 때 빠뜨리지 말아야 할 항목들
Auth / MainTab / Onboarding은 예외 Feature로 취급되어 이 체크리스트를 강제하지 않습니다.
-
@Reducer매크로 추가 -
public struct {Feature}Reducer정의 -
public let reducer: Reduce<State, Action>프로퍼티 -
public init(reducer: Reduce<State, Action>)생성자 -
public var body: some ReducerOf<Self> { reducer }구현
-
@ObservableState매크로 추가 -
public struct State: Equatable정의 - 모든 프로퍼티
public선언 -
public init()생성자 정의⚠️ 필수!
-
public enum Action정의 - 사용자 액션 정의 (
Tapped/Changed접미사) - 시스템 응답 정의 (
Response접미사) - Delegate 액션 정의 (필요 시)
-
@CasePathable매크로 추가 -
public enum Delegate정의 - Delegate 케이스 정의
-
public struct {Domain}Client정의 - 메서드 프로퍼티 정의 (
@Sendable클로저) -
public init생성자 정의 -
TestDependencyKeyextension 추가 -
DependencyValuesextension 추가
-
public struct {Feature}ViewFactory: Sendable정의 -
public var makeView: @MainActor (_ store:) -> AnyView정의 -
public init생성자 정의 -
TestDependencyKeyextension 추가 -
DependencyValuesextension 추가
-
extension {Feature}Reducer작성 -
public init()구현 (기본 생성자) -
@Dependency주입 -
self.init(reducer: Reduce { ... })호출 - 모든 Action에 대한 case 처리
- State 변경 후 Effect 반환
-
struct {Feature}View: View정의⚠️ internal -
let store: StoreOf<{Feature}Reducer>프로퍼티 -
var body: some View구현 -
store.send(action)호출 -
store.state직접 접근
-
extension {Domain}Client: DependencyKey작성 -
public static let liveValue구현 - 실제 로직 구현 (네트워크, DB 등)
-
extension {Feature}ViewFactory: DependencyKey작성 -
public static let liveValue구현 -
AnyView({Feature}View(store: store))반환
-
public enum Feature{Name}Linker정의 -
public static func link()구현 - 모든
liveValue강제 참조
- public 타입에
///주석 추가 - 간단 설명 (1-2문장)
-
## 사용 예시섹션 추가 - 코드 블록 (
swift) 추가 - 복잡한 로직은
## 동작 원리섹션 추가
/// 소셜 로그인을 처리하는 클라이언트입니다.
///
/// Apple, Kakao 등의 소셜 로그인 제공자를 통해 사용자 인증을 수행합니다.
///
/// ## 사용 예시
/// ```swift
/// @Dependency(\.authLoginClient) var authLoginClient
/// let result = try await authLoginClient.login(.apple)
/// ```
public struct AuthLoginClient { }-
#Preview("Live")- 실제 동작 -
#Preview("Mock - 성공")- Mock 데이터 -
#Preview("Mock - 에러")- 에러 상태 -
#Preview("Loading")- 로딩 상태 -
#Preview("Empty")- 빈 상태 (필요 시)
#Preview("Live") {
AuthView(
store: Store(initialState: AuthReducer.State()) {
AuthReducer()
}
)
}
#Preview("Mock - 성공") {
AuthView(
store: Store(initialState: AuthReducer.State()) {
AuthReducer()
} withDependencies: {
$0.authLoginClient = .mockSuccess
}
)
}현재 단계에서는 테스트 항목을 적용하지 않습니다.
-
@Test함수 작성 -
TestStore생성 -
withDependenciesMock 주입 -
await store.send(action)- Action 전송 - State 변경 검증
-
await store.receive(action)- Effect 응답 검증 - 최종 State 검증
-
mockSuccess구현 -
mockFailure구현 - 다양한 시나리오 Mock (필요 시)
현재 단계에서는 테스트/Testing 타겟 추가를 필수로 보지 않습니다.
-
.feature(interface:)타겟 정의 -
.feature(implements:)타겟 정의 -
.feature(example:)타겟 정의 (필요 시) -
.feature(testing:)타겟 정의 (필요 시) - 의존성 정확히 설정
// Interface는 최소 의존성만
.feature(interface: .auth, config: .init(
dependencies: [
.external(dependency: .ComposableArchitecture)
]
))
// Sources는 Interface + 필요한 모듈
.feature(implements: .auth, config: .init(
dependencies: [
.feature(interface: .auth),
.core(implements: .logging),
.external(dependency: .ComposableArchitecture)
]
))- Interface/Sources 분리 올바른가? (예외 Feature: Auth / MainTab / Onboarding 제외)
- public/internal 접근 제어자 올바른가?
- Dependency 올바르게 주입했는가?
- Reducer는 순수 함수인가? (Side Effect 없는가?)
- Action은 "What happened" 형태인가?
- 사용자 액션은
Tapped/Changed접미사 사용했는가? - Bool 프로퍼티는
is/has/should접두사 사용했는가? - 약어 사용하지 않았는가?
- State는 최소한인가? (계산 가능한 것은 computed property)
- State는
Equatable인가? - Optional은 적절히 사용했는가?
- 비동기 작업은
.run으로 래핑했는가? - Effect는 적절한 시점에 반환되는가?
- Effect 취소가 필요한 경우
.cancellable(id:)사용했는가?
- 모든 네트워크 에러 처리했는가?
- 사용자에게 에러 메시지 표시하는가?
- Retry 로직이 필요한가?
- 모든 테스트 통과
- SwiftLint 경고 없음
- 불필요한 로그 제거
- 주석 처리된 코드 제거
- TODO 주석 확인
- DocC 문서 완성
- Example 앱 정상 동작
- Preview 모두 정상 렌더링
작성일: 2026-01-12