MVC Pattern

Model-View-Controller

"Separate data (Model), presentation (View), and flow control (Controller). Each piece has one job — that's the entire idea."

CSE 135 — Full Overview | Review Questions

Section 1What is MVC?

Three components, each with a single responsibility.

The Three Components

ComponentResponsibilityKnows About
ModelData & business logic. Reads/writes database, validates data, enforces rules.Database. Not how data is displayed.
ViewPresentation. Takes data and renders it (HTML, JSON, etc.).Data format. Not how data is stored.
ControllerFlow control. Receives requests, asks Model for data, passes results to View.Both Model and View — the "traffic cop."
USER ──Request──▶ ┌────────────┐ ┌────────────┐ ┌────────────┐ ──Response──▶ USER │ Controller │──▶ │ Model │──▶ │ View │ │ Routes & │ │ Data & │ │ Renders │ │ handles │ │ logic │ │ output │ └────────────┘ └─────┬──────┘ └────────────┘ ◀──▶ Database
MVC is a pattern, not a framework. Express, Laravel, Django, Rails all use it — but you can build MVC in plain Node.js or PHP without any framework.

Section 2Why Separate Concerns?

What happens without MVC — and the benefits of splitting responsibilities.

Benefits of Separation

Without MVC

// Everything in one file: $pdo = new PDO(...); $stmt = $pdo->query('SELECT * FROM users'); $users = $stmt->fetchAll(); ?> <html> <body> <h1>User List</h1> <?php foreach ($users as $u): ?> <tr><td><?= $u['name'] ?></td></tr> <?php endforeach; ?> </body></html>

Routing + SQL + HTML all mixed together. Untestable, unreusable, unmaintainable.

With MVC

BenefitHow MVC Helps
TestabilityTest Model without HTML, test View without DB
Team WorkflowFrontend & backend devs don't collide
ReusabilitySame Model → HTML, JSON, CSV
MaintainabilityChange display? Edit View. Change schema? Edit Model.
Each piece has one job: Model = data, View = presentation, Controller = flow. The benefits compound as the application grows.

Section 3Server-Side MVC

The server renders complete HTML — the browser just displays it.

Server-Side MVC Flow

Server-Side MVC: ┌─────────┐ HTTP Request ┌──────────────┐ Query ┌─────────────┐ │ │ ──────────────────▶ │ │ ───────────▶ │ │ │ Browser │ │ Controller │ │ Model │ ◀──▶ DB │ │ │ │ ◀─────────── │ │ │ │ Complete HTML │ ┃ │ Data └─────────────┘ │ │ ◀────────────────── │ ▼ │ └─────────┘ │ ┌────────┐ │ │ │ View │ │ │ │ (EJS, │ │ │ │ PHP, │ │ │ │ Pug) │ │ │ └────────┘ │ └──────────────┘ Server

Six-Step Flow

  1. Browser sends HTTP request (e.g., GET /users)
  2. Router dispatches to the appropriate Controller method
  3. Controller asks Model for data (User.getAll())
  4. Model queries database, returns structured data
  5. Controller passes data to View template
  6. View renders complete HTML → sent to browser
The browser receives complete HTML pages. No client-side rendering — the server does everything. When the user clicks a link, the browser makes a full page request.

File Structure & Frameworks

Node.js (Express + EJS)

project/ ├── app.js # Entry point ├── routes/ │ └── users.js # URL → controller ├── controllers/ │ └── userController.js ├── models/ │ └── User.js # Data access └── views/ └── users/ ├── index.ejs # List users ├── show.ejs # User detail └── form.ejs # Create/edit

PHP (Manual MVC)

project/ ├── index.php # Front controller ├── .htaccess # URL rewriting ├── controllers/ │ └── UserController.php ├── models/ │ └── User.php # Data access └── views/ └── users/ ├── index.php # List users ├── show.php # User detail └── form.php # Create/edit
FrameworkLanguageTemplate Engine
Express + EJSNode.jsEJS, Pug, Handlebars
LaravelPHPBlade
RailsRubyERB, Haml
DjangoPythonDjango Templates, Jinja2

