Click here to Skip to main content
15,886,026 members
Articles / Programming Languages / C#

Skyhooks vs. Cranes

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
25 Jul 2011CPOL3 min read 16.3K  
Skyhooks are undesirable, how to replace them in your code.

Daniel C. Dennett wrote in his 1995 book Darwin’s Dangerous Idea [emphasis author's]

“A skyhook is an exception to the principle that all design, and apparent design, is ultimately the result of mindless, motiveless mechanicity. A crane, in contrast, is a subprocess or special feature of a design process that can be demonstrated to permit the local speeding up of the basic, slow process of natural selection, and that can be demonstrated to be itself the predictable (or retrospectively explicable) product of the basic process.”

Daniel C. Dennett, Darwin’s Dangerous Idea,1995 (p76)

Basically, a skyhook is a way to explain something without reference to a prior antecedent. Conversely, cranes have explicable antecedents – perhaps until arriving at some primary axiom.

This is a useful analogy in programming, too. Skyhooks are a code smell; indicative of a deeper problem. All skyhooks should be replaced with appropriate cranes.

A skyhook makes your code difficult to mock. Examples of skyhooks are:

  • Static methods
  • Singletons
  • Object construction using new
  • Extension Methods

Each of these make testing more difficult* by hindering your ability to inject mocks into your code, they are skyhooks and thus they are undesirable. Each is used ex nihilo – from nothing.

Thankfully, each of these can be replaced by a suitable crane which will facilitate some kind of external injection (i.e.: used ex materia – from something).

  • Interfaces
  • Dependency Injection
  • Inversion of Control
  • Factories

Let’s take an example of each skyhook and change it so that we use hooks instead.

C#
public class UsersModule : IModule
{
    public void Initialize()
    {
        var unityContainer = ServiceLocator.Current.GetInstance<IUnityContainer>();
        unityContainer.RegisterType<object, UsersDocumentContent>(
                     RegionNames.ModuleDocumentContentRegion(ModuleName));
        this.currentUser = new User();
    }
}

This method contains all four of the aforementioned skyhooks (see if you can spot where before continuing).

Firstly, the use of ServiceLocator is an example of why the Singleton pattern is my pet hate. I firmly consider it an anti-pattern.

Granted – in this instance – the ServiceLocator has a SetLocatorProvider method which unit tests can use to inject the locator, this is a less-than-desirable way of giving a class a service locator. Furthermore, you’ve now given this code the keys to the safe with regard to what services it can acquire. I’d far rather be explicit with the dependencies that a class requires:

C#
public class UsersModule : IModule
{
    public UsersModule(IUnityContainer unityContainer)
    {
        this.unityContainer = unityContainer;
    }

    public void Initialize()
    {
        this.unityContainer.RegisterType<object, UsersDocumentContent>(
                  RegionNames.ModuleDocumentContentRegion(ModuleName));
        this.currentUser = new User();
    }

    private IUnityContainer unityContainer;
}

Now, the specific dependency has been constructor-injected, allowing unit tests to provide a suitable mock.

The second and third skyhooks are similarly extracted:

C#
public class UsersModule : IModule
{
    public UsersModule(IUnityContainer unityContainer, 
           IRegionNameProvider regionNameProvider, IUserFactory userFactory)
    {
        this.unityContainer = unityContainer;
        this.regionNameProvider = userFactoy;
        this.userFactory = userFactory;
    }

    public void Initialize()
    {
        this.unityContainer.RegisterType<object, UsersDocumentContent>(
                  this.regionNameProvider.ModuleDocumentContentRegion(ModuleName));
        this.currentUser = this.userFactory.CreateNew();
    }

    private IUnityContainer unityContainer;
    private IRegionNameProvider;
    private IUserFactory userFactory;
}

I wouldn’t worry about the three constructor parameters – they’ll be injected by your IoC container.

The final skyhook, the RegisterType extension method is a specialization of the static method skyhook (in as much as extension methods are implemented using static methods, an unfortunate design decision by Microsoft). Thankfully, extension methods must operate only on the public interface of the extended interface. This means that the call will likely result in an equivalent call to a method on the interface that was injected.

In conclusion, whenever you spot a skyhook, replace it with a crane.

* Some mocking frameworks, such as TypeMock, are able to mock skyhooks. However, this should only be considered if the skyhooks are in 3rd-party, unchangeable, code.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Nephila Capital Ltd.
Bermuda Bermuda
An experienced .NET developer, currently working for Nephila Capital Ltd. in Bermuda. Author of "Pro WPF and Silverlight MVVM".

Comments and Discussions

 
-- There are no messages in this forum --