Tuesday, July 6, 2010

When To Use Abstract Classes

Introduction

Up until recently, my C# designs never started off containing abstract classes. Things always started their lives as either concrete classes or as interfaces. Occasionally an abstract method would appear in a class but that was the exception.

I had read that abstract classes weather change better than interfaces but that wasn't enough for me to embrace abstract classes. The limitation that a class can only inherit from one class was enough to keep me from "wasting" my one and only one inheritance card on an abstract class.

But then I re-read "Framework Design Guidelines" by Cwalina and Abrams and I thought I'd give abstract classes a second chance. They encourage their readers to use abstract classes. I wanted to try out their advice, but I wanted to have a game plan so that I wouldn't completely give up on interfaces. Here are the key points that guide me when choosing between interfaces and abstract classes.

Interfaces Are Weak Contracts

In their capacity as contracts, interfaces are really weak. All an interface can do is enforce method signatures and property types. Interface implementers can make their methods do whatever they want. They can throw whatever exceptions they want to. Interface implementers don't have to respect Barbara Liskov or her Substitution Principle.

Template Methods Provide Contracts With Teeth

A template method is a design pattern where a method calls one or more virtual methods. The template method might have knowledge about how the virtual methods should be called, under what condition they should be called, or what should be done before and after the calls to virtual methods, etc. To some extent the template method design pattern can be used to give a contract some teeth. For example, if a first virtual method does not meet a particular criteria, perhaps the second virtual method won't be called at all. But if the first virtual method does meet the criteria, the second virtual method will be called. What better way to express this template method than as an abstract class?

Core Abstractions Are Likely To Change

If your application's core abstraction is a Map, it is very likely to change over time as you allow your users to do more and more with a Map. It is also likely that different kinds of maps will be introduced which will result in an inheritance hierarchy. When you add the "Print Map" feature, Map may acquire some print functionality which would change its interface. Representing this core abstraction as an interface sets up your users for breaking changes. Representing this core abstraction as an abstract class does not offer perfect isolation from change but it can make change a good deal easier.

Core Abstractions Should Collaborate

I like anthropomorphic objects. If I have a Map and I want to print it, I want to be able to tell the Map to print itself. I don't want to have to instantiate a MapPrinter object and tell it to print the map. However, I don't want my Map object to know about printing APIs. To make Map anthropomorphic without depending on printing APIs, I'd introduce a collaborator that Map can interact with.

C# Supports Single Inheritance Only

As nice as abstract classes are, any given class can at most derive from one of them. This tells me that abstract classes are precious resources. My recently adopted philosophy is that if an abstraction represents essential qualities, it should be modeled as an abstract class. For example in a drawing application, the Shape abstraction represents the essence qualities of squares, circles, and polygons. On the other hand, if an abstraction represents capability or a role, it should be modeled as an interface. For example, shapes might be serializable. Serializability is not part of the shape's essence but it does express one of the Shape's capabilities: the ability to serialize itself.

These five key points guide me as I decide when I should model an abstraction as an interface or as an abstract class. The last point about essential qualities vs. capability is the strongest guide.

The Rub - Unit Testing

Here is the rub with abstract classes that adhere to the template method pattern as I've described it. It's very difficult (impossible?) to mock away abstract classes with non-virtual methods such that no production code for the abstract class winds up in your unit test. Here is where the interface shines; mocking the interface is a snap! So does this mean that I should give up on abstract classes? I don't think so. Abstract classes can be used in unit tests as long as the following criteria are met:

* Abstract classes should have their dependencies injected. If your abstract class connects to a database in its constructor, no amount of mocking will isolate your unit test from the database. The down side of this is that to mock away an abstract class, you may need to create a mock for the abstract class and any dependencies that the abstract class my require during the course of the test.

