Thursday, February 16, 2006

Add dependency support to custom rake tasks

I previously wrote about creating a NUnitTask for Rake. The NUnitTask is based on the PackageTask that comes standard with Rake. I assumed that the PackageTask would have support for adding dependencies at construction time. This turned out to be a false assumption. To add a PackageTask and dependency for that task they need to be declared separately.
Rake::PackageTask.new "foo","1.2.3" do |pkg|
pkg.need_zip = true
pkg.package_files.include("build_helpers/*.rb")
end
task :package => :test
I had expected it to work much like a standard task and dependency.
#this will not work
Rake::PackageTask.new "foo","1.2.3" => :init do |pkg|
pkg.need_zip = true
pkg.package_files.include("build_helpers/*.rb")
end
Upon discovery, I decided to alter NUnitTask to take a dependency in the expected manner. The only change required is to alter the assignment of the name variable.
def initialize(name=:nunit)
@name = name
..
end
Becomes
def initialize(params=:nunit)
@name = case params
when Hash
task params.keys[0] => params[params.keys[0]]
params.keys[0]
else
params
end
..
end
Hopefully, Jim Weirich can add the same capability to the next version of the Rake Tasks.

Rake Tutorial

If you are tired of reading my entries about Rake and not knowing what I'm talking about I suggest:

Friday, February 10, 2006

Initialization Chain

Initialization Chain allows you to chain additional property setters to an object's initialization.
Column column = new Column().WithHeader("ID").WithType(typeof(int))
Initialization Chain is a special case of Fluent Interface. It's most often seen during testing, but it also has a place in production code.

Initialization Chain can be used to reduce the number of constructors of a class. In the above example a constructor of Column could be created to take both a header and column type. However, neither of these properties are dependencies of the class. Creating constructors that initialize properties that are not dependencies can lead to constructor bloat.

Initialization Chain is more expressive than using a constructor to initialize properties. When maintaining an existing codebase you will need to understand which properties are being set by which constructor arguments. Additionally, you will need to know which constructor arguments are dependencies and thus required across all constructors of the class. Initialization Chain will explicitly show that any argument of a constructor is a dependency and any additional properties that need to be set can be done in the chain by methods that express which property is being set.

Initialization Chain can remove the need for a temporary variable. In the above example an instance of the Column class is being initialized. Generally, this type of operation will occur in some type of loop. In general you will need to create each Column instance, set the properties, and add the new Column instance to the collection. Initialization Chain allows you to set the properties following construction and immediately pass the instance to the collection without the need for the temporary variable.

There are also negatives to Initialization Chain. Readonly fields cannot be initialized from an Initialization Chain. There is overhead in creating and maintaining the Initialization Chain methods. They can clutter the API by adding an additional method for each property. And, there is no stopping someone from using one long after initialization.

Implementing Initialization Chain is quite simple. For each property that you wish to be able to initialize in an Initialization Chain you must simply add a method that sets the property and then returns the instance.
class Foo...
public string Bar
{
get { return bar; }
set { bar = value; }
}

public Foo WithBar(string value)
{
Bar = value;
return this;
}

Creating an interface for testing

When following some common unit testing guidelines you will often need to create interfaces for the purpose of testing.

A common example of this occurs when you use constructor dependency injection. For example, if you have a Foo class that takes a Bar as a constructor argument.
class Foo...
public Foo(Bar bar)
{
this.bar = bar;
}
..
}
In the above example Foo cannot be tested without creating an instance of the Bar class. However, the dependency could be mocked or stubbed (depending upon intent) if Foo instead depended upon an interface.
class Foo...
public Foo(IBar bar)
{
this.bar = bar;
}
..
}
Unfortunately, this approach is often met with criticism.

The common complaints include.
  • Complaint: Creating extra code to support testing. Response: Code written to support testing should be minimized. However, any code that allows for better testing is well worth adding. It will need to be maintained, but this level of effort should be far less than the level of effort required when working with detestable code.
  • Complaint: The overhead of maintaining the class and the interface. Response: Static languages are great at alerting you when your class/interface relationship has become out of synch. Additionally, refactoring tools such as ReShaper ensure that little effort will be necessary to maintain a good relationship.
Using an interface has additional positives.
  • Easy mocking or stubbing. Interfaces dependencies allow you to create mocks or stubs that behave specifically as your test requires. This improves the durability of the tests you write.
  • Truly unit testable classes. Classes that have constructor arguments that are not interfaces require instances of concrete types with defined behavior. When this dependency exists any change to the behavior of a dependency can cause false test failures. Classes that have interfaces as dependencies can have their behavior tested in isolation.
  • Using other types (as long as they implement the interface) as dependencies. While developing applications, requirements change. Using the example above, today it may appear that Foo will always depend on Bar. However, in the future it may turn out that Foo depends on BarNorth and BarSouth. If BarNorth and BarSouth are nothing alike they could share a base class, but will more likely simply implement the same interface. When this occurs, if Foo depends on Bar, the constructor (and likely every place that uses type Bar) will need to be changed to use the interface instead. If an interface were used from the beginning, no changes to the existing codebase would be required.
This is a simple concept, but it's often a tripping point. Don't be afraid of the overhead required to use an interface when it will improve your ability to write quality software.

Wednesday, February 08, 2006

.norm find collection usage

In my last entry I detailed how to use .norm to return an instance of an object from the database. However, often you are looking to return more than one instance. Enter DataGateway.FindCollection.

DataGateway.FindCollection is overloaded. You can call FindCollection with only a type and return an array of instances that represent each record in the database. Or, you can execute FindCollection with a type and a IWhere instance. The IWhere is used to specify which rows to return.
ConnectionInfo info = new ConnectionInfo("fieldsj2","norm","jay","jay");
DataGateway gateway = new DataGateway(info);
Bar[] results = (Bar[]) gateway.FindCollection(typeof(Bar));
The above code will return all instance of Bar stored in the database. If you only needed the instance of Bar where Bar.Baz is equal to 1 you could specify that in an IWhere parameter.
ConnectionInfo info = new ConnectionInfo("fieldsj2","norm","jay","jay");
DataGateway gateway = new DataGateway(info);
IWhere where = new Where().Column("Baz").IsEqualTo(1);
Bar[] results = (Bar[]) gateway.FindCollection(typeof(Bar),where);