Saturday, December 27, 2008

TDD-friendly CSLA solution - Part 1: Introduction

I have 3 years development experience with Rockford Lhotka’s CSLA.NET. Recently, I had considered packing my bags and moving away from the framework. Ryan Kelley seems to have felt the same way about CSLA, and in fact ended the relationship! However, my relationship with CSLA has managed to overcome my recent indiscretions! You see, I have been having an affair with test-driven-development. As you can imagine, this doesn’t sit well with CSLA.

This post, and the ones to follow, are not intended to spark debate about whether one should do TDD or not. There have been several discussions on Rocky’s forum with respect to this. The purpose of this series of posts is to propose a way to do TDD and still use CSLA.

In fact, I did give CSLA the flick for all of one hour! It was only when I left it, that I began to appreciate the good things it did that I had taken for granted … okay, enough of the metaphor, it’s getting a bit creepy! I figured that I would need to write my own framework or find another alternative, so I started making a list of all the things that this framework would need to do for a complex windows forms application (which is my specific area of interest). To cut a long story short, it ended up pointing me back to CSLA. Why write all this stuff myself, when it is already available to me? So I decided to tackle the problem from the other direction – Let’s keep all of CSLA and add to or remove from it where appropriate in order to meet my TDD needs. If that means we need to tweak the source code a bit, then so be it.

The main reason that CSLA is not TDD friendly is not due to CSLA itself, but rather the serialization mechanism. After an invocation to the data portal, the returned object is a new object. This is just the nature of using mobile objects. Since the objects need to be mobile, they must be serializable. This puts some constraints on things. For example, if I want to inject dependencies and services through the constructor, then these dependencies must be (a) serializable or (b) I need to re-assign those dependencies to the copy of the object when it is returned from the data portal. Having to make every injected dependency serializable is just a pain and in some cases it may not be possible. Also, even if the dependencies are serializable, they may be heavy, so that’s just too much extra baggage that the mobile objects need to carry across the wire. In addition, if the dependencies are marked as non-serializable and then re-assigned to the copy upon deserialization, this makes the injection through the constructor in the first place superfluous (since there are now two ways to assign the dependencies).

In an effort to make CSLA a little bit more TDD friendly, CSLA now provides the ObjectFactory which enables the separation of data access code from the business objects. However, while this may address one specific issue (taking the data access out of the business objects), it still does not address the underlying problem … making CSLA more unit-test friendly – It may not just be the data access that I want to separate out, but I may also want to separate out the validation provider, authorization provider, or other services. I could then subsequently inject different concrete implementations (or mocks for unit testing). Again, I don’t want a debate to start about why someone may want to do this, but rather I will suggest a way that I think this can be done if you want to do so.

Another reason that CSLA is not TDD friendly is that the level of encapsulation is quite high. Good encapsulation results in a business object which has one responsibility. However, this is very subjective. How do you break down responsibility? How detailed should the responsibility be? CSLA business objects tend to provide an encapsulation for one large responsibility which can be broken down into many sub-responsibilities. For example, a Product class has one responsibility, to manage all information with respect to a product. However, this also means data access, validation, authorization, etc ... And I think this is perfectly logical! This is one way to think about things. However, more often than not, it will produce large monolithic classes which could eventually become too complex to work with and maintain.

TDD, on the other hand, tends to drive out fine-grained responsibilities, resulting in extremely cohesive and low-coupled code. This naturally means that the bits are easy to “get at” and to test in isolation. CSLA business objects, however, encapsulate a lot and are not very open. So business objects constructed using CSLA can only ever be “integration” tested, not truly unit tested. Don’t get me wrong, if there is a lot of code in your CSLA objects then you will most probably still need to write a lot of code when you break up the responsibilities into other objects for the purposes of TDD … let’s face it, if you’re a developer then you have to write code. If you don’t like coding, then you’re in the wrong profession.

I have come up with a solution that is amenable to TDD and keeps most of what CSLA has to offer. I will elaborate on the details in future posts.

No comments:

Post a Comment