Skip to content

MVC, MVP, MVVM#

Three patterns that all separate what the user sees (View) from what the app does (Model). The difference is who orchestrates - controller, presenter, or viewmodel.

Model View Controller process: user action to controller, controller updates model, model updates view
Source: Wikimedia Commons. CC BY-SA.
flowchart LR
  subgraph MVC
    V1[View] -->|user action| C1[Controller] --> M1[Model]
    M1 -->|state| V1
  end
  subgraph MVP
    V2[View] -->|delegates| P[Presenter] --> M2[Model]
    P -->|updates| V2
  end
  subgraph MVVM
    V3[View] ---|two-way binding| VM[ViewModel] --> M3[Model]
  end

    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    class V1,V2,V3 edge;
    class C1,P,VM,M1,M2,M3 service;

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;

MVC dominates server-rendered web; MVP suits mockable desktop UIs; MVVM powers two-way data binding in WPF, Android, SwiftUI, Vue, and React + state libraries.

The presentation triad. All three split UI from logic; they differ in who owns rendering, who handles input, and who knows the most.

MVC - Model-View-Controller#

Coined by Trygve Reenskaug at Xerox PARC (1979). The original Smalltalk variant is not quite what we call MVC today.

sequenceDiagram
  participant U as User
  participant V as View
  participant C as Controller
  participant M as Model
  U->>V: click submit
  V->>C: dispatch action
  C->>M: update state
  M-->>V: emit change
  V-->>U: re-render
  • Model: the data and rules.
  • View: rendering of Model.
  • Controller: translates user input into Model changes.

Server-side MVC#

Rails, Django, Spring MVC: a request hits a Controller method, which calls Model methods, then picks a View template:

class PostsController < ApplicationController
  def show
    @post = Post.find(params[:id])  # model
    render :show                     # view
  end
end

The View is rendered server-side; the round-trip is the entire interaction.

MVP - Model-View-Presenter#

Used in WPF (early), GWT, Android (pre-MVVM).

classDiagram
  class View {
    <<interface>>
    +showLoading()
    +showOrders(list)
    +showError(msg)
  }
  class Presenter {
    -view: View
    -repo: OrderRepo
    +loadOrders()
  }
  class Model
  Presenter --> View
  Presenter --> Model
  • View: passive; just renders what it's told. Defined as an interface.
  • Presenter: holds all logic. Talks to Model, formats results, calls View methods.
  • Model: domain data.

Because the View is an interface, the Presenter is fully unit-testable with a mock View. This is MVP's main draw over MVC.

MVVM - Model-View-ViewModel#

Microsoft (WPF, 2005), Android (Architecture Components 2017+), SwiftUI, Vue.

flowchart TB
  V[View<br/>declarative template] ---|binding| VM[ViewModel<br/>observable state + commands]
  VM --> M[Model]

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
  • ViewModel: exposes Model data as observable properties + commands.
  • View: binds to ViewModel properties; updates fire automatically.
  • Data binding is the magic that removes most controller-style boilerplate.
// Android Jetpack
class OrderViewModel(repo: OrderRepo) : ViewModel() {
    val orders: LiveData<List<Order>> = liveData {
        emit(repo.fetchOrders())
    }
    fun cancel(id: String) = viewModelScope.launch {
        repo.cancel(id)
    }
}

@Composable
fun OrderScreen(vm: OrderViewModel = viewModel()) {
    val orders by vm.orders.observeAsState(emptyList())
    LazyColumn { items(orders) { OrderRow(it, onCancel = vm::cancel) } }
}

React and friends#

React's component model is closest to MVVM with one-way binding:

  • State is the ViewModel.
  • JSX render is the View bound to that state.
  • Updates flow state → render; events flow back via handlers.

State management libraries (Redux, MobX, Zustand) push the ViewModel out of components entirely.

Side-by-side#

MVC MVP MVVM
Orchestrator Controller Presenter (binding)
View knowledge Some None (passive) None
Testability Medium High High
Binding required No No Yes
Best fit Server-rendered web Desktop, mockable UIs Declarative UI frameworks

Modern hybrids#

  • MVI / Redux: state is reduced from actions; view is a pure function of state.
  • Flux: unidirectional MVC (action → dispatcher → store → view).
  • MVVM-C: add a Coordinator that owns navigation; useful in iOS.

Common mistakes#

  • Putting business logic in the Controller / Presenter / ViewModel. It belongs in the Model.
  • Letting the View call services directly - couples rendering to side effects.
  • Massive ViewModels - split per screen, not per app.

Where the presentation patterns sit#

flowchart TB
  MV((MVC / MVP /<br/>MVVM))
  OOP[OOP pillars<br/>polymorphism in View iface]
  CA[Clean architecture<br/>outer layer]
  SM[State machines<br/>view state modelling]
  BPL[Behavioral patterns<br/>Observer underlies binding]
  OOP -. backs .- MV
  CA --> MV
  MV --> SM
  BPL -. underlies .- MV

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
    class MV service;
    class OOP,CA,SM,BPL datastore;

Glossary & fundamentals#

Tag Concept What it is Page
LLD OOP pillars encapsulation + polymorphism in the View interface oop-pillars
LLD Clean architecture the layer above which MVC/MVP/MVVM lives clean-architecture
LLD State machines view state often modelled as a state machine state-machines
LLD Behavioral patterns Observer pattern underlies data binding behavioral-patterns

Quick reference#

At a glance#

Pattern Orchestrator View Binding
MVC Controller Active No
MVP Presenter Passive (interface) No
MVVM None (data binding) Bound Yes

Where each lives#

  • MVC: Rails, Django, Spring MVC; server-rendered web
  • MVP: Android pre-Jetpack, GWT, mockable UIs
  • MVVM: WPF, Android Jetpack, SwiftUI, Vue, React with state libs

Modern hybrids#

  • React = MVVM with one-way binding
  • Redux / MVI = state reduced from actions; view = f(state)
  • MVVM-C = adds Coordinator for navigation

Rules of thumb#

  • Business logic in Model, not in Controller/Presenter/ViewModel
  • View calls no services directly
  • ViewModel scoped per screen, not per app

Common bugs#

  • Massive controller / presenter / viewmodel
  • Two-way binding loops
  • View knowing about ORM entities

Refs#

  • Reenskaug - original MVC paper
  • Fowler - GUI Architectures
  • Android Architecture docs

FAQ#

What is the difference between MVC, MVP, and MVVM?#

All three separate the View from the Model. MVC uses a controller, MVP a presenter that owns view updates, and MVVM a viewmodel bound to the view via two-way data binding.

When should I use MVVM over MVC?#

MVVM shines when your UI framework supports data binding such as WPF, SwiftUI, Android Jetpack, or Vue. MVC fits stateless server-rendered web apps better.

Is MVC outdated?#

No. Server-side MVC is still the dominant pattern for Rails, ASP.NET, Spring MVC, Laravel, and Django. The shape is timeless even if names vary.

What is a presenter in MVP?#

A presenter owns the view's state and tells the view what to display. The view is a passive interface, which makes presenter logic easy to unit test.

Can MVC, MVP, and MVVM coexist?#

Yes. Large apps often use MVC at the routing level and MVVM inside specific screens. Pick the pattern that matches each layer's testing and binding needs.

  • Clean Architecture: MVC/MVP/MVVM are presentation-layer patterns inside a clean architecture
  • Behavioral Patterns: the Observer pattern underlies every data-binding implementation
  • State Machines: view state and navigation are often best modelled as state machines

Further reading#