Monday, July 30, 2007

Motivation for iterative development

I've been asked by many teams now, "why iterative development?"  I have a lot of strong, but not well-formed ideas why I like iterative or Agile processes over waterfall processes.  But in Craig Larman's book
"Agile and Iterative Development: A Manager's Guide", he provides a nice list of motivations (with explanations and evidence) for choosing iterative development:

  • Iterative development is lower risk; the waterfall is higher risk
  • Early risk mitigation and discovery
  • Accommodates and provokes early change; consistent with new product development
  • Manageable complexity
  • Confidence and satisfaction from early, repeated success
  • Early partial product
  • Relevant progress tracking; better predictability
  • Higher quality; less defects
  • Final product better matches true client desires
  • Early and regular process improvement
  • Communication and engagement required
  • "I'll know it when I see it" required

I'm not a fan of force-fed processes, whether they are Agile or waterfall.  Any kind of process needs buy-in from all stakeholders involved in a product or project, from the business to the developers.  Craig's book supplied the ammunition I needed to gain buy-in from business and development people who were only used to waterfall processes.

For those interested in introducing iterative development to your team, I'd start with Craig's book, then more detailed books about specific processes you're interested in.

Tuesday, July 24, 2007

Try Ruby in 15 minutes

There's been more and more buzz on Ruby and Ruby on Rails, especially in the Agile community.  If you're interested in seeing what this dynamically-typed language is all about, try out the following 15 minute interactive tutorial on Ruby:

http://tryruby.hobix.com/

I'm interested in learning more about Rails.  Something always seemed off to me with ASP.NET, where easy scenarios with classic ASP became much more difficult in ASP.NET.  Working with DataGrids and GridViews is always a nightmare.  All of the ViewState, page event lifecycle, postbacks, controls, etc. seemed to abstract the easy stuff (HTML) and mostly just get in the way of what I want to do.

If you can't wait for Team Build 2008...

I just heard of a new project on CodePlex, TfsBuildLab.  It looks like it performs a lot of the build features Orcas will provide, and it lets you do it with Team Build 2005:

  • Continuous integration builds
  • Scheduled builds
  • Build queuing
  • Build cleanup/retention policies
  • Event notifications

The TfsBuildLab project is broken into 4 separate components:

  • Database
    • Houses the scheduling and queuing data
  • Service
    • Queues builds
    • Executes manual builds
    • Executes scheduled builds
  • Admin client
    • Configures build schedules, etc.
  • Notification client
    • Notifies clients of build status, similar to CCTray

Builds are still executed by Team Build, but TfsBuildLab puts a layer on top of Team Build to provide the extra functionality.  This looks like a nice interim solution until Team Build 2008 releases early next year.

Monday, July 23, 2007

Can your dev team handle Agile/iterative development?

Too often development teams or organizations push straight into an Agile/iterative process like Scrum without considering the implications of iterative development.  Iterative development forces regular feedback and regular deliveries, but how do we know if the dev team is able to handle feedback and deliver more often?  If any of these criteria match your team, then you are going to have some major challenges adopting an Agile process:

  • Testability is not the top design concern
  • Unit tests are optional or non-existent
  • Builds happen less often than once a day
  • Deployments to test environments happen even less often, if at all
  • "Quick and Dirty" is your team's motto
  • Refactoring is considered taboo and dismissed as "over-engineering"
  • Email is the primary method of communication between team members
  • You don't see the person giving you requirements for weeks or months at a time
  • You don't see the testers until just before releasing

Feedback isn't useful if your team or application can't act on that feedback.  Without solid engineering practices in place, adopting an iterative process will likely end in disaster, as the application wasn't built to accept changes and feedback on a regular basis.

Friday, July 20, 2007

Constrained generic extension methods

When I first saw extension methods, a new feature in C# 3.0, I was a bit skeptical.  It seemed like yet another language feature shoehorned in to support LINQ.  After going a few rounds with the technology, it actually looks quite promising.  For a full explanation of extension methods and what scenarios they can enable, check out Scott Guthrie's post on the subject.

Making the extension method generic

First, let's examine the original example from Scott's post, which adds an "In" method to test whether an item is in a collection:

public static bool In(this object o, IEnumerable items)
{
    foreach (object item in items)
    {
        if (item.Equals(o))
            return true;
    }

    return false;
}

