Tag Archive for C#

Yet Another SOLID Principles Piece

Introduction

Barely a day goes by without someone mentioning SOLID principles these days.

“Hello colleagues,” I say, “I am going to the coffee machine to get some coffee. Would you also like some coffee?”
“That depends,” reply my colleagues, “on whether the coffee will made according to SOLID principles.”
I consider this for a moment before replying. “Don’t be ridiculous. It’s a cup of coffee not a software engineering project.”

And there the matter ends.

Although

As far as acronyms go, SOLID is towards the SPLINK end of the convolution spectrum. In this article I’m going to go through each of the five principles in a way that will hopefully make them more memorable.

S is for Single Responsibility

This one’s pretty straightforward, or at least initially appears to be so. A class should have a single responsibility, or in layman’s terms, should have only one job to do. But wait! Slavishly following the principle as described would lead to lots of classes with single methods inside, which will make your code somewhat obscure. There’s a qualifier to the Single Responsibility Principle, and it is that a class should have only a single reason to change. This is perhaps a little harder to understand, so let’s have an example.

Squirrel

Imagine we have a class called Squirrel. This contains two methods:

  • CountNuts() – Returns the number of nuts the squirrel currently has.
  • ClimbTree(Nuts nuts) – Checks the number of nuts with a call to CountNuts() and only climbs the tree if it is over a given threshold. Climbing trees requires squirrel fuel.

This violates the Single Responsibility Principle because there are two reasons for the Squirrel class to change:

  • The way that nuts are counted might change, eg different nuts may be given different weightings
  • The nut threshold to climb a tree might change

To fix this, as a bare minimum the ClimbTree(Nuts nuts) method should be moved to its own class, and given an additional Squirrel parameter so that the Squirrel object can be passed into it: ClimbTree(Squirrel squirrel, Nuts nuts).

O is for Open / Closed

Which is it, open or closed? Are we talking about a programming principle or a CD drawer here? This is definitely one of the more obscurely named parts of the acronym. It may as well be called Owls.

Owls

Owls, being very wise birds, are open to the idea of being extended but closed to modification. Ask a barn owl to change into a tawny owl it will quite rightly tell you to sling your hoo-k. However ask it nicely to hoot like a tawny owl and it will happily oblige.

Let’s say we have an Owl class containing a single method: Hoot(OwlType owlType)

This method takes the type of owl (barn or tawny) and returns the appropriate hoot. Logic within the Hoot method constructs the hoot depending on which type of owl is supplied.

There is a problem with this. If we want our owl to be able to hoot like a snowy owl, we will have to modify the Owl class. This breaks the Open / Close principle because our class should be closed to modifications. Instead, it should be open to being extended. In this case we should do this by changing our Hoot method to accept an interface instead of an owl type: Hoot(IOwl owl).

The interface IOwl has a method called Hoot, and it is this which is called by the Hoot(IOwl owl) method. We then have concrete implementations of IOwl for barn and tawny owls, each of which have their own implementation of Hoot. With this structure in place, adding the ability to hoot like a snowy owl is simply a matter of creating a new TawnyOwl class which inherits IOwl.

L is for Liskov Substitution

Professor Barbara Liskov is one of the first women in the US to receive a doctorate in computer science. She has been doing this shit since the ’60s and has probably forgotten more than I will ever know. Take a look at her website. Gosh, it looks like the 1990s doesn’t it? Don’t laugh, she has more important things to do than worry about that grey background. Look closer. Look at her CV. It’s 32 pages long but 30 of those pages are publications and academic contributions to computer science. It’s fair to say that she’s pretty awesome.

That’s all great, but L for Liskov doesn’t tell us much about what Liskov Substitution actually is. In Prof. Liskov’s paper with c-author Jeannette Wing summarises it as:

Let Φ(x) be a property provable about objects x of type T. Then Φ(y) should be true for objects y of type S where S is a subtype of T.

