5 ms·
Fat models are slightly better than having that crud in your views, but they're still an antipattern. Models should describe the relationships between entities
by caseydurfee 13y ago
Fat models are slightly better than having that crud in your views, but they're still an antipattern. Models should describe the relationships between entities in your business, not be the junk drawer for stuff that doesn't go anywhere else.
Fat models are already a code smell, but passing the request object to your model should really set off alarm bells. You've now made it extremely messy to use your models outside of a web context, making it impossible to unit test them, and pretty much wiped out the purpose of the controller as an encapsulation layer.
Domain-driven design (DDD) provides a lot of patterns that help to keep from either having model code in your views, or these types of junk drawer models.
Basically, DDD as it applies to MVC webapps is: If it's a complex query of some sort, create a query repository that returns model objects rather than a "fat" static method on the model itself. If it's a business transaction, create logic objects that encapsulate the biz logic, and service objects that applies the logic to the models. The controller serves as the broker between requests, services, and entities. You end up with much more testable and reusable code this way.
- gasull 13y agoThe article precisely says you should not pass the request to the models.
- karmajunkie 13y agoThat doesn't make it any less of an antipattern. The "fat model" pattern is essentially "if you can't figure out where it goes, put it in the model." In the article's example, the credit card processing code is wrapped up into the quote model. I can't think of a single situation in which this is a good idea.
- ollysb 13y agoThe "fat model" pattern is simply organising your logic and relationships into the model layer. How well you organise it is up to you. If you just dump things from the controllers into random parts of the model then that's your choice but there are plenty of ways to design it well.
- singingfish 13y agoI'm closely involved in a big system that uses Catalyst (perl's nearest equivalent to Django). We spend allmost all of our time in Model classes (MyDomain::Model::Whatever, not MyWebApp::Model::Whatever that's just a dumb connector). It works well and I get the shits every time I have to deal with code that doesn't separate this stuff out properly. Also works on the front end using modern javascript.
- collyw 13y agoI have most of my logic in the views (because I didn't now any better when starting my project). I know the Django way suggests fat models (well I know that now). But is it honestly that big of a deal? I know in my app that any complex logic will be in the views. What will I gain by following these best practices?
- singingfish 13y agoYeah, try having a fat controller or view, on a rapidly developing codebase with poor specs which change mid-project regularly while avoiding getting fired.
- collyw 13y agoSounds very like my work. Yeah, schema changes are a pain in the arse, but I don't see that moving my code from views to models would have a great deal of impact (though I am gradually moving the code that way when it does need changed).
- singingfish 13y agoA better answer is, that you get to decouple the functionality of your application's business logic from the web portion. This is achieved trivially purely by applying disciplined coding standards. Removing the web dependency makes the code much much easier to write automated tests for, and it gives a sane development path when making minor or major changes to feature sets.
- edwinnathaniel 13y agoBut the article passes other unrelated things to the models.
- owyn 13y ago"the junk drawer for stuff that doesn't go anywhere else" I really want to know where to put that stuff. Creating an object to put the "filterBlah" function that you only use once is overkill, so it sits there as a one-off method in your View or Controller or Model. I've worked with large enough code bases for long enough that I know there's always hacky junk there, and I'd just like to know more strategies for addressing it. Do large code bases have a strategy for putting the one-offs in a place where they are obvious and organizable? I'm now working on a 5M line code base, and at that scale, you kind of have to put the code into acceptable, bad, worse and awful categories and come up with strategies to fix it. There IS no good code at this point. I've actually done refactoring with regexes, but I want better tools for reasoning about extremely large and weird code bases.
- jhh 13y agoyou could simply use unbound functions which you put into a Python module which fits the bill. For example you could create a file services.py - or something more related to your actual domain.
- ollysb 13y agoIn rails filter functions like that are kept in the model. They're composable and lazily evaluated so you don't really end up with giant, one-off methods. In python I'd expect to find this sort of functionality in a service class (with each domain object having it's own service class).
- ldite 13y agoIf it's a complex query of some sort, create a query repository that returns model objects rather than a "fat" static method on the model itself. I believe that the "Django way" of doing that is to have a custom "Manager" class; https://docs.djangoproject.com/en/1.6/topics/db/managers/#custom-managers-and-model-inheritance https://docs.djangoproject.com/en/1.6/topics/db/managers/#cu... http://zmsmith.com/2010/04/using-custom-django-querysets/ http://zmsmith.com/2010/04/using-custom-django-querysets/