In Patterns of Enterprise Application Architecture, Martin Fowler talks about two patterns for organizing Domain Logic: Domain Model and Service Layer. The Domain Model pattern is the "pure OOP" approach, where models (those objects that are probably being looked up from the database using an ORM) contain business logic (albeit, probably only delegating to the logic in another class).
The Service Layer pattern is like the Domain Model pattern, but with a thin layer in front of it containing the business operations that can be performed. In MVC, the controller would mostly interact with the Service Layer. I believe that most well-designed MVC web applications use this pattern.
Now, to my question. Martin suggests that the Domain Model approach is the more object-oriented approach, and is therefore better. In my experience, it is very difficult (see: impossible) to implement in practice.
Take the example given in the first diagram above. There are two "entities" Contract
and Product
. These are persisted to the database with a mapper. In the example, there is a RecognitionStrategy
. Martin puts the methods for delegating to this strategy, which contains the actual business logic, in the entities themselves; the client performs this calculation with contract.calculateRecognitions
or contract.recognizedRevenue(someDate)
. When implementing similar designs, I usually write the client interface as strategy.calculateRecognitions(contract)
and strategy.recognizedRevenue(contract, someDate)
. This makes the service layer necessary for coordinating the strategy and contract. The concrete strategy used is injected into the service.
Martin's approach is definitely more appealing from a design perspective, but the work around the setup is much more difficult:
Product
is a pain. You need to create Product
s via a factory curried with the concrete service to use, which will in turn pass it into the entity when creating it. Contract
delegating to Product
may perform a query per Product
. Greedily loading Product
s in the mapper (or ORM) may be overzealous when we load a Contract
but don't intend to call contract.calculateRecognitions()
. My approach gives us finer-grained control, because the service has knowledge of the database abstraction layer, where as the entities shouldn't.I'm sure there are more pain points in practice that I haven't enumerated here.
What concrete advantages are there in Martin's approach that might convince me to use a pure Data Model pattern?
Regarding your first point, you should use dependency injection when instantiating the Product object. Object graph construction is a full flagged responsibility and should not be mixed with your business logic (single responsibility principle).
Regarding the second point, your vendor particularities should be hidden behind you data access layer and your DAO or Repository should return the objects according to your needs.
An alternative for your concern over greedily loading Product s (on a situation the relationship is one to many) is to have the Product DAO injected into the Contract object. With that approach you could get the Product s related to the contract when required (probably on a getter that could also be used internally).
Of course a perfect solution does not exist and there will always be trade offs. Your job as an architect to evaluate the approach that better fits you application.
On my personal experience I noticed that relying too much on service classes tends to generate gigantic classes that don't have a well defined responsibility and are usually too difficult to test.
So benefits of using the Domain Model approach are clear separation of concerns and increased testability.
Finally you don't need to use a "pure" Domain Model approach. The domain model and service layer are expected to be used together. The domain model entities cover behaviors that fall within their boundaries and the service layer cover logic doesn't belong in any domain entity.
Some additional reference you may find interesting
Domain Driven Design and Development In Practice - An interesting article on DDD
Dependency Injection, Design patterns using Spring and Guice - Great book on dependency injection
Regards,
Emanuel Luiz Lariguet Beltrame