It’s not exactly plain English but this is from an academic paper. Give your head a good scratch and you can make sense of it. In the world of C# Liskov Substitution can be described more plainly like this:

A class derived from a base class, interface or similar structure must be interchangeable with its base class or interface, etc.

Llamas

Let’s say you have some Llamas. Everyone knows that Llamas love Libraries. They are nature’s most avid readers, with a strong penchant for Literature. Unfortunately being quite Large creatures there are only so many llamas that can fit inside a library at once. We can call our collection of Llamas from the Library class and get it return its count to control the number of llamas per library.

But wait – some alpacas want to join the library. They are nature’s second most avid reader and in many other ways are similar to llamas. In fact the only way in which they differ that matters to us is that they’re about half the size of a llama. This means that more alpacas can fit into a single library.

It’s tempting to simply create a new Alpaca class with derived from the existing Llama class, and give it a Size property. This is set to 0.5. However doing so would break the Liskov Substitution Principle. Although our Library class can access the Alpaca’s Size, it cannot do the same for a Llama because the Llama class doesn’t have a Size property. The base class (Llama) cannot be substituted for its derived class (Alpaca).

One way to fix this is to add Size to the Llama class and override it in Alpaca. However this may not be the ideal solution, particularly if the Library one day decides to admit Sheep, nature’s third most avid readers. They could have all sorts of things which are different to Llamas. In that case it makes more sense to make a new base class or interface which includes the Size property, and derive Llama, Alpaca and Sheep from that.

I is for Interface Segregation

This one is more straightforward and at its heart is the idea that interfaces should contain the minimum required members. That way anything using that interface doesn’t need to concern itself with members it doesn’t use.

Insects

Let’s say with a class called Insect. This contains many members such as NumberOfWings and StingStrength. If we want to Sting() another object using our Insect class, we could just pass the whole Insect in as a parameter, like this: Sting(Insect insect). However, doing so exposes all the other members of the Insect class to the Sting method, when all we need to know about is StingStrength. We can reduce this exposure by creating an IStingable interface with a single member, StingStrength, and implementing it in the Insect class. We can then pass this into Sting like so: Sting(IStingable insect)

Similarly, if we have a Fly(Insect insect) method, we can create an IFlyable interface which contains the single member NumberOfWings, and use this like so: Fly(IFlyable insect)

Now we have two very tight interfaces for our Insect class which segregate its behaviour so that client code is only concerned with the parts it needs access to.

D is for Dependency Inversion

A common mistake is to construct high-level classes using concrete classes from further down the class hierarchy. What does this mean? Well, let’s look at everyone’s favourite seaborne scamp, the dolphin.

Dolphin

We have a higher-level class called Tricks which at the moment contains a single method, DoTrick(Dolphin dolphin). This will work, but becomes problematic if we want another animal to do a trick. As written, the high-level class is dependent on a low-level class. We need to redesign Tricks so that both it and the low-level class instead depend on an interface, ITrickable.

Now the DoTrick method is defined as DoTrick(ITrickable trick) and the Dolphin class inherits from ITrickable. Instead of the high-level class depending on a low-level class, both classes now depend on an interface. This is dependency inversion.

Summary

In conclusion then,

  • Squirrels
  • Owls
  • Llamas
  • Insects
  • Dolphins

I hope you’ve enjoyed this somewhat frivolous look at SOLID Principles. For a more in-depth look at the subject, I recommend these sites:

http://www.blackwasp.co.uk/SOLIDPrinciples.aspx
https://msdn.microsoft.com/en-us/magazine/dn683797.aspx

Bamboo Version Labelling

We’ve recently switched from CruiseControl.NET to Atlassian Bamboo for our CI. This was partly borne out of frustration with CC.NET’s XML-based configuration, but we also use Jira, Confluence and BitBucket, so the integration between these products and Bamboo had some appeal.

