Sunday, December 28, 2008

TDD-friendly CSLA solution - Part 2: Feature Analysis

The features I will use out of the box:

1. DataBinding support. I use the Supervising Controller variant of the Model View Presenter pattern in my windows forms applications (I strongly suggest that you read Jeremy Miller’s discussion on this if you have not done so already). As you will see in my future posts, while I use the presenter to encapsulate the application control logic, I still like to tunnel the business object through to the view so properties can be bound directly.

2. Undo / Redo. The undo/redo code is very nicely written and I doubt that there will be a need to inject an alternative implementation of this. This code exists in a CSLA base class from which all editable objects are derived. Even if you don’t use it, there is no need to remove it.

3. Aggregate management (parent/child management, dirty tracking, etc). This is a perfect example of the GRASP Expert pattern at work – assign a responsibility to the class that has the information needed to carry out the responsibility. Each object manages its undo/redo stack, dirty state, and validity state. At any one time, the root object can determine the resulting aggregate state.

The things I will modify a little:

1. Tracking broken business rules. I like the fact that the object can check itself and enforce rules; however, I want to be able to allocate the rules in a separate component and subsequently inject those rules. Note that the control over when those rules are checked is still in the hands of the business object. This allows me to continue using the Windows Forms ErrorProvider component.

2. Enforcing Authorization rules. I want to be able to allocate the authorization rules in a separate component. Note that the control over when those rules are checked is still in the hands of the business object. This allows me to continue using the CSLA ReadWriteAuthorization component.

3. Executing the data access code in another tier. I will use the DataPortal in an unorthodox manner so that I don’t have to deal with a copy of my object after a save.

The things I need to change or work around:

1. Data access code in the business object. Whilst the ObjectFactory provides for separation of data access code, it does not enable injection of data access code through the constructor. Constructor injection results in an explicit declaration of the class dependencies. Please see below for a further discussion on constructor dependency injection.

2. A separate copy of the object being returned after a Save via the DataPortal. As I discussed in my previous post, an insert/update invocation to the DataPortal returns a different instance of the business object. This is just the nature of using mobile objects. My solution will still use the DataPortal to execute the data access code on a server, without having to update all local references to a new instance after the save.

3. Static Factory methods and Save method exposed to UI code. As explained above, I use the Supervising Controller variant of the MVP pattern. This allows me to tunnel the business object through to the view so that properties can be databound. However, I prefer that any method calls be relayed by the presenter when an event is raised by the view. This allows me to handle exceptions and notifications (and to initiate other common application logic in response to method calls) in a consistent manner.

Subsequent posts will serve to expand on each of the above points.


A note on my preference for Constructor Dependency Injection

I am aiming for a solution where I can injection all dependencies through the constructor. The constructor, along with the properties and methods will serve to fully specify the dependencies of the class.

It is equally valid to use dynamic injection of dependencies through calls to singleton services, factories and/or service locators within the business object code. However, I prefer all dependencies to be explicit in the class interface/specification, rather than having to search through source code for calls to a service locator.

Another common way to do dependency injection is through property setters. The smelly thing about this is that it requires that construction and setting be done as two separate steps. The interface implies that the property is always settable, when in fact the case would usually be that it only be set immediately after construction. I feel that if a property or field of an object can only be set once, then it should be an input parameter during construction.

For more information, I suggest you read Martin's Fowler's discussion on which option to use.

No comments:

Post a Comment