The "In" method will be added to all objects, including primitive value types such as "int" and "double".  Here's a sample snippet using "int":

int[] values = {5, 6, 10};

bool isInArray = 7.In(values);

The value "isInArray" evaluates to "false", as the number 7 isn't in the array.  So what's wrong with this code?  The problem is that the "In" method uses the type "object" to extend types, but that will cause boxing when the number 7 is boxed to an object for the extension method call.  Generics can prevent boxing from occurring, so let's change the extension method to be generic:

public static bool In<T>(this T o, IEnumerable<T> items)
{
    foreach (T item in items)
    {
        if (item.Equals(o))
            return true;
    }

    return false;
}

Now when I call "In", the method will use "int" instead of "object", and no boxing will occur.  Additionally, since I used the generic IEnumerable<T> type, I will get some additional compile-time validation, so I won't be able to do things like this:

string[] values = {"5", "6", "10"};

bool isInArray = 7.In(values); // Compile time error!

I can now lean on the compiler to do some type checking for me.  What about some more interesting scenarios, where I want to extend some complex types?

Adding constraints to a generic extension method

I'd like to add some complex comparison operators to certain types, say something like "IsLessThanOrEqualTo".  I'd like to extend types that implement both IComparable<T> and IEquatable<T>.  That is, the extension method should only show up for types that implement both interfaces.  I can't declare both types with the "this" modifier parameter.  How can I accomplish this?  The trick is to make the method generic, and add constraints:

public static bool IsLessThanOrEqualTo<T>(this T lValue, T value)
    where T : IComparable<T>, IEquatable<T>
{
    return lValue.CompareTo(value) < 0 || lValue.Equals(value);
}

This extension method lets me write code such as:

int x = 5;
int y = 10;

bool isLte = x.IsLessThanOrEqualTo(y);
Assert.IsTrue(isLte);

This gives me a few advantages:

  • The available constraints are the same as any other generic type or method (struct, class, new(), <base class>, <interface>, and naked type constraints)
  • Using multiple constraints lets me constrain the method to types that fulfill all the constraints, such as the two interfaces in the above example
  • The signature of type T inside the generic method combines the members of all of the constraints.
    • All of the methods of IComparable<T> and IEquatable<T> are available to me in the above example.
  • The IDE filters the constraints in IntelliSense, and I won't even see extension methods whose constraints my variable doesn't fulfill

What this allows me to do in real world situations is to target specific scenarios by filtering through constraints.  Instead of using only 1 type in the "this" parameter, I can target objects that derive from a certain class, implement several interfaces, etc.  By making the class generic, interactions with the method will be strongly typed and will avoid boxing conversions and unnecessary casting.

To see the constraints fail, what happens when we try to call the IsLessThanOrEqualTo with a class that only partially fulfills the constraints?  Here's the bare-bones class:

public class Account : IComparable<Account>
{
    public int CompareTo(Account other)
    {
        return 0;
    }
}

I try to compile the following code:

Account account = new Account();
Account other = new Account();

account.IsLessThanOrEqualTo(other); // Compile time error!

It won't compile, since Account only implements IComparable<T>, and not IEquatable<T>.  This wouldn't happen while authoring the code, as IntelliSense doesn't even show the IsLessThanOrEqualTo method.

I should note that if I don't constrain the generic extension method, any instance of any type will have the method available for use, which may or may not be desirable.

Conclusion

Generic types and methods can be very helpful in eliminating boxing and unboxing as well as casting that clutters up the code.  Extension methods allow me to add functionality to types that I may not have access to changing.  By combining generic, constrained methods and extension methods, I get the power of extension methods with the flexibility of generic methods.

Thursday, July 19, 2007

LINQ to Reflection

One of the great things about LINQ is that it allows me to query over any object that implements IEnumerable<T>.  This includes arrays, List<T>, Collection<T>, and many others.  Since many operations involving reflection return arrays, this means I'm open to using LINQ over those operations.  Let's look at a few examples.

Loading up assemblies for searching

First, I'd like to load some assemblies for searching.  The easiest way I found to do this was to use System.Reflection.Assembly.LoadWithPartialName.  This method has been deprecated as of .NET 2.0, but it will suffice for simple operations such as searching.  I wouldn't use that method for production code, it's too unreliable.

I first came up with a list of assembly names I wanted to search and dumped them in an array:

