zaterdag 30 december 2006

Shelfari Bookshelf

As a software developer, I reguraly buy (and read) books on software development. I've found a website where you can create your 'virtual bookshelf', and I've decided to create one.


On my virtual shelf, you will mostly find books on software development and photography. Not all of my books are already listed, but I will complete my shelf in the near future.
For some books on my shelf, I've written a little opinion about it. If you want to buy a book that I have on my shelf, you can directly go to the Amazon.com website by clicking on a particular book.
If you want to know my opinion on a particular book for which I haven't supplied an opinion yet, do not hesitate to contact me. :)

woensdag 27 december 2006

VS.NET 2005: XML View of a Typed DataSet

Although I'm not a big proponent of (typed) DataSets ~ I rather use custom business classes ~ , I do have to use them every once in a while.

When I use a typed dataset in VS.NET 2003, I always use 'typed DataSet Annotations'.
This is very easily done in VS.NET 2003: you'll have to switch from DataSet view to XML View, and this can easily be done by the handy buttons that you can see in the lower-left corner:




Clicking on 'XML' would give you the XML view of your typed Dataset; simple as that.

A few days ago, I was working in VS.NET 2005, and I wanted to create a typed DataSet ... I wanted to use the 'annotations' like I was used to do in VS.NET 2003.

I was amazed to find out that those handy XML / DataSet View buttons that exist in VS.NET 2003 are gone in VS.NET 2005.
Apparently, Microsoft doesn't like the idea that developers sometimes want to tweak some settings via code instead of via the properties window ? At least, that's how I'm thinking about it.



After some searching, I've found out that it is still possible to get the XML View of a DataSet in VS.NET 2005, but damn, it is very well hidden.
Here's how you can see the XML definition of the DataSet:


  • Right click on the DataSet file

  • You'll see the following context-menu:


    Select the 'Open With option'

  • The following Dialog Box opens:



    Select the 'XML Editor' option

  • Now, you can see the XML View of the DataSet definition

As you can see, in VS.NET 2005, 3 user interactions are needed in order to go to your destination, instead of just a single click in VS.NET 2003.
Not very productive IMHO.

I wonder why Microsoft has removed those buttons that existed in VS.NET 2003...


zaterdag 9 december 2006

Official owners

Since yesterday, my girlfriend and I are the official and proud owners of this piece of Belgium:




Next step: building a house on it.

vrijdag 1 december 2006

High Key

Yesterday, I've been playing around a bit and wanted to create a high-key picture.
I think the result is quite ok. :)

Apart from some 'levels' adjustements in Photoshop, no other modifications have been made.
I've put the lighters on a plexiglass (hence the reflection), and used two elinchrome strobes to make the picture like it is shown here.

zaterdag 11 november 2006

Nested Transactions in SQL Server

I've been wondering if it would be possible to use 'nested transactions' in SQL Server. To test this, I've set up a little test database and executed a few
T-SQL batches:

USE testdb
BEGIN TRAN
INSERT INTO tblTest (Name) VALUES ('Name1')

BEGIN TRAN
INSERT INTO tblTest (Name) VALUES ('Name2')
COMMIT TRAN

INSERT INTO tblTest (Name) VALUES ('Name3')

COMMIT TRAN

This is trivial, and it works as expected: 3 records have been added to the table. The next batch looks like this:

USE testdb
BEGIN TRAN
INSERT INTO tblTest (Name) VALUES ('Name1')

BEGIN TRAN
INSERT INTO tblTest (Name) VALUES ('Name2')
COMMIT TRAN

INSERT INTO tblTest (Name) VALUES ('Name3')

ROLLBACK TRAN

This is no big deal either: as expected, no records have been added to the table. Up to the next one:

USE testdb
BEGIN TRAN
INSERT INTO tblTest (Name) VALUES ('Name1')

BEGIN TRAN
INSERT INTO tblTest (Name) VALUES ('Name2')
ROLLBACK TRAN

INSERT INTO tblTest (Name) VALUES ('Name3')

COMMIT TRAN

This batch fails with the following error message:

Server: Msg 3902, Level 16, State 1, Line 16

The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.

It turns out that only the last record (Name3) is inserted into the database. That's not what I expected.
Normally, one should expect that Name1 and Name3 are persisted in the database, and only Name2 gets rollbacked.



