더 좋고 꾸준하게 유지보수하기 위해서는 프로그램을 구현하기 전에 적절한 아키텍처를 선정하는 것이 필요하다는 것을 알게되고 iOS 개발에 있어서 몇 가지 아키텍처 패턴에 대해 공부하려고 합니다.
!! 이 글은 아래 글을 참고해 정리했습니다.(
https://medium.com/ios-os-x-development/ios-architecture-patterns-ecba4c38de52)
아키텍처 패턴이란?
간단하게 프로그램의 구조라고 생각한다. 위키에서는 소프트웨어 내에서의 공통적인 발생 문제들을 해결하기 위한 일반적인 해결 방법이라고 설명하고 있다.
왜 필요한가?
프로그램은 제대로 작성만 된다면 실행이 가능하다. 하지만 이런 프로그램들은 유지보수에 굉장히 많은 비용이 들어가며 실력있는 개발자가 보기에는 가독성이 떨어진다고 볼 수 있다.
좋은 아키텍처는 무엇인가?
균형잡힌 분배 (Balanced Distribution)
테스트 가능 (Testablity)
사용하기 쉬운지 (Easy of Use)
단방향성 데이터 흐름 (Unidirectional Data Flow)
4가지 조건을 충족시키는 완변한 아키텍처는 존재하지 않는다. 그러니깐 자신의 프로젝트 성격에 맞춰서 적절한 아키텍처 도입이 필요하다.
iOS에서는 4가지 조건 중 균형잡힌 분배를 위해서 크게 3가지로 나누어 코딩이 진행된다.
그래서 iOS에서 가장 많이 사용되는 아키텍처 패턴이 MVC, MVP, MVVM가 있으며 하나씩 살펴보려고 한다.
가장 유명하며 처음 접하는 개발자들이 자연스럽게 사용하는 아키텍처이다. MVC 아키텍처는 전통적으로 사용하던 방식과 애플에서 제시한 방식으로 나누어 진다. 여기서는 애플이 제시한 MVC 방식을 보려고 한다.
애플이 제시한 MVC 방식은 Cocoa MVC 라고 불린다. Controller는 View와 Model의 중재자로 View와 Model의 직접적인 연결을 막는다. 이 점이 전통적인 방식보다 높은 독립성의 보장을 기대하고 있다.
위 그림을 보면 View와 Model 사이에는 관계가 없어 마치 독립성이 보장되는 것 처럼 보일 수도 있다. 하지만, 실제는 그림과는 많이 다르다고 한다.
실제 Cocoa MVC 아키텍처에서 Controller의 역할은 UIViewController
가 담당한다. 그리고 UIViewController
는 View를 소유하며 View들의 생명주기와 강하게 연결된다. 이 말은 View와 Controller의 분리가 쉽지 않고 Controller의 재사용이 어려워지며 마찬가지로 연관되어 있는 View의 재사용도 어려워진다.
View와 Controller의 분리가 쉽지않고 강하게 연결되어 있으면 테스트 과정도 힘들다. 결국엔 독립적인 부분은 Model뿐이다.
View에서의 사용자의 액션과 메소드, UIViewController
에서 발생하는 액션들로 (Delegation, 통신 등) Controller의 크기는 점점 커지고 이를 Massive ViewController 라고 부른다.
실제의 Cocoa MVC 형태를 그림으로 보면 다음과 같다.
커진 UIViewController
를 줄이는 행위인, View Controller Offloading은 iOS 개발자들에게 중요한 과제가 됬다.
import UIKit
// Model
struct Person{
let firstName: String
let lastName: String
}
// View + Controller
class GreetingViewController: UIViewController{
var person: Person!
var showGreetingButton: UIButton = {
let button = UIButton()
button.setTitle("Click", for: .normal)
button.addTarget(self, action: #selector(didTapButton(sender:)), for: .touchUpInside)
return button
}()
var greetingLabel: UILabel = {
let label = UILabel()
label.textColor = UIColor.black
return label
}()
override func viewDidLoad(){
super.viewDidLoad()
self.view.addSubview(showGreetingButton)
self.view.addSubview(greetingLabel)
}
@objc func didTapButton(sender: UIButton){
let greeting = "Hi" + " " + self.person.firstName + " " + self.person.lastName
self.greetingLabel.text = greeting
}
}
let model = Person(firstName: "Kim", lastName: "JangGu")
let vc = GreetingViewController()
vc.person = model
위 코드에서 View에 해당하는 showGreetingButton
, greetingLabel
이 Controller 안에 위치하고 이들의 액션인 didTapButton
또한 Controller 안에 위치한다.
그럼, MVC 아키텍처는 언급했던 아키텍처의 기준에 얼마나 부합할까?
아키텍처를 잘 모를 때 사용하기 쉬운 패턴이지만 작은 프로젝트여도 많은 유지보수 비용이 들어간다.