maandag 31 juli 2006

Back in Belgium

I'm back from vacation.

I've spent the past few days in Southern Spain, in the province of Andalucia.
We stayed in a hotel nearby the 'La Barossa' beach, from where we've explored the nearby region a bit.



This picture has been taken in Medina Sidonia. A 'pueblo blanco' (white town), a few km's more inward the country.

dinsdag 18 juli 2006

DDD: A Quickstart - Implementation using Test Driven Development

Introduction


In the first part of this serie, I've focussed on the modelling of the domain-model.
Now, since the entities, aggregates, etc... have been roughly defined in the first part, I think it's time to dive into the code.
Instead of directly writing classes to model the domain, I want to develop the domain layer using the Test Driven Development Mantra.
This means that I should start with writing a test case before I actually write the 'functional' code.
I will develop the domain using C#, so I'll use the NUnit Framework to create the unit tests.

A first use case


It would be helpfull to have some kind of a use case, so that I can start with writing a test for that use case.
I can start off with the use case that can be found in part 1 of this article:
A customer places an order.
By writing a unit test for this scenario first, I'm forced to think about the class interfaces. Writing the test first, will help me in creating a clear, simple and easy to use class interface and class hierarchy since I will design the classes in the way that I want to use them.
The Unit Test for the use case 'Customer places an Order' looks like this:

[TestFixture]
public class OrderTestCase
{
[Test]
public void TestNormalCustomerPlacesOrder()
{
ICustomerRepository custRep =
new CustomerMemoryStoreRepository();
IArticleRepository artRep =
new ArticleMemoryStoreRepository();

// Get a customer from the repository. We should
// make sure that this customer is a normal customer.
Customer c = custRep.GetCustomer (1);

// Create a new order for the Customer.
Order o = c.CreateNewOrder ();

// The Customer orders some articles...
Article art1 = artRep.GetArticle (1);
Article art2 = artRep.GetArticle (2);
OrderLine ol1 = o.CreateNewOrderLine();

ol1.NumberOfItems = 2;
ol1.SetArticle (art1);

o.AddOrderLine (ol1);
OrderLine ol2 = o.CreateNewOrderLine();

ol2.NumberOfItems = 5;
ol2.SetArticle (art2);

o.AddOrderLine (ol2);

// Now, the order-total should be equal
// to ( 2 * price of art1 ) + ( 5 * price of art2 )
Assert.AreEqual ((2 * art1.Price ) + ( 5 * art2.Price ),
o.OrderTotal );

}
}

This first test is pretty simple. It shows how a Customer can place an Order, and it checks if the OrderTotal of the Order is correct.
While this test case is very simple, you can already discover the advantage of Test Driven Development: by writing a Test first, I've already defined the API, the interface of the domain classes. This will make sure that the interface of those classes will be clear and intention revealing.
By writing the test first, you're forced to design the classes in a way where it's easy to use them. I think the above test is quite self-describing and doesn't need any further explanation.

Now, we should make the test pass. However, I know that good TDD practice preaches that you should make sure that the test fails first meaningfully. This is actually a quite important step, because it enables you to make sure that you know that what you're testing is correct. However, to keep this article a little bit more concise, I've allowed myself to skip this step.
At this point the test fails offcourse since we haven't written any functional code yet, so lets start with that right away.

The first thing that you encounter, is the ICustomerRepository and the IArticleRepository interface, along with the CustomerMemoryStoreRepository and ArticleMemoryRepository classes which implement these interfaces.
For this test, it is sufficient that the ICustomerRepository and the IArticleRepository interfaces look like this:


public interface ICustomerRepository
{
Customer GetCustomer( int customerId );
}

public interface IArticleRepository
{
Article GetArticle( int articleId );
}

The CustomerMemoryStoreRepository and the ArticleMemoryStoreRepository class are not a part of the Domain Layer. These classes are 'mock objects' that live in the assembly that contains the test cases. They do not really access a database, they just hold some objects in memory.

Then, let's get along with the Customer class. To be able to make the above test pass, it would be sufficient that the Customer class only has a CreateNewOrder() method at this point. However, we also want to identify a customer (it is an entity), so let's give it a name and an id as well.
This should be the implementation of the Customer class:


public class Customer
{
private int _id;
private string _name;

public Customer() : this(-1, string.Empty)
{
}

public Customer( int id, string name )
{
_id = id;
_name = name;
}

public int Id
{
get
{
return _id;
}
}

public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}

public Order CreateNewOrder()
{
return new Order(this);
}
}

The CreateNewOrder method creates a new Order, and passes the current Customer object as an argument. This is necessary so that we know to which Customer an Order belongs.
Since we have a reference to the Order class in the Customer class, lets continue with writing the Order class.

Since an Order is also an entity, we will want to uniquely identify an Order as well, so we're going to add an Id to this class as well. Next to that, we also want to know when the Order was made, so let's give the Order class an OrderDate member as well.


public class Order
{
private int _id;
private DateTime _orderDate;
private Customer _customer;
private IList _orderLines = new ArrayList();

public Order( Customer c ) : this(-1, c, DateTime.Now)
{
}

public Order( int id, Customer c, DateTime orderDate )
{
_id = id;
_customer = c;
_orderDate = orderDate;
}

public int Id
{
get
{
return _id;
}
}

public DateTime OrderDate
{
get
{
return _orderDate;
}
}

public Customer OwningCustomer
{
get
{
return _customer;
}
}

public IList OrderLines
{
get
{
return _orderLines;
}
}

public decimal OrderTotal
{
get
{
decimal total = 0.0M;

foreach( OrderLine ol in _orderLines )
{
total += ol.NumberOfItems * ol.ArticlePrice;
}

return total;
}
}

public OrderLine CreateNewOrderLine()
{
return new OrderLine (this);
}

public void AddOrderLine( OrderLine ol )
{
// Perform some checks before adding.
if( ol.IsArticleSet == false )
{
throw new ApplicationException ("You must specify an Article.");
}

if( ol.NumberOfItems == 0 )
{
throw new ApplicationException ("You must order at least one item.");
}

_orderLines.Add (ol);
}
}

