Patterns...
패턴은 개발자들의 경험과 지식으로 만들어진 문제해결 가이드라인과도 같다. 패턴하면 주로 디자인 패턴을 떠올리지만, 아키텍쳐 패턴도 존재한다. 그리고 아키텍쳐 패턴은 프로젝트 전반적으로 적용된다. 아키텍쳐 패턴이 적용되려면 프로젝트에 참여하는 모든 개발자들과 어느정도 합의가 이루어지는 게 좋다.
아키텍쳐 패턴은 처음에 앱을 구성 하는 시점에 최적의 패턴이 적용되는 건 아니다. 분명 각 앱의 성격이나 개발자들의 방식에 따라서 더 잘 어울리는 아키텍쳐가 있을테지만, 개발하다보면 앱의 성격이 바뀌기도 하고 예상과는 다른 요구사항이 들어오기도 하고 새로운 문제가 발생하기도 하며, 개발자들의 구성이 바뀌기도 하기 요구되는 아키텍쳐가 바뀔수도 있다. 또, 새로운 언어가 등장하고 새로운 API가 등장하는 것처럼 아키텍쳐도 새로운 패턴이 등장하기도 한다. 당연한 이야기이지만, 모든 앱과 프로젝트에 완벽하게 들어 맞는 아키텍쳐는 없다. 개발자들은 앱과 팀의 상황, 그리고 당시에 많이 활용되는 아키텍쳐 패턴등을 고려해서 앱의 구조를 잡아간다.
아키텍쳐를 선택하는 것보다 이를 적용함으로써 해결하고 싶은 문제를 이해하는 게 중요하다. 현재 프로젝트의 문제점이나 개선점을 명확히 했을 때, 적용할 수 있는 아키텍쳐와 적용했을 때 효과 또한 분명해지기 때문이다. 개발자들이 아키텍쳐 패턴을 적용함으로써 궁극적으로 얻고자 하는 것이 잊어버려서는 안된다. 아키텍쳐 패턴을 도입해서 우리는 팀의 개발 속도를 높이고, 코드 퀄리티를 높일 수 있다. 좀 더 세부적으로 보자면, 코드 재사용성을 높이거나, Unit Test하기 어려운 구조라던가 컴파일 속도가 앱의 실행 속도가 느린 경우 아키텍쳐 개선을 생각해볼 수 있다.
iOS 프로젝트에서 코드 안정성을 높이고 싶다고 해보자. 가장 먼저 생각해 볼 수 있는 방법이 바로 Unit Test를 작성이다. 그런데 Unit Test를 작성하기에는 코드 구조가 적절하지 않다면, 이 문제 부터 해결해야 한다. 이럴 때 아키텍쳐 개선을 고려해볼 수 있다. 모바일에서는 가장 널리 알려진 MVVM과 Clean Architecture 이다. Clean Architecture는 무엇이고, MVVM 개념과 함께 iOS에 적용하는 방식은 어떤지 알아보고, 이 아키텍쳐를 적용했을 때의 장점을 살펴보도록 하자.
The Clean Architecture
Robert C. Martine의 블로그에서 가져온 Clean Architecture 그림이다. Clean Architecture는 계층 구조를 원형으로 표현하고 있다. 다른 아키텍쳐쳐들과는 달라보이는 모습에 보다 어려울 것 같은 느낌이 들지만, 실제로는 그렇지 않다. 원의 한쪽 단면만 잘라놓고 보면 다른 아키텍쳐와 동일하게 위-아래로 계층이 나뉜다.
Clean Architecture가 나오기 전까지 이런 저런 Architecture들이 발표 됐다. 자세히 알고 싶다면, 아래 더보기를 눌러서 확인해볼 수 있다.
- Hexagonal Architecture (a.k.a. Ports and Adapters) by Alistair Cockburn and adopted by Steve Freeman, and Nat Pryce in their wonderful book Growing Object Oriented Software
- Onion Architecture by Jeffrey Palermo
- Screaming Architecture from a blog of mine last year
- DCI from James Coplien, and Trygve Reenskaug.
- BCE by Ivar Jacobson from his book Object Oriented Software Engineering: A Use-Case Driven Approach
이 Architecture들이 원하는 건 결국 계층을 구별하고, 계층간 dependency를 끊는 것이었다. 이들을 모두 한 그림으로 표현했더니 원모양으로 표현 되었고, 안쪽 원과 바깥쪽 원 간의 dependency를 관리하도록 정의했다. 이렇게 원모양의 Clean Architecture가 나오게 되었다.
Clean Architecture에서 가장 중요한 건 The Dependency Rule이다. 소스 코드의 의존도(dependency)는 원의 안쪽으로만 향해야 한다는 규칙이다. 내부 원은 외부 원의 정보(data, object, token 등)를 어떤 것도 사용 할 수 없다. 안쪽 원은 바깥 쪽 원에 어떤 영향도 줘서는 안된다. 그래야 쌍방이 서로 참조하거나, 순환 참조하는 경우가 발생하지 않는다.
Clean Architecture에서 표현하는 계층은 원 안쪽으로 갈 수록 정책(policy)적인 성격이 강하고, 바깥 쪽으로 갈수록 원리(machenisms) 성격이 강한 계층(layer)이다. 각 Layer 별 상세한 역할은 Robert C. Martine의 블로그를 읽어보길 바란다.
MVVM in iOS
MVVM
MVVM은 기존 MVC의 문제를 해결하면서 나온 구조이다. View / View Model / Model 의 3개 계층(Layer)를 갖는다. MVVM은 Business Logic과 View를 분리함으로써 View의 구성을 다른 코드에 영향을 주지 않고 바꿀 수 있도록 하는 것이 목적이다. View와 Data간의 분리를 위해 View Model Layer를 사용하고, View Model Layer에서는 View의 상태를 관리하도록 한다. 또한 View Model은 View 와 분리되어 작성된 로직으로 테스트 코드를 작성하기에도 용이하다.
Repository Pattern
Repository Pattern은 서버를 호출하거나 디스크에 접근하는 등의 작업을 하는 데이터 객체에 접근하는 Repository를 데이터가 통하는 입출구로 사용한다. Repository에서 CRUD 메소드를 수행하고, 상황에 따라 stateless 혹은 stateful로 구현할 수 있다.
Repository와 MVVM이 합쳐지면, View Model이 Repository를 사용한다. View Model에서 수행하던 API 호출이나, DB 혹은 캐시에 접근해서 데이터를 가져오는 로직은 모두 Repository가 대신하게 된다. 그리고 View Model은 데이터를 가져오는 방식이나 세부사항은 모른 채, 데이터를 가져와서 화면에 노출될 형태로 가공하는데만 집중하게 된다.
Clean Architecture + MVVM
이제부터 Repository 패턴이 합쳐진 MVVM 패턴을 Clean Architecture에 적용 시켜 보는 내용이다. Clean Architecture에서 가장 중요한 규칙은 바로 안쪽 레이어가 바깥쪽 레이어에 의존도를 가져서는 안된다는 것(Dependency rule)이다. 바깥에서 안쪽으로만 의존도를 가질 수 있다. 이 규칙은 유념한 채, Clean Architecture 다이어그램에서 View-View Model이 작업이 이루어지는 부분과 Repository 패턴이 적용되는 부분을 표시한 그림이 아래 다이어 그램이다.(ref)
Domain Layer는 Use case와 Entity를 포함한다. 즉, 모델과 business logic을 가지고 있다. MVVM Layer 와 Data Layer는 Domain Layer 바깥 영역에 존재 한다. Clean Architecture의 Dependency Rule에 따라 구분된 Layer간의 dependency를 표현하면 아래와 같다.
iOS에서 Clean Architecture에 MVVM을 얹었더니, 역할에 따라 Presentation, Domain, Data 레이어로 그루핑 되었다. 각 Layer의 역할을 정의해보자.
Domain Layer는 Business logic이 존재하는 Layer이다. 가장 안쪽에 존재하는 영역이다. 다른 레이어와 의존도가 전혀 존재하지 않는다. (3-rd party 의존도도 없다.) Entity(Business Models), Use cases, Repository Interface가 이 영역에 포함된다. 이 영역은 다른 프로젝트에서 재사용 될 수 있어야 한다. (Use case를 중심인 아키텍쳐가 좋은 이유에 대해 알고 싶다면 : Screaming Architecture)
Presentation Layer는 UI(UIViewController or SwiftUI Views)를 가지고 있다. View는 ViewModel(Presenter)에 따라 ViewModel은 Use Case를 실행해서 결과를 가져온다.
Data Layer 는 Repository를 구현하고, 하나 이상의 Data Source 를 가진다. Repository는 서로 다른 Data source간의 데이터 전환을 담당한다. Data Source는 Remote(JSON Data..)나 Local(DB 같은..)이 될 수 있다. 예를 들어 Network JSON data를 Domain Model로 매핑 시키는 일을 한다.
아래는 Dependency 방향(빨간색)과 Data flow(주황색)를 한번에 그려 놓은 그래프이다. Domain layer에서 사용자 데이터와 Repository 데이터를 합쳐러 처리하고 그 결과를 다시 View로 돌려보내거나, Repository를 통해 데이터를 변경하는 로직을 작성한다(보라색).
Wrap up
지금까지 Clean Architecture와 MVVM에 대한 개념을 살펴보고 이를 iOS에 적용해 놓은 Architecture를 함께 살펴 봤다. Clean Architecture에서는 Dependency rule이 가장 중요햇다. 즉, 원 안쪽으로만 의존도를 가지게 해야 한다. 여기에 MVVM, 그것도 Repository가 낀 MVVM을 얹는다. Repository는 View Model에서 사용하는 데이터(DB, API, Cache 등으로 부터...)를 가져오는 출입구이다. Presentation, Data, Domain Layer로 그루핑이 되고, "Presentation(MVVM)->Domain(Use case)<-Data(Repository)" 화살표 방향과 같이 dependency를 가지게 된다. 사용자 인풋과 데이터를 처리하는 Business logic은 Use Case에 작성된다.
이 글을 작성하면서 이 구조에 참 많은 개념이 녹아 있다고 느꼈다. 단순히 Clean Architecture만 적용하기에는 iOS에서 사용하는 구조상 한계가 있어서 일까, 아니면 더 효과적이어서 일까. 아직 이를 가늠할 정도로 생각이 발전하진 못했지만, 사용하다 보면 조금 더 이해 되는 부분이 있지 않을까 싶다.
맨 처음에 이야기 했듯이 어떤 아키텍쳐 패턴을 쓰는지는 중요하지 않다. "어떤 문제를 해결하고 싶은가"가 중요하다. 프로젝트를 아키텍쳐의 그래프 그대로 끼워 맞추는 것 자체가 목적이 되어서는 안될 것이다. 그런 관점에서 봤을 때, Test Case 작성이 용이하지 않고, Massive VC 문제가 혼재하는 프로젝트라면 적용해볼만한 방법인 것 같다.
Reference
https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
https://github.com/kudoleh/iOS-Clean-Architecture-MVVM
https://tech.olx.com/clean-architecture-and-mvvm-on-ios-c9d167d9f5b3
https://www.raywenderlich.com/books/advanced-ios-app-architecture/v4.0
'개발 Story' 카테고리의 다른 글
개발자가 CI 시스템을 알아야 하는 이유. (0) | 2023.02.07 |
---|---|
M1 issue - Homebrew 설치 에러. (command not found: brew) (0) | 2022.05.07 |
SOLID 원칙. 리팩토링 할 때 알아두면 좋은 개념. (0) | 2022.05.04 |
iPad 기능. 어떤 걸 개발 해볼까. (0) | 2022.05.01 |
Realm m1 issue. Could not find module 'RealmSwift' for target 'arm64-apple-ios-simulator'; found: i386, x86_64-apple-ios-simulator, x86_64, i386-apple-ios- simulator, at:`path` (0) | 2022.04.15 |