Thursday 10 December 2009

Moving to Git

Since implementation of the core features of DDDSample is almost finished I am thinking about opening the project for external contribution. In order to make it happen I am moving the main code repository from CodePlex's TFS to github. It will allow you to branch DDDSample.Net at will and publish your modifications online.


I would be very happy to post links to your modifications here and on the project main site on CodePlex (I am not moving the site, only the repository). Test version of the git-ed repository is available here:


git://github.com/SzymonPobiega/DDDSample.Net.git


Please download it and try if it works for you.

Thursday 3 December 2009

0.5, finally asynchronous!

I am very proud to announce that just released version 0.5 of DDDSample.Net demonstrates (finally!) how inter-aggregate communication was supposed to work from the beginning: using asynchronous communication patterns.

Version 0.5 contains 3 different work modes (you can change them using solution configuration switch):
  • InMemory. In this mode domain objects are not persisted but, instead, stored in static collections in main memory. This mode is intended to help novice users head-start with DDDSample since it does not need any additional configuration to work -- just install the msi package.
  • NHibernate. In this mode NHibernate is used to persist domain model data. Inter-aggregate communicaton is done synchronously using domain event pattern.
  • NHibernateAsynch. This mode demonstrates full power of architectural approach used in DDDSample.Net. Data is stored using NHibernate while asynchronous communication between aggregates is handled by NServiceBus/MSMQ combination.
Next (minor) step in DDDSample.Net development should be probably replacing InMemory mode with SQLite in-memory database. What's the difference? Current in-memory mode doesn't use O/RM. It would be nice to have the sample as easy to run as it is now and have it persist it's data using NHibernate so that users whould be able to see the process through all the layers.

Stay tuned!

Monday 16 November 2009

Version 0.4

This release was meant to clean-up the CI stuff. Finally I managed to get scenario-based integration test 'From Hongkong to Stockholm' working correctly using SQLite both on TeamCity and localy.

There is also some increment with regard to functionality. I added 'Next expected activity' feature and modified main menu slightly. It now includes a page for listing all registered cargoes (helps greatly in testing).

Please, download from here and try if you like it!

Tuesday 10 November 2009

Continous Integration

Hi all!

I am proud to announce that DDDSample.Net finally has a Continous Integration configured. Big thanks to Kyle who accepted my registration request for a place on CodeBetter TeamCity server.

Direct effect of this event is the 'Most recent builds' area where you can track project progress. The indirect effect is that development work will be streamlined and finally there will be some hammer to hit me when I break the build.

Next thing to do is to create a WiX script to replace the Setup Project (setup projects require Visual Studio to be installed on the machine in order to generate the installation package).

In the meantime I will try to release the 0.4 version of DDDSample. Stay tuned!

Tuesday 3 November 2009

Command Query Separation

Command Query Separation is an architectural style which encourages building two separate models for one particular domain. One model is optimized for commands (modifications, like inserts, updates and deletes) and the other is optimized for queries (probably using star, warehouse-like schema).

The goals of CQS are to make both subsystems scale well using methods best suited for each one and to free the command model (which encapsulates the core business logic) from UI related code.

DDDSample is an implementation of sample from Eric Evans' book and, as such, is not using CQS principles. It is that because its purpose is to demonstrate basics of DDD not 'polluted' by derived concepts.

Yet the DDD 'knowledge crunching' process demonstrated in the book by Evans leads to a model which is very well suited for scaling. How is it done?

It is simply because DDDSample (as well as my .NET version) is built according to other good DDD practice--one which says that communication between aggregates is asynchronous. Despite not being named officially as CSQ-driven, DDDSample model has two aggregates representing the same concept (Cargo), one optimized for commands and the other one for queries.

Most of processing-intensive operations of Cargo entity are being done via Handling aggregate which asynchronously pushes notifications into the Cargo aggregate. The latter contains a lot of redundant information which is optimized for searching cargoes and displaying cargo information on the screen.

When I was thinking about future of DDDSample.Net I thought about CQS in the first place. After careful analysis I know it will not give any breaktrough in the field of scalability, but I hope it will make these scalability enabling aspects more explicit in the codebase and will clean up the core business code from presentation concerns.

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.