Note that I've used an IList for the _orderLines member, and not the generic IList<T> type which would provide strong typing. The reason why I did this, is that I'm planning to use NHibernate as an O/R mapper between the domain classes and the relational database, and the version of NHibernate that I have now does not support generics yet.
I think the Order class is pretty straightforward and doesn't need any further explanation. I think the code is pretty self-explaining.


The OrderLine and Article class haven't been created yet, so let's do that right now.


public class OrderLine
{
private int _id;
private int _articleId;
private string _articleName;
private decimal _articlePrice;
private int _numberOfItems;
private Order _owningOrder;
private bool _isArticleSet;

public int Id
{
}

internal bool IsArticleSet
{
get
{
return _isArticleSet;
}
}

public int ArticleId
{
get
{
return _articleId;
}
}

public string ArticleName
{
get
{
return _articleName;
}
}

public decimal ArticlePrice
{
get
{
return _articlePrice;
}
}

public int NumberOfItems
{
get
{
return _numberOfItems;
}
set
{
_numberOfItems = value;
}
}

public Order OwningOrder
{
get
{
return _owningOrder;
}
}

public OrderLine( Order owningOrder )
{
_owningOrder = owningOrder;
id = -1;
_articlePrice = 0.0M;
_articleName = string.Empty;
_numberOfItems = 0;
}


public void SetArticle( Article art )
{
if( art != null )
{
_articleId = art.Id;
_articleName = art.Name;
_articlePrice = art.Price;
_isArticleSet = true;
}
else
{
_articleId = -1;
_articleName = string.Empty;
_articlePrice = 0.0M;
_isArticleSet = false;
}
}
}

I've decided to not put a reference to an Article object in the OrderLine class, because, when an existing Order is retrieved, the price of the Article can already have changed opposed to the price of the Article at the time the Order was made. So, we're not interested in the current price of the Article, but in the price of the Article at the time when the Customer has ordered that Article.
Therefore, I've decided to just put the Article information that is of interest into the OrderLine class, and make that information available through read-only properties. I've created a SetArticle method so that all the required Article information can be set at once, and in this way, we're sure that the Article information in the OrderLine class is correct.
The IsArticleSet flag is marked internal since it is of no use outside our domain-assembly. At this time, only the Order class uses it to check if the OrderLine that's being added has an Article set.

The Article class is very simple:


public class Article
{
private int _id;
private string _name;
private decimal _price;

public int Id
{
get
{
return _id;
}
}

public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}

public decimal Price
{
get
{
return _price;
}
set
{
_price = value;
}
}

public Article() : this(-1, string.Empty, 0.0M)
{
}

public Article( int id, string name, decimal price )
{
_id = id;
_name = name;
_price = price;
}
}

This code now makes sure that the test we've written passes. However, as I've said earlier, if I was to follow the TDD rules strictly, I should write code first that makes the test fail meaningfully. I've chosen to skip this step though, so that I can make this post a little bit shorter.


At this stage, we have the functionality that we need for a Customer to place Orders. However, we're not there yet. The code we have now, does not take 'Gold Customers' and 'Bad Paying Customers' into account.


Test Case for Gold Customers


To implement the functionality which gives Gold Customers a discount, I'll start of with writing a Unit Test again. This test is pretty similar as the previous one, but you should note that the Repositories are now promoted to be member variables of the class that contains the test-methods.

This is how the test looks like:


[Test]
public void TestGoldCustomerPlacesOrder()
{
// 2 is a gold-customer..
Customer c = custRep.GetCustomer (2);

// To be sure of it, test it...
Assert.IsTrue (c.Status == CustomerStatus.Gold,
"We should have a gold customer.");

Order o = c.CreateNewOrder ();

Article art1 = artRep.GetArticle (1);
Article art2 = artRep.GetArticle (2);

OrderLine ol1 = o.CreateNewOrderLine ();

ol1.SetArticle (art1);
ol1.NumberOfItems = 10;

o.AddOrderLine (ol1);

OrderLine ol2 = o.CreateNewOrderLine ();

ol2.SetArticle (art2);
ol2.NumberOfItems = 7;

o.AddOrderLine (ol2);

// The expected OrderTotal is the 'regular'
// OrderTotal minus a 5% discount.
decimal expected = ( 10 * art1.Price ) + ( 7 * art2.Price );
expected -= ( expected * 5 ) / 100;

Assert.AreEqual (expected, o.TotalAmountToPay);
}

In the above test, I retrieve the Customer with Id 2 out of the Repository. I assume that this is a Gold Customer, and, to be sure, the Status property of the Customer is tested.
Note that I haven't defined this property in the first version of the Customer class since there was no need for that property in the first unit test. This means that I'll have to extend the Customer class with a Status property.
This Status property will return an enumeration-type which indicates whether this Customer is a 'Normal', 'Gold' or 'Bad Paying' Customer. This also implies that I'll have to create that enumeration type.


Let's start of with creating the enumeration type, and adding the Status property to the Customer class. The enumeration is very simple:


public enum CustomerStatus
{
Normal,
Gold,
BadPayer
}

Determining the correct Status of a Customer requires a bit more work. First of all, we need to determine whether the Customer is a 'Gold Customer'. We'll have to do this by getting the total amount of money that a Customer has spent on Orders in the last 3 months. Since the Customer class does not contain a collection of the Orders that he made, we'll have to ask a Repository what that amount is for a specific Customer.
If this amount is over 2500 euro, the Customer is a Gold Customer.
To determine whether the Customer is a bad payer, we should do something similar; we'll need to know how many of his invoices have been or are overdue. To be able to know this, we'll also have to call in a repository.
In a first case, I'll concentrate on determining whether a Customer is a Gold Customer or not.

