MVC와 MVVM으로 이어지던 앱 구조 패턴 연재의 2부로 VIPER를 다룬다. 앞 글에서 남긴 세 가지 질문, 즉 API 호출을 어디서 하고 화면 전환을 어떻게 다루며 중복 코드를 어떻게 막을지에 대한 답으로 VIPER를 놓는다. 티몬이 실제로 라우터 개념만 떼어 적용한 사례가 마지막에 붙는다.
핵심 포인트- VIPER는 View, Interactor, Presenter, Entity, Router 다섯 역할로 나눈다.
- Interactor가 비즈니스 로직과 API 호출을 맡고 그 결과로 모델을 만든다.
- Presenter는 Interactor에 데이터를 요청하고 받은 것을 View에 어떻게 그릴지 지시한다.
- Router는 화면 전환 로직을 전담하며 이것이 모바일에 특화된 지점이다.
- 역할이 늘어 복잡해 보이지만 단일 책임 원칙에 더 충실한 구조가 된다.
- 티몬은 전체 도입 대신 라우터 개념만 가져와 화면 전환 로직을 한 곳으로 모았다.
상세 정리- 앞 글이 남긴 질문: API를 호출할 일이 많은데 어디서 부를지, 화면이 많은데 그냥 호출하면 되는지, 같은 화면을 여러 곳에서 각각 push하면 중복 코드가 쌓이지 않을지였다.
- View의 역할: Presenter가 보여주려는 것을 화면에 그리고 사용자 입력을 Presenter로 넘긴다.
- Interactor의 역할: 비즈니스 로직을 갖고 API에서 데이터를 받아 엔티티를 만든다.
- Presenter의 역할: Interactor에 데이터를 요청해 받고 뷰 로직을 가지며 무엇을 어떻게 그릴지 View에 알린다.
- Entity의 역할: Interactor가 만들어내는 모델이다.
- Router의 역할: 내비게이션 로직을 담당하며 화면에서 화면으로 넘어가는 부분을 처리한다.
- 정리하면: API 관련 코드는 Interactor로, 뷰 로직은 Presenter로, 화면 이동은 Router로 보낸다.
- 프로토콜 구성 팁: 하나의 화면에서 쓰는 프로토콜을 한 곳에 모아두면 보기 편하다고 조언한다.
- 프로토콜 예시: Router에는 모듈 조립과 화면 표시, View에는 표시와 에러 메시지, Presenter에는 진입 시점과 버튼 동작, Interactor에는 입력용 조회와 출력용 성공·실패 콜백을 둔다.
- Router 구현: 스토리보드에서 뷰컨트롤러를 만들고 Presenter와 Interactor, Router 인스턴스를 생성해 서로 참조를 연결한 뒤 완성된 화면을 반환한다.
- 조립의 의미: 각 구성요소의 생성과 연결이 한 자리에 모여 있어 의존 관계가 눈에 보인다.
- View 구현: Presenter를 소유하고 진입 시점과 버튼 이벤트를 그대로 Presenter에 넘기며, 표시 관련 메서드는 확장으로 구현한다.
- Presenter 구현: View는 약한 참조로, Interactor와 Router는 강한 참조로 갖고, 진입 시점에는 조회를 요청하고 버튼 동작에는 화면 전환을 요청한다.
- Presenter의 출력 처리: 조회 실패면 에러 메시지를, 성공이면 받은 데이터를 보관하고 View에 표시를 지시한다.
- Interactor 구현: 네트워크 라이브러리로 API를 호출하고 응답을 모델로 바꿔 출력 쪽으로 넘긴다.
- 구조에 대한 평가: 구성요소가 늘어 복잡해 보일 수 있지만 앞선 두 패턴보다 세분화돼 단일 책임 원칙에 충실하고, 내비게이션 로직이 추가된 점이 모바일에 특화된 부분이다.
- 티몬의 적용: 전체를 도입하는 대신 라우터와 같은 개념으로 내비게이션 로직을 하나로 정리해 쓴다.
- 적용 배경: 추천 탭과 검색 탭, 장바구니, 외부 앱에서 모두 같은 상품 화면으로 들어가는데 각자 뷰컨트롤러를 만들어 push하고 있었다.
- 적용 방식: 라우터 클래스가 상품 식별자만 받아 화면을 만들어 push하도록 하면, 상세 화면이 필요한 어디서든 식별자를 넣어 호출만 하면 된다.
- 얻은 것: 컨트롤러마다 중복 코드가 생기지 않고 로직이 단순해지며 변경이 생겨도 한 곳만 고치면 일괄 적용된다.
- 대조: 그런 계층이 없으면 화면을 여는 모든 뷰컨트롤러에 같은 생성과 push 코드가 반복해서 들어가야 한다.
왜 읽나같은 화면을 여러 진입점에서 열면서 생성과 push 코드가 사방에 복제돼 있다면, 전체 아키텍처를 갈아엎지 않고 라우터 계층만 떼어 쓰는 선택지를 볼 수 있다.