Thursday, August 10, 2017

Building a Pipeline (the Template Pattern)

Building a Simple Pipeline

A lot of my development experience has been building back-end systems. There's been plenty of times where something I've built needed to process a request which was composed of a number of tasks. These tasks had to be performed in the correct sequence forming an algorithm. I've heard these things called many different names including Pipelines.

Unfortunately, many times this need leads to a class which contains both the steps of the algorithm, and the logic to complete the steps. These classes quickly turn into huge monsters. They also tend to become a real pain to test. It turns out, there's a GoF pattern for them: Template Method Design Pattern.

In other words, I wanted to express these simple algorithms like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public class FileCreator : IRequestHandler<CreatePackage>
{
    private readonly IPipeline<CreatePackage> pipeline;
    
    public FileCreator(IPipeline<CreatePackage> pipeline)
    {
        this.pipeline = pipeline;
    }
    
    public void Handle(CreatePackage request)
    {
        pipeline.Subject(request);
        pipelline.Do<BoxTheItems>();
        pipelline.Do<CreateTheShippingLabel>();
        pipeline.Do<ShipTheBox>();
        pipeline.Do<SendShippingNotification>();
    }
}

PS - MediatR is awesome. That's where IRequestHandler<T> comes from.

Enter LittlePipeline

LittlePipeline is a small library, or set of example code on how one can build a template that is easy to read, easy to test, and can work with an IoC container. It's designed to be a starting point, not an end-all solution to the problem. The gist of using the library (or classes if you want to copy/paste the code) is simple...

Start with a subject class. This class is the guy who holds the data necessary to process the request. It can be as dumb (or smart) as you need. The only requirement is the subject be a reference object (a class).

1
2
3
4
5
6
public class CreatePackage
{
    public int OrderId { get; set; }
    public Address ShipTo { get; set; }
    public string TrackingNumber { get; set; }
}

Create any number of tasks. These tasks should implement the ITask<T> interface where T is the subject type you created earlier.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public class SendShippingNotification : ITask<CreatePackage>
{
    private readonly IBus bus;
    
    public SendShippingNotification(IBus bus)
    {
        this.bus = bus;
    }

    public void Run(CreatePackage subject)
    {
        var notification = new ShippingNotification { TrackingNumber = subject.TrackingNumber };
        bus.Publish(notification);
    }
}

Use the baked-in pipeline creator, or your favorite IoC container to register the tasks, and create the pipeline. Then, use it like in the class above. Here's the built-in, no frills, no guaranties example.

1
2
3
var pipeline = MakePipeline.ForSubject<FirstTestSubject>()
    .With<Increment>(() => new Increment())
    .Build();

Oh, and this is what testing a pipeline looks like (with FakeItEasy):


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class PipelineTestExample
{
    [Test]
    public void ThePipelineCanBeTested()
    {
        var pipeline = A.Fake<IPipeline<FirstTestSubject>>();
        var example = new ThingThatUsesThePipeline(pipeline);

        var subject = new FirstTestSubject();
        example.Run(subject);

        A.CallTo(() => pipeline.Subject(subject)).MustHaveHappened()
            .Then(A.CallTo(() => pipeline.Do<Increment>()).MustHaveHappened())
            .Then(A.CallTo(() => pipeline.Do<Square>()).MustHaveHappened());
    }
}

public class ThingThatUsesThePipeline
{
    private readonly IPipeline<FirstTestSubject> pipeline;

    public ThingThatUsesThePipeline(IPipeline<FirstTestSubject> pipeline)
    {
        this.pipeline = pipeline;
    }

    public void Run(FirstTestSubject subject)
    {
        pipeline.Subject(subject);
        pipeline.Do<Increment>();
        pipeline.Do<Square>();
    }
}

That's It

There you have it, a simple template class that (hopefully) helps clean up some code by separating the algorithm steps from their implementations. The code is on github. The ReadMe.md file gives some information about how it might be tested.

Tuesday, February 14, 2017

NUnit Exception: Error Loading Settings

This applies to NUnit 3.4.1.

I was doing some TDD one day, when Visual Studio crashed. After a few choice words, I booted things back up. Running the tests after starting back up threw up an error window I'd never seen before. It only showed when I used the R# test runner.


It wasn't very helpful, since half the message didn't seem to be showing. I was able to get the error message using the first trick from this article. That error message wasn't much help either.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
---------------------------
ReSharper Ultimate – System.ApplicationException: Error loading settings file
---------------------------
   at NUnit.Engine.Internal.SettingsStore.LoadSettings()

   at NUnit.Engine.Services.SettingsService.StartService()

   at NUnit.Engine.Services.ServiceManager.StartServices()

   at NUnit.Engine.TestEngine.Initialize()

   at NUnit.Engine.TestEngine.GetRunner(TestPackage package)

   at JetBrains.ReSharper.UnitTestRunner.nUnit30.BuiltInNUnitRunner.<>c__DisplayClass1.<RunTests>b__0()

   at JetBrains.ReSharper.UnitTestRunner.nUnit30.BuiltInNUnitRunner.WithExtensiveErrorHandling(IRemoteTaskServer server, Action action)
---------------------------
OK
---------------------------

Fortunately, this project happened to have a build script which also ran the unit tests. Running the build script returned the full error text. That error message showed me the real problem. It turns out the NUnit settings file was empty. That was causing the root element missing error.


Deleting the NUnit30Settings.xml file from the $AppData$\Local\NUnit directory cleared the problem.