seong_hye, the developer

Design) MVVM으로 넘어가는 이유가 뭘까?( vs MVC) 본문

IOS

Design) MVVM으로 넘어가는 이유가 뭘까?( vs MVC)

seong_hye 2024. 1. 21.

 

우선 왜 코드를 나눠서 설계하려고  할까?

여러명이서 하나의 거대한 앱을 만들게 됨(수만줄의 코드)

-> 기준이나 룰에 따라 나누지 않으면 보기 힘듦

-> 유지보수가 편해야하기 때문에 코드를 계층으로 분리하려함


아키텍처란?

하나의 서비스가 어떻게 구성이 되며 어떻게 동작이 되는지 

서비스의 동작 원리를 나타내는 것

 

 좋은 아키텍처의 특징들

단단하고/안정적, 모듈화 가능(재사용), 확장 용이(향후 확장성)

테스트 가능(UI 비즈니스 로직에서 강력/안정적), Decoupling (느슨한 결합) ..

 

올바른 아키텍처 선택의 기준

- 유지보수 용이해야 한다.

- 명확한 분리 기준: 단일 책임 원칙

- 테스트 가능: TDD(테스트 주도 개발) / 유닛테스트 가능해야 ( 안전한 코드 작성 가능)

 

벽한 / 절대적인 아키텍처는 없다

앱의 규모와 앱을 운영하는 환경에 맞는 선택을 해야.. (정답이 없다)


 

코드를 작성하다보면 한 개체가 다른 개체에 의존성을 가지게 됨

ex) 다른 개체에서 하나를 바꾸면 다 바꿔야하는 문제 발생

의존성이 생기는 코드는 좋지 못한 코드임

확장성 있게 바꿀 필요가 있음

class Dog {
	var type = "dog"
}

class Wolf {
	var wolf: Dog = Dog()	// 푸들 클래스가 개 클래스에 의존하게 됨
    
    print(wolf.type)		// "dog"
}

~> 의존성 주입을 통해 개선 가능


의존성은 무엇일까?

서로 다른 객체 사이에 의존 관계가 있다는 것

주입이 무엇일까?

외부에서 객체 또는 데이터를 생성자를 통해 생성해서 넣는 것

생성 시 값을 할당하며 언제든지 교체 가능해져, 확장성이 늘어남

class Person {
	var name: String
    
    init(name:String) {
    	self.name = name
    }
}

let person = Person(name: "seonghye") //밖에서 파라미터를 통해 값을 주입

 

의존성 주입

프로그램 디자인이 결합도를 느슨하게 되도록하고

의존관계 역전 원칙단일 책임 원칙에 따르도록

클라이언트 생성에 대한 의존성을 클라이언트의 행위로 부터 분리하는 것

=> 개선된 의존성을 외부에서 주입할 수 있는 방식 [프로토콜 활용]

protocol Animal {
	var type: String {get set}
}

class Dog {
	var type = "dog"
}

class Wolf {
	var wolf: Animal
    
    init(wolf: Animal) {
    	self.wolf = wolf
    }
	
    func printType() {
    	print(wolf.type)
    }
}

 

의존성 주입을 사용하는 이유가 뭘까?

- 객체 간의 의존성을 줄여서 코드의 재활용성 / 확장성이 높아짐

- 객체 간의 결합도가 낮아져 유연한 코드 / 유연한 프로그램을 작성 가능

- 유지 보수 쉬워짐


그 중 대표적인 아키텍처 패턴들을 알아보자

 

MVC (Model - View - Controller)

단순하게 각자의 역할과 책임을 나누는 것이 목적

Controller가 Model과 View에 어렵지 않게 접근할 수 있다.

Controller에 속한 subView에 직접 접근해 설정을 변경할 수도 있고,

생성된 Model 객체를 받아왔다면 그 객체에 직접 접근해 데이터를 활용할 수도 있다.

1) 사용자의 상호작용이 Controller로 들어옴

2) 모델(데이터)를 변화시킴

3) 바뀐 결과를 받아옴

4) 받아온 결과를 가지고 다시 표시시킴(뷰에 다시 그림)

Model - Controller

계층은 분리되어 있을지라도 실질적으로 뷰컨트롤러 내부에 위치하는 형태

이론적으로는 따로 존재하지만 실제로는 내부에 같이 존재

Model에서 Controller로 뭔가 전달해야 하는 경우는 데이터가 변화했다는 사실을 알려주는 정도

애초에 Model 쪽에 있는 코드는 데이터를 제공하는 코드이기에 Controller의 구조를 몰라 직접 접근 불가능

Controller는 Model에 있는 프로퍼티에 Key-Value Observing을 이용해

그 프로퍼티의 변화를 감지할 수 있고, 그에 따라 새로운 데이터를 받아올 수 있음

혹은 Notification을 이용해 뭔가 변화했다는 신호를 보내두면,

나중에 Controller가 그 알림을 보고 다시 Model에 접근해 새 데이터를 받아올 수 있음


Controller - View

코드로 UI 작성시에 일반적으로 View를 따로 분리하지 않고 뷰 컨트롤러 내부에 작성하는 경우도 많음

View에서 Controller로 뭔가 전달해야 하는 때에는 대부분 유저와의 상호작용에 대해 전달하는 경우로

주로 Delegation 방식을 이용해 Controller에 관련 코드를 작성함

Delegate는 위임한다는 뜻을 가지고 있으로 View에 어떤 이벤트가 발생하면

그 이벤트의 처리는 delegate로 연결해둔 Controller에게 위임하는 것

ex) imageView.delegate = self

View의 delegate를 ViewController로 설정

 

==> View가 Controller에, Model이 Controller에 직접 접근할 수 없으므로