* Abstract class logic should be tested in isolation from the production classes that derive from it. This can be achieved partly through deriving a number of test-only classes from the abstract class such that the virtual methods of the derived classes put the abstract class logic through its paces and achieve good code coverage. Abstract class logic can also be tested in isolation by injecting different dependencies into the abstract class such that the abstract class' logic is put through its paces.

* Concrete classes derived from the abstract class are also tested in isolation from the abstract class' dependencies. By testing the abstract class and the derived classes independently, you achieve a higher level of certainty that your code will be correct.

Saturday, April 17, 2010

Rethinking the Evil of XML Configuration Files

Do you remember when your system's configuration grew from a simple file containing a few name/value pairs modified by a small set of people, into a large collection of files in multiple locations with their own business processes surrounding them?

When the config files were small and informal, you could easily get by with a YAML file or a Windows .INI file format. But now that there are hundreds or thousands of settings, maintaining them all has become challenging.

The main problems with YAML and .INI configuration files are:
  • Lack of Type Safety - If the configuration reading code expects 'true' or 'false' and the configuration file contains '1', how will the code handle that input? Will it log an error? Will it silently misinterpret the '1' as 'false'? Do you want to have to write type-checking code throughout your application? You could write a comment in the configuration file that specified the type of the setting but not everyone understands all the various types and formats (e.g. dates and times).
  • Lack of Range Checking - If the configuration code expects a value between 1 and 4 inclusive, and someone has configured the setting as 5, how will your system react? What if your configuration reading code expects 'high' or 'low' and someone enters 'medium'? That's another form of range violation. You could write comments that specify the range but the comments had better agree with the code that does the actual range checking.
  • Lack of Validation Support - If one of your configuration settings is mandatory for the system to operate correctly (e.g. a web service endpoint) and it's missing, you don't discover the error until run-time. You could add a comment to the configuration file that stated that the setting was mandatory, but will people read it?
  • Lack of Appropriate Defaults - If some of your configuration values have appropriate defaults that you want to communicate to the user, you are stuck writing comments in the YAML or .INI file that list the defaults. Unfortunately, you have now just introduced duplication between the code that must take the default when the configuration value is missing and the comment in the configuration file.
XML files and, more specifically, XSD files, provide for all of the above.
  • XSD allows you to specify the type of a given configuration value. If your configuration value has the wrong type, XSD validation of the configuration file will alert you to your mistake.
  • XSD has support for range checking of several types.
  • XSD by it's very nature handles validation. If your application does XSD validation upon startup, you can quickly catch configuration errors.
  • XSD allows you to specify default values for configuration settings.
  • With an XSLT transform you could generate an HTML document that would list all your settings along with their defaults.
In short XSD codifies and enforces all of the constraints that we would otherwise add to our configuration files as comments.

Maybe XML configuration files aren't completely evil. The main complaint I had about XML configuration files was that they were so hard to get right. Isn't that ironic! YAML and .INI files are hard to prove that they're right.

How many of my YAML and .INI files are wrong and I just don't know about it?

Saturday, March 27, 2010

NUnit and CruiseControl

One of my goals is to become more skilled with CruiseControl.NET because Continuous Integration plays a big part in Agile Development. Today I took the first step. It wasn't one of those easy, comfortable steps. That's why I'm documenting my results.

Here are some of the steps I took today to get a CruiseControl server running on my computer with integrated NUnit Reports. Some of these steps could definitely be improved upon. I don't like using absolute paths if I don't have to but I broke that rule left and right. This is just the first time I've gotten all this working (and trust me, it took hours).

Install Cruise Control

I installed version 1.5.6804.1 of CruiseControl.NET and after realizing that by default Vista does not enable ASP.NET, it ran quite nicely.

Incorporte NUnit into the Build Process

I wanted to make NUnit run as part of the Visual Studio 2008 build process. I tried to use the Microsft SDC NUnit Task but after hours of tracking down unhandled exceptions in the NUnit task, I decided to switch to Tigris' MSBuild NUnit Task which worked great the first time.

I had to import the tasks in my Unit Test assembly's csproj file:

<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>

And then I added the following to the same csproj file:

<IemGroup>
<TestAssemblies Include="$(TargetPath)"/>
</ItemGroup>

<Target Name="Test">
<NUnit
Assemblies="@(TestAssemblies)"
ToolPath="C:\Program Files (x86)\NUnit 2.5.3\bin\net-2.0" />
</Target>

The last step was to add "Test" to the Project element's DefaultTargets attribute:

<Project ToolsVersion="3.5" DefaultTargets="Build;Test" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

Now, whenever I built the project, the tests would run. If the tests failed, the build would fail too. I had to change the MSBuild verbosity to normal to see the actual results of the unit tests. This has the side-effect of showing too much information. If I figure out how to get the NUnit test results showing without showing too much information, I'll write another blog entry.

Build the Project with CruiseControl

I added the following to my ccnet.config file:

<project name="MyProduct">
<category>Production Code</category>
<tasks>
<msbuild>
<executable>C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MSBuild.exe</executable>
<workingDirectory>C:\Users\Tim\Projects\CruiseControl\CruiseControlTests</workingDirectory>
<projectFile>CruiseControlTests.csproj</projectFile>
<buildArgs>/noconsolelogger /p:Configuration=Debug /p:Platform=AnyCPU /v:diag</buildArgs>
<targets>Build;Test</targets>
<timeout>900</timeout>
<logger>C:\Program Files (x86)\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MsBuild.dll</logger>
</msbuild>
</tasks>
<publishers>
<merge>
<files>
<file>C:\Users\Tim\Projects\CruiseControl\CruiseControlTests\TestResult.xml</file>
</files>
</merge>
<xmllogger/>
</publishers>
</project>

The merge elements are required so that the output of the unit test run could be reported on.

Getting Reporting To Work

In the dashboard.config file I had to make a few changes too. To make a change take effect, I'd recycle the CruiseControl app pool.

I added the following elements (shown in context):

<buildPlugins>
<buildReportBuildPlugin>
<xslFileNames>
<xslFile>xsl\unittests.xsl</xslFile>

and then I added this right after </buildReportBuildPlugin>:

<xslReportBuildPlugin description="NUnit Details" actionName="NUnitDetailsBuildReport" xslFileName="xsl\tests.xsl" />
<xslReportBuildPlugin description="NUnit Timings" actionName="NUnitTimingsBuildReport" xslFileName="xsl\timing.xsl" />

After recycling the app pool, everything worked great.

Wednesday, January 13, 2010

Can we drop the S in SOLID? (Or NTP!)

Maybe I just don't get the Single Responsibility Principle (SRP). Maybe it's just named poorly. I like the O, L, I, and D principles plenty, but my stomach feels anything but SOLID when I hear about the SRP.

According to Wikipedia, "[Robert C.] Martin defines a responsibility as a reason to change". I wish Martin had picked another, less useful word to redefine. So now, to even think the acronym SRP, I have to pause mentally before the R, and then mentally replace it with RtC (as in Reason to Change).

Even with this mental substitution, I still have problems with SRP. Is the SRP telling me that every one of my classes should have one and only one reason to change? How can this be, especially if a class has multiple responsibilities (as defined by Webster and Wirfs-Brock, not Martin)?

Here's my problem. In the Business Layer I like classes that resemble their real-world counterparts. For example, the Account object resembles a real account. The SRP principle would tell me that if my Account object had more than one reason to change, I should split it up. So if an Account object can calculate its balance, and perform a withdrawal, those are two places where the Account could change. Both of those responsibilities (think Webster) could change for any number of reasons.

I refuse to break up a domain-specific class just for some arbitrary limit on the number of reasons to change. We expect that change will happen. That's one of the reasons why we refactor our code and write unit tests.

Yay OLID. Boo S.

By the way, NTP from the title stands for No Teal Principles (where I've redefined Teal to mean Useless and Overly Restrictive).