우선 MVVM 의 설계 철학은 정말 마음에 든다. MVVM 을 완벽하게 구현한다면 이론상 Designer 와 Developer 의 작업을 완벽하게 분리할 수 있으며(물론 Github, StackOverFlow 등에서는 사실상 이것이 불가능하다는 의견도 있다.), View 와 종속적이지 않게 비지니스 로직을 검증할 수 있다. 결론적으로 '유지보수성' 이 매우 높아지는 효과를 가져온다.
고전적인 Code-Behind 방식 (일반적으로 Winform, WPF 를 통해 코드를 작동시킬 때 View 영역에 `Button_Click()` 메소드를 생성하는 방식)이 비록 생산성은 MVVM 방식보다 월등히 높지만, 유지보수성에서는 MVVM 우위에 있다. 때문에 장기적으로 관리되어야 할 프로젝트라면 MVVM이 권장된다.
이하 MVVM에 관한 개요적인 내용은 MSDN 에서 확인하길 바란다.
그렇다고 MVVM 이 장점만 있다면 대부분의 기업에서 MVVM 방식으로 코드를 작성해야 할 테지만, 최소한 내가 아는 한국 기업들중 MVVM 방식으로 코드를 작성하는 기업은 매우 소수라고 생각한다 (C#기준)
이유는 Code-Behind 방식 대비 생산성이 크게 열세인 점과, '학습의 어려움' 이라는 두가지 난관이 존재하기 때문이다.
일반적으로 MVVM 방식은 인터페이스를 상속후 이를 구현한뒤, WPF 기준 `DataContext` 를 연결해서 View 와 ViewModel 을 연결하는데, 뭐 변수 연결할 때 인터페이스 구현해야되고... Command 연결할 때 인터페이스 구현 후 실질적으로 구동될 함수를 Binding 해야되고... 여간 귀찮은게 아니다!
그래서 MS 에서 이를 인지하고 만든게 바로 .NET Community Toolkit 이다. (+ 사제 라이브러리로 ReactiveUI 등이 있다.)
이 라이브러리를 사용하면 어짜피 View - ViewModel 연결시 당연히 인터페이스 상속받아 구현해야 되는 노가다를 하지 않아도 되며, MVVM 특성상 어떤 컨트롤이 하나의 필드를 참조하더라도, 불필요하게 두개의 (일반적으로 실제 데이터를 담고있는 private field, 접근용도인 public field) 필드를 만들어야 하는데, 이딴짓을 하지 않고도 MVVM 패턴을 깔끔하게 사용할 수 있다.
어? 그러면 다 해결된거 아니에요?
아니다! Button 기준해서 Click Event 는 Command 동작과 연결하면 쉽게 연동되지만.
<Button
Grid.Row="2"
Grid.Column="1"
Content="{Binding ButtonClickCount}"
Command="{Binding IncreaseCommand}"/>
이 Command 동작을 지원하는 컨트롤은 '한정적' 이다.
예로, 만약 당신이 기존 Code-Behind 방식으로 구현된 `TextBox_KeyUp` 이벤트를 MVVM 방식으로 구현한다고 생각 해 봐라. 이걸 ViewModel 단에서 '어떻게 구현해야 되지?' xaml 에 도대체 뭘 써야지 KeyUp Event 가 발생할 때 특정 함수를 실행시키고, 변수값을 갱신시킬 수 있지? 생각해 보면 막막할 것이다. (기존 방식대로 하면 그냥 Visual Studio 에서 Event 속성 클릭해서 KeyUp 함수를 만들기만 하면 그만이니까!)
여러 방법이 있지만 가장 쉬운 방법은 Microsoft.Xaml.Behaviors.Wpf 라이브러리를 사용하는 것이다. (MS 에서 반쯤(..?) 지원하는 라이브러리 이다.)
<TextBox
Grid.Row="3"
Grid.Column="1">
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyUp">
<i:InvokeCommandAction Command="{Binding KeyUpCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
근데 이 라이브러리는 공식문서도 제대로 제공되지 않는다. (위에 말한 Community ToolKit 은 공식 예제 앱과, 문서가 제공된다.)
더해서 저 `KeyUpCommad` 라는 함수는 Visual Studio 나 여타 다른 툴에서 Ctrl + Click(F12) 로 선언구역을 참조하는게 지원되지 않는다! 때문에 만약 함수가 수백개라면 디자인 영역과, 코드 영역을 넘나들며 일일이 선언된 함수를 찾아야 한다는게 여간 고역이 아니며(물론 완벽하게 디자이너와 개발자가 따로 있다면 이런짓은 하지 않아도 되지만, 경험상 개발자가 xaml 을 아예 손대지 않는경우는 드물다.), 위에서 언급한 MVVM Community ToolKit 을 사용한다면 '실질적으로' 선언된 함수의 이름도 다르다. (예로 위에서 KeyUpCommand 로 Binding되어 있지만, 실질적으로 ViewModel 단에서 [RelayCommand] 속성을 통해 구현된 함수는 `KeyUp()` 이다. 이는 Community ToolKit 문서를 살펴보거나, 주석을 살펴보면 왜 그런지 알 수 있다.)
그냥 이런거 하나하나가 처음 MVVM 을 다루는 사람에게는 난관이다. 현실적으로 프로그래머가 계속 공부하는 직업이라고 하긴 하지만 '이런 짓' 을 알아보는 개발자는 생각보다 많지 않다.(내 생각에 정말 높게 쳐줘도 10% 안쪽이다) 더하여, 보통 C 계열 개발자들은 xaml을 디자인을 하는 도구쯤으로 치부해서 깊게 살펴보지 않는 경향이 있다고 생각한다. (이건 나도 마찬가지다.)
그렇다면 디자이너의 일인가? 싶지만, 위 코드를 살펴 보면 'xaml' 내부에서 Binding 작업을 거친다. 때문에 디자이너도 '조심해서' xaml 을 다뤄야 한다. 물론 정상적인 기업 / 프로젝트 팀이라면 BackUp 시스템이 잘 갖춰져 있을테지만 어쨋든 건들이지 않아야 하는 영역이 한 파일 내에 존재한다는것... 이건 이상적인 MVVM 모델의 구현은 아니라고 생각한다.
... 아무튼 그렇다.
이번 글은 결론을 내지 않고, 내가 생각하는 현재 C#과 MVVM 모델(정확히는 모델을 사용하는 전체적인 환경) 의 문제점을 프리하게 적어 보았다.
하지만 그럼에도 MVVM 패턴의 장점은 분명히 존재한다. (좋은 유지보수 편의성!)
내가 눈여겨 보는 많은 프로젝트의 기반이 MVVM 모델로 구성되어 있으며, MS 에서도 MVVM 패턴을 적극 활용하기를 권장하고 있기 때문이다. 대표적인 예시 프로젝트로 EarTrumpet, PowerToys 등이 MVVM 방식으로 구현되어 있다.
재미있는 사실은 이상적인 MVVM 이라면 View 영역에서 Code-Behind 를 모두 제거하고 ModelView 와 결합하는 코드와 `InitComponent()` 정도만 생성자에 위치해 있어야 하지만, EarTrumpet, PowerToys 코드를 살펴보면 생각보다 많은 양의 코드가 View 영역에 위치하는것을 알 수 있다.
이는 MSDN 에서 View 의 정의에서도 언급하는 내용으로, MVVM 자체의 한계점과 문제점에 대해서 유추할 수 있다.
'Programming > C#' 카테고리의 다른 글
[C#] Task, 비동기에 대해 (0) | 2023.08.08 |
---|---|
MAUI의 미래에 대해 (0) | 2023.06.05 |
[C#] Forms.Timer vs Threading.Timer (0) | 2022.07.25 |
[C#] SharedMemory 사용법 (0) | 2022.05.12 |
[C#] UDP Multicast 수신 (0) | 2022.04.08 |