To do this, I'll have to extend the Customer class with the Status property:


public class Customer
{
...

public CustomerStatus Status
{
get
{
CustomerStatus result = CustomerStatus.Normal;

// First get the amount of orders this
// customer has made in the last 3 months.
decimal orderTotal = DomainSettings.Instance.
RepositoryFactoryObj.
CreateOrderRepository().
GetOrderTotalForCustomerSinceDate (this,
(DateTime.Now.AddMonths (-3));

if( orderTotal > DomainSettings.GoldAmountTreshold )
{
result = CustomerStatus.Gold;
}

return result;
}
}

...

}

This code is pretty straightforward I guess. First of all, we assume that the Customer is a Normal Customer. Then, I 'ask' the OrderRepository to give me the total amount for which the given Customer has placed Orders in the last 3 months. If this value is higher then a specific value, we can say that this Customer is a Gold Customer.

To be able to compile and run this code, we'll need some additional classes.
The first new class that springs into view, is the DomainSettings class, which appears to be a singleton.
I've decided to create this class to get easy access to things like repositories, and usefull constants, like the GoldAmountTreshold property. The DomainSettings class looks like this:


public class DomainSettings
{
private static DomainSettings _instance;

public static DomainSettings Instance
{
get
{
if( _instance == null )
{
_instance = new DomainSettings();
}
return _instance;
}
}

public const decimal GoldAmountTreshold = 2500;

private IRepositoryFactory _repositoryFactoryObj;

public IRepositoryFactory RepositoryFactoryObj
{
get
{
if( _repositoryFactoryObj == null )
{
object repType = Configuration.
ConfigurationManager.
AppSettings["repositorytype"];

if( repType != null )
{
switch( repType.ToString().Trim().ToLower() )
{
case "testrepositories" :
// Since I've put the 'test/mock'
// repositories in another assembly,
// along with my unit-tests,
// use reflection to load
// the correct assembly and type.
Assembly asm = Assembly.LoadFrom ("BlogShopTests.dll");
object o = asm.CreateInstance
("BlogShopTests.RepositoryMocks.TestRepositoryFactory",
true);
_repositoryFactoryObj = o as IRepositoryFactoryObj;
break;
default :
throw new ConfigurationErrorsException (
"Unknown repository-type: " + repType.ToString());
}
}
else
{
throw new ConfigurationErrorsException (
"Repository type must be defined in the app-settings.");
}
}
return _repositoryFactoryObj;
}
}
}

As you can see, I've implemented the DomainSettings class as a singleton, so that there can only be one instance of that class. The most interesting thing in this class is without any doubt the RepositoryFactoryObj property.
Since the unit-tests I've written so far are using 'mock' repositories instead of the real ones that will be used eventually, I wanted to be able to hide which implementation of the Repository that should be used. This is extremely usefull in the Status property of the Customer class. When running the tests, the 'mock' repositories should be used, and, when running the code 'for real', the 'real' Repository should be used.
To be able to do this, I've provided the DomainSettings class with a property that returns a Factory that will create the correct repository objects.
The concrete type of the factory that must be used, depends on a value in the configuration file.
Since the TestRepositoryFactory and the TestRepositories are in the assembly that contains all the unit-tests, and since I do not want to create a dependency between the assembly that contains the Domain classes, and the assembly that contains the test classes, I use reflection to create the TestRepositoryFactory. The Abstract Factory approach for the creation of the Repositories, allows me to hide which specific factory is to be used. In other words: the user -in this case the Customer class- is left unaware of which specific Factory that's being used and therefore, which specific repository that will be used.


To be able to create and use the abstract factory, an interface is needed which describes the methods that a 'RepositoryFactory' object must have. In our client code, we can then talk to that interface without knowing which specific implementation is being used.
At this moment, it is sufficient if the interface looks like this:


public interface IRepositoryFactory
{
ICustomerRepository CreateCustomerRepository();
IOrderRepository CreateOrderRepository();
IArticleRepository CreateArticleRepository();
}

Once this is done, the implementation of the TestRepositoryFactory is fairly easy; it just instantiates and returns an instance of the correct Repository:


public TestRepositoryFactory : IRepositoryFactory
{
public ICustomerRepository CreateCustomerRepository()
{
return new CustomerMemoryStoreRepository();
}

public IOrderRepository CreateOrderRepository()
{
return new OrderMemoryStoreRepository();
}

public IArticleRepository CreateArticleRepository()
{
return new ArticleMemoryStoreRepository();
}
}

In the DomainSettings class, it is now just a matter of creating the correct IRepositoryFactory object depending on the value that's found in the configuration file.
Once the GetOrderTotalForCustomerSinceDate is implemented, we're able to determine if the Customer is a Gold Customer or not. The implementation of the GetOrderTotalForCustomerSinceDate method of the OrderMemoryStoreRepository could be as simple as just returning true if the given Customer has a specific Id, and otherwise false.


We still need to make our test pass, because at this point, we haven't written any functionality yet to calculate the OrderTotal for Gold Customers. As we learn from the user story, Gold Customers receive a discount of 5% on their OrderTotal.
It is usefull to extend the Order class with a member variable that holds the discount. For Normal Customers, this discount variable will just contain 0.
I think that the best place calculate the discount -if there's one-, is in the AddOrderLine method of the Order class. Each time an OrderLine is added to an Order, the amount of the discount for a Gold Customer changes.
There's also something else were I haven't paid attention to yet: once an Order is confirmed by the Customer, it should not be possible to add or remove OrderLines from it.
It is however possible that a user cancels the complete Order. This pops up another issue: an Order should have an OrderStatus.

Let's start with one thing at a time, and begin with the calculation of the discount.
As I've said earlier, the best place to calculate this discount is in the AddOrderLine member method of the Order class. Thus, we can extend this method so that it looks like this:


public void AddOrderLine( OrderLine ol )
{
// Perform some checks here to see if all necessary stuff is provided.
if( ol.NumberOfItems == 0 )
{
throw new ApplicationException ("You must at least order 1 item.");
}

if( ol.IsArticleSet == false )
{
throw new ApplicationException (
"You must specify the article that must be ordered.");
}

this.OrderLines.Add (ol);

// Calculate the discount.
CalculateDiscount ();
}

In the CalculateDiscount method, we'll just have to check the Status property of the Customer to which the Order belongs to. However, since determining the Status of a Customer is a rather expensive operation (remember that we have to query the database to determine the status) and the fact that the AddOrderLine method is likely to be called more then one time (an Order can contain more then one OrderLine), it would be better to call this Status property only one time. We can do this like this:


private bool customerStatusDetermined = false;
private bool isGoldCustomer = false;

private void CalculateDiscount()
{
if( customerStatusDetermined == false )
{
if( _owningCustomer != null )
{
isGoldCustomer = _owningCustomer.Status == CustomerStatus.Gold;
}
else
{
isGoldCustomer = false;
}
customerStatusDetermined = true;
}

if( isGoldCustomer )
{
_discount = this.OrderTotal *
DomainSettings.Instance.GoldDiscountPercentage;
}
else
{
_discount = 0M;
}
}

I think that this code is pretty easy as well: the CustomerStatus is determined if this hasn't been done yet, and if the Customer is a Gold Customer, we calculate the discount on the Order.
Note that we'll have to add an extra property to the DomainSettings class as well, that contains the percentage of the discount for Gold Customers:


public class DomainSettings
{
...
private decimal _discountPercentageForGoldCustomers = 0.05M;

public decimal GoldDiscountPercentage
{
get
{
return _discountPercentageForGoldCustomers;
}
}
}

You should also note that the Test that has been written to test the 'Gold Customer' case, checks the TotalAmountToPay property of the Order class. This property is quite simple, and just returns the OrderTotal minus the Discount


public class Order
{
...
public decimal TotalAmountToPay
{
get
{
return OrderTotal - Discount;
}
}
...
}

This functionality makes our 2nd test pass. Now, I've already talked about the fact that an Order should have a Status. This means that, when a Customer confirms his Order, the Order should have the status 'Confirmed'. Orders that have been confirmed cannot be changed anymore. This means that it should be impossible to add or remove OrderLines from it. However, a Customer should be able to cancel a confirmed Order. However, once the Order is shipped, it cannot be cancelled anymore.
Knowing all this, we can say that an Order can have 3 states:


