Tuesday, August 08, 2006

Domain-Driven Design - Not supported!

I've just finished reading Eric Evan's book Domain-Driven Design for the second time. And again I liked it very much :-). Now, that the mainstream of enterpise development (EJB) has also figured out, that anemic domain models are bad practice, every one says: "We can create rich domain models using Java with all those little business methods and semantics in it".
Mmmh... do we? I'm not aware of a programming language which really supports creation of domain models. A domain models consists of called concepts Entity, ValueObject, Properties, (bi-directional) References etc.. I haven't heard of such concepts in Java. What I see is that the semantics of these concepts are usually implemented in a cross-cutted manner. Just have a look at the first example from the EJB3 JPA spec:


@Entity
public class Customer implements Serializable {
private Long id;
private String name;
private Address address;
private Collection<Order> orders = new HashSet();
private Set<PhoneNumber> phones = new HashSet();
// No-arg constructor
public Customer() {}
@Id // property access is used
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@OneToMany
public Collection<Order> getOrders() {
return orders;
}
public void setOrders(Collection<Order> orders) {
this.orders = orders;
}
@ManyToMany
public Set<PhoneNumber> getPhones() {
return phones;
}
public void setPhones(Set<PhoneNumber> phones) {
this.phones = phones;
}
// Business method to add a phone number to the customer
public void addPhone(PhoneNumber phone) {
this.getPhones().add(phone);
// Update the phone entity instance to refer to this customer
phone.addCustomer(this);
}
}


I guess the writers of the spec think that this is a really lightweight and convenient way to describe a domainmodel. Compared to an entity bean from 2.1 it is, but it's far away from perfect!

This would be much more convenient:

entity Customer {
@ID Long id
String name
Address address
Collection<Order> orders
Set<PhoneNumber> phones oppositeOf customers
}


Additonally the snippet from the spec is an example of a weak domain model, as it doesn't ensure consistency. Therein the user can decide if he wants to manage the bidirectional references (phones <-> customers) manually (and maybe ending up with inconsistent data) or using the 'addPhone()' method and let the implementation update the opposite reference.

There are many more useful concepts we would need in good domain models. Another example would be containment references, constraints, multiple inheritence or a built-in observer pattern.

Additionally I would like support for closures in order to write derived properties like this:


Collection<Order> ordersSince(Date date) {
return orders.select(o|o.date>=date);
}


instead of


Collection<Order> ordersSince(Date date) {
List<Order> result = new ArrayList<Order>();
for(Order o : orders) {
if (o.date>=date)
result.add(o);
}
return result;
}


For now, the only good solution is code generation, but I would prefer a first class support for such domain model concepts, because I don't think the usage of rich and consistent domain models is too specific for a general purpose language.