Laravel Model Method: Refactor into Service Class

preview_player
Показать описание
A follow-up video on a recent one about a method for the price calculation in the model, based on your comments.

Links mentioned in the video:

- - - - -
Support the channel by checking out my products:

- - - - -
Other places to follow:
Рекомендации по теме
Комментарии
Автор

Hello!

Martin Fowler wrote in his article "Anemic Domain Model" that "In general, the more behavior you find in the services, the more likely you are to be robbing yourself of the benefits of a domain model."

Robert Martin in his "Clean Code" considers Active Record as some kind of DTO and that's why business logic should be placed in services.

Programming is awesome )

al.e.k
Автор

Amazing how you collected all the information in the comments and gave explanations for each class

daniel
Автор

Thank you! Great discussions with the community.

Niboros
Автор

I try to write my apps using the same structure each time. Interfaces, Service layer, DI where possible and so on, even if the app is a "throw-away" that is only going to be used once.

Too often in my career as a developer one-off, throw-away apps have ended up being production apps for one reason or another and I do not want code out there that other developers can see and critique that has bad smell code.

So, one-off or not, my apps are the best I can make them every time.

In the case of the model in this clip, I'd put that method into a service class because it is business logic and not the responsibility of the model (remember SOLID).

But, as you say, it's all about preference.

As for comments about write now, refactor later, in my experience, this rarely, if ever happens especially once the app is in production.

tetleyk
Автор

This video is a great illustration of how service classes end up in the creation of anaemic domain models and procedural code dressed up as object-oriented code. The fact that the service class needs an instance of the apartment class in order to get at the prices is an example of a well-known code smell called feature envy. It’s a hint that something is wrong with the design. The price is intimately connected with the model and should be the model’s responsibility and thus encapsulated in the model class itself. By shifting it into a service class, you’ve just regressed to procedural code.

theceilidhboy
Автор

What I prefer: Contains the method logic for only the given model, as it does here, I include the method into the model class. (and if I have a lot of the same kind of methods and the model class gets long, i seperate them into traits as it comes closest to class partials).

If the method uses more models for it's logic, returns a specific model controlled by it's input or returns more models, I include it into the service class.

JithranSikken
Автор

It's all a matter of preference. That being said, dark theme on youtube is a blessing 😄

GutoCmtt
Автор

You can never please everyone, especially those with symfony or bigger background outisde of laravel. They will always complain about the structure. My initial thought is if you are on some good financial situation where you can spend a lot of time on researching and writing the best code ever that will work forever without refactoring good do it. But if you are low on time and finances, these things won't matter, especially in your own products that if they get a good financial support, you could always refactor it. I was always thinking about writing the best code etc and I never finished something because it takes a lot of time, but when I started doing it other way around I published few successful ones. Time is limited, knowledge is not and you can never do it all and get better results. Its just losing time. I like the method inside model, its much simpler

DeTechDivus
Автор

I think automated testing is also part of the reason why you should seperate the functionalities. I would love to see a TDD way of fixing this problem. I find it hard to come up with solutions for these kinds of 'small' problems myself as well. The term overengineering and spending too much time and 'hassle' on something as small as this feels wrong. But if you choose the 'easy' way out too often, your project becomes a mess slowly. Balance is key i suppose.

Michielofzo
Автор

When I wrote a raw query for a complicated logic, I was asked "why didn't you use eloquent relations?" and I also said "it is a personal preference, do as you like, as long as you get the results that you need and in a performant way".
I never noticed this before, but in the last year or so, the Laravel community has become a bit "annoying" with "do it this way, not that way".

kickass
Автор

In situations like this, when a logic are relating to a Model and does not depend on third parties, I use trait, achieve the same thing with your preferential method and as well keeps the model neat and shorter.

Bbtechjourney
Автор

Nice perspective you've given. Thanks much 👍🏻

manishdeshpande
Автор

And if the service class were a trait instead, then the model would use that trait. Of course, it would be a non-reusable trait, but it would concentrate the logic outside the model, and the access to these methods would be done as if they were inside the model.


I don't know which naming would fit better than service.

crazynds
Автор

Given a more real world scenario, this price logic might be way more complex. You may want to calculate price not only for dates, but also add promo codes, other types of discounts, some high demand dates more expensive... It make sense to have that logic in a separate class. For this example, one method, it doesn't make a difference

LeandroTabaj
Автор

This topic is all about layers. Price method should be the part of business layer (hope noone gonna controvert). If you use models for db reflection only, ofcourse this method should be separated from model. How exactly this should be done - its all about personal preferences. All ways would have pros and cons.
In fact, the best way should be in specifying abstraction "Can be price calculated by dates" (have no idea how to name it properly), making model inherited from AppartmentModel and that abstraction, and Calculation Service should use that abstraction as a parameter. One thing, that code would be mess, but realy extandable.

andrewvasiliev
Автор

i whit put the calculatePriceForDates method in to the resource class as a private method since that's the only place it's being used

bnandy
Автор

You can use trait, in this case will separate the code to different class file and will keep it as is, by the way I use model but when be more than 3 I move them to trait

IboOoOo
Автор

Only refactor when the codes start to gross out, at early stage of the development keep it simple first.
when it's getting large, then start to refactor into service/action/observer/trait, totally depends on situation

klg
Автор

I'm a big fan of Services but in this case I totally agree with Povilas.

zoba
Автор

i tend to keep these kind of `utilitary functions` inside models, but when it comes to business logic then i move to services
dont think its black or white aswell

danichurras