string[] assemblyNames = { "System", 
                 "mscorlib", 
                 "System.AddIn",
                 "System.Configuration", 
                 "System.Core", 
                 "System.Data",
                 "System.Data.Entity",
                 "System.Data.Entity.Design",
                 "System.Data.Linq",
                 "System.Deployment",
                 "System.Design",
                 "System.DirectoryServices",
                 "System.DirectoryServices.Protocols",
                 "System.Drawing",
                 "System.Drawing.Design",
                 "System.EnterpriseServices",
                 "System.IdentityModel",
                 "System.IdentityModel.Selectors",
                 "System.Management",
                 "System.Management.Instrumentation",
                 "System.Messaging",
                 "System.Printing",
                 "System.Runtime.Remoting",
                 "System.Runtime.Serialization",
                 "System.Security",
                 "System.ServiceModel",
                 "System.ServiceProcess",
                 "System.Transactions",
                 "System.Web", 
                 "System.Web.Services", 
                 "System.Windows.Forms", 
                 "System.Workflow.Activities", 
                 "System.Workflow.ComponentModel", 
                 "System.Workflow.Runtime", 
                 "System.WorkflowServices", 
                 "System.Xml", 
                 "System.Xml.Linq"
             };

It's pretty much all of the .NET Framework 3.5 assemblies.  Next, I want to create a LINQ query to load up all of the assemblies, so I can perform searches over those assemblies.  Just using the extension methods, it would look like this:

var assemblies = assemblyNames.Select(name => Assembly.LoadWithPartialName(name));

With LINQ magic, here's what the same query would look like:

var assemblies = from name in assemblyNames
            select Assembly.LoadWithPartialName(name);

With the "assemblies" variable (which is actually IEnumerable<Assembly>), I can start performing queries over the loaded assemblies.

Finding generic delegates

I was experimenting with an API, and I wanted to know if a generic delegate I created already existed somewhere in .NET.  I can use some handy LINQ expressions over the loaded assemblies to do just that.  But first, I need to know how to find what I'm looking for.  I can just load up a generic delegate I'm already aware of into a Type object:

Type actionDelegate = typeof(Action<>);

When I load up a generic delegate into an instance of a Type object, I notice some key properties, such as "IsGenericType" and "IsPublic".  Both of these are true for my generic delegate type.  Unfortunately, there is no "IsDelegate" property, but it turns out that IsSubclassOf(typeof(Delegate)) will return "true".  Combining these three conditions, I have a predicate to use in my search across the assemblies.

Here's the final LINQ query:

var types = from name in assemblyNames
            select Assembly.LoadWithPartialName(name) into a
            from c in a.GetTypes()
            where c.IsGenericType && c.IsPublic && c.IsSubclassOf(typeof(Delegate))
            select c;

foreach (Type t in types)
{
    Debug.WriteLine(t);
}

This is actually two LINQ queries joined together with a continuation (the "into a" part).  The first query enumerates over the assembly string names to load the assemblies.  The second query calls "GetTypes" on each assembly to load the types, and uses the "where" clause to only pull out the generic delegates using a predicate I found earlier.  The results of this block of code shows me the generic delegates:

System.EventHandler`1[TEventArgs]
System.Action`1[T]
System.Comparison`1[T]
System.Converter`2[TInput,TOutput]
System.Predicate`1[T]
System.Linq.Func`1[TResult]
System.Linq.Func`2[TArg0,TResult]
System.Linq.Func`3[TArg0,TArg1,TResult]
System.Linq.Func`4[TArg0,TArg1,TArg2,TResult]
System.Linq.Func`5[TArg0,TArg1,TArg2,TArg3,TResult]

Not a whole lot, but it did tell me what was already there.  Specifically, I had been looking for alternate overloads to Action<T>, to see if there were multiple delegate declarations like there are for Func<TResult>.  There aren't, but it turns out there are planned overloads for Action to match Func.

Context and IDisposable

I had a discussion with a team member that centered around types with names postfixed with "Context".  I was arguing that types named "Context" implied that the type implemented IDisposable, as it was intended to create a scope.  Instead of arguing in conjectures, I sought to get some actual data, and find how many types in the .NET Framework named "Context" also implemented IDisposable.  Here's the LINQ query I came up with:

var types = from name in assemblyNames
            select Assembly.LoadWithPartialName(name) into a
            from c in a.GetTypes()
            where (c.IsClass || c.IsInterface) && c.FullName.EndsWith("Context")
            group c.FullName by c.GetInterfaces().Contains(typeof(IDisposable)) into g
            select new { IsIDisposable = g.Key, Types = g };

In this query, I want to select all types that the name ends with "Context", and group these into different bins based on whether they implement IDisposable or not.  To do this, I take advantage of both grouping in LINQ, and anonymous types to hold the data.  I output the results:

foreach (var g in types)
{
    Debug.WriteLine(string.Format("{0} types where IsIDisposable is {1}", g.Types.Count(), g.IsIDisposable));
    if (g.IsIDisposable)
    {
        foreach (string t in g.Types)
        {
            Debug.WriteLine(t);
        }
    }
}

And find that my argument doesn't hold up.  Here are the results:

144 types where IsIDisposable is False
50 types where IsIDisposable is True

I left out the output that printed out all of the Context IDisposable types, as this list was fairly long.  I decided not to filter out non-public types, as MS tends to have lots of types marked "internal".  So it turned out that only 25% of types that end with "Context" implement IDisposable, so my assumptions were incorrect.

Other applications

LINQ provides a clean syntax to search assemblies using reflection.  I've also used it to argue against read-write properties for array types (they account for only 0.6% of all collection-type properties).  The continuations and joining lower the barrier for searching for specific types, properties, etc.  Since the LINQ methods are extension methods for any IEnumerable<T> type, you'll be pleasantly surprised when IntelliSense kicks in at the options available for querying and manipulating collections and arrays.

Monday, July 16, 2007

Carrot or the stick

Managerial styles regarding motivation interest me from time to time, and I always like to refer to a series of articles from Joel Spolsky:

In these articles, Joel describes a set of managerial styles and what kinds of motivation they create.  Whenever I'm trying to introduce different practices or ideas, I've always kept these styles in the back of my mind, as it's very easy to drop into a negative style without noticing.

The idea behind the carrot or the stick is that there are basically two ways to motivate a mule to do anything.  You can either dangle a carrot in front of him, to entice him to go forward, or beat him with a stick, to punish him for not going forward.

The Carrot

Relating a carrot to a development team, it could be financial or other kinds of rewards for following a certain practice.  Practices could be lines of code written, tests introduced, pages of documentation written, etc.  If the developer meets some bar, they will be rewarded.  The problem is that this style creates extrinsic motivation.  That is, I'm not doing a certain action because it matches my values and goals, but meets someone else's seemingly arbitrary measurement.

What happens in practice is that developers are smart, and will do only what is minimally required to meet the goal if the measurement is a fixed point.  If the reward is on a sliding scale, developers will game the system, play the numbers game, and make themselves appear better in the eyes of the measurement, regardless if the underlying system has actually improved.

Consider paying employees or contractors based on lines of code written.  The problem with that measurement is that the most maintainable, clear, soluble systems are usually an order of magnitude less code than a poorly written system.  With this measurement, the poorly written system will net the developer a greater financial reward, so there is no motivation to create a better system.

The Stick

The opposite of the reward would be the punishment.  If a developer does not perform a specific action, they will be punished in some form, whether it's verbal, monetary, lower review scores, etc.  Again, this creates extrinsic motivation.  The developer is smart enough to do just enough to not get punished, without any regards to the values behind the actions/processes.

Suppose we mandate code comments as part of our review process.  If you don't have your code commented, your review score is lowered.  It's not possible to measure the quality of the comments, but just that they exist.  What would happen would be the comments would exist, but they would be sloppy, misleading, and in some cases, completely incorrect.  The developer doesn't care why code comments are valuable and necessary, but only that if they don't put them in, their annual review score will suffer.

A third option: shared values

The final option is the "identify" style.  This is where I get the mule to identify with my goals, share them, and move forward together.  When I introduce new ideas, I usually start with the values I'm trying to reinforce.  We can argue over the validity of practices and processes, but it's easy to see whether or not a practice supports a value.  A development team does a much better job determining if a practice doesn't do a good job supporting our values than quibbling over individual practices.

The only times shared values have worked for me is in close-knit, collaborative development teams.  If developers are treated like commodities, only the carrot and the stick will work, with uninspiring results.  With a highly collaborative team, as agile practices reinforce, the team not only better identifies with internal values, but external ones as well since each member is acquainted with a shared value system.  When management has a process requirement, it would have a much higher success rate within the team if the team can identify with the values and goals behind the requirement.

Final thoughts

Certain styles are needed for certain contexts and people.  If a highly collaborative team is possible and obtainable, the "identify" style will reap the greatest rewards.  Most developers are smart enough to game systems based on extrinsic motivation, and will welcome opportunities for intrinsic motivation.  If someone refuses to respond to shared values, that's when the carrot or stick needs to come out.  It's only when dealing with a jackass that a carrot or stick is needed.

Wednesday, July 11, 2007

Introducing Behave#

I really like the idea of executable requirements.  Executable requirements is the idea that I can express requirements from the business in a human-readable, executable format.  Part of fulfilling the requirement is that the "executable requirement" part can execute successfully in the form of acceptance tests.

Recently, I checked out a couple of API's for executable requirements in the form of behavior-driven design (BDD).  For more information on BDD, check out these articles from Dan North's blog:

The API's I checked out were NBehave and Joe Ocampo's NUnit.Behave.  NBehave was rather cumbersome to set up, and didn't have much of a fluent interface.  NUnit.Behave was much easier to use, but forced a dependency on NUnit.  I didn't want to be forced to use NUnit, nor did I want to inherit from certain classes or implement certain interfaces.  Heavily influenced by NUnit.Behave, I created Behave#.

What is Behave#?

Behave# (http://www.codeplex.com/BehaveSharp) is a fluent interface to express executable requirements in the form of acceptance tests with a distinct BDD grammar.  Stories follow the "As a <role> I want <feature> so that <benefit>" template.  Stories are made up of scenarios, which follow the "Given When Then" template.  Through a fluent interface, Behave# shapes your acceptance tests to closely match the original user story.

What would a user story look like in code?

 The fluent interface I settled on looks like:

new Story("Transfer to cash account")
    .AsA("savings account holder")
    .IWant("to transfer money from my savings account")
    .SoThat("I can get cash easily from an ATM")

    .WithScenario("Savings account is overdrawn")

        .Given("my savings account balance is", -20)
            .And("my cash account balance is", 10)
        .When("I transfer to cash account", 20)
        .Then("my savings account balance should be", -20)
            .And("my cash account balance should be", 10);

I really like this syntax as it can be read very easily and there aren't a lot of other objects or frameworks getting in the way.  So how do we actually execute custom actions in our story definition?  Here's a full-fledged example, using NUnit to provide assertions:

[Test]
public void Transfer_to_cash_account()
{

    Account savings = null;
    Account cash = null;

    Story transferStory = new Story("Transfer to cash account");

    transferStory
        .AsA("savings account holder")
        .IWant("to transfer money from my savings account")
        .SoThat("I can get cash easily from an ATM");

    transferStory
        .WithScenario("Savings account is in credit")

            .Given("my savings account balance is", 100, delegate(int accountBalance) { savings = new Account(accountBalance); })
                .And("my cash account balance is", 10, delegate(int accountBalance) { cash = new Account(accountBalance); })
            .When("I transfer to cash account", 20, delegate(int transferAmount) { savings.TransferTo(cash, transferAmount); })
            .Then("my savings account balance should be", 80, delegate(int expectedBalance) { Assert.AreEqual(expectedBalance, savings.Balance); })
                .And("my cash account balance should be", 30, delegate(int expectedBalance) { Assert.AreEqual(expectedBalance, cash.Balance); })

            .Given("my savings account balance is", 400)
                .And("my cash account balance is", 100)
            .When("I transfer to cash account", 100)
            .Then("my savings account balance should be", 300)
                .And("my cash account balance should be", 200)

            .Given("my savings account balance is", 500)
                .And("my cash account balance is", 20)
            .When("I transfer to cash account", 30)
            .Then("my savings account balance should be", 470)
                .And("my cash account balance should be", 50);

    transferStory
        .WithScenario("Savings account is overdrawn")

            .Given("my savings account balance is", -20)
                .And("my cash account balance is", 10)
            .When("I transfer to cash account", 20)
            .Then("my savings account balance should be", -20)
                .And("my cash account balance should be", 10);

}

