I was listening to recent podcast by Taylor Otwell, Laravel Snippet episode 11, where he touched on the debate in Laravel community on where you should put your code logic – in Controllers, Models, or Services. Here’s what he said.
First, I’ll just quote Taylor, and then provide some comments and additional links below. So, “skinny” or “fat” models? What approach does creator of Laravel prefer?
I tend to prefer a “fat” Model approach. My Controllers are actually pretty skinny, I find.
I think DHH (David Heinemeier Hansson), who created Ruby on Rails, had a blog post years ago about how he likes to use only the “resource” verbs on Controllers and that he doesn’t like any other actions. So, when you have a Controller, you limit yourself to only index/show/store/update/delete, and if you need any other actions – usually that’s an indicator that you can extract the whole other Controller that follows those resource verbs conventions.
So I follow that pretty strictly, which, I find, makes my Controllers pretty thin, and then I would have pretty beefy Models that have pretty rich logic on them.
I think one misconception of this approach is that just because your Model has quite a bit of logic exposed in its public API, that doesn’t mean that all the code to perform those tasks has to be within the Model.
So, take Forge for example, just assume a hypothetical Site Model, that has a deploy() method. Of course, sticking the entirety of the deployment logic within the Site Model is probably not even possible, for starters, and probably wouldn’t be a good idea, cause it would be quite a bit of logic. But, what you could do, is still have that public method on the Site Model, but have that call another method, or another Service, or fire off some Command or Queue Job, to actually perform the task.
So, the Model is not necessarily “fat” in terms of lines of code, but it just has a rich API of public methods that give you a fluent nice interface, that is very readable. It’s very readable to have Site deploy(), even if behind the scenes it’s firing off other things. It keeps the public API really nice.
It reminds me of Adam Wathan’s talk at Laracon US 2017, called “CRUDdy By Design”:
Personally, I like this approach but don’t follow it strictly, so if I have one custom action it feels weird to create a separate full Controller for it. So it depends. Also, there was a Reddit discussion with 52 comments on this approach.
What I do like, though, from Taylor’s opinion, is to have custom methods in Models. For a long time, there was a debate in community, that Eloquent Models need to have only Eloquent stuff – settings like $table or $fillables, methods for Relationships, Accessors/Mutators, and nothing more.
But if the creator of the framework himself says that you can put whatever you want there, as long as it doesn’t include all the logic, I agree it’s more readable than calling Service/Job directly from Controller.
What do you think? Agree with Taylor? How “thin” are your Controllers and Models?
You can listen to the original Laravel Snippet #11 podcast here, this topic starts at around 6:20 minute.