Naturally the conversion hasn’t been completely smooth. One thing that initially wasn’t particularly obvious was how to auto-increment a .NET project’s version number when building a deployment package, and how to then label the build in Bamboo with that version number.

Version Increment

The easiest way of adding build tasks to a Bamboo stage is to, well, add an MSBuild task. The clue’s in the name. There are plenty of pre-made build tasks out there. For incrementing the version number we’re going to use the MSBuild.ExtensionPack. This contains a wealth of build targets, including one called VersionNumber.

If all we want is to increment the version number, we just import the VersionNumber targets and set some attributes:

[html]
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="SetAssemblyInfo" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\MSBuild.Extension.Pack.1.5.0\tools\net40\MSBuild.ExtensionPack.VersionNumber.targets"/>
<Target Name="SetAssemblyInfo">
<MSBuild.ExtensionPack.Framework.AssemblyInfo
AssemblyInfoFiles="..\..\MyProject.Interface.Web\Properties\AssemblyInfo.cs"
AssemblyBuildNumberType="DateString"
AssemblyBuildNumberFormat="MMdd"
AssemblyRevisionType="AutoIncrement"
AssemblyRevisionFormat="00"
AssemblyFileBuildNumberType="DateString"
AssemblyFileBuildNumberFormat="MMdd"
AssemblyFileRevisionType="AutoIncrement"
AssemblyFileRevisionFormat="00" />
</Target>
</Project>
[/html]

The paths above assume I have placed the saved the above as [ROOT]\SolutionFiles\BuildTasks\IncrementAssemblyVersion.csproj, where [ROOT] is the root of the solution. The structure is unimportant. What matters is that the paths to MSBuild.ExtensionPack.VersionNumber.targets and your project’s AssemblyInfo.cs are correct.

The attributes I’ve set will produce version numbers in the following format:

Major.Minor.Date.Number

Where Date is the combination of zero-padded day of the month and month, eg 0208 if built on the 2nd of March. There is provision in VersionNumber.targets to format the version number using the year as well. I wouldn’t advise this as it will (dependent on the actual date) overflow the int which backs the version number.

The Number is a simple integer increment for each daily build. eg the first build for that day wil be 0, the next 1, and so on.

I like this as it gives some useful information about the build. It should be noted that for this to work you will need to set the masking in AssemblyInfo.cs appropriately. In this case, use “1.0.0.0”

To use this file in Bamboo, add a new MSBuild task to the build stage, and supply it with the path the project file. eg

SolutionFiles\buildtasks\IncrementAssemblyVersion.csproj

Labelling in Bamboo

It would also be nice to be able to see the version number for a build from Bamboo build list. This can be achieved using labels.

Now, before I proceed I have to hold up my hand and say that this feels like a bit of a kludge. However it was the only way I could see of achieving what I wanted, so I present it here in the hope that someone knows a better way and can tell me what it is.

In Bamboo, labels can be created by parsing the build log with regex. Yes, I know. I KNOW.

What I’ve done is add a build target which will write the current version number into the log file, so that it can be parsed as a label. I’ve reused the project file we created for the version increment for this, as it makes sense to write to the log immediately after setting it. The project file now contains:

[html]
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="SetAssemblyInfo;RetrieveIdentities" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\MSBuild.Extension.Pack.1.5.0\tools\net40\MSBuild.ExtensionPack.VersionNumber.targets"/>
<Target Name="SetAssemblyInfo">
<MSBuild.ExtensionPack.Framework.AssemblyInfo
AssemblyInfoFiles="..\..\MyProject.Interface.Web\Properties\AssemblyInfo.cs"
AssemblyBuildNumberType="DateString"
AssemblyBuildNumberFormat="MMdd"
AssemblyRevisionType="AutoIncrement"
AssemblyRevisionFormat="00"
AssemblyFileBuildNumberType="DateString"
AssemblyFileBuildNumberFormat="MMdd"
AssemblyFileRevisionType="AutoIncrement"
AssemblyFileRevisionFormat="00" />
</Target>

