Strongly-Typing Your Domain Values

I love this one. I don’t know the name of the pattern, but i love using it.

Imagine your system uses strings to represent the value of a status field. potential values of this field are:

  • New
  • Requested
  • Open
  • Closed
  • Deferred
  • In Progress
  • More Information Required

…and you want to write a method (or webservice) called UpdateStatus, which takes in one of these values.

Standard signature would look something like this:

public void UpdateStatus(string newStatus)

The use of “string” for the static type has the problem that someone could pass through a rubbish value as a string, and the UpdateStatus method is now responsible for domain validation of the input.

However, following the pattern below, you’re able to statically define your domain (if known at design-time) and enforce the stronger type in subsequent method calls.

public class IssueStatus
{
	void IssueStatus(string description)
	{
		this.description = description;
	}
		readonly string description;

	public static IssueStatus New = new IssueStatus("New");
	public static IssueStatus Requested = new IssueStatus("Requested");
	public static IssueStatus Open = new IssueStatus("Open");
}

and you can then use the strong IssueStatus type in your signatures:

public SaveButton_Clicked(object sender, EventArgs e)
{
	bo.UpdateStatus(IssueStatus.New);
}

public void UpdateStatus(IssueStatus newStatus)
{
	if (newStatus == IssueStatus.New)
	{
	// do something here
	}
}

I learnt this one on the job a few years back, and think it’s fantastic.

1 comment

  1. We found a related refactoring to this recently which I thought was really cool.

    Say you want to add a new status called Imported for issues which are newly added, but came from some other database instead of being added by hand.

    So you change your code from:

    if (newStatus == IssueStatus.New)
    {
    // send a “new issue created” email
    }

    To:

    if (newStatus == IssueStatus.New || newStatus == IssueStatus.Imported)
    {
    // send a “new issue created” email
    }

    Then you find some other place in the code that also needs to change:

    if (newStatus == IssueStatus.New)
    {
    // create a record in the issue billing system
    }

    …becomes:

    if (newStatus == IssueStatus.New || newStatus == IssueStatus.Imported)
    {
    // create a record in the issue billing system
    }

    That conditional expression for the if statements is duplicate code!

    So if you’ve used a strong type IssueStatus, instead of a string, you can easily add a property to your IssueStatus class:

    public bool IsNewlyCreated { get; }
    // make it true for New and Imported, false otherwise

    Then refactor to:

    if (newStatus.IsNewlyCreated)
    {
    // whatever
    }

    Suddenly your if statements become much more expressive about _why_ the code block should be run. If we choose the property names well, then the code is not just saying “if status is X or Y”, it’s telling you the business meaning behind it. And if we choose the property names well, we should be able to come along in future and add a new status called Z, set its properties appropriately, and existing code will already understand it.

Leave a Reply

Your email address will not be published. Required fields are marked *