  • Confirmed

  • Cancelled

  • Shipped

However, this is not sufficient. When an Order is just created, it cannot have the Confirmed, Cancelled or Shipped status. As long as the Order has not been confirmed yet, it has the status 'Pending'. This means that we have in fact 4 OrderStates:

  • Confirmed

  • Cancelled

  • Shipped

  • Pending

We can now start to create some unit-tests in where we will test this behaviour. First of all, we'll create a unit-test in where we create an Order, add some OrderLines to the Order and confirm the Order. Afterwards, we'll check if we can still add or remove OrderLines from that Order.


[Test]
public void TestConfirmOrder()
{
Customer c = custRep.GetCustomer (1);

Article art1 = artRep.GetArticle (1);
Article art2 = artRep.GetArticle (2);

Order o = c.CreateNewOrder();

OrderLine ol1 = o.CreateNewOrderLine();
ol1.SetArticle (art1);
ol1.NumberOfItems = 5;
o.AddOrderLine (ol1);

o.ConfirmOrder();

Assert.AreEqual (OrderStatus.Confirmed,
o.Status,
"The OrderStatus should be confirmed.");

// Now, the Order is confirmed, so it should not be
// possible to still add or remove
// OrderLines
OrderLine ol2 = o.CreateNewOrderLine ();
ol2.SetArticle (art2);
ol2.NumberOfItems = 10;

Assert.AreEqual (o.CanOrderLineBeAdded (ol2),
OrderLineAddQueryResult.NoBecauseOrderIsConfirmed,
"It should not be possible to add an orderline now.");

// Now, just check what if the Status is correct if we cancel the order.
o.CancelOrder ();

Assert.AreEqual (OrderStatus.Cancelled,
o.Status,
"The OrderStatus should be cancelled.");
}

To be able to compile this test, we'll have to add some methods to our classes.
The first one that we encounter, is the ConfirmOrder method, which sets the status of our Order to Confirmed. This means that we'll have to add a property Status to the Order class and create an enumerated type OrderStatus.
A little bit further, you can also see the CancelOrder method that sets the Status of the Order to Cancelled.
Adding these methods is a piece of cake:


public class Order
{
...
private OrderStatus _status = OrderStatus.Pending;

...

public OrderStatus Status
{
get
{
return _status;
}
}

...

public void ConfirmOrder()
{
if( _status != OrderStatus.Pending )
{
throw new ApplicationException (
"An order can only be confirmed when " +
"it's current status is Pending.");
}
_status = OrderStatus.Confirm;
}

public void CancelOrder()
{
if( _status == OrderStatus.Shipped )
{
throw new ApplicationException (
"An order that is shipped, " +
"cannot be cancelled.");
}
_status = OrderStatus.Cancelled;
}

}

As you can see, these methods contain some simple business-logic: a check is made if the Order can be confirmed, or can be cancelled.
Now, I still need to implement the OrderStatus enumeration:


public enum OrderStatus
{
Pending,
Confirmed,
Cancelled,
Shipped
}

The above code is pretty obvious, but, it is not sufficient yet in order to make the test pass, or even compile. As you can see in the test, another method is needed: CanOrderLineBeAdded. As you can see in the test, this method does not return a simple boolean value, even though the name of the method let's you think that it would. The reason why I choose to not return a boolean here, is very simple: instead of just knowing whether it is possible or not to add an OrderLine to an Order, I also want to know why it would not be possible. Therefore, I've choosen to return an enumeration, which has these possible values:


public enum OrderLineAddQueryResult
{
Yes,
NoBecauseOrderIsConfirmed,
NoBecauseOrderIsCancelled,
NoBecauseOrderIsShipped
}

Then, the CanOrderLineBeAdded member method of the Order class looks like this:


public OrderLineQueryResult CanOrderLineBeAdded( OrderLine ol )
{
OrderLineAddQueryResult result = OrderLineAddQueryResult.Yes;

switch( this.Status )
{
case OrderStatus.Confirmed :
result = OrderLineAddQueryResult.
NoBecauseOrderIsConfirmed;
break;

case OrderStatus.Cancelled :
result = OrderLineAddQueryResult.
NoBecauseOrderIsCancelled;
break;

case OrderStatus.Shipped :
result = OrderLineAddQueryResult.
NoBecauseOrderIsShipped;
break;
}

return result;
}

The purpose of this method is that the user of our class can check if an OrderLine can be added, without exceptions being thrown. This method is usefull to know for instance which UI controls should be enabled/disabled, or what message should be given to the user of the software.
But, the existance of this method does not ensures us that this method shall be used as well, therefore, we should enforce this rule in the AddOrderLine method of the Order class as well.


public void AddOrderLine( OrderLine ol )
{
OrderLineQueryAddResult result = this.CanOrderLineBeAdded (ol);
if( result != OrderLineQueryAddResult.Yes )
{
throw new ApplicationException(
GetReasonWhyOrderLineCantBeAdded (result));
}

if( ol.NumberOfItems == 0 )
{
throw new ApplicationException ("You must at least order 1 item.");
}

if( ol.IsArticleSet == false )
{
throw new ApplicationException (
"You must specify the article that must be ordered.");
}

this.OrderLines.Add (ol);

CalculateDiscount();
}

I will not elaborate here on the GetReasonWhyOrderLineCantBeAdded member method very much. It is sufficient if you know that this is just a private method which returns an error-message, depending on the value of the OrderLineQueryAddResult parameter.
The business rules that are in the AddOrderLine method can offcourse be avoided by simply not using the AddOrderLine method at all, and instead, using the Add method of the OrderLines property which is publicly exposed. Therefore, it should be better if we do not expose the Order collection publicly, but, for now, I'll leave it like it is.

As this is one very long post already, I'll end it right here. I'll keep the rest of the implementation for another article.
Please, feel free to post your comments, critics, questions, remarks.

woensdag 24 mei 2006

Domain Driven Design: A Quickstart (Part 1)

Introduction


Some time ago, I bought the book Domain Driven Design, tackling complexity in the heart of software.
Since reading it, I became very interested in the Domain Driven Design paradigm. For enterprise applications, it would be ideal if you could express the core of the application (the domain layer; the part of the program that contains the business logic) in a good model.
The Object Oriented Programming paradigm provides a good way to express the model in a computer program.

So, although the behaviour can be expressed in an OO fashion, the data needs to be persisted as well. In most cases, a relational database is used to persist the data. Combining OO and RDBMS'es gives us the problem of the Object / Relational mismatch. You can offcourse solve this object-relational impedance mismatch yourself by writing a DAL that nicely maps the classes of your domain model to the tables of your relational database. In most cases, this means that you'll have to write a lot of code. Instead of implementing this functionality yourself, you could also opt for using one of the many existing O/R mapping tools, like NHibernate or LLBLGen.
As Frans Bouma once explained in one of his blogposts, there are different types of O/R mappers. NHibernate fits in another category then LLBLGen; In Frans' categorization, NHibernate fits in the 'Domain Approach', while LLBLGen fits in the Entity approach.
Since I'm interested in the Domain Driven approach, I've taken a look at NHibernate, and, while it's not 100% perfect, it still has a lot of advantages. It releases you from some boring tasks (like mapping - hey, that's why it's called an O/R mapper), and takes care of some more complex tasks (caching, state-tracking, ...).

The idea of this blogpost is to provide a little quickstart in Domain Driven Design and NHibernate, by creating a piece of software for a particular use case.

The Case


My idea was to create a simple application for a shop/manufacturer. A customer can order multiple goods at a time, and, when a customer has ordered for over 2500euro in the past 3 months, this customer is a gold customer.
When the order is shipped, an invoice has to be created for that Order. Gold Customers receive a discount of 5% on their invoice. On the other hand, customers that are known as 'bad payers', cannot place orders that have an order total that exceeds 250 euro. A customer is tagged as a 'bad paying customer', when 1/3rd of his invoices have been overdue.
Let’s say that a customer can make an order by phone, and via the website of the shop.
Pretty simple, no ? :) This is off-course not a real-world example, but it should be sufficient for the purpose of this article.

