Wednesday 28 October 2009

Entities

Entities are the stars of the domain model. They are the most valuable elements in terms of amount of business logic. They usually represent the most important real life concepts - those which have its own identity. And identity is something which is critical to the entities.

Entities which have different IDs are different entities. That is what the books would told you. But how does it look like in practice?

In DDDSample there is special interface for entities: IEntity. It defines one method
boolean sameIdentityAs(T other)
Implementation checks whether the other object is null (in this case returns false) and, if not, compares business identities of the objects.

There is also the equals method overridden on all entity classes. equals compares all the data contained in particular entity.

I think I understand some of the reasoning behind this solution. The sameIdentityAs method makes explicit that we are comparing business, not database, keys and that we care about identity. What I don't understand is the equals method. Why on Earth should I compare entities by their value? Ideally (in CQS?) they should expose no values at all.

I decided to get rid of the equals (in my, C#, case Equals) overriding. That was the easy decision. Now the hard one: what to do with the SameIdentityAs? As you could read in the previous episode, I decided to get rid of similar method on value types. I think I had strong reasons there, but here?

The reason I consider giving up on the sameIdentityAs at all are ORMs. They provide me with an Identity Map out of the box - a warranty that two object references with same DB key are in fact one object instance on the heap. With that promise I can simply use == and != to compare addresses and the result is the same as business key comparison.

I strongly believe that all of my applications would use ORMs to store data in the foreseeable future. Even if I am wrong, in case I had to change my data access strategy completly, I wouldn't expect that the change would be simply switching the DLLs. It certainly would be a painful task. I won't make it easier just by pretending that I am not dependant on an ORM. Yes, I am and this fact is reflected clearly by the structure of the model. If I would plan to use OODBMS, I would structure my model completely different.

So, to sum up, we will get rid of those sameIdentityAs methods as well and use plain C# equality operators for both entities and value objects. In case of entities we will depend on Identity Map implemented in the ORM. It will make our code more consistent in context of object comparison.

Tuesday 27 October 2009

A little break...

I have to stop my work on DDDSample.Net for a while. I leave you with official release 0.3 and some cool goodies in trunk (first and only integration test passing!). I've temporarily switched to NetMX--my previous project, port of JMX specification to .NET. I finally got some positive feedback from my company and other people and got excited about implementing plain WCF and WS-Management interoperability features in NetMX. If I succeed, it will be one of the firts server implementations of WS-Management in .NET. Wish me luck!

PS. Some of you probably noticed that posts are in the plural form but I am the only active committer. The explanation is simple--when we started DDDSample.Net we were a group of four, but as time went by, other people found out they are to busy to contribute, so I left alone. From now on I will write in singular not to confuse you.

PS2. Although I don't have time to code, I will try to publish on DDDSample.Net blog.

Thursday 22 October 2009

Version 0.3

I will start will little correction. Previous release announcement should certainly be '0.2', not '2.0'. This release is 0.3 and it contains totally different features then we planned when I was writing this post. As we stated in the release description, we manage to accomplish three tasks:
  • Add cargo delivery status to cargo aggregate
  • Add handling events (with web-based registration form)
  • Enable re-routing of misrouted cargoes
We have made a hard decision to postpone any work related to voyage aggregate and finding optimal routes for cargoes. Fake cargo routing algorithm was fixed (two minor bugs) and is working fine. Implementing voyages turned out to be just to hard, at least for now. As you could read in previous post, we wanted to implement cargo routing by the book. One of the major problems we encountered was related to so-called voyage numbers. They seem to identify two somewhat different concepts in DDDSample:
  • particular cargo vessel voyage from point A to point B starting at date T1 and ending at T2
  • cargo vessel route from point A to point B which is traversed by cargo vessels on a regular basis
Before we start implementing this voyage related areas we must refine conepts of voyage and voyage number in the context of both core DDDSample and cargo routing service.

Sunday 18 October 2009

Cargo routing service

For those who do not know DDDSample, cargo routing service is a domain service which is responsible for finding best routes for delivering cargo from its origin to destination. The term 'best' is out of scope of this blog post. I would like to focus on the design of the sample.

In the original code the service is defined as an interface in the domain layer. Its implementation defines an anti corruption layer between the cargo booking and handling bounded context and the routing bounded context. That is OK. But the other side of the anti corruption layer is totally neglected. There is only a simple fake algorithm which operates on pre-defined in-memory kept data.

I understand this is because DDDSample project is focused on cargo booking and handling, not routing. But since we build our .NET version from scratch and have some degree of freedom, I would like to create a cohesive solution for the routing part. For me cohesive means that data in the voyage aggregate (which is basicly all the carrier voyages available for moving cargos around) is in synch with data in the routing bounded context no matter if we are using an in-memory (fake) or real database.

I think that the best, from the DDDSample.Net educational function perspective, solution would be to build at least a part of routing BC by the book and would be responsible for maintaining the voyage and publishing voyage related data to all the interested parties (such as cargo booking and handling BC). 

Friday 16 October 2009

Version 0.2

Next version of DDDSample.Net is available on codeplex site. Please download it and let me know if you like the way the project is developed.

This release adds cargo routing feature. When cargo is registered, it now can be routed according to the route chosen from several route candidates. The route generation code is a fake in this release and generates only one simple route. The real code will be delivered in version 0.3.

Saturday 10 October 2009

Value Objects

Value Objects are those elements of domain model that do not have their own identity, only the data. Two instances of a particular Value Object are the same if they contain the same data.

In DDDSample all the Value Objects implement ValueObject interface which defines one operation
boolean sameValueAs(T other)
The implementation of the method checks whether the other object contains identical data. The equals implementation in value object uses internally the sameValueAs method.

In C# the context is a little bit different. We have some simple operator overloading and, by convention, all structs (like System.Decimal) and immutable classes (like System.String) have the equality operator overloaded. I find DDD's Value Objects very similar to these .NET stucts -- both are immutable and both are considered equal when contain the same atomic data.

We decided to make an exception in following Java DDDSample design in case of Value Objects and use standard .NET idioms to represent Value Objects. Our Value Objects define == and != overloads and we use them where sameValueAs is used in the original solution. I find this kind of code cleaner and more natural to .NET developers - the would tread Value Object instances like the simple classes they are familiar with.

To avoid code duplication in the comparison and hash code computation implementation, we created a base class for all Value Objects where we put the logic responsible for the calculations. This logic depends on the data contained by a concrete Value Object.

There is similar concept in original DDDSample experimental project (dddsample.domain.shared.experimental). It uses reflection to extract values from Value Object instance. Our approach is somewhat different. We decided to be explicit in what is and what is not considered vales contained by Vaule Object instance. We created a special protected abstract method
protected abstract IEnumerable<object> GetAtomicValues()
used by ValueObject base class methods to obtain a collection of contained data. We use another .NET idiom -- iterator blocks -- to make the code as readable as possible. For example, the RouteSpecification's GetAtomicValues implementation looks like this
protected override IEnumerable<object> GetAtomicValues()
{
   yield return _origin;
   yield return _destination;
   yield return _arrivalDeadline;
}
To sum up, we decided to drop the explicitness of comparing Value Objects which manifested itself in using special method instead of usual langugage mechanisms and, instead, use plain C#. It was possible because C# has some special features (i.e. operator overloading) which make this possible. I would argue that
trackingId == otherTrackingId
is more readable than
trackingId.sameValueAs(otherTrackingId)

Wednesday 7 October 2009

Application Events vs Domain Events

First thing that made me confused when reading original DDDSample source code were those 'application events' - an interface defined on an the application layer level which defines (possibly) asynchronous operations used to communicate between aggregates.

I used to view application layer as merely orchestrating domain operations. Application layer methods were supposed to be called either by GUI or by messaging infrastructure.This layer was also responsible for managing non-functional requirements, such as transactions and logging. I have always followed zealously the 'no logic in app layer' principle. When I started digging deep into DDD, I encountered Udi Dahan's series about domain events. I got to like the idea of domain object pushing out events.

So, now you understand my confusion when I encountered the events on the app layer level. Who and what is wrong?

I started with examining the Java way of defining app layers. In .NET we usually create one assembly per layer. A fairly complicated solution can contain as few as 4-5 assemblies and that is OK. In Java however, there is no notion of assemblies, only packages. And package is a completely different animal. A package, more or less, resembles a .NET namespace - is much more focused and fine-grained.

Application layer responsibilities which I was used to are divided into 2 main (and some helper) packages in DDDSample: the app layer itself and a facade for calling it from GUI code. The thinner app layer is, naturally, much closer to domain code, than would be in a .NET solution, because it is free of any UI or messaging dependencies. The breech in encapsulation of domain layer is much smaller in this fine-grained package structure then it would by in coarse-grained .NET code.

There is also another issue - an issue of naming. The DDDSample project names its events 'application events'. Udi called his mechanism 'domain events'. It the latter case there is a name clash with events as domain elements: the entities which don't change their state. Both live in the domain and both are events in their nature. Udi's events, however, are transient - their role is to push state change notifications out of the domain. On the contrary, events as domain elements are persistent entities. So, it makes sense, from purely naming perspective, to define these transient event as 'application events' and avoid the naming confusion.

The effect of this name and semantics clash is critical in the HandlingEvent registration function. On one hand HandlingEvent is an event as domain element - an immutable entity. And on the other hand, it is also an event in Udi's sense - it pushes out, from the Handling aggregate, a notification of state change to be processed within the Cargo aggregate. In the original code the application event is published by the app layer and this approach solves the problem quite well. But I wanted bady to use domain events as described by Udi and it came out that there is no object which can be made responsible for publishing the transient 'domain event' since only operations performed on HandlingEvents are create (using constructor) and store (using repository).

I decided to change the design in this particular area and make HandlingHistory object responsible for both storing HandlingEvent persistent events and publishing CargoWasHandler transient events. I think it finally solves my problem, at least for now. And, completely for free, I made the design follow Udi's advice not to create aggregate roots.

Friday 2 October 2009

Version 0.1

Welcome again!

I am glad to announce that first version of DDDSample.Net is available here (binary package) and here (source code)!

This version include very little business functionality - only cargo booking and redirecting. Its main goal is to give preview of how we will implement the whole project. Many design decisions has been already made and next few posts will describe some of them in detail.

Please, download the demo and give us your feedback. Every opinion is worthy:)

DDDSample.Net started!

Welcome to the DDDSample.Net blog!

DDDSample.Net is a shadow project for DDDSample, a .NET port of original Java sample application. Our goals (inspired by the original project's purpose) are following:
  • Crate a how-to example for implementing a typical DDD application. Our sample is not going to show the way to do it, but a decent way. Our initial short-term goal is to keep de design as close to DDDSample as possible to make comparations between technologies more easy.
  • Support discussion of implementation practices. Variations could show trade-offs of alternative approaches, helping the community to clarify and refine best practices for building DDD applications.
  • Lab mouse for controlled experiments. We will focus on different DDD patterns and their impact on shape of the solution. We hope to inspire the community to create forks and branches of the sample using different design approaches like Command Query Separation.
DDDSample.Net will be implemented on a feature-by-feature basis. Each feature spans all the layers, from UI down to data access.

This blog is intended to a place to publish project progress informations, discussions of design decisions made in the original project and all other 'temporary' stuff. Treat it as a stream of events. These events will be aggregated on the codeplex site where you will find up-to-date information about the project.