<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: ZjzMisaka</title>
    <description>The latest articles on Forem by ZjzMisaka (@zhangjunzhi).</description>
    <link>https://forem.com/zhangjunzhi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3918497%2F16f93074-8ab8-4d51-aaca-13a99d4e4647.png</url>
      <title>Forem: ZjzMisaka</title>
      <link>https://forem.com/zhangjunzhi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/zhangjunzhi"/>
    <language>en</language>
    <item>
      <title>Rethinking MVVM Architecture: Clarifying Layer Responsibilities</title>
      <dc:creator>ZjzMisaka</dc:creator>
      <pubDate>Thu, 07 May 2026 20:02:11 +0000</pubDate>
      <link>https://forem.com/zhangjunzhi/rethinking-mvvm-architecture-clarifying-layer-responsibilities-1hmk</link>
      <guid>https://forem.com/zhangjunzhi/rethinking-mvvm-architecture-clarifying-layer-responsibilities-1hmk</guid>
      <description>&lt;p&gt;The MVVM pattern is widely adopted in modern application development. However, in my practical development experience, there is a certain degree of misunderstanding within the team regarding the responsibilities of each layer. This has led to an imbalanced code structure, resulting in extremely bloated ViewModel layers and the degeneration of the Model layer into pure data containers. &lt;br&gt;
Based on the core principles of object-oriented design and architectural layering, this article reorganizes and redefines the responsibilities of each MVVM layer.&lt;/p&gt;

&lt;p&gt;For explanations regarding the "Anemic Domain Model" and "Rich Object" mentioned below, please refer to: &lt;a href="https://martinfowler.com/bliki/AnemicDomainModel.html" rel="noopener noreferrer"&gt;Anemic Domain Model&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Overall, design patterns like MVVM are intended for development convenience and maintainability. They might introduce some complexity, but if coding becomes a painful experience just to comply with a design pattern, it is highly likely that the pattern is being dogmatically misused.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Misconceptions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Misconception 1: The Model Layer Should Only Contain Data
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;The Model layer represents the data model and should only contain data fields and properties, strictly corresponding one to one with UI elements or database table fields.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Before being a model, a Model is fundamentally an object-oriented type. It abstracts certain sub business concepts, and these sub businesses inevitably have their own business logic.&lt;br&gt;&lt;br&gt;
Simplifying the Model into a pure data container (i.e., Anemic Domain Model) ignores the core philosophy of object-oriented design. Once all business rules and logic are moved out to the ViewModel, it not only causes an imbalance in responsibilities but also makes it impossible to independently test and reuse the business logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Misconception 2: The ViewModel Layer Should Bear All Business Logic
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;The ViewModel layer is responsible for managing Model instances and their collections, handling all business logic, and directly updating Model data to drive UI refreshes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Concentrating all business logic in the ViewModel leads to extreme bloat. As features iterate, a single ViewModel file can easily reach thousands or tens of thousands of lines, making it difficult to maintain and impossible to perform effective unit testing on the business logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Misconception 3: The View's CodeBehind Should Remain Empty
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;The `&lt;/em&gt;.xaml.cs` files should be kept as empty as possible, and all interaction logic should be transferred to the ViewModel via Attached Behaviors or Commands.*&lt;/p&gt;

&lt;p&gt;I suspect that this kind of obsession originates from trying to get around code coverage requirements for unit tests, since UI code isn’t that easy to test anyway XD.&lt;/p&gt;

&lt;p&gt;This practice confuses the concepts of "business logic" and "UI control logic". Forcing purely UI interaction logic into the ViewModel, or wrapping it in layers of Behaviors, only increases system complexity and contradicts the original intent of MVVM.&lt;br&gt;&lt;br&gt;
The MVVM advocacy to "keep CodeBehind clean" originally meant avoiding the mixing of business logic into the UI's CodeBehind, not prohibiting the writing of UI control logic itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Correct Understanding of MVVM Architecture
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Overview of Responsibility Boundaries&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Core Abstraction&lt;/th&gt;
&lt;th&gt;Primary Responsibilities&lt;/th&gt;
&lt;th&gt;Should Not Contain&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Model&lt;/td&gt;
&lt;td&gt;Business Concepts&lt;/td&gt;
&lt;td&gt;Business data, business logic, business rules&lt;/td&gt;
&lt;td&gt;UI state, UI control logic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ViewModel&lt;/td&gt;
&lt;td&gt;UI Actions&lt;/td&gt;
&lt;td&gt;UI state management, Commands, coordinating Model invocations&lt;/td&gt;
&lt;td&gt;Specific business rules, pure UI control logic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;View&lt;/td&gt;
&lt;td&gt;UI Control&lt;/td&gt;
&lt;td&gt;UI interaction logic, visual presentation control&lt;/td&gt;
&lt;td&gt;Business logic, business state&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Model Layer: Abstraction of Business Concepts
&lt;/h3&gt;

