Related
There are different levels I'm asking this question at.
Case 1: Let's think about the typical drill-down design. Say a table view controller has an array of custom objects, and tapping a cell will push a view controller that allows the user to modify the object represented by the cell. In this case, should the pushed view controller have the custom object as a property of its own, or use a data source/delegate protocol to edit the custom object but not own it.
Case 2: A similar but slightly different situation is this. I'm using a singleton store to handle an array of bank accounts in my app. A view controller will show a list of the accounts, and I'm wondering if I should have the array of accounts as a property in my view controller or get the array via the store. (The array of accounts is accessed quite often.) I guess the only difference is a single object vs. an array of objects. I'm curious about how heavy these arrays can be, so whether it's faster to load the array from the store each time or have it as a property in the view controller.
Case 3: When should the local file system be used? In my app's example, bank accounts are accessed quite often, so I have them unarchived and set as properties upon launching the app, but for much bigger data, I only load them from the file system when they should be displayed or edited. I'm still not sure what the right way is.
I am starting with MVC since a few weeks and now I have a best practice question:
I have basic data of my project, which are around 30 to 40 propertys, mostly strings.
I have a model with all my propertys for this data called "GeneralDataModel" and of course a Controller "GeneralDataController" and my View "GeneralDataView".
Now I want to have a setting page for this data.
I created a view (GeneralDataSettingView) a controller (GeneralDataSettingController) and a Model (GeneralDataSettingModel).
In fact, most of the data are the same, e.g. I have to load all data into the model when the view is loaded to display them in my TextboxFor.
Some methods are not the same, e.g. a method to save my data which only my setting page but not the display page have.
I know a few methods to have not the same model data and controller methods over and over again - e.g. I could work with inheritance, I could simply extract the methods in a class above where both controllers have access too...
What is the best practice here?
I don't like the "pull data for all views in group" approach, especially if you have to hit multiple tables and pull data you are not using in a particular set of data in a specific view.
One pattern that can work, depending on your need, is pull the common data and then use a decorator pattern to pull the additional data. But jumping to decorator can be dangerous, as it leads you to try to use it everywhere.
I like the "solve for each page and then refactor to patterns" approach, as you are not trying to then make things fit to the first pattern you find (ie, the hammer searching for nails methodology). But, if you have the pattern that shows a pattern like decorator solves the problem efficiently, then go that direction.
Hope this helps.
Want to improve this post? Provide detailed answers to this question, including citations and an explanation of why your answer is correct. Answers without enough detail may be edited or deleted.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I have a drop down list that displays values from a table to the end user. I would like to have these values be sorted alphabetically.
According to proper MVC design, at what layer should I place my sorting logic: the model, the view, or the controller?
EDIT: In response to LarsH's question, "Do you mean code that determines what sort order is desired? or code that performs the sort?", I was originally referring to the code that determines what sort order is desired.
Who controls the sort order?
(From Wikipedia)
1) Natural order within the data itself:
The order is part of the Model, so it should go there. A raw pull of "all data" would return the data in the sorted order, and there is no interface to choose the sort order.
2) The user should control how they see the data:
The View would provide an interface (such as ascending/descending arrows) that interact with the Controller, and the Model understands the data well enough to do the requested sort on the data. However, a raw pull of the data doesn't necessarily have to be sorted, unlike in (1).
In either case,
The View doesn't understand that there's a sort going on, other that the ability to show which sort direction has been chosen. Don't put the logic there.
Small caveat
The sorting functionality could go purely in the View, under one circumstance (that I can think of offhand; there may be more):
A "dumb" sort where all the data is already in the view and it doesn't have to use any domain knowledge to do the sort. Very simple string or number comparison, for example. This is not possible in, for example, search results on a webpage when results are likely to be split across multiple pages.
(Note: this quote and citation is taken from #dasblinkenlight's answer, but we disagree on our interpretation of it. read his post and make up your own mind).
According to MVC description,
A controller can send commands to its associated view to change the view's presentation of the model (for example, by scrolling through a document). It can send commands to the model to update the model's state (e.g. editing a document).
Sorting logic (e.g., the sorting comparator/sorting algorithm) belongs in the model since it contains business rules and state data. Since altering the way the model data is sorted falls squarely into the "change the view's presentation of the model" category, the controller is responsible for "doing the sorting" by calling the model.changeSortedState() method.
According to MVC description,
A controller can send commands to its associated view to change the view's presentation of the model (for example, by scrolling through a document). It can send commands to the model to update the model's state (e.g. editing a document).
According to this, sorting logic belongs in the controller, because altering the way the model data is sorted falls squarely into the "change the view's presentation of the model" category.
EDIT: To clarify multiple misunderstandings voiced in the comments, the "sorting logic" is not the code that performs the sort; it is the code that defines the sort. The sorting logic compares individual items to each other to establish an order (e.g through an instance of IComparator<T>) or contains logic that constructs an object to be used for ordering by an external system (e.g. through an instance of IOrderedQueryable<T>). This logic belongs in your controller, because it needs knowledge related to the "business" side of your application. It is entirely sufficient to perform the sort, but it is separate from the code that actually performs it. The code that sorts may be in your view, in your model, or even in the persistence layer that backs your model (e.g. your SQL database).
None of the above. Sorting is business logic, and business logic doesn't belong in any of the three. Not every piece of code in your application will be a model, view, or controller.
What I generally do in my MVC apps is I have a service layer that performs all the business logic. The methods in the service layer should have a clean, simple API with well named parameters. You can then invoke those methods from your controller to manipulate the data in the models.
In that sense, the sorting is "in the controller", but the code itself that does the sorting should not be implemented in the controller, only invoked from there.
Definetly not the controller: It sends messages to view and model but should do as little work as possible. If the user can change the sorting that request gets handled by the controller by informing the model or the view about it.
Maybe the View if it is a pure View thing. If the Application works just as well without sorting then the sorting is just part of the representation and should go in the view.
If the ordering is inherent part of the domain it should go in the model.
Views are the part of MVC which is supposed to contain presentation logic.
Model layer is where business logic is contained.
Controllers only change the state of both, based on user input.
So the choice is - do you think that this is part of the domain business logic or presentation logic.
If you were implementing a proper MVC Model2 or classical MVC pattern, then I would say that the ordering of data provided by the model layer should be triggered by the view's request to the model layer. View asks for ordered data, model layer provides it.
But, since you are using ASP.NET MVC's interpretation of MVC pattern, which is a bit different then your standard MVC - the ViewModel instance should request ordered information from the model layer (for some reason ASP.NET framework thinks that templates should be called "views" and views should be called "viewmodels" .. it's strange).
I would usually do it in the controller to remain in line with the pattern as per the other answers. See below for reasoning.
I've been mulling this over and reading the answers and related material and pragmatically speaking I would say it would depend on your application for instance:
Is it a medium/large application and/or has multiple UI's associated with it (i.e. a Windows App, Web interface and Phone interface).
In this case I would probably construct a service layer and put it in
the business object and then call the appropriate method from the
controller.
If its a well defined single UI website and you're using something like EF Code First and you do not have or have no intention of creating a service layer and plan on using a simple out of the box Extension method to acheive it:
In this case I'd probably put it in the controller as pragmatically
its the best fit with regard to time/budget.
If its the same as the above BUT cannot be implemented with an out of the box extension method.
I may well choose to pop it in the Model class (if its truely bespoke
to that single type) as it would be more appropriate here than in a
controller. If the sort could be applied to more than one class then
I'd implement it in an extension method and then call it in the
controller.
To sum up:
Dogmatic answer: Service Layer
Pragmatic answer: Usually the controller
I would suggest sorting data from a table-data that is small enough to be useful in a dropdown list-should come from the DB already sorted via the query. To me, that makes the model the place the sort is applied.
If you are determined to do the sort by hand, I think there are good arguments for using either the model or controller as your preferred spot for logic. The limitation would be your particular framework. I prefer to manage data solely in the model. I use the controller to marry data(model) and presentation(view) as I've been (self)taught.
Whilst I agree in principle with the idea that sorting is Business Logic because by breaking it down to it's origin you would end up with something like "The client would like the Product page to display with the images sorted by date" then it becomes clear that the sort order for data is typically not arbitrary - even if there is no sorting as that's still a business decision by omission (an empty list is still a list).
BUT... These answer don't seem to take into account the advances in ORM technology, I can only talk in relation to the Entity Framework (let's avoid an argument about whether this is true ORM, that's not the point) from Microsoft as that's what I use, but I'm sure other ORMs offer similar functionality.
If I create a Strongly Typed view for a Product class using MS MVC and the Entity Framework and there is a foreign key relationship between the Product and Image table (e.g. FK_Product_Image_ProductId) then I would out-of-the-box be able to quickly sort the images during their display using something like this in the view:
#foreach(Image i in Model.Image.OrderBy(e => e.DisplayOrder)){ //etc etc... }
There was mention of a specific Business Logic layer, which I also use to perform 80% of my business logic, but I'm not going to write sort functionality into my Business Logic layer that mimics something that comes out-of-the-box from the Entity Framework.
I don't think there's a correct answer to this question, other than to say that; you should abstract complex business logic where possible but not at the cost of reinventing the wheel.
Assume that you have MVC website, WebForms website and a mobile application.
If you want sorting to be consistent between these presentation layers, then I'd say sort outside of the presentation layer. Service would be a good candidate.
Otherwise, I would store that logic in a view model. Why? Because it'll be reusable and easily testable.
Out of the three you have listed, I would say that it belongs in the controller. I don't really like placing this sort of logic in the controller, though. I usually create a service layer that the controller communicates with that will be responsible for communicating with the data store and handling sorting logic. For small applications it is fine sitting in the controller, though.
This is a question asked with the asp.net in mind, but since somebody did mention Rails, I thought it would be interesting to consider the problem in that context. In Rails, it is natural and pretty common to perform the sorting along with the retrieval as a controller action, since the framework and ActiveRecord/ActiveQuery api provisions for it. On the other hand, it is possible to define some sort of custom sort order for static items and put that in the model to be used by the controller, so the model can play a part in the sorting logic even though it does not carry out the operation directly. Whatever it is, it can be safe to say that putting the sort logic in the view is generally frown upon.
I'm slightly amused that some answers are absolutely against putting the sort in either the controller or the model, and I find them too pedantic for my taste, but I suppose it depends on the nature of the framework used and the usual conventions associated with it. I also agree with Bill K's comment that having the separation in the first place is more important.
I have read online that it is bad practice to use a "kitchen sink" model:
Rule #3 – The View dictates the design of the ViewModel. Only what is
required to render a View is passed in with the ViewModel.
If a Customer object has fifty properties, but one component only
shows their name, then we create a custom ViewModel type with only
those two properties.
Jimmy Bogard's subsequent explanation of how this is good, however, left me a little questioning. It'd be so easy to have my Model just contain a list of Customers, I could even use my POCO's.
So now I get to create custom little view model fragments for every page on the site? Every page that uses a Customer property would get one, but of course could not be shared since some of the information is extraneous, if one page used Age but not Name, for example. Two new mini view model classes right?
This is very time consuming, and seems like it'll lead to a million little custom view models - can someone elaborate as to the utility of this approach and why the easier approach is bad?
View model class can be used not only to transfer values, but it also defines data types (data annotations), validation rules and relations different then ones used in model. Some advantages that come to my mind right now:
There are different validation rules when you change user's password,
change his basic data or his subscription setting. It can be
complicated to define all these rules in one model class. It looks
much better and cleaner when different view models are used.
Using view model can also give you performance advantages. If you
want to display user list, you can define view model with id and name
only and use index to retrieve it from database. If you retrieved
whole objects and pass it to view, you transfer more data from
database than you need to.
You can define display, and editor templates for view models and reuse them on different pages using html helpers. It looks much worse, when you define templates for model POCOs.
If you would use your POCO objects as view models, you would essentially be showing your private objects and break the encapsulation. This in turn would make your model hard to change without altering the corresponding views.
Your data objects may contain details that are appropriate only to the data access layer. If you expose those things to the view, someone might alter those values that you did not expect to be altered and cause bugs.
Many of the same reasons as for having private members in OO languages apply to this reasoning. That being said, it's still very often broken because it's a lot of extra work to create all these "throw-away" models that only gets used once. There exists frameworks for creating these sorts of models, though the name eludes me, that can tie objects together and pick out the interesting properties only which takes away some of the drudgery from creating specific view models.
Your View Model tells the View how data should be shown. It expresses the model. I don't think its necessary to have two view models unless you have two ways to express your model. Just because you have two pages, doesn't mean you will be showing the data any different way, so I wouldn't waste time making two mini View Models when it can be in one reusable view model, Imagine if later you have a page that needs Name and Age, you would create another view model? It's absolutely silly. However, if you had two pages both showing 'Age' and it needed to be shown in a different way, then I would create another one.
I am currently unconfident, if I can put a "if/else"-construct into my view?
How much logic do you put in your views?
My dilemma:
I am rendering a navigation. So, I have to differ between the current/active menu item and the rest. The current menu item gets a special css class. I don't know how to handle this in a better way than using if-else.
If you are doing MVC (hopefully you do), than the question is "Do I put the logic in the view or the controller?". I use a simple rule to find out the answer of that:
What if my view was not HTML, but an XML document?
If I will need this logic in both circumstances - its place is in the controller. If not - it's in the view.
In good MVC design you should be able to swap the views without touching the controller.
As much as is necessary to display the information. Just remember that the view is just a window into the internal state of the program. If you stripped the view layer completely away, the program should still be able to operate as usual, just without being able to see what it's doing.
edit: re your navigation, that seems like an okay use of an if statement. The information about which is active is still coming from the model, you're simply using the if statement to decide how to display it. You might consider a little bit about how you're rendering your navigation: is the information about which navigation items available, and which to render living in your view or your model?
One way you might choose to approach the situation is to have the model give you a list of navigation items, along with which one is active, and program the view to know how to generate appropriate HTML from that. That code might contain precisely one if statement total. (instead of one for each nav item).
I wouldn't worry about putting an if statement in a view. In fact, I think there's a bit too much hand-wringing (in general) about responsibilities in these kinds of situations.
If you make your views too dumb then your model can become too view-sentric (tightly coupled).
IMHO a view can do what it likes but the guiding principle should be: where does it get its information from? If the answer is "the model" then use as much logic as you like.
An "if/else" construct is fine if the view is alternating modes, e.g. formatting a U.S. address vs. a foreign address in an order screen.
However, any logic that you place into a view should not alter the model.
Add this helper to your application_helpers.rb It will surround your links with <li> and <li class="active"> if the link is the current page.
Use it in place of a link_to.
link_to 'home', root_url, optional_condition_argument_goes_here
def active_link_to(text, url, condition = nil)
if condition.nil? and String === url
condition = url == request.path
end
content_tag :li, link_to(text, url), :class => (condition && 'active')
end
(Courtesy of Mislav)
I might put if-else in a view. In most cases not. The real question in my mind is whether the logic could go anywhere else without being messier.
I tend to avoid putting control-flow logic in my views (ASP.NET MVC) except under circumstances where I may want a portion of the interface visible/not visible based on the presence or absence of data. In this case, it is view logic -- I'm determining the layout of the page, the elements of the page that are available, etc. I think that this is perfectly acceptable and preferable to having the controller determine this or multiplying views to account for minor variants. The controller needs to give the view enough information for it to be able to render the view and its variants as needed.
What I wouldn't put into the view is business logic that determines how to calculate something or whether to perform some action (except, perhaps, for role-based decisions -- these seem to crop up just about everywhere). Other than client-side validation, my business logic resides in the controller/model.
An example of where I might use if/then logic in a view is a view which displays events. In my app, events can have subevents, but subevents can't have further subevents: a two level hierarchy. On my display page, I have tabs for Details, Groups, Participants, and Subevents. These are the same for both events and subevents, with the exception of the Subevent tab. It shouldn't exist for a subevent. Rather than repeat myself by having two different views that are virtually identical except for that one tab, I've added a tiny amount of logic to the view to not render the Subevent tab if an event has none.
By the same token, I wouldn't go so far as to have a single "view" that uses logic to determine whether to show an overview or details or editing pane, etc. based on the value of some view data item. This seems an abuse of the single responsibility principle as applied to views. Each view should have a single-purpose, IMO.
Logic that is in the view should not be required to fully describe the current state of the model.
Said another way, logic in the view is acceptable if that logic is used to format or alter the visualization of the information. Logic in the view might also have a use in vetting data that is entered before taking the expense of transmitting that data to the controller (in a client/server or web application).
For instance, the view might include logic to split a list of items into multiple columns when the list is longer than N items. That split could be done in several different ways according to the exact nature of the view (e.g. http, mobile device, pdf, voice reader, Morris Code, etc, etc, ad nasium). The full view information might need to be paginated - and that can only be done in the view. Formatting logic should not ever be included in the controller or the model.
As a corner case, the view might include logic to check that a password entered for a new user meets the current security requirements (e.g. double entry of password matches; at least N characters long; does not include spaces or the "*" character; includes at least three of the following: lower case letters, upper case letters, numbers, symbols; is different than the last N passwords, no based on a dictionary word, etc, etc). Depending on the nature of the logic, vetting a password could be thought of as "formatting" or as "business logic". It might be that the check happens in two passes - one set of checks for formatting in the view, and another set of checks in the controller with info from the model (the last N passwords).