작성자 님에 대한 배경 지식 없이 제가 한 말씀 드리면, MVVM이 익숙치 못해서 공부하고 계신 상황 같습니다.
우선적으로 지켜져야 할 것은 업무 일정입니다. MVVM을 지키다가 due dated가 초과될 경우 스스로는 과정을 겪으셨기에 뿌듯하게 남으시겠으나 오히려 주변 동료들에게는 MVVM 지켜서 공수가 초과되었다는 안좋은 인식 또한 남길 수 있습니다. 물론, MVVM 자체가 유지보수를 잘 하기 위해 지켜져야하는 엔터프라이즈 패턴은 맞습니다. 그렇게 구분해서 개발해둔다면 나중에 미래의 내가, 아니면 잘 모르는 사람이 봐도 캡슐화된 최소한의 변경으로 기능을 유지보수할 수 있을 것입니다. MVVM은 OOP의 원칙들과도 잘 상호작용하는 패턴입니다.
그럼 공수를 지킬 수 있다고 판단이 되셨을 때 아래 사항이 추천되는 사항입니다.
초보자용 WPF 간단 가이드
.NET 6 이상의 WPF 프로젝트 사용
- WPF는 Windows Desktop Application 전용 프레임워크로, .NET Framework로도 충분하지만 .NET 자체를 상위 버전을 사용하는 것만으로 많은 최적화 혜택과 추후 유용한 API들을 사용할 수 있습니다.
최근에 제가 혜택을 봤던 부분은 FrozenDictionary 였는데 이런 것들을 .NET Framework에서는 손수 구현해서 써야 했습니다.착오가 있었네요. .NET Framework에서도 FrozenDictionary 는 사용가능합니다.
CommunityToolkit.Mvvm Nuget 을 사용
- @루나시아 님의 대표 글이고, 닷넷데브 포럼의 인기있는 글인 CommunityToolkit.Mvvm 살펴보기 (완) 를 참고하시면 많은 도움이 되실 것입니다.
- CommunityToolkit.Mvvm을 사용하면 쉬운 MVVM을 도입할 수 있습니다. .NET Framework 에서도 사용 가능하지만 .NET 5부터 추가된 Source Generator의 도움을 받기 위해서는 역시 .NET 6 WPF 이상을 사용하시는 것을 추천합니다.
- 특히 지금 가장 궁금해하시는 Timer의 사용에 지대한 영향을 줄 것입니다. 어떤 구조로 코드를 만드실지는 모르겠으나, ObservableRecipient의 Messenger 기능을 Timer와 함께 사용하신 뒤 Property를 Binding 하시면 비교적 Dispatcher.Invoke를 덜 사용한 UI Update를 이용하실 수 있습니다. 더불어 Messenger를 사용하시는 자체가 Observer Pattern을 사용하시는 것이라 코드도 깔끔해집니다.
CustomControl 사용의 지양
- CustomControl은 react.js의 component처럼 UI를 디테일하게 설계할 수 있는 유용한 기능으로 WPF를 익히는 사람이 반드시 익혀야 하지만, 지향하시는 View 구성을 보니 CustomControl을 사용할 단계까진 아니고 DataTemplate을 정의하시는 정도로 충분해보입니다. CustomControl을 비추드리는 이유는 WPF의 UI 메커니즘을 알아야 사용할 수 있기 때문입니다.
ViewModel에서 특정 네임스페이스들의 비참조
- WPF 개발자가 MVVM이라는 걸 하면서 코드의 구역을 나누고 의존성을 관리하는 이유는 코드가 이곳저곳에 얽히면 디버깅이 어렵기 때문에 최소한의 의존성을 갖고 싶기 때문이고 이것이 static object를 남발하면 안되는 이유와 일맥상통하기도 합니다. 그런 의미에서, ViewModel에서는 참조해서는 안되는 Namespace 들이 있습니다.
- System.Windows
- System.Windows.Data
- System.Windows.Controls
- System.Windows.Media
- System.Windows.Threading
등등 System.Windows로 시작하는 namespace
위 네임스페이스들은 ViewModel에서 참조하는 경우 ViewModel이 WPF FCL 기능을 사용할 여지가 있다고 판단할 수 있기 때문에 제외해야 타이트한 MVVM 관리가 됩니다.
ViewModel과 WPF의 기능을 담당하는 Class 간 혼선 방지
- ViewModel은 다른 Project에서도 가져다 쓸 수 있을 목적으로 많이들 생성합니다. View를 먼저 설계하고 그에 필요한 데이터를 후순위로 만드는 View-First 방식이 존재하고, 어떤 데이터들을 화면에 출력해줄지 결정하고 UI를 만드는 ViewModel-First 방식이 있습니다.
- 그러다보니 위의 ViewModel에서 특정 네임스페이스를 비참조하면 다른 사용자 정의 클래스들도 저런 네임스페이스나 라이브러리를 참조하면 안되는거 아닌가? 라는 뇌절에 빠질 수 있습니다. 하지만 어디까지나 ViewModel만 저런 네임스페이스들이 참조되면 안되는 것이지, ViewModel이 View와 상호작용을 할 수 있도록 도와주는 중간 단계에서 사용하는 객체들은 얼마든지 참조할 수 있습니다. 쉽게 예시를 들어, Converter나 EventToCommand를 위한 Behavior 같은 기능은 사용자 정의 클래스에서 View를 목적으로한 namespace를 사용해야만 구현이 가능합니다.
Zero-Code Behind에 대한 오해
- MVVM을 지키는 것에 세계적으로 많은 개발자들끼리도 의견이 다양합니다.
- [Code Behind를 전혀 사용하지 않고 XAML만 처리하는 방식] vs [View를 제어하는 내용의 코드라면 Code Behind를 얼마든지 사용하는 방식]
- [View에서는 ViewModel을 참조해서는 안된다고 주장하는 방식] vs [View-First 방식이라면 ViewModel은 View에 의존할 수 밖에 없는 구조이기 때문에 Code-Behind에서 ViewModel의 강한 참조를 걸어도 된다고 주장하는 방식]
- Zero Code Behind를 지향하는 이유는 간단합니다. xaml 파일만 보면서 xaml.cs를 또 쓰면 View에 대한 논리 코드의 관리포인트가 2개가 되는 것이고 관리할 게 많아지는 것은 개발자들이 꺼리는 것입니다. 그리고 Code-Behind에 작성해야하는 코드들이 대부분 AttachedProperty, Behavior 로 충분한 대안이 되면서 캡슐화까지 되다보니 주장할 수 있습니다.
위 내용들은 나열하면서 가장 중요한 것은 일정입니다.
- 위 모든 것을 빡빡하게 지켜서 구현하실 수 있거나
- 위 내용을 AI에 prompt로 제공하여 AI가 만들어준 바이브코딩을 기준을 가지고 AI가 MVVM을 빡빡하게 지켰는지 구분할 수 있는 통찰을 갖거나
- 위 기준과 맞는 사수가 빡빡하게 가이드 해줄 수 있거나
하는 경우가 아니라면 초보자가 따라했을 때 일정을 위반하기에 좋은 요소들일 뿐이고 .NET을 사용하는 회사에 또다른 worst-case를 남기는 것만 됩니다.
MVVM을 쓰는 이유는 유지보수로 인한 미래의 생산성을 챙기는 구조를 만드는 것입니다. 완벽하게 지키시기 보다는 버릴 것은 버려가시면서 공부하시길 추천드립니다.