Learn

Architecture & pattern guides

Read the idea, build it on a Grid, prove it in a challenge. Short, practical guides — illustrated with RodGrid's own nodes — on system design, design patterns, flow modeling, and how to get the most out of the app.

All articles

MVC: Model, View, Controller

In the original MVC a Controller turns the user's input into calls on the Model, and every View watching that Model redraws when it changes, which is not what web frameworks mean when they use the same name.

One drag, three redraws

Drag the red slider in a design tool's brand-colour editor from 180 to 220. Three things change on screen: the number beside the slider, the hex field, which goes from #B45028 to #DC5028, and a preview swatch with a line of white text on it, whose contrast readout drops from 5.1 : 1 to 4.0 : 1 and turns amber. The slider's code calls neither the hex field nor the preview.

They stay in step because none of them holds the colour. One object does, and the three widgets only show it. That arrangement is Model-View-Controller, the oldest of the patterns that keep screens apart from the rules they display.

The loop Smalltalk drew

MVC comes from Xerox PARC, where Trygve Reenskaug described it in 1979; Smalltalk-80 built its user interface on it. It divides the editor into three kinds of object. The Model is the brand colour: three channels from 0 to 255, the check that keeps them in range, and the arithmetic that gives the hex code and the contrast against white. It contains no widget. A View draws some part of the Model: the slider panel, the hex field and the preview are three Views. A Controller takes the user's input for one View and turns it into calls on the Model. In Smalltalk-80 each View came paired with its own Controller, so the slider's Controller reads the mouse and the hex field's reads the keyboard.

Told in that vocabulary, the drag is short. The slider's Controller sees the mouse move and calls brand.setRed(220). The Model checks that 220 is in range, stores it, and announces that it changed to every View registered as its dependent. Then the Views ask: the slider panel reads red(), the hex field hex(), the preview the colour and contrastOnWhite(), and each redraws itself.

The announcement carries the design. The Model never calls the hex field; it says that it changed, and whoever registered hears it. In Smalltalk-80 the Model sent itself changed:, and each dependent received update:. Outside user interfaces the same mechanism is Observer, which covers how subscribing and notifying work and how they go wrong.

One Model, three Views

The Controller changes the colour only through the Model. The arrows out of the Model are its change notifications to its dependents; the reads each View then makes before redrawing are not drawn.

What a Model with no screen buys

Because the Model holds no widget, a test can call setRed(300) and check that the value was refused without opening a window. And because no View keeps its own copy of the colour, Views can be added freely: register a strip that previews the colour on a dark background, and the next drag redraws it too, with no change to the Controller, the hex field or the Model.

Where the amber goes

One decision in the editor is neither a rule about colours nor drawing: below 4.5 : 1, the WCAG level AA minimum for normal-size text, show the ratio in amber with the words "Too low for body text". Computing the ratio belongs in the Model. Deciding that 4.0 means amber and that sentence is presentation logic, a decision about what the user sees, and MVC names no piece whose job it is. How its successors answer that, side by side, is in UI architecture: keeping screens apart from domain rules.

In practice it lands in the View. The preview reads the ratio, compares it with 4.5 while drawing, and picks the colour. That is easy to read, but with the decision mixed into the drawing code, it is harder to test in isolation, and a test may have to build the preview and inspect what it drew. Moving that logic into a class a test can drive without any screen is the step MVP: Model, View, Presenter takes; turning it into state the View binds to is MVVM: Model, View, ViewModel.

Two shortcuts that break the loop

Teams that dislike logic in the View often move it into the Controller, which is already code rather than drawing. The Controller then decides the amber, picks the warning text and enables the Save button, and to show those results it starts calling Views directly: preview.setWarning(true). Each such call is a path that bypasses the Model, so the dark strip added later, which nobody wired to the Controller, never shows the warning.

The opposite shortcut is a View that writes to the Model itself. The hex field already has the typed text, so it parses it and calls brand.setHex(...) without going through its Controller. It works until the input rules change: the Controller learns to accept three-digit codes such as #D52, the field's own parser does not, and the same keystrokes behave differently depending on which path handled them.

The same three words on a web server

Look up MVC today and much of what you find describes something else: server frameworks such as Ruby on Rails and Spring MVC. Put the editor on a web page and a change goes like this. The browser sends PATCH /colors/7 with the new red value. The framework routes it to an action on a controller, ColorsController#update in Rails, or a method on a @Controller class in Spring MVC. The action loads the colour through a model class, updates it and saves it. A template then renders the HTML that goes back to the browser; in Spring MVC the method can return a view name, which a view resolver maps to a template.

One request, one render

No edge leaves the Model: once the page is rendered, nothing tells it that the colour changed.

The template runs once per request, and no View observes the Model. If another designer edits colour 7 from another browser, this page keeps showing the old value until it is reloaded or something else pushes the change to it. The controller is different too: it is not paired with a widget and reads no keystrokes; it handles one request and decides what to send back. The names Model, View and Controller survived the move; the loop did not, so when someone calls a codebase MVC, it is worth asking which of the two they mean.

Draw the loop

The Model-View-Controller Challenge wants the desktop loop, not the web one: the user's input reaching a Controller, the Controller updating a Model that holds the data and rules, and a View rendering that Model. Drawn with a single View, the brand-colour editor fits in its node limit with room left over, and the room is the useful part. Give the Model a second View, then look at the edges you needed. The new View should need only the Model: its change notification and the reads that follow; if it also wanted an arrow from the Controller, one of the two shortcuts above is already on your Grid. If the amber warning still has no comfortable home in your drawing, MVP: Model, View, Presenter is where it goes next.

Practice this