God Controllers - How to prevent them? - asp.net-mvc

In a few MVC projects I've been working on, it has become apparent that there are a few problematic controllers that have organically grown into God classes - demi-gods each in their own domain, if you will.
This question might be more of a matter 'what goes where,' but I think it's an important question with regards to SRP (Single Responsibility Principle), DRY (Don't Repeat Yourself), and keeping things concise, "agile" -- and I am not experienced enough (with this pattern and in general design) to be knowledgeable about this.
In one project, we have a NutritionController. Over time it's grown to include these actions (many with their respective, GET, POST, and DELETE methods):
Index (home controller)
ViewFoodItem
AddFoodItem
EditFoodItem
DeleteFoodItem
ViewNutritionSummary
SearchFoodItem
AddToFavorites
RemoveFromFavorites
ViewFavorites
Then we have an ExerciseController, which will include many similar actions, such as the searches, and favorites actions. Should these be refactored into their own controller so that it's something like so?
SearchController {
SearchExercise
SearchNutrition
//... etc
}
FavoritesController {
ViewNutritionFavorites
AddToNutritionFavorites
AddToExerciseFavorites
EditNutritionFavorites
EditExerciseFavorites
//... etc
}
It just seems to me that if you break them out into separate controllers, you're going to grow an unbelievably large dependency at some level to deal with the information that you will need. OR you are going to have a completely generic handling application that will be very difficult to handle since you will have to jump through so many hoops to get your desired effect (either at the M, V, or C level).
I am thinking about this the wrong way? For example, should I have a generic Favorites object and then let the controller decide what view to throw it to?
*Sorry for spelling out the acronyms -- I'm doing so in case anyone else comes across this question and is clueless as to what those things are
EDIT:
All the logic I perform is pretty much handled in the service layers. For example, the controller will send the 'new' FoodItem to the service. If it already exists, or there's an error with it, the service will bubble it back up to the controller.

I would break your first list up based on responsibility:
HomeController
Index
FoodItemController
ViewFoodItem
AddFoodItem
EditFoodItem
DeleteFoodItem
SearchFoodItem
NutritionController
ViewNutritionSummary
FavoritesController
AddToFavorites
RemoveFromFavorites
ViewFavorites
SearchFavorites
Django's approach to MVC is to separate responsibilities into "applications", each with their own models, controllers, and even templates if necessary. You'd have a Food app, a Nutrition app, a Search app, and a Favorites app, most likely.
Edit: The OP mentioned that searching is more specific to each controller, so I've made those actions. However, searching may also be just a general global thing, so in those cases, a SearchController would be fine.

Do as Soviut says. You want to keep the controllers simple. It sounds like your ending up with too much coordination logic in your controllers. Remember they are responsible for hooking up a view and a model. This coordination logic should probably be split out into services.
I get this feeling because you mention the possibility of your controller growing huge dependencies. Well If FavoritesController needs to know about nutrition AND exercise favorites (to display in the same view) don't make your controller dependent on 2 repository like classes. Instead, encapsulate that coordination behavior. Maybe create a FavoritesService that knows how to return both nutrition and exercise favorites. That service might delegate to NutritionFavoritesService and ExerciseFavoritesService. This way you're controller only ends up with 1 dependency, you're keeping things DRY, enforcing the SRP, and concentrating your business logic in some place other than the controller.

I'm not too familiar with that framework, but I can offer a bit of general advice. A controller should probably only know how to complete a single action, or to invoke other, single action controllers to complete a sequence of related actions. Any information that must be passed around from action to action should probably be somehow passed through the model layer, since that information is most likely relevant to the underlying model.

I have also experienced these sorts of maintenance headaches and find sticking to a "Rails" like method to be very helpful in keeping my controllers focused and unbloated.
If I find myself adding actions with unusual names Eg. To use a blogging example, AddPostToBlog, that would be a flag to create a new Post controller with a Create action.
In other words, if the action is not either one of the Index, New, Create, Show, Edit, Update and Destroy actions, then I add a new controller specific to the action I require.
For your example.
SearchController {
SearchExercise
SearchNutrition
//... etc
}
I would refactor this to...
SearchExerciseController {
Index
}
SearchNutritionController {
Index
}
This may mean having more controllers, but in my opinion thats easier to manage than ever expanding "god" controllers. It also means that the controllers are more self documenting.
Eg. Does the SearchExercise action, return the View to search the exercise or does it actually perform the search? You could probably ascertain this by looking at parameters and body, but its not as easy as for example a New and Create, or Edit and Update action pair.
SearchController {
SearchExercise
}

