refactor: 네트워크 레이어 리팩터링#60
Conversation
## Walkthrough
이 변경사항은 네트워크 및 DI 관련 모듈에서 기존의 do-catch 기반 동기 에러 처리 방식을 Combine의 AnyPublisher 기반 비동기 스트림으로 리팩토링하고, Autowired의 사용 시점에 대한 가이드 및 예시를 문서화하는 작업을 포함합니다. 일부 불필요한 에러 타입이 제거되고, 네트워크 에러 타입이 통일되었습니다.
## Changes
| 파일/그룹 | 변경 요약 |
|---|---|
| BKCore/Sources/DiContainer/Autowired.swift | Autowired 사용 예시 및 가이드 문서화 변경(구현/인터페이스 변경 없음) |
| BKData/Sources/Error/NetworkError.swift | NetworkError enum에 retryTrigger, unknown 케이스 추가 |
| BKData/Sources/Interface/Network/NetworkProvider.swift<br>BKNetwork/Sources/Provider/DefaultNetworkProvider.swift<br>BKNetwork/Sources/Provider/OAuthNetworkProvider.swift | request 메서드 반환 타입을 AnyPublisher<T, Error> → AnyPublisher<T, NetworkError>로 변경 및 에러 처리 방식 통일 |
| BKData/Sources/Interface/Network/URLBuilding.swift<br>BKNetwork/Sources/Helper/URLBuilder.swift | makeURL 메서드를 동기/throwing → AnyPublisher<URL, NetworkError>로 변경 |
| BKNetwork/Sources/Extension/RequestTarget+.swift | makeURLRequest 메서드를 동기/throwing → AnyPublisher<URLRequest, NetworkError>로 변경, accessToken 파라미터 제거 |
| BKNetwork/Sources/Helper/AuthInterceptor.swift | RetryTrigger 에러 사용 → NetworkError.retryTrigger 사용으로 변경 |
| BKNetwork/Sources/Error/RetryTrigger.swift | RetryTrigger 에러 타입 파일 삭제 |
| BKNetwork/Sources/Extension/Publisher+.swift | Publisher extension이 Failure == NetworkError일 때만 동작하도록 제약 추가 |
| BKNetwork/Sources/Extension/HTTPURLResponse+.swift<br>BKNetwork/Sources/Extension/URLRequest+.swift | BKData 모듈 import 추가(기능 변화 없음) |
## Sequence Diagram(s)
```mermaid
sequenceDiagram
participant ViewModel
participant NetworkProvider
participant RequestTarget
participant URLBuilder
participant Network
participant Decoder
ViewModel->>NetworkProvider: request(target, type)
NetworkProvider->>RequestTarget: makeURLRequest()
RequestTarget->>URLBuilder: makeURL(target)
URLBuilder-->>RequestTarget: AnyPublisher<URL, NetworkError>
RequestTarget-->>NetworkProvider: AnyPublisher<URLRequest, NetworkError>
NetworkProvider->>Network: URLSession.dataTaskPublisher
Network-->>NetworkProvider: Data, Response
NetworkProvider->>Decoder: decode(Data)
Decoder-->>NetworkProvider: Decoded Object / Error
NetworkProvider-->>ViewModel: AnyPublisher<T, NetworkError>Assessment against linked issues
Poem
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
src/Projects/BKNetwork/Sources/Extension/RequestTarget+.swift (1)
12-25: 인증 로직이 인터셉터로 이동한 것을 확인했습니다.
accessToken파라미터와addAuthorization호출이 제거되었지만,OAuthNetworkProvider에서AuthInterceptor.adapt()를 통해 처리되는 것을 확인했습니다. 이는 관심사의 분리 측면에서 더 나은 설계입니다.다만, 구현을 더 간단하게 개선할 수 있습니다:
- Just(()) - .setFailureType(to: NetworkError.self) - .tryMap { _ in + Deferred { + Future<URLRequest, NetworkError> { promise in + do { var request = try URLRequest(baseURL + path, query: query) request.makeURLHeaders(headers) request.httpMethod = method.rawValue request.cachePolicy = .reloadIgnoringLocalCacheData if let body { request.setBody(body) } - return request + promise(.success(request)) + } catch { + promise(.failure(error as? NetworkError ?? NetworkError.invalidURL)) + } } - .mapError { error in error as? NetworkError ?? NetworkError.invalidURL } + } .eraseToAnyPublisher()src/Projects/BKNetwork/Sources/Provider/DefaultNetworkProvider.swift (2)
30-30: 프로덕션 환경에서debugError사용 시 주의가 필요합니다.
debugError는 개발 중에는 유용하지만, 프로덕션에서는 민감한 정보가 로그에 노출될 수 있습니다. 조건부 컴파일을 사용하여 디버그 빌드에서만 활성화하는 것을 고려해보세요.- .debugError("Decoding Failed", logger: AppLogger.network) + #if DEBUG + .debugError("Decoding Failed", logger: AppLogger.network) + #endif
31-31: 에러 매핑 시 더 구체적인 에러 타입을 고려해보세요.현재 모든 비-NetworkError를
.invalidResponse로 매핑하고 있는데, 이로 인해 디코딩 에러나 다른 유용한 에러 정보가 손실될 수 있습니다.- .mapError { $0 as? NetworkError ?? .invalidResponse } + .mapError { error in + if let networkError = error as? NetworkError { + return networkError + } else if error is DecodingError { + return NetworkError.decodingFailed + } else { + return NetworkError.unknown + } + }참고:
NetworkError에decodingFailed케이스가 없다면 추가를 고려해보세요.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
src/Projects/BKCore/Sources/DiContainer/Autowired.swift(1 hunks)src/Projects/BKData/Sources/Error/NetworkError.swift(1 hunks)src/Projects/BKData/Sources/Interface/Network/NetworkProvider.swift(1 hunks)src/Projects/BKData/Sources/Interface/Network/URLBuilding.swift(1 hunks)src/Projects/BKNetwork/Sources/Error/RetryTrigger.swift(0 hunks)src/Projects/BKNetwork/Sources/Extension/HTTPURLResponse+.swift(1 hunks)src/Projects/BKNetwork/Sources/Extension/Publisher+.swift(1 hunks)src/Projects/BKNetwork/Sources/Extension/RequestTarget+.swift(1 hunks)src/Projects/BKNetwork/Sources/Extension/URLRequest+.swift(1 hunks)src/Projects/BKNetwork/Sources/Helper/AuthInterceptor.swift(1 hunks)src/Projects/BKNetwork/Sources/Helper/URLBuilder.swift(1 hunks)src/Projects/BKNetwork/Sources/Provider/DefaultNetworkProvider.swift(1 hunks)src/Projects/BKNetwork/Sources/Provider/OAuthNetworkProvider.swift(2 hunks)
💤 Files with no reviewable changes (1)
- src/Projects/BKNetwork/Sources/Error/RetryTrigger.swift
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: clxxrlove
PR: YAPP-Github/Reed-iOS#56
File: src/Projects/BKPresentation/Sources/Constant/PresentationKeys.swift:3-5
Timestamp: 2025-07-07T13:53:13.006Z
Learning: clxxrlove prefers using enum over struct for constants namespace due to better runtime performance, memory layout, and compiler optimizations. Enum prevents instantiation at compile time without needing private init().
🧬 Code Graph Analysis (1)
src/Projects/BKNetwork/Sources/Provider/OAuthNetworkProvider.swift (7)
src/Projects/BKNetwork/Sources/Extension/RequestTarget+.swift (1)
makeURLRequest(12-25)src/Projects/BKNetwork/Sources/Provider/DefaultNetworkProvider.swift (1)
request(16-34)src/Projects/BKNetwork/Sources/Helper/AuthInterceptor.swift (2)
adapt(13-19)retryIfNeeded(21-31)src/Projects/BKNetwork/Sources/Extension/Optional+.swift (1)
orThrow(6-11)src/Projects/BKNetwork/Sources/Extension/HTTPURLResponse+.swift (1)
validate(9-27)src/Projects/BKNetwork/Sources/Extension/Data+.swift (1)
decode(6-10)src/Projects/BKNetwork/Sources/Extension/Publisher+.swift (1)
retryIf(7-20)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (13)
src/Projects/BKCore/Sources/DiContainer/Autowired.swift (2)
10-14: 예시 확장 추가 👍
ViewModel에서 네임드 의존성을 주입하는 구체적인 예시가 추가되어@Autowired사용법이 한층 명확해졌습니다. 실제 코드에서도 동일한 패턴을 유지하면 신규 합류자에게 큰 도움이 될 것 같습니다.
16-20: 가이드 문구의 논리적 모순 수정 제안
17 ~ 19행에서 “ViewModel을 제외한 모든 계층에서는@Autowired”, 이어서 “Data, Domain 계층은 생성자 주입을 사용”이라고 안내하고 있어 혼동을 줄 수 있습니다. ViewModel 사용 여부가 앞뒤에서 상반되므로 표현을 하나로 통일해 주세요.
[ suggest_nitpick ]가능한 수정 예시:
-/// ViewModel을 제외한 모든 계층에서는 `Assembly`에서 `@Autowired`로 주입합니다. -/// Data, Domain 등의 계층에서는 테스트가 필수불가결적이므로 생성자 주입을 통한 DI를 활용해주세요. -/// 단, ViewModel의 경우에는 편리하게 `@Autowired` 주입을 추천드립니다. +/// • Data, Domain 등 테스트 중심 계층: **생성자 주입** 권장 +/// • ViewModel 및 Presentation 계층: 불필요한 보일러플레이트를 줄이기 위해 **`@Autowired` 사용** 권장 +/// • 기타 계층: 상황에 따라 `@Autowired` 또는 생성자 주입 선택src/Projects/BKNetwork/Sources/Extension/URLRequest+.swift (1)
3-3: 모듈 구조 개선을 위한 적절한 import 추가
NetworkError가BKData모듈로 이동함에 따라 필요한 import를 추가한 것이 적절합니다.src/Projects/BKNetwork/Sources/Extension/HTTPURLResponse+.swift (1)
4-4: 네트워크 에러 통합을 위한 일관된 import 추가
NetworkError타입 사용을 위해BKData모듈 import를 추가한 것이 리팩터링 목표와 일치합니다.src/Projects/BKData/Sources/Error/NetworkError.swift (1)
9-10: 네트워크 에러 처리 통합을 위한 새로운 케이스 추가
retryTrigger와unknown케이스를 추가하여 에러 처리를 통합한 것이 좋습니다. 특히retryTrigger는 기존RetryTrigger구조체를 대체하여 에러 타입을 단일화했습니다.src/Projects/BKNetwork/Sources/Helper/AuthInterceptor.swift (1)
29-29: 에러 타입 통합을 위한 적절한 변경
RetryTrigger구조체 대신NetworkError.retryTrigger를 사용하여 에러 타입을 통일한 것이 리팩터링 목표와 일치합니다.src/Projects/BKNetwork/Sources/Extension/Publisher+.swift (2)
3-3: NetworkError 타입 사용을 위한 필수 import
NetworkError타입을 사용하기 위해BKData모듈을 import한 것이 적절합니다.
6-6: 타입 안전성 향상을 위한 제네릭 제약 추가
Publisher확장을Failure == NetworkError로 제한하여 네트워크 에러 처리의 타입 안전성을 높인 것이 좋습니다. 네트워크 레이어의 에러 처리가 더욱 명확해졌습니다.src/Projects/BKData/Sources/Interface/Network/NetworkProvider.swift (1)
7-10: 에러 타입을 구체화한 좋은 변경입니다!
Error에서NetworkError로 타입을 좁힌 것은 타입 안전성을 높이고 에러 처리를 더 명확하게 만듭니다.src/Projects/BKData/Sources/Interface/Network/URLBuilding.swift (1)
3-8: Combine 기반 비동기 처리로의 일관된 전환입니다.동기식 throwing 함수에서
AnyPublisher를 반환하는 비동기 함수로 변경한 것은 네트워크 레이어 전체의 리팩토링 방향과 일치합니다.src/Projects/BKNetwork/Sources/Helper/URLBuilder.swift (1)
8-19: Publisher 체인을 활용한 깔끔한 구현입니다.
makeURLRequest()의 결과에서 URL을 추출하고, 적절한 에러 처리를 수행하는 구현이 잘 되어 있습니다.src/Projects/BKNetwork/Sources/Provider/OAuthNetworkProvider.swift (1)
3-3: BKCore 임포트가 추가되었습니다.BKCore 모듈이 필요한 이유를 확인해주세요. 사용되지 않는다면 제거하는 것이 좋습니다.
src/Projects/BKNetwork/Sources/Provider/DefaultNetworkProvider.swift (1)
17-34: Combine 기반 비동기 처리로의 리팩토링이 잘 구현되었습니다!반환 타입을
NetworkError로 구체화하여 타입 안전성을 향상시키고, reactive chain을 통해 비동기 처리를 깔끔하게 구현한 점이 좋습니다.
🔗 관련 이슈
📘 작업 유형
📙 작업 내역
@Autowired의 가이드 수정🧪 테스트 내역
💬 추가 설명 or 리뷰 포인트 (선택)
@Autowired는 사실 생각한게 있어서 그 부분 수정하려고 했는데 이미 잘 되어있었어서... 문서만 수정했습니다.AnyPublisher로 전부 묶는게 맞는 건지 잘 모르겠습니다.Summary by CodeRabbit
문서화
@Autowired프로퍼티 래퍼 사용 예시와 가이드가 개선되었습니다.신규 기능
retryTrigger와unknown케이스가 추가되었습니다.버그 수정
NetworkError타입으로 통일되었습니다.리팩터
RetryTrigger)이 제거되었습니다.NetworkError.retryTrigger조건에 맞게 개선되었습니다.기타