|
#61
|
|||
|
|||
|
Regarding the persistence question with the Employee class as an example. I think this is a really bad example for the purpose of discussing domain model design as it's clearly not been taken from a proven design. In my experience you can only have a useful discussion based on a proven design.
For example, is it the responsibility of the fire() method on the Employee class to clean the employee's desk? It's hard to be sure, but Employee is probably an Aggregate and Desk an immutable Value Object. I don't see what functionality would be implemented in the clean() method of the Desk class. A more useful thing to do in the fire() method to me seems to set the desk member variable to null. So the fire() method looks like this: Code:
class Employee{
public void fire(){
setDesk(null);
setStatus(FIRED);
setSalary(0);
setFiredDate(new Date());
}
}
What's the impact on persistence? If you use Hibernate the relationship between Employee and Desk will be automatically removed. A comment on the exact role of the Desk class. First I talk about Desk as a Value Object, next I say it's managed by Hibernate as an Entity. Which one will it be? In this use case Desk clearly is a Value Object for Employee, and probably for the entire application. It's not the role of an HR application to manages desks in a database. Even if the HR application does manage desks, this should be implement as a separate module using it's own domain model. In this case you can implement the Desk class as a value object yet configure the class as an Entity in Hibernate. How to call the fire() method when the FIRE! button is clicked in the web browser? First of all, the Employee that is being viewed should be loaded in the HTTP session (or flow scope is you use Spring Web Flow) to enable Optimistic Locking. In the controller I would call a EmployeeManager.fire() method. The method looks like this: Code:
public class EmployeeManager {
/* setter ommitted */
public void fire(Employee employee) {
employee.fire();
employeeOrmRepository.attach(employee);
}
}
Why? Well, I guess there's only one place in the application where an Employee can be fired, for example the Employee detail screen. Does this answer all questions about persistence and domain models? No. Do we need a catalog of domain models used in real applications for educational purposes? Yes. |
|
#62
|
|||
|
|||
|
Quote:
I went through this example and here are a few words of caution a) It is too "Hello World" ish to demonstrate DDD b) It encourages the anemic domain model with all the code being in the OrderServiceSpringImpl.java and the Order and OrderLineItem to have no behavior. |
|
#63
|
|||
|
|||
|
>The business layer should be responsible for the following:
>* Managing transactions Business, real world transactions yes, but not implementation specific transactions >* Adding flexibility between the presentation and the persistence layer so they do not directly communicate with each other That is the responsibility of a controller layer not domain layer |
|
#64
|
|||
|
|||
|
Hi folks,
been reading this thread with enormous intrest, because im at the Fowler book these days, too. Just wanted to post my 2 cents on two topics you discussed here: 1. The business objects <-> DAO issue To my understanding business objects should not contain any "data access" access code at all. To me there are 2 important reaseons for that. First, why should BOs know that they are held persistent? So for me its kind of task of the application infrastructure to do this job. If you develop a domain model you abstract "real world" objects into domain objects. So when a Product in the real world doesn't know anything about being saved, why should the domain object? Second, there is the problem of cyclic dependencies. Your DAO has to know about your domain object. If you domain object has to know about your DAO you've just created such kind of dependency. It makes objects harder to test, harder to deploy, harder to reuse... I personally use the domain layer as some kind of vertical layer all my other layers (DA, Service, Presentation) use. 2. Domain methods in presentation layer You've mentioned an intresting problem with using domain objects at presentation level. You want to avoid domain logic methods be called from the presentation layer. I recently thought about introducing an interface (e.g. ProductView) where you only define the methods you want to give access to and let your domain objects implement this interface. As long the methods in the interface are a subset of the domain objects methods, theres no more work to do actually. Now place the Interface into your presentation package and typecast the objects that return from services to that ViewInterface. ProductView product = (ProductView) someService.getProduct(id); It's just a brainstorming idea. I haven't tried it so far... should work, shouldn't it? Regards, Ollie |
|
#65
|
|||
|
|||
|
Hi,
I agree with #1 and I initially like the concept of having a view specific interface. However, if the interface resides in the presentation layer and your domain objects implement that interface, haven't you made your domain objects dependant on your presentation layer? Quote:
|
|
#66
|
|||
|
|||
|
You definately would if you'd have to write extra methods in the domain class to implement the interface. What you do here is simply abstract away already existing interfaces of that object. It seems to me a little bit like defining remote and home interfaces for EJBs (uhhh... that ugly word
... But in a pure object oriented way you are right, of course.I think that the problem is, that if the Service returns a domain object, you have to import it into your presentation class for example. And if you can't force presentation class developers to use the interface, all the fancy interfacing isn't worth a penny ![]() Damn... it looked to good ![]() Regards |
|
#67
|
|||
|
|||
|
Couldn't your services return the View Interface?
|
|
#68
|
|||
|
|||
|
Quote:
In the "anaemic" view of course, you would be happy to permit arbitrary modification by your domain objects through view, since this would have no behavioural impact until the modifications were inspected by the service layer. I do accept all the arguments against anaemic models, but am continuing to find they offer a number of practical and design benefits - on the other hand I'm firmly convinced we must make sure not to adopt principles and technologies that rule out the use of "full" domain models. In general I think some form of declarative proxying ("declarative" used in the sense that Spring offers "declarative" transaction management to contrast with the "programmatic" variety) could be very productive in this area. |
|
#69
|
|||
|
|||
|
When I code domain objects I like to break them into 2 types: regular domain objects( Customer, Address, etc.) and stateful Use Case controllers. I don't break controllers one for every use case. They might be responsible for few related use cases and they use the state and references to regular domain objects to fulfil their responsibilities. I like to move as much as possible domain logic into regular domain objects except data access. Controllers are aware and initiate calls to DAOs or repositories.
|
|
#70
|
|||
|
|||
|
Hi folks, excelent post. I'd like to share my experiance in a quite big project, with hundreds (or even thousands) of services and tens of business modules.
I also have some architectural and design questions, some related to Spring usage good practices. The application was built upon business modules, each consisting of these layers: BUSINESS MODULE +---------------+ | view | +---------------+ | communication | +---------------+ | service | +---------------+ | domain | +---------------+ | dao | +---------------+ * Business modules where divided so as to model different business areas of the client organization. * Interaction beween business modules was service-driven, with the idea of hiding business details (and model) inside each module. We had some trouble though, in the dao layer, when objects from one module needed to store references to objects from another module. * The communication layer was completely use-case oriented (see ahead what I mean). This layer consisted basically in dto's and proxies with logic for transforming domain objects to and from the dto's. By use-case oriented I mean that each use case had it's own dto with only extrictly the information needed for the use case. DTO's where first intendend to serve as the clasic pattern suggests, since the view and the application server where in separate machines. They also accomplished an excelent work in decoupling the business domain and the views, flattening complex domain object graphs into simple single objects. Another achievement of this layer was that these dto worked as dettached objects allowing to close hibenrate sessions BEFORE rendering the view. * The service layer worked properly as a service layer :P, only as a facade of the underlying domain and for transaction demarcation. They where NOT AWARE of the dto's. All the transformations between dto's and model-objects was handled by the communication layer. * The domain layer consisted in all business logic. * The dao layer consisted in crud and query operations, with no business logic. In my experience, the DTO's did a great job in the last two points and I prefer this approach rather than the "Open Session in View" pattern, which is not applicable in a distributed environment. Even if the environment is not distributed, I'd prefer this pattern rather than coupling the view to such low-level implementation issues. The fact that they were use-case specific also draw in a significant performance improvement, compared to initializing the whole domain-graph before detaching. We worked a lot with code generation, to simplify the coding and mantenience of this DTO's. So, here is are a few questions: 1. Does your view layers interact directly with the domain objects? 2. If so, Don't you think this approach couples the view and the domain too tight? How do you manage the detaching? Do you initialize the complete graph? 3. If not so, do you work with dto's? how do you create them? by hand? code generation? dynamically? 4. Which should be the scope of the application contexts / bean factories (ej: layer, module)? How many of them should exists? 5. Which classes should do de beanFactory.getBean("someBean")? 6. Quote:
PS: Quote:
|
![]() |
| Thread Tools | |
| Display Modes | |
|
|