Can anyone 'splain, using little words, or refer me to a 'splanation of just enough Rails info to follow this article?
(Highly amused formerly chubby gal who felt fine about her body back in the day and got drawn into reading this piece by the ridiculous "sexist!" accusations -- highly amused because this stupid stuff might lead me down the slippery slope to actually begin learning to program. Thus any cooperation is much appreciated. Mmkay? Thanks!)
In Rails, "models" represent data (like a User or an Order), how they are saved to the database, and how they behave. "Controllers" coordinate pulling the correct models out of the database when they need to be rendered to HTML or other request. The longstanding conventional wisdom regarding the two is "fat model, skinny controller"; i.e., if you have complicated logic about for example which User can view which Orders, don't put that logic where you generate the page, but move it into the User object.
The problem is that eventually you get very fat models. You can easily imagine how much behavior something as common as a User might have, and you get massive classes that act like junk drawers for can_view_order? and can_order_new_item? and has_archived_orders? etc. DHH here is presenting a possible solution to that problem. There are links elsewhere here to other solutions.
If the model gets big, it's an indication that it is doing too much work. You want every class in your system to have a single well-defined role--if the classes are getting huge it might mean that there's code duplication or it might mean that the class is taking on too much work.
In this context, DHH is pointing out that rather than duplicating the code for tagging and the code for managing visibility and the code for managing a Dropbox account on each class that needs these things you can use a Concern to abstract out each of those groups of functionality and then apply them case-by-case with one line of code. It's a pretty neat trick and used appropriately it looks like it would really help keep the model layer trimmed down to its bare essentials.
It's not a problem for the computer if you have a lot of code in a single file, but it is a problem for the computer programmer. If there's a lot of functionality in a single file, class, or other grouping of code, that makes it much more difficult for a human to understand and remember the details.
It's easier to work with a project if you can break it down into small pieces that are each individually easy to understand, so a goal of good project organization is to make your code out of small parts - small files, small models, a small number of lines of code - and have the parts be easy to distinguish and remember.
If you split one big "User" model into separate bits for billing, authorization, and user settings, not only is it easier to understand what parts there are, when you need to go in and make a change to the billing code, you immediately know that 2 out of 3 of the pieces can be safely ignored.
Similarly, if you take some very common functionality that models often have and generalize it, you only need to learn the general version once and then it applies to each of the parts. That's what the article describes. Many models are "Searchable" or "Taggable", but you only need to learn how searching or tagging works once, and the same search or tag code applies in multiple places.
Excellent. I may have to read more of this man's work. What works best for humans seems to frequently be given short shrift and the importance of it undervalued or missed entirely.
The chubbiness, itself, isn’t so much the problem. It’s that your models end up becoming arbitrary bags of logic whose contents lack rhyme or reason.
Let me unpack that claim.
In the models-and-controllers view of the world, there’s no obviously good place to represent the relationships between models. The relationship logic usually ends up getting stuffed into controllers (making them “fat”) or into arbitrarily designated models (making them “chubby”). For a long time now, though, everyone has been told to keep their controllers “skinny,” so now most of this logic ends up in models. And so we get a lot of “chubby” models these days.
Example time.
Say you have employees, who have roles at companies, which own assets. You’ll have a model class for each of these real-world concepts: Employee, Role, Company, Asset. So far, so good.
Now say you need a way to determine whether a given employee should be allowed to sell a given asset. Well, the answer to that question depends on the role that the employee has at the company that owns the asset. So where do you put the logic that answers the question?
Some people would put it in the Employee class, so they can write employee.can_sell?(asset). Others would put it on the Asset class, so they can write asset.sellable_by?(employee). Others would mix it into controller logic somewhere, because that’s where the employee and asset objects interact. And yet others would create a separate module of permissions logic to house the interaction, so they can write permissions.has_sell_on?(employee, asset).
If you choose to put that kind of relationship logic into a model class, and lots of people do, odds are you’ll make the same decision again and again. And, in time, your models will get “chubby.”
The problem is that, after a while, your models get bloated up with logic about other models and become harder to reason about.
(Highly amused formerly chubby gal who felt fine about her body back in the day and got drawn into reading this piece by the ridiculous "sexist!" accusations -- highly amused because this stupid stuff might lead me down the slippery slope to actually begin learning to program. Thus any cooperation is much appreciated. Mmkay? Thanks!)