-
Notifications
You must be signed in to change notification settings - Fork 7
Description
맥북을 깜빡해서 노트에다 끄적끄적거리면서 주말간 고민들을 리스트 업 해보았다.
- Presetner의 Input에 대한 접근제어자. private으로 하니 테스트할 수 없어.
- Interactor의 output과 Presetner의 Input 연결
- Interactor의 output 1개를 presenter의 여러개 input으로 Event를 Passing해야될 경우.
Presetner의 Input에 대한 접근제어자. private으로 하니 테스트할 수 없어.
Test를 위해선 input에 대해서 접근제어자 제약을 걸기에는 불가능 합니다.
따라서 두가지 방법으로 생각해봤는데 첫째로는 Interactor에서 presenter에 대한 PresenterInputLogic에 대한 protocol을 정의함으로써 제약을 거는 방법이 있습니다.
class Interactor {
var presenter: PresenterInputLogic
}다른 방법으로는 이전 연구일지 #4 에서 언급한대로 Interactor Output Logic을 Presenter로 넘겨서 Presenter내부에서 Input로직에 대해서 binding처리를 해주는 방법이 있겠습니다.
class Presenter {
func bind(_ interactor: InteractorOutputLogic) { ... }
}Interactor의 output과 Presetner의 Input 연결
이전 연구일지 #4 에서는 presenter에서 Interactor Output Logic을 받아서 bind처리해주는 method를 만들었지만, 기존 레이몬드님의 CleanSwift 에서는 interactor가 presenterLogic을 프로퍼티로 가지고 있고 그것을 접근해서 사용합니다.
레이몬드님 제안
class Interactor {
var presenter: PresenterInputLogic?
}장점: Interactor Output 과 presenter Input연결에 대한 코드 응집력이 증가한다.
단점: Interactor가 Massive해진다. (비대해짐, DataStore + Input, Output + Presenter Input...)
필자 및 동료개발자가 기존에 생각한 방법
class Presenter {
init(_ interactor: InteractorOutputLogic) {
// TODO:
}
}장점: Presenter에서 바인딩 처리를 해주기 때문에 Interactor 무게가 줄어들고 presenter input 연결에 대해서 가시적이다.
단점: Response -> ViewModel가공영역에 만족하면 좋지만 굳이 interactor output 처리를 presenter input 매칭 및 바인딩을 여기서 해야하는가?
Interactor의 output 1개를 presenter의 여러개 input으로 Event를 Passing해야될 경우.
CleanSwift 문서에 따르면 어떠한 Interactor 한개의 Logic 동작시 여러개의 Presenter에 Response를 전달할 수가 있다고 되어있다.
var presenter: PresenterInputLogic?
func didTapLikeButton() {
let response: Response = .init()
self.presetner?.responsePass1(response)
self.presetner?.responsePass2(response)
self.presetner?.responsePass3(response)
self.presetner?.responsePass4(response)
// ...
}RxSwift를 쓰게되면 여러 worker들을 map/flatMap 처리하면서 적절히 catchError처리해가면서 이벤트 스트림을 보기 좋게 조리할 수 있다.
단, 이전 이벤트 값에 따라서 WaterFall 처럼 이벤트가 전달되면 처리되는 로직이 있는경우 각각 단계에서 presenter가 response를 전달해주는 경우와 Interactor Input로직에 따라 분산 처리되어 response를 전달해주는 경우 두가지의 경우를 가정해보자.
이전 이벤트 값에 따라서 WaterFall 처럼 이벤트가 전달되면 처리되는 로직이 있는경우 각각 단계에서 presenter가 response를 전달
var step1Output: Observable<Res1> {
return interactorInput.flatMap { worker1 }
}
var step2Output: Observable<Res2> {
return step1Output.flatMap { worker2 }
}
var step3Output: Observable<Res3> {
return step2Output.flatMap { worker3 }
}
var step4Output: Observable<Res4> {
return step3Output.flatMap { worker4 }
}
var step5Output: Observable<Res5> {
return step4Output.flatMap { worker5 }
}Interactor Input로직에 따라 분산 처리되어 response를 전달해주는 경우 두가지의 경우
var step1Output: Observable<Res1> {
return interactorInput.flatMap { worker1 }
}
var step2Output: Observable<Res2> {
return interactorInput.flatMap { worker2 }
}
var step3Output: Observable<Res3> {
return interactorInput.flatMap { worker3 }
}
var step4Output: Observable<Res4> {
return interactorInput.flatMap { worker4 }
}어플리케이션 비즈니스로직 연결 포인트의 복잡도에 따라서 자칫하면 이해할 수 없는 코드가 될까 봐 무섭기도하다.
주말내내 머리칼 잡다가 문뜩 레이몬드 CleanSwift는 Max howell 아저씨의 PromiseKit이 제법어울릴꺼 같다는 발칙한?발상도 해보았다..
protocol InteractorLogic {
func didTapLike(_ req: Request)
}
class Interactor: InteractorLogic {
var presenter: PresenterLogic?
func didTapLike(_ req: Request) {
firstly {
worker1()
}.map {
self.presenter.input1(Res1.init($0))
self.worker2()
}..map {
self.presenter.input2(Res2.init($0))
self.worker3()
}.map {
self.presenter.input3(Res3.init($0))
self.worker4()
}.map {
self.presenter.input4(Res4.init($0))
self.worker5()
}.done { foo in
self.presenter.input5(Res5.init($0))
}.catch { error in
}
}
}