This problem that MVC has is similar to the problem with OOP itself, with monads, or with some design patterns: the original/popular definitions were so incredibly abstract and disconnected from real life usage that they ended up being whatever the person implementing it wanted it to be.
And then, 10, 20 years after the fact, people will start attacking popular implementations that differ from the original using some "new canonic interpretation" that is either extremely recent, or an interpretation that is old but was lost in time.
This is especially common around Smalltalk and OOP for some reason. Smalltalk's OOP is nothing like what existed either before or after, but since Alan Kay invented the term, Smalltalk is weaponised against C++/Java-style OOP. Not that C++/Java OOP is the bees knees, but at least their definition is teachable and copyable.
Design patterns suffer because in most explanations the context is completely missing. Patterns are totally useless outside very specific contexts. "Why the hell do I need a factory when I can use new"? Well, the whole point is that in some frameworks you don't want to use new Whatever, you dummy. If only this was more than a two-sentence blurb in the DDD book (and the original patterns book totally glosses over this, for almost all patterns).
And monads became the comical case, because they are totally okay in Haskell, but once it gets "explained" and migrated to other languages they become this convoluted mostly useless abstraction at best, footgun at worst (thinking of the Ruby one here).
ozim · 4m ago
From my experience patterns suffer from new devs thinking that patterns are guidelines for writing their code and that they should create code that is generic and implements patterns. (Yes if their job is implementing framework, not when their job is to use framework to build business app)
Like everyone totally forgot patterns are mainly for understanding existing systems like you use a framework - hey this looks like a factory let’s use one from the framework we built stuff with instead of implementing our own.
Besides of course every developer wanting to build framework so others adhere to what he built not the other way around ;)
asalahli · 11m ago
> the original/popular definitions were so incredibly abstract and disconnected from real life usage that they ended up being whatever the person implementing it wanted it to be.
This is what happened with REST too, and it frustrates me more than it probably should.
The original pattern is such a good idea and not even remotely abstract. It's a well defined architectural pattern for a well defined problem yet people still managed to bastardize it to the point that the term REST barely means anything today
skydhash · 1h ago
> *Design patterns suffer because in most explanations the context is completely missing. Patterns are totally useless outside very specific contexts.
It's hard to define how a pattern can be useful, because they're patterns, not recipes or snippets. They're supposed to fit in the reader's solution, not the author's examples. You're supposed to have the problem before reaching out for a solution and patterns are not solutions, they're models of solution, each with their own tradeoffs, costs and advantages.
procaryote · 19m ago
This is why reading a book on design patterns is more than most junior devs can handle without then spending years trying to shove extra complexity into everything to make it use said patterns
Every `new` can be a factory or builder, but usually `new` is the right thing
adityaathalye · 1h ago
MVC (and other OOP patterns) work around the fact that the language does not solve the Expression Problem.
You could say, the key to getting MVC correct is understanding the Expression Problem, and designing its solution into your programming language in the first place, so you don't need MVC, but if you want to do it, it becomes actually neat and clean and modular.
MalinGamer123 · 19m ago
Understanding the Expression Problem in MVC and OOP
frumplestlatz · 2h ago
> with monads
There are a set of three short laws that define what a monad is. I’m not sure that really fits in with MVC, OOP, or design patterns.
It’s weird that your comment seems to be downvoted. Monads have a precise mathematical definition. Comparing them to those other broad, handwavy things is delusional ignorance.
metanonsense · 9m ago
But isn’t that exactly what GP meant? There is an original, very precise but also very abstract definition (and what is more abstract than category theory). Then people come along who give a different definition that matches the original one in their specific context („three laws in Haskell“). After that people take these three laws and apply them (sometimes overly simplistic) to other contexts („just give it a flatMap in Scala to get a monad“). And at some point the original meaning got lost, and there are competing definitions out.
frumplestlatz · 1h ago
I see that your comment is now downvoted into the negatives.
When people are confused by something, they will often blame the target of their confusion instead of admitting to themselves that they don’t understand.
hurril · 24m ago
You both have good points. But there is monads the mathematical and programmatic concept, and there is also something a little bit handwavy in how these things are incorporated into an application architecture. The latter is what is being used on the one hand in comparison to MVC, etc, on the other.
I.e.: a monadic architecture in Haskell is good, but one in Java is going to suck. A sort of half-way point is in The Elm Architecture, which is a sort of deconstructed IO monad.
(Writing this as someone with decades of experience in writing monadic architectures.)
yakshaving_jgt · 16m ago
What does a “monadic architecture” look like? I’ve been writing web applications in Haskell for the past decade and all of them are MVC.
frumplestlatz · 19m ago
I don’t really understand what a “monadic architecture” is supposed to mean.
Haskell’s `Monad` type class is hardly the only possible encoding of a monad. They’re just a simple mathematical construction with useful properties, and — like functors and applicative functors — they emerge everywhere.
aryehof · 2h ago
> Smalltalk's OOP is nothing like what existed either before or after, but since Alan Kay invented the term.
Rubbish. In terms of OO language constructs, Smalltalk is almost entirely derived from Simula. Let’s not revise history.
whstl · 2h ago
This is an oversimplification, and part of the problem I mention.
The "big leap" in Smalltalk was the idea that everything is an object and computation is message-passing, not just classes and instances. That’s not from Simula. Simula was more like an extension of Algol with OO bolted on. Smalltalk was a whole new conceptual model, which is not as simple to explain as Simula/C++/Java-style OOP.
mpweiher · 1h ago
Hmm...have you looked at Smalltalk-72?
Now Alan makes it clear that the inspiration for OO came from Simula (and a bit from the Burroughs 220 and 5000, from Sketchpad etc.), but to say that Smalltalk is just that is a stretch at best.
The more direct line goes from Simula (Algol with classes) to C++ (C with classes).
to11mtm · 2h ago
IDK I think it's still worth considering where certain languages 'got the right things right together' to be constructive...
That said as someone fairly unfamiliar with Smalltalk I'd like an example of what other parts of Smalltalk play well with it's OOP Sauce...
travisgriggs · 42m ago
For me, one of the examples was control flow. Smalltalk had none. Or, rather, it had one: send a message to an object/receiver. It was cool that ifTrue:ifFalse: was just a message you sent to a Boolean with a closure (or two) as an argument. And various iterations as well, so you could write your own. This you can do in Swift/Kotlin/etc as well of course. Where Snalltalk went next level was that closures were objects to. And you got them to run with messages like value/value:/value:value:, etc. In most languages with anon functions/closure, you just use argument list (i.e. parens) to invoke it. But you can’t send messages to the closure itself. Smalltalk had a host of introspection methods you could send to it, different flavors of evaluation, and of course any of the ones it inherited from Object. But where it got really cool (imo), was that you could add your own methods to BlockClosure. So you could implement all kinds of control messages on anonymous functions yourself. This was cool, it was all objects, all the way down. Where “object” meant things you can add behavior to, and send messages to.
travisgriggs · 2h ago
As a former and long smalltalker who learned MVC from the ParcPlace crowd…
I used to say things like this. M and V were always pretty unambiguous, but “controller” was kind of like “Christianity”, everyone talks like it’s a unifying thing, but then ends up having their very own thoughts about what exactly it is, and they’re wildly divergent.
One of the early ParcPlace engineers lamented that while MVC was cool, you always needed this thing at the top, where it all “came together” and the rules/distinctions got squishy. He called it the GluePuppy object. Every Ux kit I’ve played with over the years regardless of the currently in vogue lets-use-the-call-tree-to-mirror-the-view-tree, yesteryears MVVM, MVC, MVP, etc, always ends up with GluePuppy entities in them.
While on the subject, it would be remiss to not hat tip James Depseys MVC song at WWDC
“Mad props to the Smalltalk Crew” at 4:18, even though he’d just sung about a controller layer in cocoa that was what the dependency/events layers did in various smalltalks.
neilv · 44m ago
Controller seemed fairly straightforward to me initially, when I was first learning Smalltalk (ParcPlace), and I took my simple understanding on faith.
My programs were simple, so M was data, V was presentations of the data, C was interaction on the M and maybe V.
It only got confusing when I got more experience.
travisgriggs · 41m ago
Where “interaction” meant user interaction.
jerf · 2h ago
One of the other markers of "true MVC" I look for is that you ought to have pervasive mixing and matching of the pieces. It is common for models to see some reuse in multiple "views" and "controllers", but if all or almost all of your controllers match up to precisely one view, then you're burning design budget on a distinction that is buying you nothing. If you've got strictly one-to-one-to-one matches for each model, view, and controller, then you're just setting your design budget on fire.
Another major aspect of the original "true" MVC is multiple simultaneous views on to the same model, e.g., a CAD program with two completely live views on the same object, instantly reflecting changes made in one view in the other. In this case MVC is less "good idea" than "table stakes".
I agree that MVC has fuzzed out into a useless term, but if the original is to be recovered and turned into something useful, the key is not to focus on the solution so much as the problem. Are you writing something like a CAD program with rich simultaneous editing? Then you probably have MVC whether you like it or realize it or not. The farther you get from that, the less you probably have it... and most supposed uses of it I see are pretty far from that.
catlifeonmars · 2h ago
> if all or almost all of your controllers match up to precisely one view, then you're burning design budget on a distinction that is buying you nothing.
This is a really insightful way to frame it.
skydhash · 1h ago
> If you've got strictly one-to-one-to-one matches for each model, view, and controller, then you're just setting your design budget on fire.
That's sensible. But it's generally useful to split your core state from your presentation, and then you'll find strands of logic that belongs to neither, generally glue code, but some can be useful enough to warrant a module of their own. Also your core state can be alien from the view itself (think a game data (invisible walls, sound objects) and the actual rendering).
Maybe this architecture is not MVC, but MVC can be a first stab for a quick and dirty separation. Then once a cleaner separation can be done by isolating specific modules (in layers, graph, whatever)
hurril · 18m ago
I think that a big problem here is the fact that in OOP, everything is an object, i.e.: a class. And if all you have is a hammer, then .... But it is much better to picture the model, controller and the view as emergent. But implementing this in OOP is too challenging because some things in either of those three domains are going to be a process, or a piece of state or a role, etc.
And in implementing some process, what is it? As in: what is its encoding in $language and where does it go?
So you end up with the local stamp collectors in the office and get into an argument of: it is part of the model, so should be in the Model class. "Process, nah, that is totally a controller aspect. It does something." etc.
kqr · 1h ago
Oooh. Now I get it. I've been dismissive of MVC for nearly as long as I've known it but I realise I've only seen the bad versions. What you describe as correct sounds much more sensible.
mmahemoff · 3h ago
A major advantage of pure models is testability. If your conception of a "model" is perversely a user-facing widget, congratulations, you'll need to write UI tests that simulate button presses and other such user actions, and maybe even inspecting pixels to check resulting state. Tests like that are a pain to compose and are fragile since the UI tends to evolve quickly and may also be vulnerable to A-B experiments. Juice ain't worth the squeeze in most cases.
In contrast, pure model components tend to evolve slowly, which justifies the investment of a comprehensive test suite which verifies things like data constraints, business logic, persistence. If automated testing were seen as a priority, this would be a no-brainer for any serious app. However, testing tends to be underappreciated in app development. This goes some way to explaining why frameworks carelessly fold in M, V, C to the same component.
mikepurvis · 3h ago
Yes to all of this with the provisos that a) there’s enough meat in terms of business logic and validation to justify the indirection of a separate object and b) you’re under a language or CI regime that can validate the boundary between the two classes for basic flubs like function misnames or bad arguments.
andrewflnr · 2h ago
> If your conception of a "model" is perversely a user-facing widget
Do people really do this? That's mind-numbing.
zkmon · 1h ago
It was basically the 3-tier architecture hijacked by some authors with hyper sales-pitch who messed it up beyond recognition. The 3-tier model has 3 simple layers - Data, Business, Front-end. The MVC inventors called data as "Model" - I could not get my head around this weird naming. What does "Model" mean in plain English? And why do you need those dotted lines between Front-end and Data layers bypassing the Business layer? MVC is a fake that lasted for decades.
mjevans · 3m ago
It makes so much more sense in that light.
It was __sold__ not to programmers, but to NON programmers.
The model is the underlying shape (the data in storage).
The Controller is like the security guard for the warehouse / building.
The View is what's presented to external clients (end users).
lukasb · 3h ago
Any implementation of MVC I've seen the V and the C are so tightly coupled the separation seemed artificial. Skill issue?
andrewflnr · 2h ago
Yeah, it's really hard to tease them apart in a GUI sort of environment, since the input is so tightly tied to the graphical view. Model and View have always seemed pretty obvious to me but I've never gotten a compelling answer as to what a controller is.
My best guess from this article, given then "associated by observer" link from View to Controller, is that the View is supposed to pass events to the Controller, which will interpret them into changes to the Model. But what's the format of these events that's both meaningfully separate from the View, e.g. could be emitted from different views to maybe different controllers, but doesn't just force the View to do most of the work we want the Controller to do?
skydhash · 1h ago
Controller is where your logic is. Your model is your state, and the view is presentation. Both are static. The controller is the dynamic aspect that update the view to match the state and update the state according to interaction or some other system events.
Splitting the logic from the state and presentation make the code very testable. You can either have the state as input and you test your presentation, or have the presentation as input (interaction and lifecycle events) and test your state (or its reflection in the presentation).
Also this decoupling makes everything more flexible. You can switch your presentation layer or alter the mechanism for state storage and retrieval (cache, sync) without touching your logic.
dsego · 23m ago
In the server-side web world the controller should ideally only receive http actions and call services or fat models. It should have no business logic, only validation and parsing. In the frontend UI world the controller is bound to UI events and communicates those from the view to the model objects. (1).
At least in my head, the 'controller' is what can either take 0 or more parameters or input models as 'input' and the controller can either provide direction to the browser as to what to do next.
e.x. in a 'proper' ASP.NET MVC 4 project I 'inherited', the View took input data in and with a tiny bit of JS magic/razor fuckery around the query page etc, but overall the controllers would return the right hints for the Razor/JS 'view' to move the application flow along or otherwise do a proper reload.
mjevans · 1h ago
Agreed, but maybe my mental model is splitting the 'Controller' aspect into the client / server model. Everything must get validated server side, there's no other rational choice. Otherwise you cannot enforce any consistency or business logic.
That just leaves formatting the requested changes into a language the server model accepts.
Maybe model is more 'database', controller is API interface (server side + client request requirements), and view is end user render?
avodonosov · 53m ago
Everyone knows what is model. Almost noone knows what is controller.
adityaathalye · 1h ago
I used to be very confused about MVC and MVCC and what have you---I can't keep design patterns straight in my head (personal limitation)---I finally went down a rabbit hole of trying to figure it out from scratch.
Like, why do we even need any of that stuff? I blogged about it [1] and spoke about it [2] and the post even got some HN love [3].
The opening parable concludes with this...
Multitudes of sworn "Rails developer"s, "Laravel developer"s, "Django
developer"s, "Next.js developer"s and suchlike throng the universe…
Why?
...
...
Once upon a time, there was one.
WebObjects.
Now they are numberless.
The occasional email and DM gives me succour that I am not alone in my confusion. Even people who've "grown up" using traditional MVC frameworks took a minute to self-check and felt "huh, looks like I can look harder at this thing that I do".
Clojuring the web application stack: Meditation One
165 points by adityaathalye 3 months ago | 39 comments
pixelworm · 3h ago
I think nearly every definition of MVC I've read has been different. At this point it just means you split something into three classes as far as I can tell.
I think what Qt is doing with the Model being written in C++ and notifying to a QML View using Signals & Slots is the best way to do it.
b_e_n_t_o_n · 2h ago
I feel like MVC is trying to get at a core concept of having your application state in one place, your view objects/state in another place, and then having a third piece that updates the application state.
So like in React, you'd have your Redux store as the Model, React components (with useState etc) as the View, and then your Controller is the reducer which is called from UI code and updates the Model.
Maybe that's incorrect definitionally, but it makes sense to me.
samtheprogram · 1h ago
> For example, in ObjC an int is an object, but it is not observable. However, an ObjC object with an int property is observable using Key-Value Observing
I haven't written Objective-C in a decade or so, but isn't this a pretty big mischaracterization of the language? NSInteger is a typedef to a C type IIRC, while there's NSNumber for the cases you want an object and/or are deserializing -- and which has observable propeties?
gundmc · 3h ago
Getting totally lost in several different enterprise software implementations of MVC was a major contributor to my impostor syndrome early in my career. Glad to have some sort of vindication that I wasn't alone
aryehof · 2h ago
This perpetuates the myth that a model is an object. One object. This has lead to todays common misconception that a model is one anaemic data-bucket representing typically a database table.
Instead a model is one or more collaborating objects.
hansvm · 2h ago
And what do you call the Model object holding those collaborating objects? Is that not still one object? The article explicitly supports your position that models can be complicated (see the paragraph starting with "to support more complex views").
jpalomaki · 1h ago
It would be interesting to read a case study of how the MVC was applied in some larger SmallTalk app.
mpweiher · 46m ago
Largely agreed, I wrote about the confusion around 10 years ago[1] and wrote 2 years later about the problem of concept capture we have with MVC[2] :
I'd like to add a couple of points to TFA.
Yes, it is absolutely paramount to understand what the model is. It is the abstract representation of the domain. The rest of the architecture serves the model and should be as minimal and transparent as possible. Particularly Apple-space code tends to get this very wrong by having very thin models and all the logic in the Massive View Controllers.
It is also important to understand that MVC is not about specific objects, but rather about roles and communication patterns. Different objects can have those roles, and they can actually be usefully combined at times (though do keep the model separate, please).
One crucial part of the communication patterns that TFA duly notes is that models do not know about views. That means that views only ever pull data from models, models never push data towards views. It also means that in an update, the model just says "I have changed". It does not send the data that changed. The "the model changed" notifications is also the only reason a view gets updated.
No, the controller doesn't poke the correct updated data into the view after it has notified the model, that leads to and update chains and cycles.
Having the view always update itself from the model means that view state is always consistent, even if you miss or skip intermediate updates. Skipping intermediate view updates is important, because the model can potentially change a lot faster than the view can update, never mind the user processing those view updates.
Also, one common misunderstanding (that also leads to Massive View Controllers) is the mistaken belief that views must not edit models, that you must have a controller to edit it. That is actually not in the original MVC paper[3]. In the original paper, views can edit models and that makes things a lot more sensible.
Controllers are a bit of a catch-all for stuff that didn't fit anywhere else. The Views in Cocoa actually take over some of those roles, and that works absolutely fine. (Imagine my confusion when ViewControllers were introduced...)
The reason MVC got so abused was because of RAD frameworks: rapid application development. Most of this started with visual basic.
Basically, the thinking was to let the programmer design the view and then implement the code-behind. I'll spare you from my rants about this, but it was popular.
Nowadays, with vibe coding, there is no need to use obtuse design patterns for the sake of RAD. Sensible architectures can easily by used by LLMs without sacrificing engineer or designer agility.
And then, 10, 20 years after the fact, people will start attacking popular implementations that differ from the original using some "new canonic interpretation" that is either extremely recent, or an interpretation that is old but was lost in time.
This is especially common around Smalltalk and OOP for some reason. Smalltalk's OOP is nothing like what existed either before or after, but since Alan Kay invented the term, Smalltalk is weaponised against C++/Java-style OOP. Not that C++/Java OOP is the bees knees, but at least their definition is teachable and copyable.
Design patterns suffer because in most explanations the context is completely missing. Patterns are totally useless outside very specific contexts. "Why the hell do I need a factory when I can use new"? Well, the whole point is that in some frameworks you don't want to use new Whatever, you dummy. If only this was more than a two-sentence blurb in the DDD book (and the original patterns book totally glosses over this, for almost all patterns).
And monads became the comical case, because they are totally okay in Haskell, but once it gets "explained" and migrated to other languages they become this convoluted mostly useless abstraction at best, footgun at worst (thinking of the Ruby one here).
Like everyone totally forgot patterns are mainly for understanding existing systems like you use a framework - hey this looks like a factory let’s use one from the framework we built stuff with instead of implementing our own.
Besides of course every developer wanting to build framework so others adhere to what he built not the other way around ;)
This is what happened with REST too, and it frustrates me more than it probably should.
The original pattern is such a good idea and not even remotely abstract. It's a well defined architectural pattern for a well defined problem yet people still managed to bastardize it to the point that the term REST barely means anything today
It's hard to define how a pattern can be useful, because they're patterns, not recipes or snippets. They're supposed to fit in the reader's solution, not the author's examples. You're supposed to have the problem before reaching out for a solution and patterns are not solutions, they're models of solution, each with their own tradeoffs, costs and advantages.
Every `new` can be a factory or builder, but usually `new` is the right thing
You could say, the key to getting MVC correct is understanding the Expression Problem, and designing its solution into your programming language in the first place, so you don't need MVC, but if you want to do it, it becomes actually neat and clean and modular.
There are a set of three short laws that define what a monad is. I’m not sure that really fits in with MVC, OOP, or design patterns.
https://wiki.haskell.org/index.php?title=Monad_laws
When people are confused by something, they will often blame the target of their confusion instead of admitting to themselves that they don’t understand.
I.e.: a monadic architecture in Haskell is good, but one in Java is going to suck. A sort of half-way point is in The Elm Architecture, which is a sort of deconstructed IO monad.
(Writing this as someone with decades of experience in writing monadic architectures.)
Haskell’s `Monad` type class is hardly the only possible encoding of a monad. They’re just a simple mathematical construction with useful properties, and — like functors and applicative functors — they emerge everywhere.
Rubbish. In terms of OO language constructs, Smalltalk is almost entirely derived from Simula. Let’s not revise history.
The "big leap" in Smalltalk was the idea that everything is an object and computation is message-passing, not just classes and instances. That’s not from Simula. Simula was more like an extension of Algol with OO bolted on. Smalltalk was a whole new conceptual model, which is not as simple to explain as Simula/C++/Java-style OOP.
Now Alan makes it clear that the inspiration for OO came from Simula (and a bit from the Burroughs 220 and 5000, from Sketchpad etc.), but to say that Smalltalk is just that is a stretch at best.
The more direct line goes from Simula (Algol with classes) to C++ (C with classes).
That said as someone fairly unfamiliar with Smalltalk I'd like an example of what other parts of Smalltalk play well with it's OOP Sauce...
I used to say things like this. M and V were always pretty unambiguous, but “controller” was kind of like “Christianity”, everyone talks like it’s a unifying thing, but then ends up having their very own thoughts about what exactly it is, and they’re wildly divergent.
One of the early ParcPlace engineers lamented that while MVC was cool, you always needed this thing at the top, where it all “came together” and the rules/distinctions got squishy. He called it the GluePuppy object. Every Ux kit I’ve played with over the years regardless of the currently in vogue lets-use-the-call-tree-to-mirror-the-view-tree, yesteryears MVVM, MVC, MVP, etc, always ends up with GluePuppy entities in them.
While on the subject, it would be remiss to not hat tip James Depseys MVC song at WWDC
https://youtu.be/kYJmTUPrVuI?feature=shared
“Mad props to the Smalltalk Crew” at 4:18, even though he’d just sung about a controller layer in cocoa that was what the dependency/events layers did in various smalltalks.
My programs were simple, so M was data, V was presentations of the data, C was interaction on the M and maybe V.
It only got confusing when I got more experience.
Another major aspect of the original "true" MVC is multiple simultaneous views on to the same model, e.g., a CAD program with two completely live views on the same object, instantly reflecting changes made in one view in the other. In this case MVC is less "good idea" than "table stakes".
I agree that MVC has fuzzed out into a useless term, but if the original is to be recovered and turned into something useful, the key is not to focus on the solution so much as the problem. Are you writing something like a CAD program with rich simultaneous editing? Then you probably have MVC whether you like it or realize it or not. The farther you get from that, the less you probably have it... and most supposed uses of it I see are pretty far from that.
This is a really insightful way to frame it.
That's sensible. But it's generally useful to split your core state from your presentation, and then you'll find strands of logic that belongs to neither, generally glue code, but some can be useful enough to warrant a module of their own. Also your core state can be alien from the view itself (think a game data (invisible walls, sound objects) and the actual rendering).
Maybe this architecture is not MVC, but MVC can be a first stab for a quick and dirty separation. Then once a cleaner separation can be done by isolating specific modules (in layers, graph, whatever)
And in implementing some process, what is it? As in: what is its encoding in $language and where does it go?
So you end up with the local stamp collectors in the office and get into an argument of: it is part of the model, so should be in the Model class. "Process, nah, that is totally a controller aspect. It does something." etc.
In contrast, pure model components tend to evolve slowly, which justifies the investment of a comprehensive test suite which verifies things like data constraints, business logic, persistence. If automated testing were seen as a priority, this would be a no-brainer for any serious app. However, testing tends to be underappreciated in app development. This goes some way to explaining why frameworks carelessly fold in M, V, C to the same component.
Do people really do this? That's mind-numbing.
It was __sold__ not to programmers, but to NON programmers.
The model is the underlying shape (the data in storage).
The Controller is like the security guard for the warehouse / building.
The View is what's presented to external clients (end users).
My best guess from this article, given then "associated by observer" link from View to Controller, is that the View is supposed to pass events to the Controller, which will interpret them into changes to the Model. But what's the format of these events that's both meaningfully separate from the View, e.g. could be emitted from different views to maybe different controllers, but doesn't just force the View to do most of the work we want the Controller to do?
Splitting the logic from the state and presentation make the code very testable. You can either have the state as input and you test your presentation, or have the presentation as input (interaction and lifecycle events) and test your state (or its reflection in the presentation).
Also this decoupling makes everything more flexible. You can switch your presentation layer or alter the mechanism for state storage and retrieval (cache, sync) without touching your logic.
(1) https://github.com/madhadron/mvc_for_the_web
e.x. in a 'proper' ASP.NET MVC 4 project I 'inherited', the View took input data in and with a tiny bit of JS magic/razor fuckery around the query page etc, but overall the controllers would return the right hints for the Razor/JS 'view' to move the application flow along or otherwise do a proper reload.
That just leaves formatting the requested changes into a language the server model accepts.
Maybe model is more 'database', controller is API interface (server side + client request requirements), and view is end user render?
Like, why do we even need any of that stuff? I blogged about it [1] and spoke about it [2] and the post even got some HN love [3].
The opening parable concludes with this...
The occasional email and DM gives me succour that I am not alone in my confusion. Even people who've "grown up" using traditional MVC frameworks took a minute to self-check and felt "huh, looks like I can look harder at this thing that I do".Clojuring the web application stack: Meditation One
[1] blogged: https://www.evalapply.org/posts/clojure-web-app-from-scratch...
[2] talked: https://www.youtube.com/watch?v=YEHVEId-utY&list=PLG4-zNACPC...
deck: https://www.evalapply.org/posts/clojure-web-app-from-scratch...
source: https://github.com/adityaathalye/clojure-multiproject-exampl...
[3] discussed: https://news.ycombinator.com/item?id=44041255
165 points by adityaathalye 3 months ago | 39 comments
THE OG
So like in React, you'd have your Redux store as the Model, React components (with useState etc) as the View, and then your Controller is the reducer which is called from UI code and updates the Model.
Maybe that's incorrect definitionally, but it makes sense to me.
I haven't written Objective-C in a decade or so, but isn't this a pretty big mischaracterization of the language? NSInteger is a typedef to a C type IIRC, while there's NSNumber for the cases you want an object and/or are deserializing -- and which has observable propeties?
Instead a model is one or more collaborating objects.
I'd like to add a couple of points to TFA.
Yes, it is absolutely paramount to understand what the model is. It is the abstract representation of the domain. The rest of the architecture serves the model and should be as minimal and transparent as possible. Particularly Apple-space code tends to get this very wrong by having very thin models and all the logic in the Massive View Controllers.
It is also important to understand that MVC is not about specific objects, but rather about roles and communication patterns. Different objects can have those roles, and they can actually be usefully combined at times (though do keep the model separate, please).
One crucial part of the communication patterns that TFA duly notes is that models do not know about views. That means that views only ever pull data from models, models never push data towards views. It also means that in an update, the model just says "I have changed". It does not send the data that changed. The "the model changed" notifications is also the only reason a view gets updated.
No, the controller doesn't poke the correct updated data into the view after it has notified the model, that leads to and update chains and cycles.
Having the view always update itself from the model means that view state is always consistent, even if you miss or skip intermediate updates. Skipping intermediate view updates is important, because the model can potentially change a lot faster than the view can update, never mind the user processing those view updates.
Also, one common misunderstanding (that also leads to Massive View Controllers) is the mistaken belief that views must not edit models, that you must have a controller to edit it. That is actually not in the original MVC paper[3]. In the original paper, views can edit models and that makes things a lot more sensible.
Controllers are a bit of a catch-all for stuff that didn't fit anywhere else. The Views in Cocoa actually take over some of those roles, and that works absolutely fine. (Imagine my confusion when ViewControllers were introduced...)
[1] https://blog.metaobject.com/2015/04/model-widget-controller-...
[2] https://blog.metaobject.com/2017/03/concept-shadowing-and-ca...
[3] https://web.archive.org/web/20090424042645/http://heim.ifi.u...
Basically, the thinking was to let the programmer design the view and then implement the code-behind. I'll spare you from my rants about this, but it was popular.
Nowadays, with vibe coding, there is no need to use obtuse design patterns for the sake of RAD. Sensible architectures can easily by used by LLMs without sacrificing engineer or designer agility.