However, as my collegue Geert pointed out: the BEGIN TRANSACTION statement increments the @@TRANCOUNT Server Variable with 1, and the COMMIT TRANSACTION decrements the @@TRANCOUNT variable with 1.
The ROLLBACK TRAN statement however, decrements the @@TRANCOUNT server variable to 0. That's why the last COMMIT statement gives us the error message: there has been a rollback, and therefore the @@Trancount is set to zero.
Apparently, the ROLLBACK TRANSACTION also rollbacks to the most outer begin transaction, that's why the record 'Name1' is not persisted into the database.

As it turns out, it is not possible to use nested transactions in this way. There is however a way to solve this 'problem':

Savepoints to the rescue

It is possible to use 'savepoints' to solve this problem. As stated in the SQL Server books online:

Savepoints offer a mechanism to roll back portions of transactions.
You use savepoints like this:
BEGIN TRAN
INSERT INTO tblTest (Name) VALUES ('Name1')

SAVE TRANSACTION sp1
INSERT INTO tblTest (Name) VALUES ('Name2')
ROLLBACK TRAN sp1

INSERT INTO tblTest (Name) VALUES ('Name3')

COMMIT TRAN

In this code example, you start a transaction, execute a statement, and save the transaction using the SAVE TRANSACTION sp1 statement.
This statement sets a savepoint with the name 'sp1'. You can then rollback to that savepoint using the ROLLBACK TRAN <savepointname> command.
The result of this batch is as expected: 2 records are inserted into the tblTest table: 'Name1' and 'Name3'

zondag 5 november 2006

Aspect Oriented Programming in .NET

A while ago, there was somebody who asked the question on a programming forum whether it was possible to retrieve the values of the arguments that are passed to a method in .NET. The purpose was to create some kind of a 'logging' system so that he could log which methods have been called, and what values were passed to those methods.
This person had already created a method that retrieved all kinds of information of a certain method, but getting the values of the parameters via reflection was not possible.

The disadvantage of this approach is that your methods are being polluted by this logging method. You always have to add a call to this logging method in your 'business methods'.
For instance:

public void SomeMethod()
{
LogThisMethod (MethodBase.GetCurrentMethod());

// Do the real work here.
}

The call to the LogThisMethod method is not likely a core concern in the application, yet, if you want to log calls to certain methods, you’ll have to write a call to this method in every method that you want to log.
In other words: the logging is a cross-cutting concern because it is an aspect of our program that has nothing to do with the core-problem that is to be solved by our program and it appears in multiple parts of the program.

Luckily, there's a much cleaner approach to solve this problem. Aspect Oriented Programming offers a way to separate cross-cutting concerns like logging in a much cleaner way.
AOP allows you to remove the cross-cutting concerns from your 'business code', and create an 'aspect' for it instead.
This ‘aspect’ will then be weaved into your code at runtime which means that you do not have to call it yourself in the core parts of the application.
In this way, the cross-cutting concerns can be decomposed from the core logic of the application and this will result in more readable and better maintainable software.

In .NET, you can use the Spring.NET framework to apply Aspect Oriented Programming.
In the examples that follow, I’ll be using the Spring.NET framework.

You can solve the logging-problem that I've mentioned earlier using AOP in C# in the following way:

Suppose we have a class 'TestClass' and we want to log every method that is being invoked in this class. Our TestClass looks like this:

public interface ITest
{
void SayHello( string name );
void Shout( string message );
}

public class TestClass : ITest
{
public void Method1( string name )
{
Console.WriteLine ("Hello " + name + " ! ");
}

public void Shout( string message )
{
Console.WriteLine (message + "!!!!!!!");
}
}

These are the steps that have to be taken to create some kind of logging functionality using AOP:


  • Create an Advice that takes care of the logging. An Advice describes a certain ‘procedure’ that must be executed at certain points (joinpoints) in the application. For instance: an Advice can be executed at the entry point of a method.

    If you use Spring.NET, you can create a class which implements the IMethodBeforeAdvice. This will make sure that this Advice is called before a method-call.
    The Advice can look like this:

    public class MethodInvocationLoggingAdvice : IMethodBeforeAdvice
    {

    public void Before( System.Reflection.MethodInfo method,
    object[] args, object target )
    {
    string message = method.Name + " called with ";

    string arguments = string.Empty;

    for( int i = 0; i < args.Length; i++ )
    {
    arguments += args[i] +", ";
    }

    Console.WriteLine (message + arguments.SubString (0, arguments.Length - 2));
    }
    }

    Now, we have separated the logging logic in a separate class.

  • Tell our program to use the Advice
    In our program, we must indicate that our Advice has to be called when we invoke the methods of a certain class.
    Using Spring.NET, we can do this with only 3 lines of code:
    static void Main()
    {
    ProxyFactory f = new ProxyFactory (new TestClass());

    f.AddAdvice (new MethodInvocationLoggingAdvice());

    ITest t = (ITest)f.GetProxy();

    t.SayHello ("Frederik");

    t.Shout ("Watch out");
    }

    The beautiful thing is, that we've kept our 'business methods' clean and every time we invoke a method, the logging functionality is called. If we extend our TestClass with a couple of new methods, we do not have to worry about this logging functionality, since those new methods will also call our MethodInvocationLoggingAdvice as well.

