ReactorKit을 실제 서비스에 적용해보며 고민한 점을 정리했습니다.
low한 레벨의 고민들을 정리
코드를 작성하기 전에 어떤 방식으로 작성할지에 대한 충분한 고민이 필요하고, 이런저런 시도한 것들과
CompositionRoot으로 의존성 주입
모든 것을 컴포지션 루트에서 생성합니다. 컴포지션 루트에서 모든 의존성을 생성하고 주입합니다.
Reactor는 어디에서 주입하는 것이 올바를까 ? 에대한 고민을 많이 했었습니다. 정답은 없지만, 클린 아키텍쳐 처럼 최상단에서 의존성을 주입하는 파일을 두고 이를 해결하는 CompositionRoot.swift 파일을 발견했습니다.
이 방식에서의 문제의식은 파일의 양이 길어지고 복잡해진다는 점 입니다. A 페이지에서 B로 가고 B에서는 C, D, E 페이지로 넘어가지는 구조를 작성하다보면 뎁스가 깊어져서 가독성이 떨어졌습니다.
Cell에 Reactor 주입하기
ReactorKit을 사용하더라도, CollectionViewCell을 만들때에 기존의 Delegate 패턴으로 Cell에게 data를 주입할 수 있습니다.
하지만 이렇게 되면 data에 대한 비즈니스 로직 처리를 ViewController 내부에서 하게됩니다.
RxDatasource를 사용하여 Cell에 Reactor를 주입하는 코드를 작성하였습니다.
API 로직은 상단에서 처리
예시는 API 로직이지만, 핵심은 비즈니스 로직을 모두 포함하는 내용입니다.
다음과 같은 화면이 있습니다. 각 UI는 모두 Reactor을 가지고 있습니다. 저기 초록색 Cell의 하트 버튼을 누르면 like API를 호출할 예정입니다.
다소 극단적인 예시이지만, Cell의 Reactor에서 하트 버튼이 클릭되면 like API를 호출하는 코드를 작성했다고 해봅시다.
여기서의 문제의식은 2가지 입니다.
- 자식이 너무 많은 책임을 진다. (SRP: 단일책임원칙)
- 변경점을 부모에게 알려야 한다. (DIP: 의존역전원칙)
하나씩 살펴보겠습니다.
- 자식이 너무 많은 책임을 진다.
지금 현재 구조는 ViewController안에 View안에 Cell이 있는 구조입니다. UI의 분리목적은 코드의 복잡성을 피하기 위함과 재사용성을 높이기 위함입니다. 하지만, Cell의 Reactor에서 API 로직을 갖는 순간 API 로직의 의존성을 갖게 되므로, Cell을 재사용하기 어려웝니다. 왜냐하면 해당 Cell은 API를 호출하도록 설계되었기 때문에 API 호출을 안하고 단순히 보여주기 위한 용도로 사용하기 어렵습니다.
2. 변경점을 부모에게 알려야 한다.
하트 버튼에 따라서 좋아요 수가 결정되고, 좋아요 수에 따라서 Cell이 재정렬되어야 합니다. 이말은 즉 부모인 View가 Cell이 API 로직이 끝나는 비동기적 시점을 알아야 합니다. 이 자체로 의존 역전이 발생합니다. 자식이 부모를 알아야 한다는 점이 가장 문제입니다.