Modelling the domain


Following the Domain Driven Design principle, a model consists of entities, value objects and services. We can already extract some entities out of the given text:

  • Customer

  • Article

  • Order

  • Invoice


Another entity that is not so obvious, is the OrderLine entity. This one is needed because a Customer can order more then one article at a time, so we need to know which Articles have been ordered, and how many of them are ordered.
For the Invoice entity, it's the same story: there must be an InvoiceLine entity that represents each 'line' on the invoice.
This means that, at this time, our model consists of 6 entities. There are no Value objects and Services defined yet.

The entities that we've defined can be drawn in a first schema:

As you can see, a customer can have 0, 1 or more Orders, an Order contains one or more OrderLines, and every OrderLine must contain exactly one Article.
For each Order, there can be one Invoice.
If this were a database schema, this would be perfect. However, this is an (concise) UML diagram, and the classes in this diagram should not describe how our data must be persisted, but how our application should behave.

Now, there are some things in this ‘design’ that can be improved. If you look at the Customer and Order classes in the schema, you see that a Customer has a collection of Orders. This is in fact correct, but, I wonder if this is necessary to express in our domain-model.
In this case, we’re more interested in knowing to which Customer a specific Order belongs, rather then knowing or getting all the Orders of a specific Customer. To get a list of all the Orders of a specific Customer, we can always add a method in a Repository that gives us the list of Orders for a Customer, instead of giving the Customer class a collection of Orders. (I will come back on the Repository part later). This will simplify things a bit. This also means that, if we have customers that have made a lot of Orders, the Customer Object for that Customer doesn’t have to hold a large collection of Order objects.
For the relationship between the Order and OrderLine class, things are a bit different. I do not think we can give a direction to this relationship, since, we do want to know the OrderLines of an Order, since they are coupled to each other: an Order exists only because of its OrderLines. And for each OrderLine, we do want to know to which Order it belongs. So, this association has to be kept bidirectional.
Then again, the relationship between Order and Invoice, doesn't have to be bidirectional. I do not even know if we should have a 'coded' relationship between these 2 entities, because I don't think that it will often occur that we need to see the invoice that is linked to an order, or, the related order of an invoice. If we do need that, we can always get them by calling a method on the repository. However, I will keep the link between Order and Invoice on the schema, since, they're in a way linked to each other.