&lt;p&gt;The core responsibility of the Model layer is to abstract business concepts. It is not just a data container, but a complete object-oriented type that carries the business data and business logic within its business domain. Furthermore, the Model further abstracts sub business concepts, which also possess their own business rules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Responsibility Boundaries:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Encapsulate business data and state.&lt;/li&gt;
&lt;li&gt;Implement business rules and operations belonging to this business domain.&lt;/li&gt;
&lt;li&gt;Further abstract sub business concepts and maintain the sub businesses' own logic.&lt;/li&gt;
&lt;li&gt;Provide business operation interfaces for the ViewModel to invoke.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Design Principles:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Model should be a Rich Domain Object, not an Anemic Domain Model.&lt;br&gt;&lt;br&gt;
The ViewModel does not need to know these business details; it simply calls the corresponding interfaces to intuitively control the UI display and actions in a manner consistent with business intuition.&lt;/p&gt;

&lt;h3&gt;
  
  
  ViewModel Layer: Coordinating UI Actions
&lt;/h3&gt;

&lt;p&gt;The core responsibility of the ViewModel layer is to abstract and coordinate UI actions. It maintains additional UI states required by the interface and organizes UI actions and state changes by invoking the business logic of various Models. The ViewModel is a bridge between the View and the Model, not a container for business logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Responsibility Boundaries:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maintain UI specific states that are not strongly related to specific business logic (e.g., &lt;code&gt;IsLoading&lt;/code&gt;, &lt;code&gt;IsSelected&lt;/code&gt;, &lt;code&gt;ErrorMessage&lt;/code&gt;, etc.).&lt;/li&gt;
&lt;li&gt;Expose Commands to respond to user operations.&lt;/li&gt;
&lt;li&gt;Invoke business methods of the Model and coordinate interactions between multiple Models.&lt;/li&gt;
&lt;li&gt;Handle page/view navigation logic.&lt;/li&gt;
&lt;li&gt;Should not contain specific business rules.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Design Principles:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The ViewModel should be a lightweight Coordinator, not a dumping ground for business logic. If a large amount of business judgment and rule code is found in the ViewModel, it should be pushed down to the corresponding Model layer. A reasonable ViewModel should primarily consist of property bindings, Command definitions, management of Model instances, and invocations of public functions exposed by the Model.&lt;/p&gt;

&lt;h3&gt;
  
  
  View Layer: Pure UI Control Logic
&lt;/h3&gt;

&lt;p&gt;The core responsibility of the View layer is to handle user input and output logic at the UI level. CodeBehind should not contain business logic, but for logic that falls purely within the scope of UI control, implementing it directly in CodeBehind is completely reasonable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Responsibility Boundaries:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Handle pure UI interaction logic (e.g., focus management, animation triggering, control linkage, etc.).&lt;/li&gt;
&lt;li&gt;Handle visual interaction behaviors that are impossible or difficult to express through data binding.&lt;/li&gt;
&lt;li&gt;Should not contain business rules and business state management.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Design Principles:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The core criterion for determining whether a piece of logic should be placed in CodeBehind is: &lt;em&gt;Is this logic solely related to UI presentation and unrelated to the business?&lt;/em&gt; If so, placing it in the View layer is appropriate. Only when a piece of UI logic needs to be reused across multiple Views should you consider encapsulating it as an Attached Behavior.&lt;/p&gt;

</description>
      <category>mvvm</category>
      <category>wpf</category>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
  </channel>
</rss>