<Target Name="RetrieveIdentities">
<GetAssemblyIdentity AssemblyFiles="..\..\MyProject.Interface.Web\bin\MyProject.Interface.Web.dll">
<Output TaskParameter="Assemblies" ItemName="AssemblyInfo"/>
</GetAssemblyIdentity>
<Message Text="MyProject.Interface.Web.dll has been set to Version_%(AssemblyInfo.Version)" />
</Target>
</Project>
[/html]

It’s pretty straightforward. The RetrieveIdentities target is called after SetAssemblyInfo. It uses the GetAssemblyIdentity target to get the current version number from the specified .dll. It then writes a message to the log containing the version number.

To make use of this message, go to the Miscellaneous tab for your job in Bamboo. At the bottom is a section title Pattern Match Labelling. This is where we enter a regex pattern to retrieve out version number from the logs. The following pattern will do this:

(Version_[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)

Finally we just need to tell Bamboo to use the first match as the build label. Do so by entering \1 in the Labels box.

Using local blocks to refine EPiServer’s on-page editing experience

The on-page editing interface introduced with CMS 7 is, on the whole, quite nice.* It allows fast, intuitive editing of properties in most situations. However on busier pages it can all get a bit out of hand. The editor bounding boxes start to overlap and the screen begins to resemble that old Amiga demo that draws rectangles on the screen at (as then) mind-blowing speeds. There are also some properties which don’t lend themselves to on-page editing in isolation. Links for example, typically use two properties in tandem for the text and the URL. Fortunately there’s a way to tidy things up, and that is to use local blocks

Local blocks allow you to group properties together so that they can be edited together. As an example, let’s say we have a promotional box on our home page. It shows a title and a link over a background image and has the following properties:

  • Title
  • Image
  • Link URL
  • Link Text

If these are defined in the home page model, then on-page editing becomes tricky. If it’s enabled for the image, its bounding box will cover the title and link making them uneditable. And even without that, there isn’t a direct way editing the Link Url. We could just let the editors use the all properties view, but that’s not very friendly.

Instead, we can create a local block called, imaginatively called PromoBlock, add the properties there, then add the local block to the home page. Now we can do this in the home page’s view:

[html]
<div class="promo" @Html.EditAttributes(x => x.CurrentBlock.Promo)>
<div style="background: url(@Model.Promo.Image)>
… other promo markup …
</div>
</div>
[/html]

Setting EditAttributes using the PromoBlock as a property will result in an edit box being drawn around the whole promo. Clicking on the promo will pop out the right-hand edit panel with all four of our PromoBlock properties there, ready to edit.

That isn’t all we can do though. We can also create a display template for the PromoBlock. To do this, create a new view in your project’s DisplayTemplates folder. This will typically be found at Views\Shared\DisplayTemplates. Give the View a model with a type of PromoBlock, and move all our PromoBlock markup from the home page’s view, like so:

[html]
@model PromoBlock

<div class="promo">
<div style="background: url(@Model.Image)>
… other promo markup …
</div>
</div>
[/html]

Now we can reduce the promo block code in the home page to this:

[html]
@Html.PropertyFor(x => x.CurrentPage.PromoBlock)
[/html]

Which is rather neat. Another advantage of this is that should the promo block be used elsewhere, there’s no need to duplicate the markup. Just add a local PromoBlock property to the page in question and use PropertyFor with it.

*Let’s gloss over the pain and anguish of Dojo for now.

Conditionally hiding properties from editors in CMS 7

Completely hiding properties from editors is simple enough – just add the [ScaffoldColumn(false)] attribute to the property. However there are times when I want to show the property in some situations, and hide it in others. A typical scenario is sharing a local block between several page types. For example, let’s say we have a local block called PromoBlock. PromoBlock has two properties:

  • Title
  • Image

It is used on two page types, LandingPage and ContentPage.

However it has become vital that the PromoBlock on LandingPage has an optional video. We could add the property VideoUrl to PromoBlock, but then it would be presented to editors on the ContentPage, and we don’t want a video there.

One option is to simply make another block for this purpose. In most situations this is the route I’d advise, but it isn’t always the most appropriate. My example is deliberately simplified, and in reality PromoBlock could be used on many pages and have complex behaviour. It could also already be in production and used on many pages, making its replacement a tedious editing task.

Another option is to programmatically hide the VideoUrl property on the ContentPage. In CMS 6 this was easily achieved using the EPiServer.UI.Edit.EditPanel.LoadedPage event. This is no longer available in CMS 7, so we need a different approach. That approach is to use an EditorDescriptor:

[EditorDescriptorRegistration(TargetType = typeof(Url))]
public class HidePromoVideoUrl : EditorDescriptor
{
  public override void ModifyMetadata(
    ExtendedMetadata metadata,
    IEnumerable<Attribute> attributes)
  {
    base.ModifyMetadata(metadata, attributes);
    if (metadata.PropertyName == "VideoUrl" && metadata.Parent.ContainerType == typeof(ContentPage))
    {
      metadata.ShowForEdit = false;
    }
  }
}

The main points of interest here are:

  • EditorDescriptorRegistation attribute needs its TargetType setting to the type of the property we are modifying. In this case it is a Url.
  • metaData.Parent.ContainerType gives the type of the page containing the local block which in turn contains the property we are modifying. metaData.ContainerType would give the type of the block itself, in this case PromoBlock.
  • Once we’ve determined we’re in the right place, hiding the property is a simple matter of setting metadata.ShowForEdit to false.

Restricting blocks in content areas

EPiServer 7.5 introduces the AllowedTypes attribute. This accepts an array of types, effectively making a whitelist of blocks that can be added to a ContentArea. An editor attempting to drag and drop a block not included in the type array will see the block turn grey and will not be able to place it. Here’s an example of its use:

Display(
         Name = "My Content Area",
         GroupName = SystemTabNames.Content,
         Order = 100)]
        [AllowedTypes(new[] { typeof(AllowedBlock), typeof(AlsoAllowedBlock) })]
        public virtual ContentArea MyContentArea { get; set; }

