Strong Typing to Reduce Defect Count

A long time ago, I was having a discussion with the Director of Development in my office. He was teaching me how we can prevent errors, before they even get to QA, through better coding practices. For example, imagine that you have an integer which represents a high score. Further, imagine that you have an integer that represents loyalty points. Unfortunately, it would be too easy to goof up and pass the high score into a function that was expecting loyalty points. That would compile, and the only way to find the bug would be through Unit Tests, or a QA tester. One easy way to prevent that kind of error is to wrap the high score in a HighScore class, and the loyalty points into a LoyaltyPoints class.

Granted, it might seem silly to have a class with no properties or methods. But, strong typing allows the compiler to differentiate between the two, and prevent a whole class of errors. As an added benefit, it would be much easier to evolve the code if you needed to change the high score to a long, rather than an int.

Recently, I was testing a tool that I had built, and I encountered the following error message:

Could not locate a repository with the name “/branches/release/rewards/2.32”.

It was immediately clear to me that I had passed a branch name where I should have passed a repository name. When I went to the code, I found the following method signature:

Public Asset ReadAsset(string applicationName, string repositoryName, string branchName, string assetName)

Rather than simply swap the arguments, I recalled the discussion about the high score parameter. I needed to strongly type these strings. So, I created a wrap the applicationName string.

public class ApplicationName {
    private readonly string _value;
    public ApplicationName(string value) {
        _value = value;
    }
    public override ToString {
        return _value;
    }
}

I created four of those classes. Then I refactored them into a common base class called StringName. In fact, I also create a custom JsonConverter allowing my JSON to deserialize into strongly typed strings, too. Returning to the original example, I now had something like this:

public Asset ReadAsset(ApplicationName applicationName, RepositoryName repositoryName, BranchName branchName, AssetName assetName)

Much better. I’ve eliminated the possibility of transposing parameters in this method. And, tracing that change through all of the other usages, the body of code become so much easier to understand.

Before closing I want to ensure that I point out another requirement of the ApplicationName class. This tripped me up at first. Originally, I could compare the strings with the == operator. But, that comparison failed everywhere I used these classes, because they are not “the same instance”. To resolve this, I converted all of my == comparisons to Equals() comparisons, and then implemented the Equals() method on my class. I will detail that in another post, too.

Finally, you may be looking at that long method signature, thinking that four parameters are too many. I don’t think a method signature should be forced to line-wrap. I solved this by using a parameters class, but in a novel way, which I will detail in a separate post.