Methods & Tools Software Development Magazine

Software Development Magazine - Project Management, Programming, Software Testing

Scrum Expert - Articles, tools, videos, news and other resources on Agile, Scrum and Kanban

An Introduction to Domain Driven Design - Page 3

Dan Haywood, Haywood Associates Ltd, http://danhaywood.com/

Problems and Hurdles

Enforcing a layered architecture

Here's the first thing: it can be difficult to strictly enforce the architectural layering. In particular, the seeping of business logic from the domain layer into the application layer can be particularly insidious.

I've already singled out Java's EJB2 as a culprit here, but poor implementations of the model-view-controller pattern can also cause this to happen. What happens is the controller (= application layer), takes on far too much responsibility, leaving the model (= domain layer) to become anaemic. In fact, there are newer web frameworks out there (in the Java world, Wicket [10] is one up-and-coming example) that explicitly avoid the MVC pattern for this sort of reason.

Presentation layer obscuring the domain layer

Another issue is trying to develop a ubiquitous language. It's natural for domain experts to talk in terms of screens, because, after all, that is all that they can see of the system. Asking them to look behind the screens and express their problem in terms of the domain concepts can be very difficult.

The presentation layer itself can also be problematic, because a custom presentation layer may not accurately reflect (could distort) the underlying domain concepts and so compromises our ubiquitous language. Even if that isn't the case, there's also just the time it takes to put together a user interface. Using agile terminology, the reduced velocity means less progress is made per iteration, and so fewer insights are made into the domain overall.

The implementation of the repository pattern

On a more technical note, newbies also sometimes seem to get confused separating out the interface of a repository (in the domain layer) from its implementation (in the infrastructure layer). I'm not exactly sure why this is the case: it's a pretty simple OO pattern, after all. I think it might be because Evans book just doesn't go down to this level of detail, and that leaves some people high and dry. But it's also possibly because the idea of substituting out the persistence implementation (as per the hexagonal architecture) is not that widespread, giving rise to systems where persistence implementation has bled into the domain layer.

The implementation of the service dependencies

Another technical concern - and where there can be disagreement between DDD practitioners - is in terms of the relationship between entities and domain/infrastructure services (including repositories and factories). Some take the view that entities should not depend on domain services at all, but if that's the case then it falls to the outer application services to interact with the domain services and pass the results into the domain entities. To my way of thinking this moves us towards having an anaemic domain model.

A slightly softer viewpoint is that entities can depend on domain services, but the application service should pass them in as needed, for example as an argument to an operation. I'm not a fan of this either: to me it is exposing implementation details out to the application layer ("this entity needs such-and-such a service in order to fulfil this operation"). But many practitioners are happy with this approach.

My own preferred option is to inject services into entities, using dependency injection. Entities can declare their dependencies and then the infrastructure layer (eg Hibernate, Spring or some other framework) can inject the services into the entities:

public class Customer {
...
private OrderFactory orderFactory;
public void setOrderFactory(OrderFactory orderFactory) {
this.orderFactory = orderFactory;
}
...
public Order placeOrder( ... ) {
Order order = orderFactory.createOrder();
...
return order;
}
}

One alternative is to use the service locator pattern. All services are registered, for example into JNDI, and then each domain object looks up the services it requires. To my mind this introduces a dependency on the runtime environment. However, compared to dependency injection it has lower memory requirements on entities, and that could be a deciding factor.

Inappropriate modularity

As we've already identified, DDD distinguishes several different levels of granularity over and above entities, namely aggregates, modules and BCs. Getting the right levels of modularization right takes some practice. Just as an RDBMS schema may be denormalized, so too can a system not have modularity (becomes a big ball of mud). But an overnormalized RDBMS schema - where a single entity is broken out over multiple tables - can also be harmful, and so too can an overmodularized system, because it then becomes difficult to understand how the system works as a whole.

Let's first consider modules and BCs. A module, remember, is akin to a Java package or .NET namespace. We want the dependency between two modules to be acyclic, for sure, but if we do decide that (say) customer depends on order then there's nothing in particular extra we need to do: Customer can simply import the Order package/namespace and uses its interfaces and classes as needed.