However there is a problem with this attribute. It only restricts block placement when dragging and dropping existing blocks in a content area. An editor can still create a new block directly on the content area, which is frankly a bit of a headache, as we can’t rely on the attribute to enforce block placement rules.

A crude workaround

I’ve worked around this issue by creating a custom validation attribute for content areas. This will prevent content from being saved if a content area contains a disallowed block. Here’s the code:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
    public class AllowedBlocksAttribute : ValidationAttribute
    {
        private readonly Type[] _allowedBlocks;

        private List AllowedBlockTypeFullNames
        {
            get { return _allowedBlocks.Select(a => a.FullName).ToList(); }
        }

        public AllowedBlocksAttribute(Type[] allowedBlocks)
        {
            _allowedBlocks = allowedBlocks;
            ErrorMessage = "This content area can only accept the following block types: {0}";
        }

        public override string FormatErrorMessage(string name)
        {
            return string.Format(CultureInfo.CurrentCulture, ErrorMessage, FormattedAllowedBlockTypes);
        }

        public override bool IsValid(object value)
        {
            var contentArea = value as ContentArea;
            if (contentArea == null)
                return true;

            foreach (var item in contentArea.Items)
            {
                if (!AllowedBlockTypeFullNames.Contains(item.GetContent().GetOriginalType().FullName))
                    return false;
            }

            return true;
        }

        private string FormattedAllowedBlockTypes 
        {
            get
            {
                return string.Join(", ", _allowedBlocks.Select(s => s.ToString().Split('.').Last().ToCamelCase()));
            }
        }
    }

