100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
.NET

The Model in MVVM

What belongs in the Model layer of MVVM, how it differs from ViewModel state, and how to test it.

FoundationsIntermediate8 min readJul 10, 2026
Analogies

The Model in MVVM

The Model in MVVM is the layer that represents the application's data and business rules: domain entities, validation logic, calculations, and access to persistence or network sources. It has zero knowledge of the ViewModel or View — no observable properties for UI binding, no formatting for display, and no awareness that a UI even exists — which means the exact same Model code could power a mobile app, a server API, and a batch job without modification. This strict independence is what lets the Model be reused and tested completely separately from any presentation concern.

🏏

Cricket analogy: The ICC's official playing regulations and a scorer's raw ball-by-ball record are the Model: they define what counts as a wide or a no-ball regardless of whether the match is being watched on TV, radio, or not broadcast at all.

What Belongs in the Model

Concretely, the Model layer typically includes: domain entities (plain classes like Order or User with their invariants), repositories or data-access objects that abstract away whether data comes from a REST API, a local database, or a cache, domain services that encapsulate business rules spanning multiple entities (like calculating shipping cost from an Order and a ShippingPolicy), and validation logic that enforces invariants such as 'an Order must have at least one line item.' None of these classes should import UI framework types, reference formatting concerns like currency symbols for display, or know about loading spinners — those are ViewModel or View responsibilities.

🏏

Cricket analogy: A player-eligibility repository that checks whether a cricketer qualifies for a domestic league under residency rules is Model logic; it should never contain code for how the eligibility badge is colored on screen.

Model vs ViewModel State

A subtle but important distinction is that the Model represents durable, domain-true state — an Order's total, a User's email — while the ViewModel represents transient, UI-specific state, like whether a spinner is currently visible, whether a form field currently shows a validation error bubble, or which tab is selected. If you find a boolean like isLoading or isPasswordVisible in your Model classes, that's a sign UI concerns have leaked into a layer that should be UI-agnostic; those flags belong in the ViewModel, which is explicitly allowed to know about presentation state even though it must not know about concrete View controls.

🏏

Cricket analogy: A player's career batting average is durable Model state that exists whether or not anyone is watching, while 'is the stats overlay currently expanded on this viewer's screen' is transient ViewModel state specific to one broadcast session.

swift
// Model: pure domain logic, no UI awareness
struct Order {
    let id: UUID
    let lineItems: [LineItem]

    var subtotal: Decimal {
        lineItems.reduce(0) { $0 + $1.price * Decimal($1.quantity) }
    }

    func validate() throws {
        guard !lineItems.isEmpty else {
            throw OrderError.emptyOrder
        }
    }
}

protocol OrderRepository {
    func fetchOrder(id: UUID) async throws -> Order
    func save(_ order: Order) async throws
}

// Notice: no SwiftUI import, no @Published, no formatting.

The repository pattern is the idiomatic way to expose Model data to the ViewModel: a repository's interface (e.g., OrderRepository) hides whether data comes from a REST API, GraphQL, a local SQLite cache, or a combination with offline-first sync, so the ViewModel that consumes it never needs to change when the data source changes.

Testing the Model

Because the Model has no UI dependency, its tests are typically the fastest and most stable in the codebase: pure unit tests that construct domain objects, call methods, and assert on results, with no need for a UI test runner, simulator, or emulator. A well-designed Model also makes it possible to test complex business rules — like tiered shipping discounts or overlapping-booking detection — exhaustively with many edge cases, something that would be slow and flaky if those rules were entangled with rendering code.

🏏

Cricket analogy: A statistician can exhaustively test 'does this Duckworth-Lewis-Stern calculation handle a rain delay at over 35' using nothing but input numbers and expected outputs, with no stadium or broadcast required.

A common mistake is letting the Model return already-formatted strings, like an Order returning '$45.00' instead of the Decimal 45.00, because that silently bakes a locale and currency assumption into the domain layer; formatting for display, including currency symbols, date formats, and pluralization, belongs in the ViewModel or a dedicated formatter the ViewModel calls.

  • The Model holds domain entities, business rules, and persistence access, with zero UI awareness.
  • Model code can be reused across mobile, server, and batch contexts because it never imports UI types.
  • Repositories abstract data source details away from the ViewModel that consumes the Model.
  • Durable domain-true state (an Order's total) belongs in the Model; transient UI state (isLoading) belongs in the ViewModel.
  • Model logic is fast and stable to unit test since it needs no UI framework, simulator, or emulator.
  • Avoid returning display-formatted strings, like currency-formatted text, from the Model.
  • Complex business rules are best exhaustively tested at the Model layer, not entangled with rendering code.

Practice what you learned

Was this page helpful?

Topics covered

#NET#MVVMDesignPatternStudyNotes#MicrosoftTechnologies#TheModelInMVVM#Model#MVVM#Belongs#ViewModel#StudyNotes#SkillVeris