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