Surely, the weather was much better there then it is now here in Belgium and every evening, we could enjoy a beautiful sunset:
zondag 27 augustus 2006
woensdag 23 augustus 2006
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
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.
"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.NumberOfItems = 10;
OrderLineAddQueryResult result = o.CanOrderLineBeAdded (ol1);
"The 1st OrderLine should pose no problem.");
// At this time, the OrderTotal should be 150eur.
"The OrderTotal should be 150eur.");
// Create a 2nd OrderLine which will cause
// the Order-limit to be exceeded.
OrderLine ol2 = o.CreateNewOrderLine();
ol2.NumberOfItems = 10;
result = o.CanOrderLineBeAdded (ol2);
"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.
Invoices are created from
Orders that have been shipped, we can start with this unit-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
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
public DateTime InvoiceDate
public DateTime DueDate
dueDate = value;
public Customer OwningCustomer
public InvoiceStatus Status
public bool IsOverdue
isOverdue = value;
public DateTime DatePayed
public decimal SubTotal
public decimal Discount
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 method will add an
InvoiceLine object to the
invoiceLines collection for each
OrderLine object that is contained by the
private void AddInvoiceLine( int articleId,
int numberOfItems )
new InvoiceLine (this, articleId,
articleName, articlePrice, numberOfItems));
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.
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
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.
InvoiceLineclass is implemented and the
CreateInvoicemethod has been written, the tests compile. However, the first test still fails, because we still have no functionality written to determine if a
Customeris a bad payer.
To do this, we can extend the
Statusproperty of the
public CustomerStatus Status
CustomerStatus result = CustomerStatus.Normal;
// First get the amount of orders this
// customer has made in the last 3 months.
decimal orderTotal = DomainSettings.Instance.
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 =
int numberOfOverdueInvoices =
if( numberOfOverdueInvoices > 0 )
int totalInvoices = invRep.GetNumberOfInvoicesForCustomer (this);
if( numberOfOverdueInvoices / totalInvoices > 0.333 )
result = CustomerStatus.BadPayer;
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
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
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 )
if( customerStatusHelper == CustomerStatus.Gold )
_discount = OrderTotal * 5 / 100;
_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
public OrderLineAddQueryResult CanOrderLineBeAdded( OrderLine ol )
OrderLineAddQueryResult result = OrderLineAddQueryResult.Yes;
if( customerStatusDetermined == false )
if( customerStatusHelper == CustomerStatus.BadPayer )
if( this.TotalAmountToPay + ol.LineTotal >
result = OrderLineAddQueryResult.NoBecauseOrderLimitExceeded;
// the other checks that were shown before, are now not shown any more.
The GetReasonWhyOrderLineCantBeAdded needs to be extended as well, but I'm not going to discuss that.
Until this time, we're still unable to create
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.
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 =
IInvoiceRepository invoiceRep =
IList orders = ordersRep.FindShippedOrdersWithoutInvoice();
foreach( Order o in orders )
Invoice inv = o.CreateInvoice();
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.
IInvoiceRepository should be used that gives us all
Invoices that haven't been payed yet.
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
public static class MarkOverdueInvoicesService
public static void MarkOverdueInvoices()
IInvoiceRepository invRep =
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
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
... 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.