brunch

You can make anything
by writing

C.S.Lewis

by 웅쓰 Nov 25. 2021

iOS Coordinator Pattern 고전읽기

2021년 11월, iOS 개발자 이야기 feat. woongs

안녕하세요! 위드코로나에 갑자기 추워진 날씨, 수능 등등 휴일만 없고 꽤나 많은 일들이 있었던 11월이 거의 다 지났습니다. 얼마전 저희 파트에 새로오신 에버(짝짝짝)가 Coordinator 패턴으로 라이트닝 토크를 해주셨었는데요, 거기에 자극을 받아 오늘은 iOS Coordinator 패턴을 처음 제안해주셨던 고전(?)에 대해 정리해보는 시간을 가져보려고 합니다.






현재 브런치 코드에도 Coordinator 가 있기는 하지만 좀 더 개선해야 할 부분들이 보여서 조만간 적극적으로 도입해보기로 했는데요, 오늘은 그에 앞서 Coordinator 패턴을 처음 고안하셨던 khanlou 님의 글을 요약 및 정리해보도록 하겠습니다. 오역이나 잘못 이해한 부분이 있을 수 있으니 정확하 내용은 원문 참고해주시고 수정 사항이나 추가 의견은 댓글로 남겨주시면 감사하겠습니다!


원문의 전체적인 흐름은 이렇습니다.

1. 무엇이 문제인가 - Three Problems

2. 그럼 어떻게 하는 게 좋은가 - Libraries vs Frameworks

3. 그래서 만들었다 코디네이터! - What is a coordinator?

4. 코디네이터의 장점 - Why are coordinators great?

저도 이 흐름에 따라 원문의 타이틀은 가져가고 그 안에서 정리해보려고 합니다.



Three Problems

애플이 기본적으로 제시하는 가이드(MVC 이 되겠죠?) 에 크게 3가지 문제가 있다고 주장하고 있습니다.

(여기서부터 잠시 음슴체로 가겠습니다)


1. overstuffed App Delegates


앱 딜리게이트는 앱의 시작점이고 os와 앱 하위 시스템 사이에서 메시지를 전달해야 하기 때문에

책임을 과도하게 떠넘기기 쉬운 형태가 문제!


특히 루트로 탭 바 컨트롤러가 있을 때 하위 탭 바를 구성하는 부분을 앱 딜리게이트에서 하기 쉬움.

이를 숨기기 위해 커스텀 탭 바 컨트롤러 같은 걸 만들 수 있지만 이는 임시방편일 뿐.


We’re subclassing a thing that was never intended to subclassed, just so we can hide away some code that doesn’t have a home.


탭바를 구성하는 얼마 안 되는 코드를 위해 탭바 컨트롤러를 서브 클래싱 하는 건 의도에 맞지 않음!

갈 곳 없는 코드들을 숨기기 위해 서브클래싱 하지 말자...!



2. Too Many Responsibilities


앱 딜리게이트와 마찬가지로 뷰컨도 많은 책임을 떠 안기 쉽다.


1. Model-View Binding

2. Subview Allocation

3. Data Fetching

4. Layout

5. Data Transformation

6. Navigation Flow

7. User Input

8. Model Mutation

9. and many more besides


뷰컨이 이러한 책임들을 다 가지고 있으면 소위 말하는 Massive ViewController가 되기 십상!

이러한 책임을 없애기 위한 방법들은 8 Patterns to Help You Destroy Massive View Controller 여기서 더 확인할 수 있음.

아무튼 뷰컨에게 많은 책임을 떠넘기지 말자!



3. Smooth Flow


navigation flow 또한 문제.


(원문은 objective-c 지만 간단하게 swift로 살펴보겠습니다.)

위 코드는 흔히 볼 수 있는 코드지만 문제가 되는 부분을 좀 더 살펴보면,


(1)

여기가 앱이 복잡해지기 시작하는 부분. 뷰컨이 다음 뷰컨을 인스터화하고 구성하고 있음.

뷰컨이 다음에 나타날 뷰컨을 알고 있고, 어떻게 구성되어야 하는지까지 아는 건

뷰컨에게 너무 과한 정보.


(2)

궤도를 완전히 이탈하는 부분! 뷰컨은 상위 뷰컨을 알고 있을 뿐만 아니라 어떻게 하라고 지시까지 내리고 있음.

프로그래밍에서는 "자식이 부모가 누구인지 조차 모르게 해야한다." 라고 주장할거다! 라고 함.


이때 위에 소개한 8 Patterns to Help You Destroy Massive View Controller 에서
Navigator 를 주입시켜 주는 형태를 제안했고 한 곳에서 사용할 때는 좋은 해결책이 될 수 있지만,

여기도 문제가 있음.


가령, 사진을 저장할 때 아래와 같은 흐름으로 진행 된다고 생각해보면

사진 선택 -> 편집 -> 필터 -> 캡션 --> 종료

Navigator를 넘겨주는 방식으로는 각 뷰컨이 너무 강하게 결합되어서

사진 선택을 종료하는 부분은 멀---리 떨어진 캡션에서 이루어지게 됨.



Libraries vs Framworks


그럼 어떻게 해야하나!

저자의 강의 슬라이드에서 인용: https://www.slideshare.net/secret/3jJlEE1weo0RRl


최대한 Frameworks 말고 Libraries 처럼 사용하자!