Section 4Client-Side MVC (SPA)

The server sends JSON — JavaScript renders everything in the browser.

Client-Side MVC Flow

Client-Side MVC (SPA): ┌───────────────────────────┐ ┌──────────────────────────┐ │ Browser │ │ Server │ │ │ │ │ │ ┌─────────────────────┐ │ fetch() / XHR │ ┌────────────────────┐ │ │ │ JavaScript App │ │ ─────────────────▶ │ │ Controller │ │ │ │ │ │ │ │ Calls Model │ │ │ │ ┌───────────────┐ │ │ │ └────────┬───────────┘ │ │ │ │ View (React, │ │ │ │ │ │ │ │ │ Vue, Angular)│ │ │ JSON │ ┌────────▼───────────┐ │ │ │ │ Renders DOM │ │ │ ◀───────────────── │ │ Model │ │ │ │ └───────────────┘ │ │ │ │ Queries DB │ │ │ └─────────────────────┘ │ │ └────────────────────┘ │ └───────────────────────────┘ └──────────────────────────┘

Six-Step Flow

  1. Browser loads a minimal HTML shell with a <script> tag
  2. JavaScript app initializes (React, Vue, Angular boots up)
  3. App makes API request: fetch('/api/users')
  4. Server Controller processes request, calls Model
  5. Model queries database, returns data as JSON
  6. JavaScript renders the DOM — builds/updates HTML in browser
The server returns JSON data only. JavaScript handles all rendering. Navigation happens without full page reloads.

SPA Frameworks & Tradeoffs

FrameworkApproach
ReactComponent-based, virtual DOM
VueReactive data binding, single-file components
AngularFull framework with dependency injection, RxJS

When to Use

  • Highly interactive UIs — dashboards, collaborative editors, chat
  • Desktop-like experiences — where page reloads would feel jarring
  • Offline-capable apps — cache data locally, sync when reconnected
  • Separate frontend/backend teams — API contract is the only shared interface
SEO & Accessibility Warning: If your app requires JavaScript to display any content, you've excluded users with JS disabled and made SEO harder. SSR frameworks (Next.js, Nuxt.js) exist to fix this — but that may be "solving an architectural problem with even more complexity."

Section 5Adaptable / Hybrid MVC

One backend, two paths — HTML for browsers, JSON for JavaScript clients.

Two Paths, One Backend

Adaptable MVC: Two Paths, One Backend Path A: JavaScript Enabled (Enhanced Experience) ┌──────────┐ fetch('/api/users') ┌────────────┐ ┌───────┐ │ Browser │ Accept: app/json │ │ Query │ │ │ (JS on) │ ────────────────────▶ │ Controller │ ─────────▶ │ Model │ ◀──▶ DB │ │ ◀──────────────────── │ │ ◀───────── │ │ │ Renders │ JSON response │ Checks │ Data └───────┘ │ via DOM │ │ Accept hdr │ └──────────┘ └────────────┘ Path B: No JavaScript (Baseline Experience) ┌─────────┐ GET /users ┌────────────┐ ┌───────┐ │ Browser │ Accept: text/html │ │ Query │ │ │ (JS off)│ ────────────────────▶ │ Controller │ ─────────▶ │ Model │ ◀──▶ DB │ │ ◀──────────────────── │ │ ◀───────── │ │ │ Displays│ Complete HTML page │ Checks │ Data └───────┘ │ HTML │ │ Accept hdr │ └─────────┘ └────────────┘
Progressive enhancement applied to architecture. The app works without JavaScript — every page is fully rendered HTML. When JS is available, the experience is enhanced with dynamic updates and partial page refreshes. The controller inspects the Accept header to decide.

Section 6REST vs MVC

They're not competing — they operate at different layers.

REST is the Interface, MVC is the Organization