This gives us the following schema:



In this schema, you can see the directions of the associations.

The next step, is to define the aggregates in the model. An aggregate ‘clusters’ the entities and value objects that belong together.
In this case, we can define 4 aggregates: Customer, Order, Invoice and Product.
The Customer and Product aggregate only contain 1 entity, while the Order aggregate and the Invoice aggregate contains 2 entities; the Order and the OrderLine entity make up the Order aggregate, and the Order entity is the ‘aggregate root’. The aggregate root is the only object in the aggregate, where other objects that are outside of that aggregate, may have references to.
The Invoice aggregate is very similar: it's made up by the Invoice and the InvoiceLine entity, and the Invoice entity is the aggregate root.

Once we know the aggregates, we can define the repositories for our domain model. A repository is an abstraction which gives us references to our aggregates, and allows us to persist those aggregates. The underlying infrastructure can be a relational database, a file, … but our model doesn’t need to know that. We just have to be able to get aggregates, and save them back, so the repository provides us this abstraction.
We should not create a repository for every class in our model, we should create a repository per aggregate. In our example, it makes no sense to be able to retrieve OrderLine objects, without retrieving the corresponding Order object.
Knowing all this, we can extend our schema:



Here, you can see the 4 repositories (I've added some example operations to it), and the 4 aggregates. I've also drawn the aggregate boundaries of the Order and the Invoice aggregate. Since the other 2 aggregates (Customer and Product) only consist out of 1 entity, it is not necessary to draw their boundaries as well.

There is one thing that we'll need to keep in the back of our mind: we have to be able to create Invoices for Orders that are shipped and that have no Invoice yet. It would be a good idea to create a batch-process that runs every night, and that creates Invoices for Orders that are shippend and have no invoice yet. In other words: this would be ideally implemented as a service.

Now that we have identified the entities, aggregates and repositories that make up our domain model, we could start to put the model into code,
but, I'll keep that for another post that I hope to finish soon. :)

maandag 1 mei 2006

Is Software Development too hard, or too easy ?

I've come across some rather interesting blog-articles, like this one from Scott Bellware and this one from Jeffrey Palermo.

Both articles are a reaction to this article from Rockford Lhotka. Rockford Lhotka says in his article that software development is too hard, that we -developers- have to spend too much time doing 'plumbing work', instead of concentrating on delivering business value.
In a way, he has a point: the main point in writing a business application, is to create an application that solves the business problem, and, since time is money and business is constantly changing, it should be done as quick as possible. Isn't this what we're all striving for ?

However, this should not be done at all costs. I mean, there are RAD tools available that will allow you to 'develop' an application quickly, but, if those tools are used in an inappropriate way, you'll end up with an 'application' that is a hell to maintain and to extend.
I think we've all seen those kind of applications: in a first phase, those app's do what they have to do, but, as requirements change, the code gets messier and gets hard to understand and it gets even harder to implement new functionality or change existing functionality.

This is where the opinion of Jeffrey Palermo comes in: the RAD tools allow you to build an application without requiring to know what's going on under the hood, and they make it possible that somebody who is not trained in software engineering can create an application. However, the quality of that application will most likely be poor.
To put it in his words:

It’s too easy for an unskilled person to throw a screen together and deploy it. It’s too easy for Joe blow to create a database application that pulls over entire tables to the client for modifying one record (but it works – initially). It’s too easy for a newbie to get excited about a new technology and completely screw up an application with web service calls to itself and overdo sending XML to Sql Server 2000. It’s too easy to a database guy to throw tons of business logic in stored procedures, call them from ASP and call it an application (until a skilled programmer looks at it later and has a heart attack).

The problem with RAD tools, is that everybody can now create an application that does what it should do. It allows people that are not trained in software engineering to create an application that does what it has to do, and it's possible that the user of the application doesn't notice that the application is actually a piece of crap. And I believe this happens all too often.

My opinion is that RAD tools can reduce the workload, but they should be used with care.

When a RAD tool is used inappropriatly to create a business application, the chances are big that the developer uses the 'Smart UI' antipattern. This means that all the business logic of the application is put directly into the user interface. This is off course problematic when the requirements change. Since the business functionality is scattered throughout the user interface, the programmer who has to maintain this application will have to delve into the UI to find all the code and the related code that has to be changed. When the application is large, it's easy to forget or overlook something that has to be changed, and it will result in a buggy application.
Or, imagine that you've build a Windows application, and once it's delivered, your customer or boss wants to have a web interface for this application as well. When all business logic is implemented in the user interface, this means that you will not be able to just reuse that code in the web application. The result will most likely be duplicated business logic.

That's why I believe that a RAD tool should be used with care. In my opinion, you should use the RAD features of your development tool to build the User Interface, and that's about it.
Developing software is more then just dragging some components on a form, glueing them together by setting some properties and using wizards to get the data from the database and bind it to some kind of control.
Scott Bellware is right when he says that the RAD functionality of Microsoft's development tools encourages one to create badly designed software. Microsoft shows in demo's how one could create an application very fast, with a very small number of lines of code with their RAD tools. The sad thing is that there are developers attending these demo's who think afterwards that this must be the way to develop applications. And this is not only true for developers attending these sessions. Managers seeing these demo's can think that software development isn't that hard at all, and they also do not understand how it comes that it takes so much time developing an application.
This is not a good way of building software. Those RAD tools and wizards are very good for giving demo-sessions (and selling the tools), but they're defenitly not showing a correct way on how to build software.
What about the maintainability and flexibility of software created in this way ? What about the ability to create unit-tests to test the functionality of the implemented business rules ? It is all impossible with applications that are developed in this way.

For the core of the application -the business functionality- the development team should create a domain model that expresses the business problem that the application must tackle. This means off course
that the initial development cost of the application will be higher, but, this development cost should be seen as an investment. The model will be easier to maintain, extend and to reuse, and, by using Agile development
techniques
, the customer can be involved in the development process. By using small development iterations and having customer input after each iteration, the customer knows that the development of the application is going forward, and he can ring the alarm when he sees that the functionality of the application or the business logic is wrong.

To conclude: RAD tools provide a way to make software development easier, and because of that, one could be tempted to create an application in a quick and dirty way. However, building high-quality software still requires skilled and educated/trained developers. They're not only required to be able to create a good domain model. They also have to be skilled in a way that they know for what they should and shouldn't use RAD tools.

zaterdag 1 april 2006

.NET 2.0: Could not find schema information for ... part 2

Today, I've been playing a bit with the new Configuration classes in .NET 2.0.
Again, I came across those annoying 'Could not find schema-information for ... ' messages.
I do not like warnings and information messages in my projects, so I had the urge to solve these issues.

I was playing a bit with the 'Settings' class in a Windows Forms application. I added a user-scope setting, and I received this warning from Visual Studio.NET 2005:

The requirePermission attribute is not declared

After some crawling on the web, I've found an article written by Peter Richie. It appears to be a negligency from Microsoft: it seems that the DotNetConfig.xsd schema-file is not complete. Peter Richie has adapted this XSD file, so you can download this file and replace the original file with his one. By doing so, I got rid of this error.
Click here for Peter's article.
I can't understand how Microsoft could be so sloppy to not deliver a correct xsd.

Then, I was still annoyed by some 'Information messages' Visual Studio gave me. These were due to a custom configuration section for NHibernate I have in my app.config file.
This is a snippet from my App.Config file:

<configSections>
<section name="nhibernate"
type="System.Configuration.NameValueSectionHandler"/>
</configSections>
<nhibernate>
<add key="hibernate.connection.provider"
value="NHibernate.Connection.DriverConnectionProvider"/>
...
</nhibernate>


The 'information message' here told my that a schema definition for the element nhibernate couldn't be found. Off-course, this is not an error, but... I find those things annoying.

So, to get rid of those messages, I've created a simple XSD that describes this 'nhibernate' section. (You can download this XSD here). I've copied this xsd to the Program Files\Microsoft Visual Studio 8\Xml\Schemas\ directory. The next step I had to do, was to include this schema in the DotNetConfig.xsd file.
So, in the same directory, edit the DotNetConfig.xsd file and add this line:

<xs:include schemaLocation="nhibernate_configuration.xsd"/>


If you have a rather complex custom Configuration Section in your App.Config file, you can create your own XSD for it.
You're not only going to get rid of those 'could not find schema information...' messages, but you'll also have Intellisense for your custom configuration section in VS.NET 2005 as well!

Click here for my first post about this problem.

donderdag 30 maart 2006

Low key portraits with a Hasselblad

The past few weeks, I (and my fellow photography students) have been playing with Hasselblad camera's in the studio.

This is a low key portrait that one of my collegue students took from me.





Unfortunately, I was not able to scan the entire picture (it is to big for my scanner), so that I cannot present it here in its original and typical square Hasselblad format.

I also took some very nice shots from other persons, but I'm not going to post them here (yet), since I do not have the permission of those persons to do so.

I really like those Hasselblad camera's. They're great to work with and provide great quality. I even think of buying one (a 2nd hand, because these things are expensive...)

donderdag 9 maart 2006

NHibernate: where's the productivity ?

I've been playing around with NHibernate the past few days, and I've encountered a rather strange bug...

I wanted to perform a rather simple HQL query. I wanted to know the total value of the Orders that were placed by a Customer.
So, I thought that this simple HQL query would do the job:

IQuery q = theSession.CreateQuery("select sum(ol.Price * ol.NumberOfItems)
from OrderLine ol");

However, this didn't work...
This query did work however:

IQuery q = theSession.CreateQuery("select sum(ol.Price) from OrderLine ol")


It appeared that the query (the one with the multiplication in the sum function) that was sent to the database looked like this:

select sum(orderline0_.NumberOfItems*orderline0_.ItemPrice) as x0_0_
from tblOrderLine orderline0_

while NHibernate was then trying to access a result-column that was called x1_0_
This will offcourse not work, since the field has been given the alias x0_0_

After some searching, I've found out that this was a bug that also existed in Hibernate, but has been fixed in Hibernate 3.0.

So, I had to look for an alternative.
The idea came up that I could retrieve all the orderlines that belong to a specific Customer, and then, do the calculation myself.
So, I came up with this HQL query:

IQuery q = theSession.CreateQuery ("from OrderLine ol " +
" inner join Order inner join Customer " +
" where Customer.Id = :custId");

This didn't work as well... An exception was thrown saying that the BY keyword was expected after a GROUP or ORDER. However, I didn't use any group by or order by statements ? Then, I've noticed that I've a class that's called Order, so maybe I had to escape the classname.
However, I couldn't find how to do that (if it is possible), so I've rewritten the query to something like this:

IQuery q = theSession.CreateQuery ("select ol " +
" from OrderLine ol, Order o, Customer c" +
" where ol.Owner = o and o.Owner = c " +
" and c.Id = :custId");

This didn't work as well...
The exception now said:
Could not resolve property:Id of Customer
I found this very strange, since this class has an Id property.
After some research, I found out that the Id did not appear in my hibernate mapping file indeed.
This is, because the Id is used as the 'id' in my mapping file, and, since the Id property is read-only in my class, I use a field access method to set this field. This is specified in my hbm mapping file like this:

<class name="NamespaceName.Customer, NamespaceName" table="tblCustomer">
<id name="id" access="field" column="Id"... >
...


So, what should I do next ? I didn't want to make the Id property of my Customer clas s writable.

I tried to add the Id property to my Customer mapping file, without touching the 'id' element.
So, I've added the Id property to my mapping file, but, since I've introduced the same database column twice, I had to use some attributes:

<class name="NamespaceName.Customer, NamespaceName" table="tblCustomer">
<id name="id" access="field" column="Id"... >
...
<property name="Id" update="false" insert="false">
...


Now I tried to rerun my query. However, retrieving a Customer was already a problem. I received an exception that said that the property value of the Id property could not be set via reflection. Damn.
I really don't want that somebody can set the Id of a Customer via the property...

Luckely, .NET 2.0 came to the rescue. In .NET 2.0, you can define different access-modifiers on your property getter and setter. So, my Customer class looked like this :

public class Customer
{
private int id;

public int Id
{
get { return id; }
}
}

I've changed this to

public class Customer
{
private int id;

public int Id
{
get { return id; }
private set { id = value; }
}
}


And this finally did the trick...

I've spent something like 2 hours in getting something simple like this to work in NHibernate. With a self-written Data Access Layer, this would have taken me something about 10 minutes I guess, to implement this functionality.
Conclusion: there's a lot of work to be done on NHibernate before I will really call it 'productive'. However, it is a promising project though.

For more information about my quest, I refer to a topic I've opened regarding this issue on the NHibernate support forum.

maandag 6 maart 2006

Troubles with Visual Sourcesafe, looking for alternatives

Today, I've encountered some rather unpleasant moments with Visual Sourcesafe. Around 4 o'clock, it appeared that my VSS repository was corrupt. :(
Trying to restore the latest backup didn't succeed as well, since there was a problem with that tape. :(

This means I had to use the backup of last thursday... Luckely, after some extra work, I've been able to restore most of my work.

However, I do not want to experience these problems again, so, just like Sam Gentile, I'm going to ditch VSS, and look for an alternative.

At this moment, I've 2 options in my mind:

  • SubVersion

  • Sourcegear's Vault


Some time ago, I've downloaded a trial version of Vault, and it looked ok to me. However, I've heard that it doesn't integrate very well in VS.NET (haven't tried that yet).
On the other hand, we have Subversion, however, I haven't worked with it before.

Anybody who has experience with one of these 2 systems and wants to share his/her opinion ?

zondag 5 maart 2006

Formula One: The new season is coming...

At last, after a long winter of F1-less Sundays, the new Formula 1 season will start next sunday.
I find it always interesting to see during the first race of the year which teams have done their home-work, and will be the teams to beat during the season.
I bet that, for the 2006 season, Renault and Honda will be the favorites for the World Championship with Ferrari and McLaren on their heels.

Who will be world champion ? Will Alonso extend his title, or is Schumacher able to fight back ? Can Raikonnen, who has been close to catch the title last year and in 2003, finally clinch the championship ?
However, I think that Jenson Button also has a chance to win some races this year...

All questions that will be answered during the next months, and the first race in Bahrein should already give a strong indication of who holds the best cards.

Anyway, I'll be supportering for Kimi Raikonnen and Jacques Villeneuve. I just like the driving style of these 2 guys.
I hope that it will be an interesting season, with a lot of exciting duels on the track.


To get into the F1-mood, here (18mb) is a video-clip of one of the most exciting duels in F1 history.
This video shows the last 3 laps of the 1979 French Grand Prix which was held in Dijon. René Arnoux and Gilles Villeneuve are contending for 2nd place. René Arnoux is driving a Renault Turbo (with a defect Turbo), while Villeneuve is driving an atmospherical Ferrari with worn out tires. (You'll see the reason for those worn out tires...). The commentary is from the legendary Murray Walker.

woensdag 1 maart 2006

It's been a while...

It's been a while since I've made a post on my blog. I'm currently busy reading the book Agile Software Development and I'm also playing with NHibernate a little bit.
I am thinking of creating a little tutorial / Quickstart about NHibernate and post it here, but I'm not sure yet. It is a lot of work, and takes some time... :)