To perform actions with each "Given When Then" fragment, I pass in a delegate (anonymous in this case, but much prettier with lambda expressions in C# 3.0).  This delegate is executed as the story execution proceeds, and is cached by name, so each time the story sees "my cash account balance is", it will execute the appropriate delegate.  I don't need to define the custom action every time.

The result of the execution is the story results outputted in a human readable format (by default, to Debug):

Story: Transfer to cash account

Narrative:
   As a savings account holder
   I want to transfer money from my savings account
   So that I can get cash easily from an ATM

   Scenario 1: Savings account is in credit
      Given my savings account balance is: 100
         And my cash account balance is: 10
      When I transfer to cash account: 20
      Then my savings account balance should be: 80
         And my cash account balance should be: 30

      Given my savings account balance is: 400
         And my cash account balance is: 100
      When I transfer to cash account: 100
      Then my savings account balance should be: 300
         And my cash account balance should be: 200

      Given my savings account balance is: 500
         And my cash account balance is: 20
      When I transfer to cash account: 30
      Then my savings account balance should be: 470
         And my cash account balance should be: 50

   Scenario 2: Savings account is overdrawn
      Given my savings account balance is: -20
         And my cash account balance is: 10
      When I transfer to cash account: 20
      Then my savings account balance should be: -20
         And my cash account balance should be: 10

This format closely resembles the original user story I received from the business.

Conclusion

I like being able to verify deliverables in the form of automated tests.  When these tests closely resemble the original requirements as user stories, I'm more confident in the deliverables.  Having executable requirements in the form of acceptance tests in a fluent interface that matches the original requirements can bridge the gap between what the business asks for and what gets delivered.  Behave# gets us one step closer to bridging that gap.

Thursday, July 5, 2007

When Technical Debt leads to bankruptcy

One of my favorite technical metaphors is Technical Debt.  It's easy to recognize a system that is collapsing under its own weight with Technical Debt.  Those are the ones that are pretty much impossible to change, and making even the most insignificant change requires levels of analysis many times more expensive than the effort to actually make the change.

I've seen a couple applications where Technical Debt increased to the point where no one could speak the name of the application without shouting expletives.  First it was a chuckle, but the chuckle turned sarcastic, then into a sneer, finally cursing and head shaking.

The mounting debt

Debt can build to a point before it needs to be addressed.  But as many new to credit cards can attest, ignoring the debt building up won't make it go away.  In fact, those with large debts may spend most of their income on interest, unable to pay down the principal.  If these debts are ignored long enough and build up high enough, bankruptcy is the only solution.

Filing for bankruptcy

With enough Technical Debt built up, Technical Bankruptcy is the next step.  That's when the cost of building a new solution is less than the cost of maintaining the existing application.  Developers file for bankruptcy by constantly complaining about the existing application and begging to do a re-write.  Once you decide to do a re-write, you've filed for Technical Bankruptcy.

Technical Bankruptcy gives developers a clean slate, but not in the eyes of the debtors (the ones signing the checks).  The business doesn't want a rewrite every two years, but unless Technical Debt is paid off regularly, that's what will continue to happen.  If rewrites keep occurring because Technical Debt is never addressed and is only allowed to build up, eventually the business will get wise and find someone else who can handle debt.

Keeping debts low

There's really no such thing as "doing it right the first time".  Debt is nearly impossible to avoid, and in some cases, unwise to avoid.  Sometimes incurring a debt is inevitable and advantageous, like purchasing a car or building credit.  But debt can only be reduced by paying off the principal.  All we can strive for is to keep as little Technical Debt around as possible, and pay it off as early and often as we can.  The answer to avoiding Technical Bankruptcy is not to avoid Technical Debt, but to pay it down through refactoring and continuous design.

Tuesday, July 3, 2007

Refining daily stand-ups

I rediscovered a great article that helped my old Scrum team to refine and improve our daily stand-ups:

http://www.martinfowler.com/articles/itsNotJustStandingUp.html

Most of the smells mentioned manifested themselves at one time or another, but frequent abuses included:

  • Reporting to the Leader
  • Stand-up Meeting Starts the Day... Late
  • I Can't Remember
  • Problem Solving

I only found this article the first time after our 10th sprint or so, unfortunately.  So many activities and artifacts, whether it's a process, project management, developing, code, etc. have recognizable smells, it can be difficult to recognize these smells when they exist.

I think I need a new general, all-encompassing smell of "smell ignorance".  That's when you don't know the smells of a particular area, and not knowing the smells limits your ability to improve and succeed.

Limitations of generic base classes

I thought I had created something fairly useful with a generic Value Object in a previous post.  Generic base classes are nice, and there are several recommended base classes for creating collections classes.  Whenever I try to make an interesting API with a generic base class, limitations and faulty assumptions always reduce the usefulness of that base class.  Let's first start with a couple of classes that we'd like to include in a generic API:

public class Address
{
    private readonly string _address1;
    private readonly string _city;

    public Address(string address1, string city)
    {
        _address1 = address1;
        _city = city;
    }

    public string Address1
    {
        get { return _address1; }
    }

    public string City
    {
        get { return _city; }
    }
}

public class ExpandedAddress : Address
{
    private readonly string _address2;

    public ExpandedAddress(string address1, string address2, string city)
        : base(address1, city)
    {
        _address2 = address2;
    }

    public string Address2
    {
        get { return _address2; }
    }
}

Fairly basic classes, just two types of addresses, with one a subtype of the other.  So what kinds of issues do I usually run in to with generic base classes?  Let's look at a few different types of generic base classes to see.

Concrete generic implementations

A concrete generic implementation is a concrete class that inherits a generic base class:

public class AddressCollection : Collection<Address>
{
    public AddressCollection() {}

    public AddressCollection(IList<Address> list) : base(list) {}
}

Following the Framework Design Guidelines, I created a concrete collections class by inheriting from System.Collections.ObjectModel.Collection<T>.  I also have the ExpandedAddress class, so how do I create a specialized collection of ExpandedAddresses?  I have a few options:

  • Create an ExpandedAddressCollection class inheriting from AddressCollection
  • Create an ExpandedAddressCollection class inheriting from Collection<ExpandedAddress>
  • Use the existing AddressCollection class and put ExpandedAddress instances in it.

All of these seem reasonable, right?  Let's take a closer look.

Inherit from AddressCollection

Here's what the ExpandedAddressCollection class would look like:

public class ExpandedAddressCollection : AddressCollection
{
    public ExpandedAddressCollection() {}

    public ExpandedAddressCollection(IList<Address> list) : base(list) {}
}

That's not very interesting, it didn't add any information to the original AddressCollection.  What's more, this ExpandedAddressCollection ultimately inherits Collection<Address>, not Collection<ExpandedAddress>.  Everything I try to put in or get out will be an Address, not an ExpandedAddress.  For example, this code wouldn't compile:

List<ExpandedAddress> addresses = new List<ExpandedAddress>();
addresses.Add(new ExpandedAddress("Address1", "Austin", "TX"));

ExpandedAddressCollection addressList = new ExpandedAddressCollection(addresses);

Because of limitations in generic variance, namely that C# does not support generic covariance or contravariance.  Even though ExpandedAddress is a subtype of Address, and ExpandedAddress[] is a subtype of Address[], IList<ExpandedAddress> is not a subtype of IList<Address>.

Inherit from Collection<ExpandedAddress>

In this example, I'll just implement the ExpandedAddressCollection in the same manner as AddressCollection:

public class ExpandedAddressCollection : Collection<ExpandedAddress>
{
    public ExpandedAddressCollection() {}

    public ExpandedAddressCollection(IList<ExpandedAddress> list) : base(list) { }
}

Now I my collection is strongly types towards ExpandedAddresses, so the example I showed previously would now compile.  It seems like I'm on the right track, but I run into even more issues:

  • ExpandedAddressCollection is not a subtype of AddressCollection
  • Collection hierarchy does not match hierarchy of Addresses (one is a tree, the other is flat)
  • I can't pass an ExpandedAddressCollection into a method expecting an AddressCollection
  • Since there is no relationship between the two collection types, I can't use many patterns where a relationship is necessary

So even though my collection is strongly typed, it becomes severely limited in more interesting scenarios.

Use existing AddressCollection class

In this instance, I won't even create an ExpandedAddressCollection class.  Any time I need a collection of ExpandedAddresses, I'll use the AddressCollection class, and cast as necessary.  I won't be able to pass an IList<ExpandedAddress> to the constructor because of the variance issue, however.  If I need to include some custom logic in the collection class, I'll run into the same problems highlighted earlier if I'm forced to create a new subtype of AddressCollection.

So we've seen the limitations of concrete generic implementations, what other options do I have?

Constrained generic base classes

I'd like a way to propagate the concrete type parameter back up to the original Collection<T>.  What if I make the AddressCollection generic as well?  Here's what that would look like:

public class AddressCollection<T> : Collection<T>
    where T : Address
{
    public AddressCollection() {}

    public AddressCollection(IList<T> list) : base(list) {}
}

public class ExpandedAddressCollection : AddressCollection<ExpandedAddress>
{
    public ExpandedAddressCollection() {}

    public ExpandedAddressCollection(IList<ExpandedAddress> list) : base(list) { }
}

So now I have a constrained base class for an AddressCollection, and an implementation for an ExpandedAddressCollection.  What do I gain from this implementation?

  • ExpandedAddressCollection is completely optional, I could just define all usage through an AddressCollection<ExpandedAddress>
  • Any AddressCollection concrete type will be correctly strongly typed for an Address type

Again, with some more interesting usage, I start to run into some problems:

  • I can never reference only AddressCollection, as I always have to give it a type parameter.
  • Once I give it a type parameter, I run into the same variance issues as before, namely AddressCollection<ExpandedAddress> is not a subtype of AddressCollection<Address>
  • Since I can never define any method in terms of solely an AddressCollection, I either need to make the containing class generic or the method generic.

For example, I can write the following code:

public void TestGenerics()
{
    AddressCollection<Address> addresses = new AddressCollection<Address>();
    addresses.Add(new Address("132 Anywhere", "Austin"));

    int count = NumberOfAustinAddresses(addresses);

    AddressCollection<ExpandedAddress> expAddresses = new AddressCollection<ExpandedAddress>();
    expAddresses.Add(new ExpandedAddress("132 Anywhere", "Apt 123", "Austin"));

    count = NumberOfAustinAddresses(addresses);
}

private int NumberOfAustinAddresses<T>(AddressCollection<T> addresses)
    where T : Address
{
    int count = 0;
    foreach (T address in addresses)
    {
        if (address.City == "Austin")
            count++;
    }
    return count;
}

This isn't too bad for the implementation nor the client code.  I don't even need to specify a generic parameter in the method calls.  If I can live with generic methods, this pattern might work for most situations.

The only other problem I'll have is that I might need to create subtypes of AddressCollection, like I did above with ExpandedAddressCollection.  In this case, I'd can continue to make each subtype generic and constrained to the derived type:

public class ExpandedAddressCollection<T> : AddressCollection<T>
    where T : ExpandedAddress
{
    public ExpandedAddressCollection() {}

    public ExpandedAddressCollection(IList<T> list) : base(list) { }
}

Again, if I can live with generic methods, I would be happy with this implementation, as I now keep the same hierarchy as my Addresses.  It is a little strange declaring ExpandedAddressCollection with a type parameter (ExpandedAddressCollection<ExpandedAddress>), but I'll live.

There's one more type of generic base class I'd like to explore.

Self-constrained generic base classes

Sometimes, I need to implement a certain generic interface, such as IEquatable<T>.  I could simply pass in the concrete type into the generic parameter like this:

public abstract class ValueObject : IEquatable<ValueObject>

But if I'm trying to create an abstract or a base class for subtypes to use, I'll run into problems where derived types won't implement IEquatable<DerivedType>.  Instead, I can make this abstract class generic and self-constraining:

public abstract class ValueObject<T> : IEquatable<T>
    where T : ValueObject<T>

Now, derived types will implement IEquatable<DerivedType>, as I showed in my post on value types.  Unfortunately, subtypes will only implement the correct IEquatable<T> for the first derived class:

public class Address : ValueObject<Address>
public class ExpandedAddress : Address

In this case, ExpandedAddress is not a subtype of ValueObject<ExpandedAddress>, and therefore only implements IEquatable<Address>.  I can't use the same tricks with the constrained generic base class, as I would need to declare Address as generic, and therefore never instantiable by itself.  The self-constrained generic base or abstract class is unfortunately only useful in hierarchies one level deep.

Conclusion

So generics aren't the silver spoon I thought it would be, but there are some interesting proposals to allow variance for generic types out there.  I might not be able to cover all of the scenarios I'd like for a generic base class, but by identifying several options and their consequences, I can make a better decision on solving the problem.