This functions like any other validation attribute. If validation fails while saving content, a notification is displayed in the notification area at the top right of the page. It complements the existing AllowedTypes attribute, so ideally it should be used wherever that attribute is placed, eg

Display(
         Name = "My Content Area",
         GroupName = SystemTabNames.Content,
         Order = 100)]
        [AllowedTypes(new[] { typeof(AllowedBlock), typeof(AlsoAllowedBlock) })]
        [AllowedBlocks(new[] { typeof(AllowedBlock), typeof(AlsoAllowedBlock) })]
        public virtual ContentArea MyContentArea { get; set; }

Suggested improvements

There’s some scope for improvement here. Firstly, having to add two attributes with the same array of allowed types is somewhat clunky. Any suggestions as to how I could combine this with the existing attribute are welcome.

Secondly, although it stops content being saved with unwanted blocks, it doesn’t prevent an editor from creating said blocks. So although it acts as a final gatekeeper, it can lead to a frustrating experience for editors. It would be better if there’s a way of preventing the editor from creating the block in the first place. Ideally the disallowed blocks would not be available in the list of blocks when creating one on the content area, but I haven’t figured out a way of doing that yet.

Finally, you may have noticed that I’m crudely constructing a block name for display in the error message from its type name. This is because I couldn’t work out how to get the block name from its type definition. Now, surely there’s a way of doing that so I’d be grateful if someone could point me in the right direction. It would also mean I could get rid of this wee beastie:

/// 
        /// Splits a string on humps in a camel case word, eg camelCaseWord => camel Case Word
        /// 
        /// The camel case string to split
        /// The string, with a space between every incidence of a lower case letter and an upper case letter
        public static string ToCamelCase(this string input)
        {
            return System.Text.RegularExpressions.Regex.Replace(input, "(?<=[a-z])([A-Z])", " $1", System.Text.RegularExpressions.RegexOptions.Compiled).Trim();
        }

A couple of notes on using Endjin’s Templify

I’ve been working on an internal project which uses Endjin’s Templify. For those not familiar with Templify, it’s a handy piece of software which tokenises (or templifies, to use their parlance) keywords within solutions such that they can be used as templates for new solutions. What I’ve been working on is a server-based implementation of Templify that works with our CI server to allow us to centrally maintain templates. This ensures everyone’s working with the latest version and avoids having to update template packages locally. I ran into a couple of interesting points while doing this, which I think are worth documenting.

Choose tokens carefully

I had initially used the same word for the package name and the token. This was pleasingly consistent, however it caused Templify to break. The problem turned out to be with the manifest.xml file that Templify generates. This file lists all files included in the template along with some Templify metadata, such as its package name and tokens. This file is itself tokenised as part of the Templify process, so if the package name is the same as the token, it too gets tokenised. This results in Templify being unable to deploy the package after its creation. So the lesson here is to make sure the package name is not the same (or does not contain) any of the tokens.

Configuration path

This one isn’t something that’s likely to cause a problem for general usage of Templify, but it was a pain for me. The installer for Templify offers no option to install for all users, and only installs for the current user. This presented a problem when running on our CI server under credentials specially created for the purpose, as Templify will attempt to read its configuration from the current user’s profile directory. Unfortunately the configuration file doesn’t exist for that user profile, but instead of failing completely it gives rise to some odd behaviour.

What happens is this: Templify maintains a list of files to exclude in its configuration file. These files are deleted from the package prior to tokenisation. However if the configuration file is missing, it reads the exclusion list as string.empty, which results in all tokenised files and directories being deleted as exclusions. Whoops! Fortunately this is easily remedied by copying the configuration from the profile it was installed under to the profile of the user you want to run it under. The default location is C:\Users\$USER\AppData\Roaming\endjin\Templify\config

Enumerations, Bitwise Operators, Shiftiness

I like enumerations. They’re really useful for writing clear code and they’re also really easy to use. Like this:

public enum TvChannels
{
    BbcOne = 0,
    BbcTwo = 1,
    ItvOne = 2,
    ChannelFour = 3
}

Right?

Wrong. Enumerations can be decorated with the [Flags] attribute, which allows them to be combined. This allows them to be grouped together:

var BbcChannels = TvChannels.BbcOne | TvChannels.BbcTwo

The variable BbcChannels is defined as a bitwise OR between BbcOne and BbcTwo. The way we previously defined our enum values presents a problem however. The values must be multiples of two, otherwise the bitwise operations will yield incorrect results. The enumeration should instead be defined as follows:

public enum TvChannels
{
    None = 0
    BbcOne = 1,
    BbcTwo = 2,
    ItvOne = 4,
    ChannelFour = 8
}

There are two points to note here.

Firstly, the multiples of two allow the OR operations to work. In binary, the value of BbcOne is 0001, and that of BbcTwo is 0010. The result of an OR operation between the two (defining the variable BbcChannels) is then 0011.

This allows us to then check the BbcChannels for other enumeration values, eg

var IsBbcChannel = (BbcChannels & TvChannels.BbcOne) == TvChannels.BbcOne

This will be True, because the bitwise AND between BbcChannels (0011) and BbcOne (0001) is 0001 – ie equal to BbcOne.

The second point is that we have introduced a value of None = 0 at the start of the enumeration. This is because a value of zero cannot be tested for using a bitwise AND in the same way as in the example above; the result would always be zero.

Finally, a bitshift operator can be used to make the enumeration a bit nicer to look at. Because we’re assigning specific bits to each successive element in the enumeration, we can simply bit shift to the left by the appropriate number of times:

public enum TvChannels
{
    None = 0
    BbcOne = 1 << 0,
    BbcTwo = 1 << 1,
    ItvOne = 1 << 2,
    ChannelFour = 1 << 3
}

Lovely.

Here’s a photo of a rabbit with a cup on its head:

Test Driven Development – A Real world example

Test Driven Development (TDD to its friends) is a well-blogged topic. There are many examples of TDD around the blogosphere, crossing a multitude of technological frontiers. What follows is my own, slightly tongue-in-cheek overview of what TDD is.

Methodology

Death Star

This would never have happened with good test coverage.

TDD is essentially a process that states the acceptable criteria of something before building it. In code, this is typically the output of a method, but there are loosely analogous real world examples. It could be argued that examinations are tests that classify candidates as acceptable or unacceptable. A candidate with a perfect score is equivalent in this case to a method which satisfies all its unit tests. And anything with driven in its name is just begging for a car analogy. So instead of talking about either of those things, I’m going to build the Death Star.

The first thing we need to do is describe the Death Star. What should it look like? What should it do? What are its essential features? We describe it with a series of questions. Anything we subsequently build which can give satisfactory answers to those questions is to all intents and purposes the Death Star.

These questions are unit tests. They test a single scenario for a particular method. Methods can have more than one unit test depending on their complexity, but where possible it is best to break complex methods into smaller, more easily testable components.

Below are two basic requirements of the Death Star, along with the unit tests which would need writing before implementation.

That’s no moon

How big should the Death Star be? The only acceptable answer here is as big as a moon. Our test should be to measure the diameter of our object, in Imperial Moons.

Fully operational

The Death Star should be fully operational. We can test this by attempting to destroy Alderaan.

Implementation

When the unit tests are first written, they will fail because we have no implementation. The next step is to build the Death Star itself, in such a way that it satisfies each test.

One immediate problem that presents itself is the requirement for it to be fully operational. The test involves destroying Alderaan, something which we can only do once. To get around this, we require a mock Alderaan, which we can create in our unit test with the intention of using it to test the Death Star’s destructive function. This removes the test’s dependency on an external resource, and the same approach is taken when testing methods dependent on, say, database operations.

Stay on target