UIKit을 사용하면 pushViewController(_: animated:) 같은 메소드를 호출해야 하고

또 다음 뷰컨의 viewDidLoad()에서 많은 작업을 해야함.


UIKit을 제거해서 UIKit이 코드를 통제하도록 두지 말고 코드 전체를 내가 통제하도록 하자.

뷰가 뷰컨에 완전히 종속되듯 뷰컨도 그런 관점으로 보면 어떨까? 궁금.


Coordinators


What is a coordinator?


코디네이터는 뷰컨의 이동 로직을 담당하는 객체.

뷰컨의 이동에 관한 모든 로직을 한 층 위로 올리는 건 삶을 윤택하게 해줄 것임.


이제 모든 건 app coordinator에서 시작한다.

→ overstuffed App Delegates 문제를 해결

→ 앱의 주요 화면 설정

→ 이런 걸 Application Controller라 부르고

    이러한 패턴은 Patterns of Enterprise Application Architecture 여기서 확인할 수 있음

→ AppCoordinator는 iOS에 특화된 버전

    뷰컨을 만들고 구성하거나 하위 코디네이터들을 생성


코디네이터는 뷰컨으로부터 navigation and model mutation 의 책임을 가져와야 함.

(model mutation은 디비를 바꾸거나 PUT, POST 요청 같이 사용자 데이터를 바꿀 수 있는 부분을 의미함)


이러한 부분을 뷰컨에서 제거할 때 뷰컨을 비활성화(inert) 상태로 만들 수 있음.

뷰컨은 보여지고, 데이터를 패치하고, 보여질 특정 형태로 가공할 수는 있지만, 직접 바꿀 수는 없음.

이벤트나 사용자 입력은 delegate에게 위임.



Code Example


- App Delegate

(1) 코디네이터 초기화와 시작을 분리! 원하는 타이밍에 시작 가능.


- 코디네이터는 UIKit을 사용하지 않고 그저 NSObject 라서 심플함.

매우 폐쇄적인 UIViewController로 부터 자유선언.


- 필요한 데이터로 초기화, root 뷰컨도 포함


- start 메소드를 사용해 시작 타이밍 결정


(원문에서는 예제가 더 있지만 여기선 생략하겠습니다)

정리하면, 생성과 시작을 분리해서 원하는 타이밍에 시작할 수 있고, 시작부터 코디네이터가 의사결정을 하고 있음.

그리고 코디네이터는 childCoordinators를 가질 수 있어서 뷰를 트리 구조로 계층화 시킴.

사용지 인풋은 딜리게이트로 상위 계층에 넘겨서 위에서 결정하도록 함.



Why are coordinators great?


결론적으로 이런 것들이 좋다!


1. Each view controller is now isolated.

뷰컨은 데이터를 표시하는 법 외에는 아무것도 모른다.

2. View controllers are now reusable.

따라서 재사용하기 용이하다.

3. Every task and sub-task in your app now has a dedicated way of being encapsulated.

이제 모든 작업과 하위 작업을 캡슐화 시킬 수 있다. 가령 iPad에서 하위 작업 중 일부만 재사용 하는 경우도 매우 쉽게 처리가능.

4. Coordinators separate display-binding from side effects.

뷰 컨트롤러가 model mutation 하지 때문에 사이드 이펙트 걱정없이 사용할 수 있다.

command-query separation 이 컨셉과 유사함.

5. Coordinators are objects fully in your control.

더 이상 viewDidLoad 를 기다리지 않고 코드를 완전히 통제할 수 있다.

UIKit은 원할 때 호출하는 Library



의역과 오역이 많이 포함되어 있을 수 있으므로
정확한 내용은 원문을 참고해주세요!
https://khanlou.com/2015/10/coordinators-redux/







아무래도 위 글은 2015년도에 쓰여졌기 때문에 시간이 꽤나 흘렀죠. 요즘은 MVC 말고도 다양한 형태의 아키텍처들이 많이 보이는 것 같고, 코디디네이터에 대해서도 다양한 의견들이 많이 나온걸로 아는데요. 혹 내용들이 100% 공감되지 않더라도, 저자가 주장하신 본질은 여전히 중요하고 많은 인사이트를 주는 글이었던 것 같습니다. 많이 배운 것 같네요 :)


곧 브런치 코드도 더 개선된 모습으로 만날 수 있겠죠? 벌써부터 기대가 되네요!

나중에 여기서 더 발전된 이야기를 들려드릴 수 있으면 좋겠어요.


iOS 개발자가 한 분 더 오셨지만

여전히 글이 작품이 되는 공간을 함께 만들어 갈 여러분을 기다리고 있습니다.

(빨리 오세요)


.

.

.


우리는 채용 중


https://careers.kakao.com/jobs/P-12253




# 참고자료 && 함께 보면 좋을 자료

- https://khanlou.com/2015/10/coordinators-redux/

- https://www.slideshare.net/secret/3jJlEE1weo0RRl

- https://khanlou.com/2015/01/the-coordinator/

- https://khanlou.com/2014/09/8-patterns-to-help-you-destroy-massive-view-controller/

- https://khanlou.com/2014/03/model-view-whatever/

- https://khanlou.com/2014/11/a-controller-by-any-other-name/


 

읽어주셔서 감사합니다.

브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari