Saturday, August 30, 2008

Book Review: Agile Principles, Patterns and Practices in C#

Agile principlesI already had this book lying around on my desk for about 2 years now. Boy, am I a douche bag for no reading it sooner. I welcome this book into my personal hall of fame.

The first section contains some basic introductions to Agile, XP, Agile planning, Testing and Refactoring. Mostly basic stuff if you are already familiar with these concepts, but very nicely written and definitely worth a read.

The second section goes into Agile design. It starts of with a discussion about design smells continuing with the most important concepts of OOP:

Do I need to mention again that these are essential principles?

Then its time for a couple of short chapters about UML. Don't worry. The authors just want to point out the parts of UML that they believe are essential and when to apply it. See it as a light version of UML without the waste. The authors also make it very clear that creating detailed diagrams in a CASE tool is probably a waste of time, which I certainly agree with. The only scenario  when it useful to create UML diagrams in a CASE tool is when I'm sure if the diagram is actually going to be read by someone else besides me. Otherwise, a drawing on a whiteboard or a cocktail napkin will do just fine, which is encouraged by the authors.

The third section is a nice refresher to some design patterns like Command, Template Method, Strategy, Facade, Mediator, Null Object, etc. ... . All these patterns are applied in the final chapter of the section where the authors are designing and implementing a Payroll system using TDD.

The fourth and final section starts off with a chapter about the principles of package and component design:

Really neat stuff and I learned a ton. These are the basic principles that can be measured by NDepend. This section goes on with discussing some design patterns like Composite, Observer, Adapter, Bridge, Proxy, Gateway, Visitor, etc. ...

I also want to mention appendix B which is an article written by Jack Reeves for the C++ Journal in 1992 named What is Software?. You can also find a a copy of this article here. The article is 16 years old and contains a lot of wisdom about software engineering that is still sooooo relevant today. I wish our industry would learn more from this. There is still a long way ahead of us.

Again, I really enjoyed reading this book. Don't let its size scare you. Its very well written and an easy read. In fact, at times I really had a hard time putting it away. I'm already looking forward to Clean Code, which is on my order list. 

I want to round off this post with some remarkable quotes from the book:

"Continuous attention to technical excellence and good design enhances agility. High quality is the key to high speed. The way to go fast is to keep the software as clean and robust as possible. Thus, all agile team members are committed to producing only the highest quality code they can. They do not make messes and then tell themselves that they'll clean up when they have more time. They clean any messes as they are made."

"Databases are implementation details! Consideration of the database should be deferred as long as possible. Far too many applications were designed with the database in mind from the beginning and so are inextricably tied to those databases. Remember the definition of abstraction: "the amplification of the essential and the elimination of the irrelevant." At this stage of the project, the database is irrelevant; it is merely a technique used for storing and accessing data, nothing more."

"Interfaces belong to the client, not the derivative. The logical binding between the client and the interface is stronger than that between the interface and its derivatives."

"All instances of the STATE pattern are also instances of the STRATEGY pattern, but not all instances of STRATEGY are STATE".

Now I'm going to start reading Release It!. Ayende has nice things to say about it, so it has to be good. I'm also reading Beautiful Code which I received from my fellow Elegant Coders, but the progress is slow.

Till next time,

Jan, the bookworm 

Friday, August 29, 2008

What's Wrong with a Data-Driven Approach?

Suppose we are building yet-another-order-basket-application. We have the requirement for adding items to an order, otherwise the business of our entire company falls down and we are losing tons of money (while not overdramatizing things).

The code I see popping up over and over again looks something like this:

public class DataDrivenService { private Database _database; public SomeService() { // Setup database member variable } public void AddItem(Int64 orderId, Int64 productId, Int32 quantity) { String sql = " INSERT INTO ORDERITEMS " + " VALUES(@OrderId, @ProductId, @Quantity) "; // Code for setting SQL parameters _database.ExecuteNonQuery(sql, parameters); } }

Besides the fact that it uses some crappy data access framework like the Data Access Application Block of the Enterprise Library, there are some things that are really wrong with this code.

For starters, this code completely neglects the concepts of our business domain. Its is all about database connections and executing SQL statements.

Secondly, it violates the Single Responsibility Principle. This code clearly has the concept of SQL and the database schema. As mentioned earlier, it also hides the concept of adding items to an order. Both of these concerns change for different reasons.

Third, this code is simply not testable without incorporating the database. It probably has not unit or integration tests at all. This is also called legacy code.

What's a better approach then?

public class Order { private IList<Item> _items = new List<Item>(); public void AddItem(Product product, Int32 quantity) { _items.Add(new Item(product, quantity)); } } public class SomeAppService { private IRepository<Order> _orderRepository; private IRepository<Product> _productRepository; ... public void AddItem(Int64 orderId, Int64 productId, Int32 quantity) { Order order = _orderRepository.Get(orderId); Product product = _productRepository.Get(productId); order.AddItem(product, quantity); Repository<Order>.SaveOrUpdate(order); } }

This code nicely separates the two concerns discussed earlier. If the database schema changes, then the database code inside the repositories needs to be changed while the business logic is left untouched. What I probably like the most about this orthogonal approach, is that it enables me to forget about the database until the last responsible moment.

I've said this quite a number of times already: Databases are just a detail. There just another piece of software to efficiently store data on disk. That's all! Why some people want databases to be  at the center of their application is simply beyond my intellectual capacities.

As always, there is a time and place for data-driven applications. I just don't buy that it is well suited for applications with more complexity than vanilla ice cream. This means that it is almost always the wrong choice for any long-lived application.

Tuesday, August 26, 2008

Decoupled Domain Models

On the DDD user group, there has been endless discussions about whether a service or repository can be directly called by classes that are part of the domain model. There is a group of people that believe that this is just fine and then there are a group of people who believe that this violates encapsulation and the very nature of a centralized domain model.

I'm definitely in the second group of people. I believe that domain models can be seen like the kernel of an operating system. It is completely and utterly decoupled from the rest of the application. There are only afferent couplings, no efferent couplings in my DDD book ;-).

However, I do recognize that there are some scenarios where there is a need for calling a service or a repository from the domain model. In fact, I came across this urge in our previous sprint. During the execution of some business logic, its possible that something needs to be resolved by an infrastructure service. How did I keep the domain model decoupled from this infrastructure concern. Domain events!

Udi has written about How to create fully encapsulated Domain Models in the past (make sure to read the comments) and has further refined this approach in one of his latest articles.

I must admit that the solution I applied for achieving multi-threading and dealing with memory leaks is less elegant, but certainly equivalent. But hey, that's what refactoring is for :-).

Monday, August 25, 2008

Three years ago ...

... I wrote my very first blog post (in Dutch). I've learned a lot of stuff since then. Time really flies, I must say.

NHibernate 2.0 went gold!

Yesterday I got back from a refreshing holiday in Italy. First thing I noticed after opening my RSS reader was that NHibernate 2.0 got released. Aah, life couldn't get any better. Kudos to Fabio Maulo and the gang for all the hard work.

Friday, August 15, 2008

My New Home Developer Rig

I finally got my new desktop up-and-running and fully installed. Last weekend, me and my dear colleague Sven Erkens (kudos!) assembled the different parts to what became a lean, mean development machine. Here are the specs:


Antec Midi Tower Sonata III Life Style ATX 500W

Motherboard MSI P45 Platinum iP45, SATA2 RAID, GLAN, Crossfire
CPU Intel Core 2 Quad Q9450 2.66GHz FSB1333 Box
Memory Kingston 2x2GB DDR2 SDRAM PC6400 CL5.0 (x 2)
HD Samsung 640GB SATA300 16MB, HD642JJ (x 2)
CPU Cooler Zalman Processor Cooler CNPS9700 LED AMD & Intel
VGA MSI PCI-e GeForce 9600GT 512MB 2xDVI/HDMI

The 8Gb's of RAM are really VM friendly. The guest operating systems are really flying now. I'm running Windows Vista x64 and to me it feels much better than the 32 bit variant (I don't know why, but the 8Gb RAM has probably got something to do with it).

One small catastrophe happened the very next morning: the motherboard of my old PC died on me. Talking about bad luck, huh? I spent quite some time transferring data from the old disks to my new rig. Of course, needless to say that I didn't have any back-ups so this took me reasonable amount of time.

One more major bummer was the fact that I couldn't find a 64 bit driver for my WinTV PVR 350 card. I sent an e-mail to Hauppauge support asking for, ... well, ... support! Some douche bag answered me that they didn't have a 64 bit driver and that they don't have any plans for providing one in the near future either. Come on! I mean, this TV-card isn't even that old. I bought it last year fresh from the store.

Besides some quirks, running a 64 bit system is great although I noticed that there isn't much 64 bit software available just yet. I hope that this will improve in the next decade or so?

Anyway, I'm leaving the country tomorrow to enjoy a week of peace, rest and happiness in one of the most beautiful countries in the world named Italy. Hopefully I will catch up with some reading. Till next week.

Jan, the tourist