The idea
What it is
Put a database call inside a button's click handler and your app rots fast: you can't test the logic without clicking, you can't reuse it on another screen, and one change ripples everywhere. MVC, MVP, and MVVM are three cures for the same disease. All three split your app into three parts: a Model (the data and the rules that guard it), a View (the buttons and pixels the user sees), and a middle coordinator that shuttles between them. The Model never touches the screen; the View never touches the database. That separation is the whole point — it's [[separation-of-concerns]] applied to UI.
Picture a restaurant. The kitchen is the Model — it holds the food and the recipes, and it doesn't care who's sitting at table 5. The dining room is the View — plates, menus, the stuff the guest actually sees. Between them stands a waiter who carries orders one way and dishes the other. The kitchen and the dining room never speak directly. That waiter is the middle coordinator — and MVC, MVP, and MVVM are simply three different waiters with three different sets of rules.
So what's actually different? Just who the middle guy is and which way data flows. In MVC the Controller takes your input and the View reads the Model itself. In MVP a Presenter does everything and hands finished results back to a totally passive View. In MVVM a ViewModel exposes state that the View is bound to, so a change on either side updates the other with no code you wrote. The trend across the three: the View gets progressively dumber and you write less and less manual wiring.
The one sentence to remember
All three separate a passive Model from a View via a middle coordinator; the only differences are who the coordinator is (Controller → Presenter → ViewModel) and how the View learns about changes — in MVC the View reads the Model, in MVP the Presenter pushes to the View, and in MVVM a two-way data binding syncs them automatically.
You've already used all three
Wrote a Rails, Django, or Spring controller? That's MVC. Built an old Android or WinForms screen with a Presenter and a passive view interface? That's MVP. Used Angular's [(ngModel)], Vue's v-model, WPF, SwiftUI, or Jetpack Compose? The framework handed you MVVM with data binding built in.
Mechanics
How it works
The three roles they all share
Before the differences, the common skeleton. Every one of the three has these three parts:
- Model — the data plus the rules that protect it (a temperature, a user, a shopping cart, and the logic that says what's valid). It is passive about the UI: it never imports a button, never draws a pixel. It just holds truth.
- View — everything the user sees and touches: labels, text fields, buttons. Its job is to display and to capture raw input. How much thinking it's allowed to do is exactly what separates the three patterns.
- The middle coordinator — the piece that connects the two so they never touch directly. This is the Controller, the Presenter, or the ViewModel. Renaming this box and rewiring its arrows is the entire difference between MVC, MVP, and MVVM.
MVC — the Controller takes input, the View reads the Model
Model-View-Controller is the classic, and the oldest (Smalltalk, 1979). The flow: the user acts on the View, the Controller receives that input, decides what it means, and updates the Model. The Model changes, and the View reads the Model to redraw itself. The key move is that the View is allowed to look at the Model directly — it pulls the data it needs. The Controller is mostly a router for input.
class TempModel { celsius = 20; } // data + rules
class TempController {
constructor(private model: TempModel) {}
onPlusClicked() { this.model.celsius += 1; } // input → update Model
}
class TempView {
constructor(private model: TempModel) {}
render() { return `${this.model.celsius}°C`; } // View READS the Model itself
}This is what server frameworks give you — Rails, Django, Spring MVC, Laravel, ASP.NET MVC. A request hits a controller action, the action touches the model, and a template (the view) renders from that model. It fits the request/response web perfectly: each click is a fresh round trip.
MVP — the Presenter does everything, the View is passive
Model-View-Presenter makes the View as dumb as possible. The View captures a click and immediately forwards it: presenter.onPlusClicked(). It contains no logic — it doesn't read the Model, doesn't format anything, doesn't decide anything. The Presenter holds all of that. It updates the Model, formats the result, and pushes the finished value back to the View by calling methods on a small View interface like view.showTemperature("21°C").
interface TempView { // the ONLY door the Presenter uses
showTemperature(text: string): void;
}
class TempPresenter {
constructor(private model: TempModel, private view: TempView) {}
onPlusClicked() {
this.model.celsius += 1; // update the Model
this.view.showTemperature(`${this.model.celsius}°C`); // PUSH result to View
}
}Why MVP is the testable one
Because the View is just an interface the Presenter talks to, you can write a fake View in a unit test — call presenter.onPlusClicked() and assert the fake received "21°C". No screen, no framework, no clicking. That's why classic Android (pre-Jetpack) and WinForms teams loved MVP.
MVVM — data binding syncs the View and ViewModel for you
Model-View-ViewModel removes the manual push entirely. The ViewModel exposes bindable state — an observable temperatureText property. The View declares, once, that its label is bound to that property. From then on, two-way data binding keeps them in sync automatically: change the ViewModel and the label updates itself; type in a bound text field and the ViewModel updates itself. You write no glue code to copy values back and forth — the framework does it.
class TempViewModel {
private model = new TempModel();
temperatureText = observable(`${this.model.celsius}°C`); // bindable state
increment() {
this.model.celsius += 1;
this.temperatureText.set(`${this.model.celsius}°C`); // binding auto-updates the View
}
}
// In the view template: <label text="{bind temperatureText}" /> ← no push codeThis is the modern default because frameworks ship the binding engine: WPF/XAML (where MVVM was coined), Angular, Vue, Knockout, SwiftUI, and Jetpack Compose. You describe what the UI should reflect, not when to update it.
The through-line: the View keeps getting dumber
MVC → MVP → MVVM is one story told three times, each time moving more work out of the View. In MVC the View still reads the Model. In MVP the View knows nothing and is fed by the Presenter. In MVVM the View doesn't even get fed — it's bound, and updates happen with no wiring you wrote. Less manual glue at every step.
A quick side-by-side
- Who's the middleman? MVC → Controller · MVP → Presenter · MVVM → ViewModel.
- How does the View get updated? MVC → it reads the Model · MVP → the Presenter pushes to it via an interface · MVVM → data binding updates it automatically.
- How smart is the View? MVC → medium (reads Model, some logic) · MVP → dumb (pure interface) · MVVM → declarative (just bindings).
- Coupling of View↔coordinator? MVC → Controller doesn't reference the View much · MVP → Presenter holds a View interface reference · MVVM → ViewModel doesn't even know the View exists (it just exposes observable state).
- Where you meet it: MVC → Rails, Django, Spring · MVP → old Android, WinForms · MVVM → WPF, Angular, Vue, SwiftUI, Compose.
Interactive prototype
See it. Build it. Break it.
A sandboxed, hands-on simulation — no setup, no install. Play with it as you read.
About this simulation
A tiny temperature app — a 📦 Model holding one number in °C, a 🖼 View that shows it, and a +1°C button. Flip between the MVC, MVP, and MVVM tabs, then press +1°C and watch which arrows light up. In MVC the View pokes the Controller, the Controller writes the Model, and the View reads the Model back. In MVP the View is dumb — it only ever talks through the Presenter, which pushes the finished text back to it. In MVVM one glowing ⇄ binding arrow does the work both ways automatically — notice the "glue you wrote" counter stays at 0. Same app, same number; the only thing that changes is who carries the plates.
Hands-on
Try these yourself
Open the prototype above, predict what happens, then verify.
Trace the MVC round trip
Make sure the MVC tab is selected. Press +1°C in the View box. Watch the arrows light up in order: View → Controller (you told the controller), Controller → Model (it bumped the number), then Model → View (the View re-reads the Model to redraw). The shared temperature ticks up by one. Notice the explain line: the View had to reach back to the Model itself.
See the passive View in MVP
Switch to the MVP tab and press +1°C. Now the flow is View → Presenter (the View just forwards the click), Presenter → Model (update), then Presenter → View (the Presenter pushes the finished '°C' text back through the view interface). The View never touched the Model — it only ever spoke to the Presenter. Watch the 'glue you wrote' counter tick up: in MVP you hand-wire every push.
Watch binding do the work in MVVM
Switch to the MVVM tab and press +1°C. One glowing ⇄ arrow between View and ViewModel pulses both directions — that's two-way data binding. The ViewModel updates the Model, and the bound label refreshes with zero push code. Check the 'glue you wrote' counter: it stays at 0. Hit ↺ Reset any time to set the temperature back to 20°C and clear the counters.
In practice
When to use it — and what trips people up
Reach for...
- MVC — when you're building a server-rendered, request/response app. Each click is a round trip: controller handles the request, touches the model, renders a template. Rails, Django, Spring, Laravel, and ASP.NET MVC are all built around it.
- MVP — when the View must be dumb and unit-tested. If you need to verify presentation logic without spinning up a screen (a fake view interface in a test), MVP's passive View is exactly the shape you want. Classic for legacy Android and desktop WinForms/GWT.
- MVVM — when your framework gives you data binding. If you're in WPF, Angular, Vue, SwiftUI, or Jetpack Compose, lean into the ViewModel and let bindings erase the glue code. Fighting the binding engine to do MVP by hand is wasted effort.
Which to pick / skip when...
- The app is tiny — a one-screen toy doesn't need any of them. A Model plus a click handler is fine; adding a Presenter is ceremony with no payoff. Reach for a pattern when logic grows.
- No binding engine? Don't fake MVVM. Two-way binding by hand is fiddly and leaky. Without framework support, MVP (explicit pushes) is usually cleaner and easier to follow than a homegrown binding layer.
- Don't mix the roles. The moment SQL or business rules leak into the View, or the Model starts importing UI widgets, you've lost the [[separation-of-concerns]] that made you pick a pattern at all.
What it gives you
- Separation of concerns — the Model (data + rules) stays free of UI, so business logic is reusable across screens and independently testable.
- Testability, especially in MVP and MVVM — the coordinator holds the logic and can be tested with a fake or headless View, no clicking required.
- Parallel work — once the interfaces are set, one person can build the View while another builds the Model and coordinator.
- Less glue over time — MVVM's data binding erases the manual copy-values-back-and-forth code that MVC and MVP require.
Common mistakes
- Overhead for small apps — three roles plus interfaces is real boilerplate that a trivial screen doesn't earn back.
- MVP can get chatty — the Presenter needs a method on the View interface for every little UI update, which balloons on complex screens.
- MVVM binding is hard to debug — 'why did this update?' hides inside the framework's binding engine, and leaky bindings can cause subtle bugs and memory leaks.
- Blurry boundaries in practice — teams argue endlessly over what belongs in the Controller vs Model vs View, and the lines drift as the app grows.
Reference
Code & further reading
A minimal reference implementation and pointers worth bookmarking.
// ---- MVC: Controller takes input, View reads the Model ----
class TempModel {
celsius = 20; // data + the rule that guards it
bump(delta: number) { this.celsius += delta; }
}
class TempController { // the middleman: routes input
constructor(private model: TempModel) {}
onPlus() { this.model.bump(1); } // input → update Model
}
class TempView {
constructor(private model: TempModel, private ctrl: TempController) {}
clickPlus() { this.ctrl.onPlus(); } // View tells the Controller
render(): string {
return `${this.model.celsius}°C`; // View READS the Model directly
}
}
const model = new TempModel();
const ctrl = new TempController(model);
const view = new TempView(model, ctrl);
view.clickPlus();
console.log(view.render()); // "21°C"References & further reading
6 sources- Articlemartinfowler.com
GUI Architectures — Martin Fowler
The definitive deep history of MVC, MVP, Presentation Model, and the ideas MVVM grew from — traces exactly why each variant moved logic out of the View. The canonical reference.
- Docsen.wikipedia.org
Model–view–controller — Wikipedia
Concise reference on MVC's origins (Smalltalk-79), its three components, and how it relates to MVP and MVVM. Good for the shared vocabulary.
- Docsen.wikipedia.org
Model–view–viewmodel — Wikipedia
Covers MVVM's WPF origins, the role of the binder/data binding, and the ViewModel as a 'model of the view'. Explains why binding is the defining feature.
- Docsdeveloper.android.com
Guide to app architecture — Android Developers
Google's modern take: a ViewModel-centered, unidirectional-data-flow architecture. Shows MVVM applied in a real, current framework (and why they moved off MVP).
- Docslearn.microsoft.com
The Model-View-ViewModel Pattern — Microsoft Learn
A practical, code-first walkthrough of MVVM: ViewModel responsibilities, data binding, and commands — from the platform where MVVM was invented.
- Talkyoutube.com
MVC, MVP and MVVM — clear comparison (video)
A short, visual side-by-side of the three patterns and how their data flow differs. Handy if you learn better by watching the arrows move.
Knowledge check
Did it land?
Quick questions, answers revealed on submit. Sign in to save your best score.
question 01 / 06
What do MVC, MVP, and MVVM all have in common?
question 02 / 06
Which of the three patterns uses two-way data binding to sync the View and the coordinator automatically?
question 03 / 06
In MVP, who does the View talk to, and how much logic does the View contain?
question 04 / 06
In classic MVC, how does the View learn about a change after the Controller updates the Model?
question 05 / 06
What is the overall trend as you move from MVC to MVP to MVVM?
question 06 / 06
You're building a server-rendered app where each user click is an HTTP request that returns a rendered page. Which pattern fits most naturally?
0/6 answered