If we put the customer and order into separate BCs, however, then we have substantially more work to do, because we must map the concepts in the customer BC to those of the order BC. In practice this also means having representations of the order entities in the customer BC (per the general ledger example given earlier), as well as the mechanics of actually collaborating via message bus or something else. Remember: the reason for having two BCs is when there are different end-users and/or stakeholders, and we can't guarantee that the related concepts in the different BCs will evolve in the same direction.

Another area where there can be confusion is in distinguishing entities from aggregates. Every aggregate has an entity acting as its aggregate root, and for lots and lots of entities the aggregate will consist of just this entity (the "trivial" case, as mathematicians would say). But I've seen developers fall into thinking that the whole world must reside within a single aggregate. So, for example, Order contains OrderItems (so far so good) which reference Products, and so the developer concludes that Products are also in the aggregate (no!) Even worse, a developer will observe that Customer have Orders, and so think this means we must have mega-aggregate of Customer / Order / OrderItem / Product (no, no, no!). The point is that "Customer have Orders" does not mean imply aggregation; Customer, Order and Product are all aggregate roots.

In practical terms, a typical module (and this is very rough and ready) might contain a half-dozen aggregates, each of which might contain between one entity and several. Of these half-dozen, a good number may well be immutable "reference data" classes. Remember also that the reason we modularize is so that we can understand a single thing (at a certain level of granularity). So do remember that the typical person can only keep in their head between 5 and 9 things at a time [11].

Getting Started

As I said at the outset, you might well have encountered many of the ideas in DDD before. Indeed, every Smalltalker I've spoken with (I'm not one, I'm afraid to say) seems glad to be able to go back to a domain-driven approach after the wilderness years of EJB2 et al.

On the other hand, what if this stuff is new? With so many different ways to trip up, is there any way to reliably get started with DDD?