Related

break up the session controller into 3 separate controllers?

I have a sessions_controller with 3 actions:
new
create
destroy
but I am thinking that it would be clearer if I created separate controllers for each action, with each controller only doing one thing (sessions#new is less clear to me than login#new):
signup
login
logout
essentially breaking up the actions at a file level rather than a function level.
are there reasons to do one over the other?
While you certainly could break them into separate controllers, I don't think it is necessary and it would make your life a lot harder.
It sounds like you need to utilize routes.rb to match up requests with the controller. This will keep your session logic grouped while making your paths a little more sensical.

Handling Singular Resource in REST

i have a case where i am actually using some resources that are singular in nature. This is about buildings, so in a city i have a single sawmill and a single town_center.
Now, i am creating everything in a RESTful manner using resources(with :except or :only) where needed. In this case though, i am having a town_center_controller and a sawmill_controller that just have a different show action(they have no other actions).
One can say that a buildings_controller sounds better, but in that case, i would have a single show action to display totally different views(like the one for the sawmill and the town_center). They have many differences and i don't really see how i could stack them in a single controller. However, when i destroy or create a building, i do use the buildings_controller.
I would like to ask you, how would you go about it ? How would you design your controllers ? Would you do what i do and create building based controllers(one controller per each building), or something else ?
I would create a general controller that has the generic functions to support all building cases, like destroy/create/edit, then I would create new controller that inherits from that base controller. This way I will keep my generic functions DRY, and my specific (overridden) functions separate.

Is an abstract CRUD controller a good idea?

We're developing quite a big application using ASP.NET MVC and at the beginning we saw that could be useful to have an abstract base controller with common CRUD actions (new, save, delete...) plus a default list action. In our case we have 20+ entities that are managed through this kind of controllers.
That works and avoids duplicating some code and makes the application more homogeneous but when you see a Controller is difficult to see exactly which actions does it implement and it may implement some actions that should not exist. And for example, imagine you want to edit passing the name and not the id, you have to create a new EditByName(name) and even doing that, you still have the Edit(id) action available because it's in the base.
To me the whole thing smells a little bit to me but I've not found any example showing an alternative because the MVC applications I see have a pretty narrow domain. Any advise? Any example? (I does not necessarily be in ASP.NET MVC, the problem I think is quite generic to any MVC framework).
In some respects I think this is a good idea, but in others I think that it's an abuse of inheritance. I do have a common base controller, but it exists because I've refactored common code from my controllers into it rather than being designed a priori. If your entities are enough alike that the code that you're sharing in the base controller outweighs the cruft that you're forced to drag around, then perhaps it's worth it. If, on the other hand, the code that's being shared is rather minimal and simply invokes a private abstract method that does the work (so that you're implementing it in the real controller anyway), I don't know what it buys you. It's not like you're instantiating your controllers directly anyway (except in your tests) so having a common interface beyond that required by the framework isn't all that important.
My vote would be to refactor into the base class those things that are truly common or are cross-cutting concerns and not try to force an "is-a" relationship that may not really exist.
I created a version of what you're suggesting (though admittedly relatively non OOP) and it's worked very well for me.
I've created a MasterController that sets up a db instance and a few other variables. Once I started looking at the similarities in my CRUD actions, I realized this could be abstracted and moved into a method within the master. Two methods, actually.
protected ActionResult DisplayValidateAndEditModel<TModel>(TModel model, string modelPrefix,
string editViewName, string successActionName, object routeValues, string successMessage,
string[] includeProperties, bool acceptFiles
) where TModel : class
and
protected ActionResult DisplayValidateAndEditModel<TModel>(TModel model, string modelPrefix,
string editViewName, string successActionName, string successMessage,
string[] includeProperties
) where TModel : class
The Edit covers Create/Read/Update and Delete is Delete. Listing is a single line in a controller -- i just get a group of models and add to viewdata.
Both methods check if it's a post. If not, they return the view. If so:
edit calls TryUpdateModel and also does some xVal validation. If all is ok, it redirects to the successAction with any routeValues. If not, it shows the view again. includeProperties can be passed so that my controller can specify exactly what can get updates. And acceptFiles adds additional functionality where it looks for a file posting and, if there, puts it in the database and creates a link between the file record and the model.
delete updates the model's Cancel_Date and Cancel_User properties (I have a ICancelable interface) and redirects to the success action
This is one of the things Rails packs with ( along with generating the relevant CRUD views for you ) and it's great for whipping up a very quick application but once you get serious about development it is very unusual for the vanilla CRUD stuff to stay in because the things you need for each table start to change and need further customisation.
That isn't to say it doesn't form a useful foundation and a convenient way of setting things up while you're developing and prototyping - much easier than tinkering about in database fields - but certainly the way it works with Rails you don't expect to have any of those pages in your final administration system.
To me the whole thing smells a little..
The same smell here :-)
It is common pratice to have little code in the controller. Its main purpose is to decide what View is rendered with which Model next.
If you wish to have a common place for all the controller code it shows, that you probably have to much logic in the controller.
Try to move the logik into the Model. Use Filters and CustomModelBinder.
Just a though: As you know ASP.NET MVC supports basic scaffolding like Ruby on Rails. What you may consider is to customize the T4 files used to create the Create, Update, Details Views to meet your specific needs.
http://blogs.msdn.com/webdevtools/archive/2009/01/29/t4-templates-a-quick-start-guide-for-asp-net-mvc-developers.aspx

When should I create a new controller class in ASP.NET MVC?

I'm learning MVC and am having trouble deciding when I should create a new controller versus just adding an action and view associated with an existing controller. On the one hand, Single Responsibility would seem to say a controller should be limited to a few actions. When I try this, though, the number of classes grows exponentially (model, views and controller for each)- to the point I wonder if I'm going overboard.
For example, the default AccountController has Login, ChangePassword, and Register actions. I would tend to instead create a LoginController, PasswordController, and ProfileController, and related model classes. So where there was 1 class, there would be 3-6.
Is there any good rule of thumb on this?
You should dedicate a controller for each model type you're manipulating. The controller acts as a collection of actions that act upon those models. This is generally the rule of thumb, but sometimes a controller's scope transcends a single model.
The AccountController deals with all things authentication related. This is an example of going beyond a single model's scope to encompass authentication in general. What are the key parts of authentication? Retrieving users, changing passwords, etc.
I think you need to be pragmatic about it. I'm working on a project that consists of a StatsController. The number of actions is continuously growing (RandomStat, MostPopular, MostViewed, MostVoted, etc...) the list goes on and on. These actions are simple to satisfy since the StatsController's dependencies don't change. I'm using an IoC to satisfy what my Controllers need and when I start to see my Controllers needing references to new objects, this is a signal that they need to be broken apart.
If your LoginController, PasswordController, and ProfileController all rely on the same objects, why break them apart?
My current AccountController has 12 methods which to me is completely manageable.
I have another controller which currently has 34 methods but those are all tied to a single view and they each have around 8-10 lines of code max (check required parameters, update the model, and redirect as necessary).
They key is to encapsulate your business logic in an entirely separate module. That will allow your action handlers to remain extremely light weight and can make testing your business logic easier.

Rails Model, View, Controller, and Helper: what goes where?

In Ruby on Rails Development (or MVC in general), what quick rule should I follow as to where to put logic.
Please answer in the affirmative - With Do put this here, rather than Don't put that there.
MVC
Controller: Put code here that has to do with working out what a user wants, and deciding what to give them, working out whether they are logged in, whether they should see certain data, etc. In the end, the controller looks at requests and works out what data (Models) to show and what Views to render. If you are in doubt about whether code should go in the controller, then it probably shouldn't. Keep your controllers skinny.
View: The view should only contain the minimum code to display your data (Model), it shouldn't do lots of processing or calculating, it should be displaying data calculated (or summarized) by the Model, or generated from the Controller. If your View really needs to do processing that can't be done by the Model or Controller, put the code in a Helper. Lots of Ruby code in a View makes the pages markup hard to read.
Model: Your model should be where all your code that relates to your data (the entities that make up your site e.g. Users, Post, Accounts, Friends etc.) lives. If code needs to save, update or summarise data related to your entities, put it here. It will be re-usable across your Views and Controllers.
To add to pauliephonic's answer:
Helper: functions to make creating the view easier. For example, if you're always iterating over a list of widgets to display their price, put it into a helper (along with a partial for the actual display). Or if you have a piece of RJS that you don't want cluttering up the view, put it into a helper.
The MVC pattern is really only concerned with UI and nothing else. You shouldn't put any complex business logic in the controller as it controls the view but not the logic. The Controller should concern itself with selecting the proper view and delegate more complex stuff to the domain model (Model) or the business layer.
Domain Driven Design has a concept of Services which is a place you stick logic which needs to orchestrate a number of various types of objects which generally means logic which doesn't naturally belong on a Model class.
I generally think of the Service layer as the API of my applications. My Services layers usually map pretty closely to the requirements of the application I'm creating thus the Service layer acts as a simplification of the more complex interactions found in the lower levels of my app, i.e. you could accomplish the same goal bypassing the Service layers but you'd have to pull a lot more levers to make it work.
Note that I'm not talking about Rails here I'm talking about a general architectural style which addresses your particular problem.
Perfect explanations here already, one very simple sentence as conclusion and easy to remember:
We need SMART Models, THIN Controllers, and DUMB Views.
http://c2.com/cgi/wiki?ModelViewController
The Rails way is to have skinny controllers and fat models.
Do put stuff related to authorization/access control in the controller.
Models are all about your data. Validation, Relationships, CRUD, Business Logic
Views are about showing your data. Display and getting input only.
Controllers are about controlling what data goes from your model to your view (and which view) and from your view to your model. Controllers can also exist without models.
I like to think of the controller as a security guard/receptionist who directs you the customer(request) to the appropriate counter where you ask a teller (view) a question. The teller (view) then goes and gets the answer from a manager (model), who you never see. You the request then go back to the security guard/receptionist (controller) and wait until you are directed to go another teller (view) who tells you the answer the manager (model) told them in response to the other teller's (view) question.
Likewise if you want to tell the teller (view) something then largely the same thing happens except the second teller will tell you whether the manager accepted your information. It is also possible that the security guard/receptionist (controller) may have told you to take a hike since you were not authorized to tell the manager that information.
So to extend the metaphor, in my stereotyped and unrealistic world, tellers (views) are pretty but empty-headed and often believe anything you tell them, security guard/receptionists are minimally polite but are not very knowledgeable but they know where people should and shouldn't go and managers are really ugly and mean but know everything and can tell what is true and what isn't.
One thing that helps separate properly is avoiding the "pass local variables from controller to view" anti-pattern. Instead of this:
# app/controllers/foos_controller.rb:
class FoosController < ApplicationController
def show
#foo = Foo.find(...)
end
end
#app/views/foos/show.html.erb:
...
<%= #foo.bar %>
...
Try moving it to a getter that is available as a helper method:
# app/controllers/foos_controller.rb:
class FoosController < ApplicationController
helper_method :foo
def show
end
protected
def foo
#foo ||= Foo.find(...)
end
end
#app/views/foos/show.html.erb:
...
<%= foo.bar %>
...
This makes it easier to modify what gets put in "#foo" and how it is used. It increases separation between controller and view without making them any more complicated.
Well, it sort of depends upon what the logic has to deal with...
Often, it makes sense to push more things into your models, leaving controllers small. This ensures that this logic can easily be used from anywhere you need to access the data that your model represents. Views should contain almost no logic. So really, in general, you should strive to make it so that you Don't Repeat Yourself.
Also, a quick bit of google reveals a few more concrete examples of what goes where.
Model: validation requirements, data relationships, create methods, update methods, destroy methods, find methods (note that you should have not only the generic versions of these methods, but if there is something you are doing a lot, like finding people with red hair by last name, then you should extract that logic so that all you have to do is call the find_redH_by_name("smith") or something like that)
View: This should be all about formatting of data, not the processing of data.
Controller: This is where data processing goes. From the internet: "The controller’s purpose is to respond to the action requested by the user, take any parameters the user has set, process the data, interact with the model, and then pass the requested data, in final form, off to the view."
Hope that helps.
In simple terms, generally,
Models will have all the codes related to table(s), their simple or complex relationships (think them as sql queries involving multiple tables), manipulation of the data/variables to arrive at a result using the business logic.
Controllers will have code/pointers towards the relevant models for the job requested.
Views will accept the user input/interaction and display the resultant response.
Any major deviation from these will put unwanted strain on that part and the overall application performance may get impacted.
Testing, Testing ...
Put as much logic as possible in the model and then you will be able to test it properly. Unit tests test the data and the way it is formed by testing the model, and functional tests test the way it is routed or controlled by testing the controllers, so it follows that you can't test the integrity of the data unless it is in the model.
j

Resources