But, what if you only want to log invocations of certain methods, instead of logging every method call? This can also be done rather easily by defining a PointCut. Everytime the pointcut is reached, our Advice will be executed.
.NET attributes provide a great way to define PointCuts.

Building on the previous example, we can extend our code so that the MethodInvocationLoggingAdvice is only called when a method is decorated with a specific Attribute. For instance: only invocations of methods that have the 'Log' attribute, must be logged.
To do this, we must first create this Log attribute:

[AttributeUsage(AttributeTargets.Method)]
public class LogAttribute : Attribute
{
}

We can now change the TestClass to indicate that only method-calls to the Shout method should be logged:
public class TestClass : ITest
{
public void Method1( string name )
{
Console.WriteLine ("Hello " + name + " ! ");
}

[Log]
public void Shout( string message )
{
Console.WriteLine (message + "!!!!!!!");
}
}

All what's left to do, is to make a change to the code that will be responsible of weaving the advice into our code. We must now indicate that our Advice should only be executed on methods that have the Log attribute.
static void Main()
{
ProxyFactory f = new ProxyFactory (new TestClass());

f.AddAdvisor (new DefaultPointCutAdvisor (
new AttributeMatchMethodPointcut (typeof(LogAttribute),
new MethodInvocationLoggingAdvice()));

ITest t = (ITest)f.GetProxy();

t.SayHello ("Frederik");

t.Shout ("Watch out");
}

When you execute this program, you'll see that only the method-call to 'Shout' is being logged.



zaterdag 30 september 2006

Changing the default access modifier when adding a new class in VS.NET 2005

When you add a new class or interface to an existing project in Visual Studio.NET 2005, VS.NET 2005 will not define this class (or interface) as public by default.
In Visual Studio.NET 2003 however, new classes and interfaces always received the public access modifier by default, and I do like this VS.NET 2003 approach far better.

When I create a class-library, most of the classes and interfaces that are contained in this library are meant to be used outside the library itself. This means that I have to explicitly add the public access modifier to most of my classes, and this is a dreadfull job.
Not only is it a boring job to manually define this access modifier for (almost) every new class that you create, it sometimes causes me loosing some time as well:
Today, I created a new class in VS.NET 2005 in where I've written some unit-tests. I'm using Testdriven.NET to execute my unit-tests in Visual Studio, and as long as I executed only one Test-method at a time, everything went fine.
However, when I wanted to run all the test-methods that I've written in that class, Testdriven.NET didn't execute a single one of them. I didn't get any error-message, I just received the message: '0 tests passed, 0 tests failed'.
After some investigating, it turned out that my class didn't had the public access modifier, and was therefore internal. Adding the public access modifier fixed the problem, and all my tests ran smoothly.

After living with this little annoyance for a while, I thought that it should be possible to change this behaviour and make sure that every new class I create in Visual Studio.NET 2005 is marked as public. In the rare cases that I'll need an internal class, I'll just explicitly change the public modifier to internal.

Since every new item that you can create in VS.NET is based on a template (just like a Word document is based on the normal.dot Document Template), it should be rather easy to change this behaviour.
After some digging in the directory-structure of VS.NET 2005, I've finally found where those templates are being kept. They're in this directory:

<PF>\Microsoft Visual Studio 8\Common7\IDE\ItemTemplates\CSharp\1033

(where <PF> is your Program Files directory, or the directory where you've installed VS.NET)

In this directory, you'll find a number of zip files. I've just unzipped the Class.zip file, and editted the Class.cs file that was in it to this:

using System;
using System.Collections.Generic;
using System.Text;

namespace $rootnamespace$
{
public class $safeitemrootname$
{
}
}

Then, I've just added the changed template-file back into the zip-file and thought the job was done, so I tried to create a new class in an existing Class Library... Sadly, the new class was still not public by default...
After some searching, it appeared that I had to execute a command which would load the Item Templates into Visual Studio. The command to do so is:

devenv /InstallVsTemplates

This finally did the trick! When I add a new class in VS.NET 2005, this new class now has the public access modifier by default!

donderdag 28 september 2006

Session on Unit Testing & TDD

Tomorrow, I'll be giving a talk on Unit Testing and Test Driven Development at work. I just hope that everything will go smoothly, and that I can encourage a few collegues to effectively use Unit Testing. :)


VS.NET 2003 not supported on Vista ?

Today, I've encountered some articles on blogs that some unpleasant news.
It seems that Microsoft will not support Visual Studio .NET 2003 on Windows Vista; however, Visual Basic 6 will be supported. I do not understand the logic behind this;
I thought VB6 was deprecated ?
Why is VS.NET 2003 not supported ?

I hope that these rumours will not turn into reality, since I'm still using VS.NET 2003 as my primary dev-tool at work.


Frans Bouma: So, VB6 is more important then VS.NET 2003
Fear and Loathing: Join the Windows XP club ... for 5 more years or so
Paul Wilson: Vista will NOT support developers

zondag 3 september 2006

Collections in Business Entities

A while ago, I've been thinking on what would be the best approach to work with collections inside business entities.

As an example, I'll refer back to the domain classes I'm using in another post of me.
There, I have a class Order, and an OrderLine class. The Order class contains a collection of OrderLines.
In C# 2.0, this could look like this:

public class Order
{
private List<OrderLine> orderLines
= new List<OrderLine>();
}
The problem here, is that I want to have 'controlled access' to the OrderLines collection in the Order class.
What I mean is, that a consumer of these classes should not be able to add an OrderLine to the Order directly, since some additional action(s) need to be executed.



More precisely, if an OrderLine is added to the Order, I want to set a member of the OrderLine, so that the OrderLine knows to which Order it belongs.
Therefore, I create an AddOrderLine method in the Order class:
public void AddOrderLine( OrderLine ol )
{
ol.OwningOrder = this;
this.orderLines.Add (ol);
}
A consumer of the code should always use the AddOrderLine method if he wants to add an OrderLine to the Order.
You can enforce this easily by not making the orderLines member public; easy enough.
However, at one time, the consumer of your code (or you :) ) will want to iterate through the OrderLines of the Order, or he will want to know how many OrderLines an Order contains.



Now, you'll have several options to achieve this:

One solution is to expose the orderLines collection to the public. In other words: create a public property which exposes the collection to the outside:

public class Order
{
private List<OrderLine> orderLines
= new List<OrderLine>();

public List<OrderLine> OrderLines
{
get
{
return orderLines;
}
}
}

Although this is a solution, I do not like it.
Now, we're unable to force the user to use the AddOrderLine method. Since the OrderLines collection is now publicly exposed, it is now possible to just use the Add method of the List to add OrderLines to the Order.
The documentation of the classes could of course mention that you should always use the AddOrderLine method, but there's no real hard constraint here. (If the classes are used inappropriatly, the program could of course crash, so then there is a constraint after all. ;) However, then the programmer using those classes will maybe lose a lot of time to detect the error he made.

Another solution is to keep the OrderLines collection private, and to add some extra members to the Order class. In this way, uncontrolled access to the OrderLines is not possible.
However, there are offcourse disadvantages to this approach as well. First of all, you'll have to write some tedious code that just delegates the functionality to the Collection class, like this:

public class Order
{
private List<OrderLine> orderLines = ...

public void AddOrderLine( OrderLine ol )
{
ol.OwningOrder = this;
orderLines.Add (ol);
}

public int NumberOfOrderLines
{
get
{
return orderLines.Count;
}
}
}
Unnecessary to say that this is just a boring task.
Then, to be able to iterate through the OrderLines of an Order, you could write code like this:
public class Order
{
private List<OrderLine> orderLines = ...

...

public OrderLine[] GetOrderLines()
{
return orderLines.ToArray();
}
}
Actually, I think this is plain ugly.

I always have to make a choice between these 2 approaches, where each one has his disadvantages. After doing this too much, I wanted a better solution for this problem, and after some reading and experimenting, I finally found one. It is in fact such a simple solution that I can't imagine why I haven't been using this one much earlier...

It's just nothing more then this:
Keep the collection private, create the necessary methods to provide the necessary controlled access to the collection (for instance the AddOrderLine method, and create a public property which returns a read-only instance of the collection, so that you can iterate through the collection, change existing instances of objects within the collection (at least, this is only true if you have reference types in the collection; you will not be allowed to modify value types on a ReadOnlyCollection, get the number of objects that are in the collection, ...

In code, it looks like this:

class Order
{
private List<OrderLine> orderLines =
new List<OrderLine>();

public void AddOrderLine( OrderLine ol )
{
ol.Order = this;
orderLines.Add (ol);
}

public ReadOnlyCollection<OrderLine> OrderLines
{
get
{
return orderLines.AsReadOnly();
}
}

}
This is the C# 2.0 version.
Now, it is impossible to add OrderLines in an uncontrolled way, but it is possible to iterate the OrderLines that are in the collection, and modify existing OrderLine objects that are already in the collection (since it are instances of a reference type; if OrderLine was a struct, it would not be possible to modify them.

In C# 1.x, it looks like this:
class Order
{
private IList orderLines = new ArrayList();

public void AddOrderLine( OrderLine ol )
{
ol.Order = this;
orderLines.Add (ol);
}

public IList OrderLines
{
get
{
return ArrayList.ReadOnly (orderLines);
}
}
}
Here, I return a readonly copy of the ArrayList. It is still possible to iterate and change the items that are in the collection, but it is impossible to Add an OrderLine to the Order in an uncontrolled fashion like this:
Order o = new Order();
OrderLine ol = new OrderLine();
o.OrderLines.Add (ol);

In this case, a System.NotSupportedException will be thrown.
It would of course be nicer to not have an Add and Remove method on the read-only ArrayList property, like we've achieved in the C# 2.0 version (the ReadOnlyCollection class does not have Add and Remove methods).
In .NET 1.x we can achieve that by letting the property return an ICollection instead of an IList, however, then we're not able to use an indexer to retrieve an OrderLine like this:
OrderLine ol = theOrder.OrderLines[i] as OrderLine;
Therefore, I prefer to return an IList instead of an ICollection

zondag 27 augustus 2006

1 month ago....

... I was still in Spain.
Surely, the weather was much better there then it is now here in Belgium and every evening, we could enjoy a beautiful sunset:


woensdag 23 augustus 2006

WinFX == .NET 3.0 ?

Scott Bellware makes an excellent point here, when he says that Microsoft should not rename WinFX to .NET 3.0.
I can only agree with him that it will be confusing to rename WinFx to .NET 3.0, since WinFx is another product.
WinFX is just an API, while .NET is a platform, so, why giving an API the name of a platform ?

Anyway, I'm not going to repeat all of it here, so, if you also think that Microsoft will be making a huge mistake here, you should sign the petition.

zaterdag 19 augustus 2006

DDD: A Quickstart - Part III

Introduction

This is the 3rd post of a serie of posts on Domain Driven Design and Test Driven Development.
In this article, I'll continue from where the previous article ended. This means that I'll continue with the implementation of the Domain Model that was defined in the first article of this serie.

In the previous article, we tackled the functionality of Customers placing Orders, and Gold Customers receiving a discount.
In this article, I'll focus on the behaviour for Bad Paying Customers and the creation of Invoices.



Bad Paying Customers

Now that we can determine whether a Customer is a 'Gold' Customer or not, we should build the functionality to determine whether a Customer is a bad payer or not.
Just like I've done for the 'Gold Customer' case, I'd like to kick off with writing a small unit-test.

A Customer is tagged as a bad paying Customer when 1/3 of his invoices are overdue/payed too late. The consequence of being a bad paying Customer is, that such a Customer cannot place Orders whose OrderTotal exceeds 250 euro. The test looks like this:

public void TestBadPayingCustomerPlacesOrder()
{
Customer c = custRep.GetCustomer (3);

// We 'know' that Customer 3 is a bad paying Customer.
// To check this, we can check the
// Status of the Customer.
Assert.AreEqual (CustomerStatus.BadPayer,
c.Status,
"This should be a bad paying Customer.");

// Get the Articles that we'll need.
Article art1 = artRep.GetArticle (1);
Article art2 = artRep.GetArticle (2);

// Check the prices of the articles, so that we
// do not make any false assumptiosn here.
Assert.AreEqual (15M, art1.Price,
"The 1st Article should have a unit-price of 15eur.");
Assert.AreEqual (12.5M, art2.Price,
"The 2nd Article should have a unit-price of 12.5eur.");

// Create the Order...
Order o = c.CreateNewOrder();

// and add the order-lines.
OrderLine ol1 = o.CreateNewOrderLine();
ol1.SetArticle (art1);
ol1.NumberOfItems = 10;

OrderLineAddQueryResult result = o.CanOrderLineBeAdded (ol1);

Assert.AreEqual (OrderLineAddQueryResult.Yes,
result,
"The 1st OrderLine should pose no problem.");

// At this time, the OrderTotal should be 150eur.
Assert.AreEqual (150M,
o.TotalAmountToPay,
"The OrderTotal should be 150eur.");

// Create a 2nd OrderLine which will cause
// the Order-limit to be exceeded.
OrderLine ol2 = o.CreateNewOrderLine();
ol2.SetArticle (art2);
ol2.NumberOfItems = 10;

result = o.CanOrderLineBeAdded (ol2);

Assert.AreEqual (
OrderLineAddQueryResult.NoBecauseOrderLimitExceeded,
result,
"Bad Paying Customers are not allowed to place orders > 250eur.");
}

Before we can make this test succeed, we must be able to compile it. This means that we'll have to extend the OrderLineAddQueryResult enumeration with the NoBecauseOrderLimitExceeded value. This is a simple task, and just a matter of adding this value to the enumeration type. This is in fact so simple, that I'm not going to elaborate on that here.
Once this is done, the test compiles, but it fails. This is due to the fact that we haven't implemented any functionality yet to determine whether a Customer is a bad paying Customer or not, so lets do that right away.
A Bad Paying Customer is a Customer that has at least one out of three overdue invoices. To be able to check this, we need to introduce a new entity: the Invoice.
Invoices are made for Orders that are shipped. An invoice contains a date when the Invoice has been created, and a due-date. Offcourse, it also contains the list of Articles that have been ordered and where the Customer has to pay for, and, it contains the amount that the Customer has to pay.
Since Invoices are created from Orders that have been shipped, we can start with this unit-test:

[Test]
public void CreateInvoice()
{
Order o = orderRepository.GetOrder (2);

Invoice inv = o.CreateInvoice();
}

This is rather simple! But simple is good.

As we can learn from the test, we'll need an Invoice entity, and we'll need to write a CreateInvoice method in the Order class.
Let's start off with the new entity. The Invoice class contains these members:

public class Invoice
{
private int id;
private DateTime invoiceDate;
private DateTime dueDate;
private Customer owningCustomer;
private InvoiceStatus status;
private bool isOverdue;
private DateTime datePayed;
private decimal subTotal;
private decimal discount;
private IList invoiceLines = new ArrayList();

public int Id
{
get
{
return id;
}
}

public DateTime InvoiceDate
{
get
{
return invoiceDate;
}
}

public DateTime DueDate
{
get
{
return dueDate;
}
set
{
dueDate = value;
}
}

public Customer OwningCustomer
{
get
{
return owningCustomer;
}
}

public InvoiceStatus Status
{
get
{
return status;
}
}

public bool IsOverdue
{
get
{
return isOverdue;
}
internal set
{
isOverdue = value;
}
}

public DateTime DatePayed
{
get
{
return datePayed;
}
}

public decimal SubTotal
{
get
{
return subTotal;
}
}

public decimal Discount
{
get
{
return discount;
}
}
}

An Invoice should not be created directly by the user of our Domain classes, so it's not necessary (and not favorable) to have a public constructor in this class. Therefore, I've decided to create an internal constructor. An Invoice is also created for one Order, so the constructor can take the Order for which the invoice is created, as an argument. Then, the constructor and it's implementation looks like this:

public class Invoice
{
...

internal Invoice( Order o, DateTime invoiceDate, DateTime dueDate )
{
id = -1;
this.invoiceDate = invoiceDate;
this.dueDate = dueDate;
owningCustomer = o.OwningCustomer;
status = InvoiceStatus.Open;
isOverdue = false;
subTotal = o.OrderTotal;
discount = o.Discount;

foreach( OrderLine ol in o.OrderLines )
{
AddInvoiceLine (ol.ArticleId,
ol.ArticleName,
ol.ArticlePrice,
ol.NumberOfItems);
}
}
}

The AddInvoiceLine method will add an InvoiceLine object to the invoiceLines collection for each OrderLine object that is contained by the Order:

private void AddInvoiceLine( int articleId, 
string articleName,
decimal articlePrice,
int numberOfItems )
{
invoiceLines.Add (
new InvoiceLine (this, articleId,
articleName, articlePrice, numberOfItems));
}

An InvoiceLine object contains information about the article for which the Customer has to pay, and, offcourse, it contains a pointer to the Invoice to which it belongs.

The CreateInvoice method should also be implemented. This is quite simple; in this method, we'll just use the internal constructor of the Invoice class, and we can also check if the Order has been shipped, since it is not allowed to create Invoices for Orders that haven't been shipped.

public class Order
{
...
public Invoice CreateInvoice()
{
if( this.Status != OrderStatus.Shipped )
{
throw new ApplicationException ("The order hasn't been shipped yet.");
}

return new Invoice (this, DateTime.Now, DateTime.Now.AddDays (30));
}
}

As you can see, the dueDate for the Invoice is calculated in this method. By default, the Customer has 30 days time to pay his invoice.
Since this logic is quite simple, it can safely be placed inside the CreateInvoice method. If the calculation of the due date would becomes more complicated, we could opt to factor this logic into a specification object.


Once the InvoiceLine class is implemented and the CreateInvoice method has been written, the tests compile. However, the first test still fails, because we still have no functionality written to determine if a Customer is a bad payer.
To do this, we can extend the Status property of the Customer class.

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;
}

// Check if the Customer is a bad Payer,
// if the Customer is a Gold Customer AND a bad payer,
// the Status should be 'Bad Payer'.

// Get the number of invoices for this customer,
// and get the number of overdue invoices.
IInvoiceRepository invRep =
DomainSettings.Instance.
RepositoryFactoryObj.
CreateInvoiceRepository();

int numberOfOverdueInvoices =
invRep.GetNumberOfOverdueInvoicesForCustomer (this);

if( numberOfOverdueInvoices > 0 )
{
int totalInvoices = invRep.GetNumberOfInvoicesForCustomer (this);

if( numberOfOverdueInvoices / totalInvoices > 0.333 )
{
result = CustomerStatus.BadPayer;
}
}

return result;
}
}

In order to get this code to compile, the IInvoiceRepository interface and an implementation of it have to be created:

public interface IInvoiceRepository
{
int GetNumberOfOverdueInvoicesForCustomer( Customer c );
int GetNumberOfInvoicesForCustomer( Customer c );
}

I'll also create an InvoiceMemoryStoreRepository for the test-cases in the project that contains the unit-tests, and I'll extend the IRepositoryFactory interface (and the classes that implement this interface) with a method that creates the correct IInvoiceRepository.
Once that is done, the CanOrderLineBeAdded member method of the Order class needs to be extended, so that we check if a Customer is allowed to add the OrderLine to it's Order. This means that we'll have to adapt the Order class a bit.
First of all, I'd like to change the isGoldCustomer boolean member that acted as some kind of a helper variable, in order that we do not have to check the Status property of the OwningCustomer (because checking this status can be considered as expensive).
I want to do that because it is not sufficient any more to know if the 'owning customer' of the order, is a Gold Customer or not; now, I want to know whether the customer is a Normal Customer, a Gold Customer or a Bad Payer. Therefore, I removed the isGoldCustomer member variable, and changed it to a customerStatusHelper member, that is of type CustomerStatus.
I've put the code that has to keep track of the CustomerStatus into a separate method that looks like this:

private void DetermineCustomerStatus()
{
customerStatusHelper = owningCustomer.Status;
customerStatusDetermined = true;
}

Then, the CalculateDiscount() member method of the Order class has to be changed as well:

private void CalculateDiscount()
{
if( customerStatusDetermined == false )
{
DetermineCustomerStatus();
}

if( customerStatusHelper == CustomerStatus.Gold )
{
_discount = OrderTotal * 5 / 100;
}
else
{
_discount = 0M;
}
}

Although this is a rather small refactoring, thanks to our unit-test, we can be assured that our code is still correct.

Now, we can add a test to the CanOrderLineBeAdded member method to check whether the 'OrderLimit' is exceeded, when a Customer who's a Bad Payer, makes an Order:

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

if( customerStatusDetermined == false )
{
DetermineCustomerStatus();
}

if( customerStatusHelper == CustomerStatus.BadPayer )
{
if( this.TotalAmountToPay + ol.LineTotal >
DomainSettings.BadPayerOrderLimit )
{
result = OrderLineAddQueryResult.NoBecauseOrderLimitExceeded;
}
}

// the other checks that were shown before, are now not shown any more.
...
...

return result;

}