If you look around the Java landscape (it's not as bad for .NET) there are literally hundreds of frameworks for building web apps (JSP, Struts, JSF, Spring MVC, Seam, Wicket, Tapestry, etc). And there are scores of frameworks out there targeting the infrastructure layer, both from a persistence perspective (JDO, JPA, Hibernate, iBatis, TopLink, JCloud and so on) or other concerns (RestEasy, Camel, ServiceMix, Mule etc). But there are very few frameworks or tools to help with what DDD says is the most important layer, the domain layer.

Since 2002 I've been involved in with (and these days am a committer to) a project called Naked Objects, open source on Java [12] and commercial on .NET [13]. Although Naked Objects wasn't explicitly started with domain-driven design in mind - indeed it predates Evans' book - it holds by a very similar set of principles to DDD. It also makes it easy to overcome the hurdles identified earlier.

You can think of Naked Objects analogously to an ORM such as Hibernate. Whereas ORMs build a metamodel of the domain objects and use this to automatically persist the domain objects to an RDBMS, Naked Objects builds a metamodel and uses this to automatically render those domain objects in an object-oriented user interface.

Out-of-the-box Naked Objects supports two user interfaces, a rich client viewer (see Figure 9), and a HTML viewer (see Figure 10). These are both fully functional applications that require the developer to write only the domain layer (entities, values, repositories, factories, services) to run.

Figure 9: Naked Objects Drag-n-Drop Viewer

Figure 10: Naked Objects HTML Viewer

Let's take a look at the (Java) code for the Claim class (shown in the screenshots). First off, the classes are basically pojos, though we normally inherit from the convenience class AbstractDomainObject just to factor out the injection of a generic repository and provide some helper methods:

public class Claim extends AbstractDomainObject {
...
}
Next, we have some value properties:
// {{ Description
private String description;
@MemberOrder(sequence = "1")
public String getDescription() { return description; }
public void setDescription(String d) { description = d; }
// }}

// {{ Date
private Date date;
@MemberOrder(sequence="2")
public Date getDate() { return date; }
public void setDate(Date d) { date = d; }
// }}

// {{ Status
private String status;
@Disabled
@MemberOrder(sequence = "3")
public String getStatus() { return status; }
public void setStatus(String s) { status = s; }
// }}

These are simple getter/setters, with return types of String, dates, integers and so on (though Naked Objects supports custom value types too). Next, we have some reference properties:

// {{ Claimant
private Claimant claimant;
@Disabled
@MemberOrder(sequence = "4")
public Claimant getClaimant() { return claimant; }
public void setClaimant(Claimant c) { claimant = c; }
// }}

// {{ Approver
private Approver approver;
@Disabled
@MemberOrder(sequence = "5")
public Approver getApprover() { return approver; }
public void setApprover(Approver a) { approver = a; }
// }}

Here our Claim entity references other entities. In fact, Claimant and Approver are interfaces, so this allows us to decouple our domain model into modules as discussed earlier on.

Entities can also have collections of entities. In our case Claim has a collection of ClaimItems:

// {{ Items
private List<ClaimItem> items = new
ArrayList<ClaimItem>();
@MemberOrder(sequence = "6")
public List<ClaimItem> getItems() { return items; }
public void addToItems(ClaimItem item) {
items.add(item);
}
// }}

And we also have (what Naked Objects calls) actions, namely submit and addItem: these are all public methods that don't represent properties and collections:

// {{ action: addItem
public void addItem(
@Named("Days since")
int days,
@Named("Amount")
double amount,
@Named("Description")
String description) {
ClaimItem claimItem = newTransientInstance(ClaimItem.class);
Date date = new Date();
date = date.add(0,0, days);
claimItem.setDateIncurred(date);
claimItem.setDescription(description);
claimItem.setAmount(new Money(amount, "USD"));
persist(claimItem);
addToItems(claimItem);
}
public String disableAddItem() {
return "Submitted".equals(getStatus()) ? "Already
submitted" : null;
}
// }}
// {{ action: Submit
public void submit(Approver approver) {
setStatus("Submitted");
setApprover(approver);
}
public String disableSubmit() {
return getStatus().equals("New")?
null : "Claim has already been submitted";
}
public Object[] defaultSubmit() {
return new Object[] { getClaimant().getApprover() };
}

// }}

These actions are automatically rendered in the Naked Objects viewers as menu items or links. And it's the presence of these actions that mean that Naked Objects apps are not just CRUD-style applications.

Finally, there are supporting methods to display a label (or title) and to hook into the persistence lifecycle:

// {{ Title
public String title() {
return getStatus() + " - " + getDate();
}
// }}

// {{ Lifecycle
public void created() {
status = "New";
date = new Date();
}
// }}

Earlier I described Naked Objects domain objects as pojos, but you'll have noticed that we use annotations (such as @Disabled) along with imperative helper methods (such as disableSubmit()) to enforce business constraints. The Naked Objects viewers honour these semantics by querying the metamodel built at startup. If you don't like these programming conventions, it is possible to change them.

A typical Naked Objects application consists of a set of domain classes such as the Claim class above, along with interfaces and implementations for repository, factory and domain/infrastructure services. In particular, there is no presentation layer or application layer code. So how does Naked Objects help with some of the hurdles we've already identified? Well:

  • Enforcing a layered architecture: because the only code we write are the domain objects, there's no way that domain logic can seep out into other layers. Indeed, one of the original motivations for Naked Objects was to help develop behaviourally complete objects
  • Presentation layer obscuring the domain layer: because the presentation layer is a direct reflection of the domain objects, the whole team can rapidly deepen their understanding of the domain model. By default Naked Objects takes the class names and method names straight from the code, so there is a strong incentive to get the naming right in the ubiquitous language. In this way Naked Objects also supports DDD's model-driven design principle
  • The implementation of the repository pattern: the icons / links that you can see in the screenshots are actually repositories: an EmployeeRepository and a ClaimRepository. Naked Objects supports pluggable object stores, and normally in prototyping we use an implementation against an in-memory object store. As we move towards production, we then write an implementation that hits the database.
  • The implementation of the service dependencies: Naked Objects automatically injects service dependencies into every domain object. This is done when the object is retrieved from the object store, or when the object is first created (see newTransientInstance(), above). In fact, all that such helper methods do is delegate to a generic repository/factory provided by Naked Objects called the DomainObjectContainer.
  • Inappropriate modularity: We can modularize into modules just by using Java packages (or .NET namespaces) in the normal way, and use visualization tools such as Structure101 [14] and NDepend [15] to ensure that there are no cyclic dependencies in our codebase. We can modularize into aggregates by annotating as @Hidden any aggregated objects that represent the inner workings of our visible aggregate root; these then won't appear in the Naked Objects viewers. And we can write domain and infrastructure services to bridge over to other BCs as we need to.

There are plenty of other features that Naked Objects offers: it has an extensible architecture that - in particular - allows other viewers and object stores to be implemented. The next generation of viewers being developed (for example Scimpi [16]) offer more sophisticated customisation capabilities. In addition, it offers multiple deployment options: for example, you can use Naked Objects just for prototyping and then develop your own more tailored presentation layer as you move towards production. It also has integration with tools such as FitNesse [17], and can automatically provide a RESTful interface to your domain objects [18].

Next Steps

Domain-driven design brings together a set of best-practice patterns for developing complex enterprise applications. Some developers will have been applying these patterns for years, and for these guys DDD is perhaps little more than an affirmation of their existing practices. For others though, applying these patterns can be a real challenge.

Naked Objects provides a framework for both Java and .NET that, by taking care of the other layers, allows the team to focus on the bit that matters, the domain model. By exposing the domain objects directly in the UI, Naked Objects allows the team to very naturally build up an unambiguous ubiquitous language. As the domain layer firms up then the team can develop a more tailored presentation layer if required.

So, where next?

Well, the bible for DDD itself is Eric Evans original book, "Domain-Driven Design" [1], recommended reading for all. The Yahoo newsgroup for DDD [19] is also a pretty good resource. And if you're interested in learning more about Naked Objects, you can search out my book, "Domain Driven Design using Naked Objects" [20], or my blog [21] (NO for Java) or the Naked Objects website [13] (NO for .NET). Happy DDD'ing!

References

[1] Domain Driven Design Community http://domaindrivendesign.org/

[2] Spring BeanDoc http://spring-beandoc.sourceforge.net/

[3] Anaemic Domain Model, Martin Fowler http://martinfowler.com/bliki/AnemicDomainModel.html

[4] FitNesse http://fitnesse.org

[5] Hexagonal Architecture, Alistair Cockburn http://alistair.cockburn.us/Hexagonal+architecture

[6] Big Ball of Mud,> Brian Foote & Joseph Yoder http://www.laputan.org/mud/

[7] Dependency Inversion Principle, Robert Martin http://www.objectmentor.com/resources/articles/dip.pdf

[8] LINQ http://msdn.microsoft.com/en-us/netframework/aa904594.aspx

[9] Hades http://hades.synyx.org/

[10] Apache Wicket Web Framework http://wicket.apache.org

[11] Magical Number Seven, ±2 http://en.wikipedia.org/wiki/The_Magical Number_Seven,_Plus_or_Minus_Two

[12] Naked Objects for Java http://nakedobjects.org

[13] Naked Objects for .NET http://nakedobjects.net

[14] Structure101 (for Java) http://www.headwaysoftware.com/products/structure101

[15] NDepend (for .NET) http://www.ndepend.com/

[16] Scimpi http://scimpi.org

[17] Tested Objects (FitNesse for Naked Objects) http://testedobjects.sourceforge.net

[18] Restful Objects (REST for Naked Objects) http://restfulobjects.sourceforge.net

[19] Yahoo DDD Newsgroup http://tech.groups.yahoo.com/group/domaindrivendesign/

[20] Domain Driven Design using Naked Objects, Dan Haywood http://pragprog.com/titles/dhnako

[21] Dan Haywood's Blog http://danhaywood.com

Related Methods & Tools articles

More Domain Driven Design Knowledge

Modeling Microservices with Domain Driven Design

The Good Parts of Domain Driven Design

7 Years of Domain-Driven Design


Go to Page 2


Click here to view the complete list of archived articles

This article was originally published in the Winter 2009 issue of Methods & Tools

Methods & Tools
is supported by


Testmatick.com

Software Testing
Magazine


The Scrum Expert