Client REST API MVC Backend Database ┌──────────┐ ┌──────────────┐ ┌──────────────────┐ ┌───────────┐ │ │ │ │ │ │ │ │ │ Browser │ HTTP │ /api/users │ │ Controller │ │ │ │ Mobile │ ─────────▶ │ /api/items │ ────────▶ │ │ │ │ PostgreSQL│ │ Another │ │ /api/orders │ │ ▼ │ │ MongoDB │ │ Service │ ◀───────── │ │ ◀──────── │ Model ──▶ View │ ◀──▶ │ MySQL │ │ │ JSON/HTML │ Defines: │ │ │ │ │ └──────────┘ │ - URLs │ │ Organizes: │ └───────────┘ │ - Methods │ │ - Data logic │ │ - Status │ │ - Presentation │ │ codes │ │ - Flow control │ └──────────────┘ └──────────────────┘

The Restaurant Analogy

  • REST = the menu — defines what you can order and how to ask for it
  • MVC = the kitchen organization — how chefs, prep cooks, and plating stations fulfill orders

You can have REST without MVC (a single-file API script), MVC without REST (a server-rendered app with no API), or both together (the most common real-world pattern).

REST is the menu (what you can order). MVC is the kitchen organization (how orders are fulfilled). You can swap PostgreSQL for MongoDB without changing REST URLs. You can switch Express to Fastify without changing DB queries.

Section 7MVC in Frameworks

Same concepts, different file names and conventions.

Cross-Framework Comparison

FrameworkRoutesControllerModelView / Template
Express (Node.js) routes/users.js controllers/userController.js models/User.js views/users/index.ejs
Laravel (PHP) routes/web.php app/Http/Controllers/UserController.php app/Models/User.php resources/views/users/index.blade.php
Django (Python) urls.py views.py models.py templates/users/index.html
Rails (Ruby) config/routes.rb app/controllers/users_controller.rb app/models/user.rb app/views/users/index.html.erb
Django's naming confusion: Django calls its pattern "MTV" (Model-Template-View). What other frameworks call a "Controller" is Django's views.py. What others call a "View" is Django's templates/. The concepts are identical — only the names differ.

Section 8Building a CRUD App

The same application built three different ways.

Tutorial Modules: User Stories CRUD

ModuleApproachWhat the Server Returns
06: Database SetupPostgreSQL fundamentalsSQL: CREATE, INSERT, SELECT, UPDATE, DELETE
07: Server-Side MVCFull server renderingComplete HTML pages (EJS / PHP templates)
08: Client-Side MVCSPA with JSON APIJSON data only; JS renders the DOM
09: Adaptable MVCProgressive enhancementHTML or JSON based on Accept header
  • Same entity (User Stories) across all three approaches
  • Each available in both Node.js and PHP
  • The Model stays the same — only Controller and View change between approaches
  • Module 07 uses POST/Redirect/GET pattern for form submissions
Building the same app three ways shows what MVC actually separates. The Model (data layer) is the most stable component — the Controller and View adapt to the delivery mechanism.

SummaryKey Takeaways

8 sections of MVC fundamentals in one table.

MVC Pattern at a Glance

ConceptKey Points
MVCSeparates Model (data), View (presentation), Controller (flow). A pattern, not a framework.
ModelData & business rules. Talks to DB. No knowledge of display.
ViewRenders output (HTML, JSON, etc.). No knowledge of storage.
ControllerReceives input, coordinates Model & View. The "traffic cop."
Server-Side MVCServer renders complete HTML. Best for content sites, SEO, progressive enhancement. Frameworks: Express+EJS, Laravel, Django, Rails.
Client-Side MVCServer sends JSON, JS renders UI. Best for interactive apps. Frameworks: React, Vue, Angular. Requires JS.
Adaptable MVCSame controller serves HTML or JSON via Accept header. Progressive enhancement: works without JS, enhanced with it.
REST vs MVCREST = external API interface. MVC = internal code organization. Complementary, not competing.