몇 개월 전에 SwiftUI에 MVVM 적용을 하지 맙시다! 라는 제목의 article을 본 적이 있습니다. 제목을 보고 'MVVM도 만능이 아니군' 이라는 생각이 들었는데, 이번에 관심을 가지고 해당 토픽에 대해 좀 더 알아보게 되었습니다.
왜 SwiftUI에 MVVM이 필요가 없는가?
일단 MVVM은 Model View ViewModel의 약자로 UI를 담당하는 View로직과 데이터를 처리하는 ViewModel을 깔끔하게 나누는 것에 관심을 갖는 패턴입니다. 저도 항상 사용해왔던 패턴입니다. 이 패턴을 사용하던 것에 익숙해지다보니, SwiftUI에서도 자연스럽게 사람들이 사용하고 있었던 것 같습니다.
하지만 사실 SwiftUI의 'view'는 어떤 종류의 타입도 conform 할 수 있는 protocol이라고 합니다.
심지어 Int도 SwiftUI.View를 따르게 할 수 있는 것을 보고 좀 놀랍긴 했습니다. UIKit에서 다루는 view와는 큰 차이가 있었습니다.
제가 본 자료에서 예시를 빌려오자면, 아래처럼 Int 조차도 View를 conform할 수가 있고, 마치 Button, Text 등 'view'처럼 사용하는데 전혀 지장이 없습니다.
extension Int: View {
var body: some View { Text("I am \(self) and I am not a view") }
}
struct PerfectlyFineView: View {
var body: some View { 1 }
}
struct CounterView: View {
@State var count = 1
var body: some View { counter }
}
실제로 SiwftUI.View 는 view에 대해 설명해주는 역할을 하는 것이지 실제 view가 아닙니다. 이런 개념을 ELM architecture에서는 “virtual view”라고 부르는데, 말 그대로 "가상의 view"입니다.
NOTE: ELM architecture는 이는 SwiftUI가 토대로 하고 있는 설계방식이며, ELM 이라는 웹앱용 언어에서 사용하는 패턴입니다.
그래서, View가 실제로 대개 생각하던 view가 아니기 때문에, view와 view model을 나누는 MVVM을 채택할 이유가 없다는 것입니다.
'필요없다' 가 아닌, 오히려 '사용해서는 안되는' 이유?
만일, 기존의 MVVM 방식대로 나누어서 로직을 작성하다보면 오히려 SwiftUI에서 제공하는 property wrapper 사용이 어려워지는 경우들이 있습니다. @AppStorage, @Query, @Environment와 같이 View struct 내에서만 사용 가능한 property wrapper 들이 있습니다. 그런데 이런 wrapper들은 데이터를 다루는 역할을 하다보니, MVVM을 따른다면 view model에서 작성되어야 합니다. 그러나, view model은 View struct를 따르지 않을 테니 사실 사용이 불가능합니다.
결론..
이렇다 보니, SwiftUI와 MVVM 조합은 사실상 무의미 하다는 결론이 나오게 된 것 같습니다.
물론 정말 대단한 분들이 많기 때문에 그 조합으로도 멋진 설계를 해내신 분들도 있을 것이라고 생각합니다.
하지만, 이번 조사를 통해서 사용하는 프레임워크나 언어에 대한 큰 이해 없이 무턱대고 'MVVM이 좋지' 라는 태도로 일관하지는 않았었는지 돌아봐야 한다는 깨우침을 얻게 되었습니다.
논란이 있는 소재이기도하고 저도 어느 정도 설득이 되는 글을 읽었기 때문에 SwiftUI를 사용할 때는 MVVM보다는 clean-architecture를 참고해서 코드를 작성해나가려 합니다. (https://github.com/nalexn/clean-architecture-swiftui)
참고자료
https://medium.com/@redhotbits/from-swiftui-vanilla-to-mvvm-like-a-pro-470b22f304c9
https://nalexn.github.io/clean-architecture-swiftui/
ELM Architecture