سؤال

Let's say I have a three tier application structure, with Presentation, Service and Data layers. The data layer is managed by an ORM and has two models/entities, Show and Episode, with a one-to-many relationship (one show consists of many episodes).

In the service layer there is a ShowService, which can manage shows. The application will frequently need to display only episodes where the publication time is in the past (i.e. which are published).

Now to the question - where should I put logic to retrieve the episodes?

I think it makes sense to have a getPublishedEpisodes() method in the Show model/entity, because episodes are in essence the parts that make up a show. The ORM I'm using (RedBeanPHP) would make it very easy to implement something like this in the Show model:

public function getPublishedEpisodes(){
    $allEpisodes = $this->ownEpisodeList;
    return filterPublished($allEpisodes);
}

Now I can just call

$episodes = $show->getPublishedEpisodes();

and all I need is a Show to be able to get its published episodes.

The other option would be putting the method in the ShowService, which somehow doesn't feel as natural, but I have a feeling this is the "correct" way to do it. I'm thinking I would have to do something like this in the ShowService:

public function getPublishedEpisodes(Show $show){
    $allEpisodes = $show->ownEpisodeList;
    return filterPublished($allEpisodes);
}

But then I would always need to get the ShowService every time I want to get published episodes. With the other approach I can pass around Show objects all over the place and just call $show->getPublishedEpisodes() any time I want.

Will the first option, which feels a lot easier - at least in the short term, give me problems that I can't really see right now?

هل كانت مفيدة؟

المحلول

This is a hard question to answer as many have pointed out via comments, but I guess I will weight in.

My first thought is to do what is best for your application. We can get deep into theory of DDD and the like where I might have a different opinion(and I will, if you bear with me).

If it makes the most sense to you to simply load a show via your ORM and call some method like getPublishedEpisodes() than do it! If you subscribe to an agile approach or you refactor often, you can always change it later. It is possible (and likely) that your first attempt at a pattern or architecture will be wrong... Sometimes we just don't know what we need until we try.

If you ORM is rather unintrusive and does not impose a direct dependency on the Show class, then you are probably fine to go that route. Aspect Oriented Programming is something you may want to look into and it works well with your ideas. It may not be possible in PHP or with your ORM, though.

Anyway, I would find it cleaner to use your models to encapsulate business logic, and in that sense I would imagine your Episodes would be children of the Show. If that is so, I would probably have a ShowRepository to load the Show where the repository is a dependency of the ShowService. The ShowService would manage linking up your entities and would handle the coordination of business logic.

In my version of this app, just from a 1000ft view, when I loaded the Show I would pretty much always load all of the Episodes with it. When I needed to get just the Episodes for a particular view I may use some form of a Query Object to execute a more custom query. The only reason I would do this, however, is if my app was really underperforming using the original idea of just fetching the Show with the Episodes attached.

Using the Query Object idea leads into CQRS which is a rather advanced topic and may not even be worth the trouble in your application.

To reiterate, do what feels easiest to understand and maintain for you and your team. We can only give so much advice on the internet, especially without seeing and understanding the application and its domain.


That being said--and I would take the rest of this with a grain of salt--if I were writing this application I would favor a different approach, probably closer to that of your ShowService idea.

When you say "entity" I think of DDD. This may or may not be accurate. Many ORM Providers call their models "entities"--ahem Entity Framework ahem--which is sort of a misnomer. Entity Framework "entities" are really just Data Transfer Objects. In my opinion, "entities" are entities as they relate to Domain Driven Design. Entities, as seen here, are defined by their identity. They are the core models that represent the strategically important concepts of a domain or business.

If we subscribe to DDD and DDD-like patterns, our entities will never have dependencies like a service would. Think about an order and its corresponding order lines. Can the order lines exist in isolation without an order? Can you have a rouge order line? No. A major portion of the order line identity is the order itself. The order is the aggregate entity.

So, in this instance, the Show seems like it is your aggregate while the Episodes seem like child entities. If this is the case, you would not even have a means of loading the Episodes from the database directly. They would always come with the Show. This is why you may feel like the ShowService is the "correct" way to solve your problem. You have probably heard something along these lines somewhere down the road. Maybe you are already very familiar with DDD and everything I am saying is for naught. Either way, I figured I would share.

DDD is great, and offers a lot of clarity into how you should think about your app and where particular logic belongs, but DDD is hard. If your app is a simple CRUD app with little logic about it, I would avoid DDD altogether. It is just a lot of work and very difficult to do well.

That was a tangent, but hopefully it helps.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى softwareengineering.stackexchange
scroll top