11 ms·
Model View Controller isn't
- mpweiher 8y agoYep: https://blog.metaobject.com/2015/04/model-widget-controller-mwc-aka-apple.html https://blog.metaobject.com/2015/04/model-widget-controller-...
- sparkie 8y agoMy understanding of the Model-View-Adapter pattern is that the adapter is the dependant of both the view and the model, which are disjoint objects. The diagram shown here has the arrow inverted between the adapter and the view, and the author mistakenly assumes it is isomorphic to the MVVM pattern. This might seem nitpicking, but it's an important distinction. In the MVA pattern, the adapter is the only thing that knows about both the model and the view, ensuring that the two are cleanly separated. The MVA pattern is underused. People have a tendency to make their views dependant directly on the model, or vice-versa, and often don't keep a clean separation.
- mpweiher 8y agoI'd say the MVA (or MVP, or Apple MVC) pattern is overused. There is usually neither a point to separating the view and the model like that, nor is it usually possible. In practice, you get lots and lots (and lots and lots) of glue code that is (a) boring, (b) repetitive, (c) error-prone and (d) non-reusable. The code is non-reusable because it is specific to both the view and the model. And it doesn't usually help in keeping the view model-agnostic, because after all the view is there for displaying the data that's in the model. Additional layers can't change that fact. See also: Massive View Controller.
- deleted 8y ago[deleted]
- chiefalchemist 8y ago> "because after all the view is there for displaying the data that's in the model." I wouldn't disagree. But I also believe there's another way to look at the view, and that is as the interface between the application and the user. That UI has or needs to have (design) patterns, a la Atomic Design for example. http://atomicdesign.bradfrost.com/ http://atomicdesign.bradfrost.com/ For example, a list is a list is a list. In a well designed UI / UX that will follow / maintain a pattern. At that point, there's no real relationship per say to particulars in the model. The view / partial is "free standing" and can be repurposed as required. In the mind of the view, there is no model. Maybe I'm splitting a hairs and/or have gone off on a tangent? My apologizes.
- usrusr 8y agoI would conceptually put reusable view components ("a list representation") completely outside of the scope of all MV* thinking. The "V" part is a composition of high or low level view components, not the components themselves (at implemention time - at runtime the view is the sum of active components). When you write universally reusable view components, you are not implementing the V of an MV*, you are working on tools to implement a V. Just like writing a database engine isn't defining a domain model.
- mpweiher 8y agoHmm... > a list is a list is a list. I would think that to be useful, a list will be a list of something. And that something will almost certainly be domain/model specific. Even if you expose just a list of strings, those strings will have some sort of semantic actions associated with them.
- chiefalchemist 8y agoYes. But it's not (or shouldn't be) a one to one between view and model. At least that particular view should be independent. Note: It was simply a basic example. The crux being to also look at the view from the frontend - user and frontend dev, and not only from the model forward. Fwiw I've recently taken over a project where I've found the same essentially partial four times. Not fatal, but more to maintain, as well as confusing when you're trying to unscramble things.
- deleted 8y ago[deleted]
- westoncb 8y agoFrom the conclusion: > If you design a system, it is not helpful to consider options like MVC vs MVVM vs MVP. Instead, identify potential problems and if necessary solve them. I think that's a pretty good take on it. There's an annoying tendency for most conversations including the notion of MVC to devolve into nitpicking about which variant is actually being discussed and whether some architecture is 'really' MVC or something else that looks like it. Its main value is in an abstract principle that it references: when modeling something, it's useful to separate a thing's essence from representations of that essence (the Model in MVC would be the essence and Views representations). This is an idea that shows up all over the place; it's almost certainly related to human cognitive structure in some way. (The Controller component is more arbitrary; you can see it pointed out in the article also that it was more related to implementation than the more general Model/View concepts.) One way I've found useful for thinking about the principle is in terms of causality within a system. When you're separating out the model/essence from the view/representation portions of a system, the most important distinction is: the essence carries all the information necessary to determine (a configuration of) the representation. In this case, you can set up a mapping from the essence to the representation once; after that, you can stop thinking about the view/representation because changes to the model/essence already cover everything. It's a very general kind of information compression that helps us manage system complexity by creating causal hierarchies. (An example of another kind of 'causal hierarchy' I was thinking about recently: the decomposition of changes in position in Newtonian mechanics ultimately to forces (rather than working with e.g. velocity directly). If you know about the forces (and mass), they imply everything you need to know about acceleration, from which you may deduce, velocity, and then position. Once you have that mapping from force->acceleration->velocity->position your mind is freed up to only thinking about forces.)
- chiefalchemist 8y ago> "There's an annoying tendency for most conversations including the notion of MVC to devolve into nitpicking about which variant is actually being discussed and whether some architecture is 'really' MVC or something else that looks like it." Agreed. I'd like to add, for as long as I've been in any code / tech discussions (which goes back to the first commercially available home PCs), conversations nearly always default to nitpicking about something. Anecdotally, many of the tech-minded seemed to be exhibitionists. They'll go out of their way to show everyone else they're willing to masturbate over the details of some technology they hold close to their heart (?). Sorry. I had to get that off my chest.
- catpolice 8y agoI tend to use the "model" and "view" concepts a lot when discussing architecture, but in my experience it's almost always a mistake to try and reference any specific MV* pattern for explanatory purposes - it does not have the effect of making the discussion clearer. The issue is that there isn't actually a consensus about what constitutes the definitional features of these patterns, especially when it comes to how the concepts involved actually translate into code. For any sufficiently notable discussion of an MV* pattern, you're going to find an argument in the comments about whether the author actually understands the pattern or is talking about something else, and typically the commenters will be talking past one another. Note that I'm NOT claiming that there's anything wrong with your favorite explanation of MV* - it may be perfectly well defined and concrete and useful once you understand it. The issue is a feature of the community: lots of other people have a different (and possibly worse) understanding of what MV* means, so when you start talking about it and your understandings don't align, confusion arises. Getting those understandings back in alignment is more trouble than the acronyms are worth. I've seen enough conversations about concrete development issues suddenly turn into disagreements about the meaning of words to realize that nothing useful is conveyed by mentioning MV* and assuming anyone knows what you're talking about - it's better to spell out exactly what you mean in reference to the code you're actually talking about, even if you have to use more words.
- deleted 8y ago[deleted]
- hyperpallium 8y agoGo to, let us go down, and there confound their pattern language, that they may not understand one another's speech.
- dwaite 8y agoI tend to think of MV* as a misnomer, because people generally seem to understand now that "Model" constitutes the business logic and any associated business data (be it a database or document). But every single environment is going to have a different circle drawn around what a View is - what is provided, what you are expected to build yourself, and how to interface the two. For instance, the V and C are partially a separation assuming it is appropriate to have a decoupling of input and output. The most important concept is that your model should be separate from all that. If you want to show the model in some new clever way, that should be via some View-ish functionalities manipulating data gained from the model. If you want some cool new behavior or functionality though, you should put that business logic entirely within the model. Then, you can properly control the boundary between the two sides - if all you do is add new methods or expose new data without changing behavior, you know that everything outside the model will still work without change. Start changing existing behavior, and your UI pieces will likely need to change to accommodate that.
- drostie 8y agoThe absolute most important thing to understand about models as they were originally intended, is that they are not descriptions of a data model per se. This is not to say that data modeling is not important, or that your model won’t have a similar shape as your data model; it will. But that is not the original point. In MVC as it was originally understood, a model is a list of subscribers. You can add yourself to that list, you can remove yourself from that list, and whenever a “value” changes, if you are on that list, you get a notification that the value has changed. You have a couple of different designs of these, depending on whether you want to send a current-state message as a notification on subscription, or just give everybody read access to the current state. The latter commits you to initializing your models in ways that indicate the absence or staleness of data (someone loads your app, you need to send out a network request to get a new thing) but also allows you to use variable scope to augment how much multiplexing and state tracking you need. Models vary from data models in having view-relevant data. So for example you switch from the type const urlList = new Model<UrlRow[]>([]) to the type type Fetching<x> = { state: "init" } | { state: "loaded", data: x }, | { state: "fetching", staleData: x }, | { state: "fetch error", staleData: null | x } const urlList = new Model<Fetching<UrlRow[]>>({ state: "init" }) Notice that these Fetching indicator statuses are a part of the data model for the UI, not the underlying data model that exists at the database level. If this begins to feel a lot like React and Redux, that is because there is a shared lineage there. React originally made its splash as “the V in MVC” but its setState/state system, while it doesn't contain a subscriber list, effectively does something equivalent by insisting on destroying anything that has the old values and then superficially identifying things which appeared to remain the same from moment to moment, with the basic model then being a “subscription tree.” Redux of course takes this from being a tree to being something more generic by making the store global... I think that models should not be app-global the way that Redux likes (it does not want to solve the problem of multiplexing models, which is understandable but it turns out to be a much simpler problem than you'd think) and that the pattern of reducers is more verbose than one generally needs, but I love the time travel browser features that Redux gives me. Somehow Redux has encouraged abominations like redux-thunk which complect separate concerns into the same dispatch function unnecessarily. But the fundamental workings involve that same basic structure: a subscriber list.
- 8y ago
- lostphilosopher 8y agoI'm not dogmatic about MVC (or any similar acronym), but I think MVC serves as a good reminder to (follow the more agreed upon maxim to) separate your concerns. Your application logic, data, and presentation layers need not be intertwined.
- Retric 8y agoLike everything it’s a tradeoff. A signup page that just collects email addresses does not need to care about architecture. Best practices always have the hidden assumption that going deal with the same situations as 99/100 cases. But, clearly that’s not always true, so you need to keep in mind the reasoning behind them.
- stevebmark 8y agoI've always found MVC or any flavor of it to be a flawed paradigm. Instead, a separation of APIs, and clients that consume them, is a more pleasant way to work with things that need a view layer. "Controllers" are undefined things. We get frameworks like Rails that encourage spaghetti code placement (and make spaghetti a first class citizen), because the fundamental concept of a controller doesn't make sense.
- deleted 8y ago[deleted]
- dwaite 8y agoMVC actually works really well for a HTTP framework like rails, because the separation of input (the controller) and output (the view) fits well when your model is based on request/response. Rails goes a bit far in pushing for your model to be built around your database-backed data model (but does properly push you to include data integrity and business logic there as well). Since there is not object classification in rails called Spaghetti, I can't really speak to it being a first class citizen in rails - nor can I guess which of Rails' shortcomings you are referring to. Even with a client/API separation, your API still has input, output, and business logic - the three components of MVC. An API can benefit from having MVC once it has multiple views; for instance, if you later find you must support different clients utilizing multiple concurrent versions. In that vein, I consider a framework like Sinatra to be controller-centric - with both the model and view layers being optional and bring-your-own. I've certainly used it as MVC.
- mikekchar 8y agoI think the OP is probably complaining about people tending to put all of the business logic into the controller. This essentially leads the the controller functions being modular/procedural in nature rather than object oriented. And I think that's what they mean by "spaghetti" -- you have either a big honking function, or you have a whole bunch of functions with no clear place to put them. This is made worse with the strategy of "service objects", which are usually not objects, but rather highly coupled modules of functionality that expose all of the properties in a way that is global to the entire module. However, IMHO the OP is incorrect that the problem is with MVC. The problem is actually with the active record pattern (or, again in IMHO, anti-pattern). In active record, your "model object" has a one to one relationship with the (usually relational) table where you are storing the data. The problem with this is that what makes sense from an OOD perspective does not make sense from a relational perspective. This is why there are entire books written about the problems of object relational mapping. From a relational perspective, we want to store things in a way that makes the relational calculus cleaner. We want to be able to efficiently store and query the data. From the OOD perspective, we want to increase cohesion for the functionality by grouping common state together. These two goals are usually at odds. Just like we have a view layer in MVC with respect to the UI, so too do we need a view layer with respect to other kinds of external representations. Probably people don't remember the old, old frameworks where you designed forms graphically for the UI and the system automatically generated C++ code for the "model objects" that could be used to populate those forms. Most people don't know about these because they were an incredibly bad idea that thankfully died out. No sane developer would build their model objects to be one to one relationships with their UI view objects. The same should be true for other representations like the DB layer, or indeed communication layers (serialising model objects so you can ship out the data for a different application is incredibly common, but also incredibly bad). You want view objects to translate the data to and from the model objects. Once you've done that, then you can design your model objects so that they can sanely calculate your business logic. Your controller object become the thing that they were meant to be in the first place: objects that forward incoming requests on to the model layer and put the result into the view layer. Rails (at least if you are using ActiveRecord) is just broken. It's not a representation of how MVC should work. It works well enough for some cases, but gradually the stink gets worse and worse until you start asking yourself if there was some advantage to using Rails in the first place.
- dwaite 8y agoIn my experience, the most common way people get MVC wrong is equating "model" to "data model", and "controller" to "business logic". Since the controller is responsible for also interacting with a specific view, you haven't made your software decoupled, rather just spread logic into three buckets. IMHO, the real goal is establishing a somewhat stable boundary between the business logic and state and your UX, both to allow logic to be reused in other presentations and to allow both to evolve without constantly breaking code. MVC vs MVP or MVA is a difficult distinction IMHO, because the UX portion is really split between the view and controller, which may also include interactions with a more sophisticated UI system (for example, with its own input event handling and data binding). For a lot of these systems, what constitutes a "View" or a "Controller" really depends on the infrastructure provided to the developer. Template-based web frameworks can actually be fairly close to MVC - the controller handling the input request, translating that to commands against the model, and then taking data from the model and handing that off to the view to present to the user. A component-based system has components which constitute the UI presentation, but also handle user input and may have data binding. At this point you are far closer to "Model View Adapter", which as the article points out is what you'll see in most componentized frameworks. Again IMHO, but the difference between MVA and "Model View ViewModel" (MVVM) are really around implementation strategies for the adapter layer. That there are different strategies is one of the reasons that attempts by frameworks to simplify this adapter layer result in different terminology (for instance, ViewControllers and Delegates and DataSources, vs ViewModels)
- virmundi 8y agoI like Clean Architecture. There is a particularly annoying, but powerful piece: the Presenter. While it makes for some awkward code, it does separate concerns. The controller has a use case, which is the business logic, injected into it. The controller also has the Presenter injected into it. The controller invokes like so: UseCase.execute(input, Presenter). The use case does its thing. Then calls presenter.present(ResultData). The presenter can be responsible for creating the actual response on the wire. It is also responsible for getting data from the database for lists, and other UI features. Finally, the Presenter invokes whatever machinations are required write update the client. In the case of HTML, the presenter knows which template to invoke. In JSON, just serialize the output. What's awkward about it is the .present when in failure, which in Go is all the time. if err != nil { presenter.present(FailureStruct) return } This is repeated all over the place. That return is important. Since the result is not returned from the UseCase, getting this wrong could lead to failure. In my code, the Unit of Work is managed by two entities: the controller and the presenter. The controller gets everything warmed up. The presenter knows when all the data calls complete. If the presenter is for an HTML page that needs to get data, the presenter is essentially a micro controller that couples the use case to the view. All of this is tucked away nicely. The domain gets to drive a lot. Everything is testable since the presenter is type CreateUserPresenter interface { present(Output) } Interfaces for everyone. Use Case has interfaces for the domain repositories it needs. Controller gets injected, or in my case calls a factory, the use case and presenter. Things are actually decoupled. No more transaction scripts spread across multiple thinly veiled layers.
- regularfry 8y agoWhy is the result not returned from the use case?
- virmundi 8y agoTo truly seperate the controller from the process of invoking the use case and view. A better question is why does the use case have the presenter pushed as part of the invocation? You could easily have a use case take an input and nothing else. Why have the controller get an instance of the presenter, pass that to the use case, then have the use case call the presenter? The answer is that it makes explicit the fact that there will be a response. It also allows the controller to either directly, or indirectly, more likely indirectly, get the UI component ready. In my codes case, the presenter is gained through a factory method. The factory takes the response for the request, context and that's it. It creates the REST response handler that holds onto the response struct, in Go. This allows the system to safely switch the thread underneath the actual request/response of the handler. Since the Use Case gets the presenter as an argument, it naturally carries the presenter when the thread changes without having to store it into the Context. All of this fits nicely with Go. Go handlers return void. So in the handler, my controller, the use case kicks off, and the handler is done. The presenter sets the response code, body, and anything else. For more information. https://softwareengineering.stackexchange.com/questions/357052/clean-architecture-use-case-containing-the-presenter-or-returning-data https://softwareengineering.stackexchange.com/questions/3570...
- svilen_dobrev 8y agopeople... two things: * MVC is not only about user interaction/UI. User interaction/UI is just most used area. i have used MVC inside a compiler, and inside data-crunching-pipeline. Fits perfect, as long one abstracts oneself from what user/business means. * MVC is not single thing, it's a fractal idea. The View (may) has its own internal MVC (e.g. in UI: a widget, i.e. scrollbar), Model has its own (e.g. somewhat around ORM), ... and this may go further down - or up. * it's a general concept saying that 3 islands/aspects talking to each other are needed for complete system; 2 are too few, 4 might be too many. have fun
- axilmar 8y agoI think part of Controller should be in the Model, because I often found business logic is highly coupled with the data. I've more often used the Model-View pattern, where the business logic was inside the Model. What I have decoupled from the above is State controllers though; State controllers have to do with the application itself, they have nothing to do with the data or the presentation of them.
- tabtab 8y agoThe biggest problem is that the Web doesn't fit GUI's well. MVC and its variants are an ugly fudge, largely to make the stateless Web protocols "seem" stateful. One has to split the work up into bigger teams to do something that was easy, trivial, one-man-band work in things like Powerbulder, Delphi, Oracle Forms, etc. We devolved from the 1990's, turning bicycle science into rocket science. Our Oracle Forms team is 4x more productive than our MVC team. It's embarrassing. Sure, the web apps are arguably "prettier", but at a cost. (If not for Java security going bad, our org would keep using Forms. Oracle should have kept the "EXE" based client.)