The GetReasonWhyOrderLineCantBeAdded needs to be extended as well, but I'm not going to discuss that.

Creating Invoices

Until this time, we're still unable to create Invoices for Orders that are shipped. As discussed earlier, creating Invoices from shipped Orders would best be implemented as a Service.
This 'Domain Service' can then be used by a Windows Service, so that this task is done every night. The CreateInvoices service should use an IOrderRepository to get all the Orders that are shipped, and for which no Invoice has been created yet.
For those Orders, the service should create Invoices. Given the text, the service should look like this:

public static class CreateInvoicesService
{
public static void CreateInvoices()
{
IOrderRepository ordersRep =
DomainSettings.RepositoryFactoryObj.CreateOrderRepository();
IInvoiceRepository invoiceRep =
DomainSettings.RepositoryFactoryObj.CreateInvoiceRepository();

IList orders = ordersRep.FindShippedOrdersWithoutInvoice();

foreach( Order o in orders )
{
Invoice inv = o.CreateInvoice();
invoiceRep.Save (inv);
}
}
}

This is pretty straightforward. However, there is something that we haven't considered yet: transaction handling/boundaries.
The Repository itself should not be responsible for starting and committing or rollbacking transactions.
The Repository is not aware of the context of the transaction, so therefore, it is not the task of the repository to start and commit a transaction. Only the client knows when to start and commit a transaction, so it's his responsability. In this case, it's the CreateInvoicesService service that is responsible for starting and committing (or rollbacking) the transaction.
But since we haven't focused on persistence yet, we'll just keep this in the back of our mind.
Now that we're able to create Invoices, we're still not able to determine whether an Invoice is overdue or not. This batch-process should also be implemented as a service.
An IInvoiceRepository should be used that gives us all Invoices that haven't been payed yet.
Then, each Invoice that has been returned can be checked by a Specification class if the Invoice is overdue or not. If the Invoice is overdue, the IsOverdue flag can be set, and the Invoice can be persisted. If the logic to determine whether the Invoice is overdue or not would be complicated, and depend on several other factors (like, for instance the CustomerStatus of the Customer), then this would be a good solution.
In this case however, things are quite simple: an Invoice is overdue if it is past its duedate (however, we could allow a retention period of say 4 days). This means that marking all Invoices that are past their due date as overdue, could be done be just one query. In other words, the MarkOverdueInvoices Service could be as simple as just calling a method on the IInvoiceRepository:

public static class MarkOverdueInvoicesService
{
public static void MarkOverdueInvoices()
{
IInvoiceRepository invRep =
DomainSettings.RepositoryFactoryObj.CreateInvoiceRepository();

invRep.MarkOverdueInvoices();
}
}

So, I think that's about it. I think we've discussed the most important part of the Domain. Now, we can concentrate on the persistance of the objects in a relation database. For more information about test driven development, you can read these guidelines, written by Jeffrey Palermo.

That's it for now. In the next article (if it ever comes, since I still have to start writing...) of this series, I'll try to tackle the persistence functionality using NHibernate.

maandag 7 augustus 2006

New photography toy!

I was planning to blog about this, but I constantly postponed it until I almost forgot about it. And how could I forget this...

After years of using only a film-camera, I've finally decided to go digital. Well, I'm not really telling the truth here, since I already own a digital compact camera since 2003.
Anyway, I finally decided to buy a digital SLR camera. Since I already have a Nikon F55 film SLR, the choice was easy: my digital SLR would also be a Nikon.
After reading some reviews and testing different models, I've made a decision on the model as well: it would be a Nikon D200.

I've ordered the camera in May 2006, and I got it in my hands in the first week of July 2006.

I have the D200 now for about one month, and it is a great camera. I've done about 1000 shots in past month, and although I've already achieved some satisfying results, I feel that I haven't unleashed its full potential yet.
I hope that I'll be able to show the progress I make by regularly posting a photo here on my blog.

Here you see my F55 film camera next to the D200. Quite a difference in size!
Image taken with a compact digital camera



zondag 6 augustus 2006

This is the end....

... of my holiday.
The last day of my holiday is coming to an end. This means that, as from tomorrow, I'll be spending most of my time behind my workstation at work, developing in .NET.

I've had a nice 3 weeks of vacation wich have passed very fast, which is a good sign: it means that I haven't bored myself. :)
My girlfriend and I made a trip to Spain, continued our search for a suitable and affordable piece of terrain where we could build a house. Hopefully, that quest will come to an end soon, because it becomes quite exhausting.

Next to that, I've read some books, and I've continued reading Applying Domain Driven Design and Patterns, and so far, I find it a very good book.

I've also spent some time preparing for a session about Unit Testing and Test Driven Design wich I'm planning to do in the near future at work.
I hope to finish those preparations very soon, so that I can concentrate on the next episode of my blog article regarding Domain Driven Design.

I think I can say that the past 3 weeks were well spent, and I'll be ready to get back to work with a fresh, relaxed mind.

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. :)