Although TDD can give developers confidence that the code they write will satisfy requirements and can be refactored with confidence, it does not guarantee that the final code is problem-free. It can only test what has been anticipated.

However if the input and output of each method is covered by tests, we can be confident that the system as a whole will work as designed. In out Death Star example, the reactor core would also have unit tests, as would all the components it interacts with. The situation where an unexpected input (such as a proton torpedo) causes an unexpected output, which is then input into the next component until a chain reaction destroys the whole system would never arise with good test coverage.

Conclusion

I hope this brief overview of TDD demonstrates that as a methodology it isn’t that difficult a concept. The actual implementation of unit tests themselves is a much wider topic however, with a rich selection of frameworks to choose from. As primarily a C# developer, I have no serious complaints about NUnit, which is more or less the de facto standard now, although Microsoft does ship Visual Studio with its own unit testing framework, which may work well enough for yourself.

Conditional method attributes

Sometimes I like to include some code which will only run when complied in Debug config. This is simple enough, just add some preprocessor commands like so:

#if DEBUG
  //Do some debug-only stuff here.
#endif

However this always looks a bit ugly to me. A much tidier way of achieving the same is to use conditional method attribute like so:

[Conditional("DEBUG")]
private void DoSomething()
{   
  //Do some debug-only stuff here.
}

The only catch with this is that the method must return void. This is necessary to allow it to be included/excluded depending on the compilation config used. It can be worked around by using reference parameters on the method itself.

Anyway, here’s a photo of a skiing penguin.

Skiing Penguin

RESTful WCF services without .svc file and with very little configuration

WCF is, on the whole, pretty neat. It’s a doddle to decorate methods with UriTemplates and specify DataMembers. Building the actual meat of a web service is made very easy by the wealth of functionality available in WCF4, and this is the bit I usually happily chip together whenever I need to write a RESTful web service.

Then I get to the part where I have to add the service’s endpoint to web.config. It’s usually been several months since I last did it. I look it up on google, but the results don’t quite seem to apply to me. I open up an old project where I last did this ridiculous dance, but evidently I’m missing something because the damned thing still won’t work. The problem is most likely a subtly mis-set attribute. Or may web.config is just a monster which will eat us all.

With that in mind, I was recently delighted to find this blog post by Steve Michelotti. It’s a little old, but the knowledge within was new to me, so it may be new to you too.

In a nutshell, it leverages the WebServiceHostFactory class to allow a ServiceRoute to your WCF service to be defined. The advantages of this are two-fold:

  • No service-specific entries are needed in web.config
  • The WCF service can be defined in a plain C# class rather than a .svc file.

Steve covers this in much more detail in his blog post, so what follows is a quick summary of the steps required to get a service up and running:

  • Define your service in a C# class (implementing an interface is recommended but not required).
  • Decorate your class with
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]

    This is required for the service to operate over HTTP.

  • A teensy bit of web.config tweaking is required. This is the other half of the configuration above.
    
      
    
  • Add a reference to System.ServiceModel.Activation. This is not to be confused with System.ServiceModel.Activision.
  • To add the ServiceRoute, add a line similar to the one below to Application_Start in Global.asax.cs:
    RouteTable.Routes.Add(new ServiceRoute("Services", new WebServiceHostFactory(), typeof(Your_Service_Class)));

    Where Your_Service_Class is the name of the class you previously wrote for your service. Leaving the first parameter of ServiceRoute blank results in all requests to the service being relative to the site route. Services in the example above is the route prefix of your service url. You can leave it blank, but I prefer to specify a path to keep my services tidily organised.  You should decorate your service methods with a suitable UriTemplate, eg

    [WebGet(UriTemplate = "MyService", ResponseFormat = WebMessageFormat.Json)]

    In the above case the service can be called via a browser on http://my_hostname/services/myservice

That’s it! I can now get on with the meaty business of writing code instead of wrestling with the beast that is web.config.

In the meantime, here are some goats in a tree.

Goats in a tree