결국 Controller가 그 역할을 도맡아 하고 있다.

말그대로 Controller가 Model과 View가 해야할 일을 ‘위임’받아 하고 있는 느낌이다.

결국 Controller 안에 대부분 존재하게 됨

Controller가 비대하지고 역할이 너무 커짐

 

MVC의 장점?

개발 용이함 (이해가 쉬움)

개발 속도가 빠를 수 있음

Apple에서는 아키텍처로 MVC 패턴을 권장


MVVM (Model - View - ViewModel)

로직을 소유한 뷰모델의 도입

 

뷰모델?

뷰를 위한 데이터를 가진 모델

뷰와 모델 사이에 하나의 계층이 추가된 형태

모델이 가지고 있는 데이터를 가지고 완벽하게 뷰를 위한

데이터의 형태와 뷰를 위한 로직

1) 사용자의 상호작용이 view에 전달됨

2) 그 내용을 viewModel에 전달

3) 관련 데이터를 변화시킴

4) 바뀐 결과를 받아옴

5) 받아온 결과를 가지고 다시 표시 시킬 수 있도록 전달

(뷰를 다시 그릴 수 있도록 전달)

 

Model

데이터를 다루는 공간

데이터를 파싱하기 위해 필요한 데이터 구조를 정의함

초기값과 비즈니스 로직을 관리함

View, ViewModel 계층을 전혀 신경쓰지 않아도 됨 

View

앱의 UI에 대한 코드와 생명주기 코드를 담고 있는 계층이다.

MVC의 ViewController + View를 합친 형태

MVVM 패턴에서는 Model을 직접 소유하지 않아야 함

ViewModel로부터 받아와서 View에 정보를 집어넣어주는 방식이 일반적

 

ViewModel

Model이  얻어온 데이터를 View에 맞게 가공,처리하는 역할

Model이 변경되면 View에게 notification을 보내주는 역할을 함

또한, View로부터 전달받는 요청을 해결할 비즈니스 로직들을 담고 있음

ViewModel은 UI 관련 코드로부터 완전히 분리되어있고,

따라서 ViewModel 파일에는 SwiftUI같은 UI 프레임워크를 import할 이유조차 없음

 

MVVM의 장점?

복잡성이 감소함 -> ViewControlle의 비대해짐 해소

비즈니스 로직이 더 잘 표현됨

비즈니스 로직과 뷰의 분리가 가능( 테스트 코드 작성 가능)

바인딩까지 활용한다면 데이터가 변했을 때 뷰가 자동으로 갱신되는 것까지도 쉽게 구현 가능


 

iOS가 MVC에서 MVVM으로 넘어가는 이유?

기존에 많이 사용한 프레임워크인 UIKit은 MVC 패턴을 기반으로 만들어졌다.

최근 발전중인 SwiftUI는 MVVM 패턴을 기반으로 발전하고 있다.

이론 상으로는 Controller 계층과 ViewModel 계층이 맡은 역할이 크게 다르지 않아 보이는데,

iOS 개발에서는 MVC와 MVVM이 어떤 큰 차이를 가지고 있을까?

우선 UIKit에서는 ViewController가, SwiftUI에서는 View가 사용자와 가깝다는 점이 다르다.

UIKit의 MVC에서는 ViewController가 거의 모든 역할을 하고 있었지만

 

SwiftUI의 MVVM에서는 각 View가 필요한 비즈니스 로직(ViewModel)들을 가져와 사용하는 구조다.

따라서 View와 Model을 모두 알고 있었어야 하는 Controller와 달리,

ViewModel은 View에 대해서는 알고 있을 필요가 없다.

 

또한, UIKit의 ViewController는 온전히 Controller 역할만을 하지 못하고 있었다.

ViewController는 Model과 View가 해야할 일을 가지고 있어 계층을 제대로 분리하지 못하고 있다.

하지만 ViewModel은 비즈니스 로직만 가지고 있도록 깔끔하게 분리된 계층이기 때문에,

ViewController만큼 복잡해지지 않다.

View 입장에서는 필요한 비즈니스 로직을 담은 ViewModel을,

해당 화면의 니즈에 따라 골라서 사용하기만 하면 되는 입장이 된다.

이렇게 각 계층이 더욱 모듈화되면 테스트가 보다 용이해진다.

또한 바인딩까지 활용한다면 데이터가 변했을 때 뷰가 자동으로 갱신되는 것까지도 쉽게 구현 가능하다.

 

MVVM도 당연히 완벽한 디자인 패턴은 아니다.

SwiftUI를 반응형으로 설계한 만큼 MVC보다는 MVVM을 채택해 구조적인 이득을 챙겨오기 위한 것으로 보인다.


참고자료)

https://linsaeng.tistory.com/35

https://www.inflearn.com/course/%EC%8A%A4%EC%9C%84%ED%94%84%ED%8A%B8-%EB%AC%B8%EB%B2%95-%EB%A7%88%EC%8A%A4%ED%84%B0-%EC%8A%A4%EC%BF%A8-%EC%95%B1%EB%A7%8C%EB%93%A4%EA%B8%B0/dashboard

https://medium.com/hcleedev/ios-%EA%B0%9C%EB%B0%9C-mvc-%ED%8C%A8%ED%84%B4%EA%B3%BC-uikit%EC%9D%98-viewcontroller-3fdb52f6b4b8

'IOS' 카테고리의 다른 글

iOS) 클래스(Class) vs 구조체(Struct) 제대로 알아보기  (0) 2024.03.27
iOS) SwiftLint는 무엇일까?  (0) 2024.03.17
8/23 프로젝트 회고  (0) 2023.08.24
swift 내용 정리  (0) 2022.12.13
동기 비동기 차이에 대하여  (0) 2022.11.10
Comments