Publish/Subscribe Patterns

Previously, I talked about patterns where you were unlikely to implement them yourself, since they are now considered part of the infrastructure that goes with a modern language.  The publish/subscribe model isn’t quite ready to be described as infrastructure, but it’s getting close.  So, here are two patterns I don’t honestly think it’s worth knowing.  Here, it’s not so much that the patterns are bad, just that you’re better off understanding and using the publish/subscribe model.  Here’s how the pub/sub model works:

  • Participants are called services.
  • They do not communicate directly with one another, but through messages/events raised by one and consumed by others.
  • Each service can register its interest in the messages for any other participant.
  • However, no service references any other participant.  Instead, messages are placed on a message bus, and consumed by means of method calls on the destination object or objects.
  • In asynchronous scenarios, when an event is raised, it is placed on a queue.  The service consumes the messages in the order they were sent, but not necessarily on the same box and definitely with no guarantee of exactly when it happens.

Now, here’s some implementations of the pub/sub pattern you can use for free:

Of these, each has their advantages.  Personally, I dislike .NET events because getting a message from one service to another pretty much requires you to be able to reference both objects, which cuts down on the decoupling that pub/sub gives you.  Of the others:

  • nServiceBus is most appropriate for long running processes, and those that split across machines. 
  • retlang is preferable when you’ve got low-latency requirements, and you’re happy with everything running on one machine.
  • Udi Dahan’s code is incredibly short, and appropriate when you don’t feel the need for a more complex solution.  It is synchronous and single threaded, which can be a blessing or a curse depending on your context.

Now, I was promising that I’d talk about GoF patterns, so let’s get back to it:

Observer

One object listens to events/messages pushed out by another.  Any consuming service in a pub/sub framework could be considered an observer, as could anything that listens to .NET events.  However, it’s very generality means that it’s not really that useful as a concept.

Mediator

A term used to describe an object that is used when services don’t directly communicate with one another.  In the publish/subscribe model, this is the message bus. 

Summary

The Observer and Mediator patterns should not be implemented directly by your code.  If it looks like one or the other might be appropriate, you should consider the use of a publish/subscribe framework.

NOTE:  I’m going to have to revise this in light of Rx, a useful framework that targets the observer pattern directly.

Infrastructure Patterns

Some patterns are so good they become part of the way that people think about systems.  They get implemented using general solutions and then people just use them as a piece of technology.  In these cases, a modern developer is himself unlike to implement the pattern, he’s much more likely to just use the libraries that implement the pattern.  I’m terming these infrastructure patterns.

Proxy and Decorator

A modern developer lives with proxy objects the whole time.  If you have an object X, a proxy for object X behaves is an object that exposes the same interface as X and delegates calls through to X.

In many ways, Decorator and Proxy are the same pattern.  If you don’t believe me, check the UML diagrams on Wikipedia (this from the guy who hates UML).  The major difference is one of intent.  We call it a decorator if it modifies functionality, or a proxy if it doesn’t. 

You can do quite a few things with a proxy/decorator:

  • NHibernate uses entity proxies to allow objects to be lazily loaded.
  • You could use Castle DynamicProxy to log all calls to a destination object.
  • Equally, you could a use a proxy to restrict access and add a permissioning system.
  • You use client proxies in WCF to make it look like you’re calling a service directly.  In practice, you call a proxy, the proxy performs network communication with the server and then the server calls the real object.

In practice, quite a lot of the time the boundary between the two terms is blurred.  It’s usually called a proxy if you’re crossing a system boundary, but if you’re checking permissions?  Strictly it’s a decorator.

In practice, most of your needs for true proxy objects are handled by framework libraries.  Those that aren’t, I recommend using a general proxy solution like DynamicProxy.  Krzysztof has written an excellent tutorial.  However, just because you’re not implementing proxies yourself, it doesn’t mean you don’t need to know what one is.  On the other hand, most modern developers do understand this stuff already, because much of what we write these days involves some form of remote component.

The classic example of the decorator pattern in the .NET Framework is the IO library (it pretty much copies Java’s approach).  In the call “new BufferedStream(stream)”, the BufferedStream is a decorator that buffers the calls to the underlying stream.  It’s exactly the same as the original stream, except that it’s buffered. 

For large APIs such as System.IO.Stream, it’s rarely advisable to do this stuff by hand, because delegating methods is both dull and error prone. 

Iterator

Steve Yegge pointed out that this pattern basically just works around a deficiency in the design of C++.  In C#, it’s the foreach statement.  Call it iterator if you want, I tend to call it IEnumerable.

Interpreter

An interpreter is a language that is executed without going through a compilation state.  The interpreter pattern is basically the same.  Now, there’s basically two cases in which you’d be hit with this as a requirement:

  • You’ve been provided with an external language specification that you need to parse and process.
  • You need to create a small language to deal with a particularly flexible requirement.

In the first case, it doesn’t matter what you do, you’re writing an interpreter or compiler.  Since anything you did could be described as matching the interpreter pattern, it’s hard to see how useful the terminology is.  Interpreter was a term of art in the 1960s, not a design pattern in the 80s.

In the second case, you’re writing a DSL.  And here, frankly, I wouldn’t use an interpreter.  Most modern thinking on this subject says that you’re better off using a language that already exists and tweaking it to your purpose. 

The most obvious language choices are IronPython, IronRuby or Boo. 

  • IronPython has a relatively inflexible syntax, but it’s extremely sophisticated and can be happily used for scripting purposes. 
  • IronRuby (and Ruby in general) is the most popular DSL base language in the world, with a very flexible syntax.  It’s not as mature as IronPython, though, which may put you off.
  • Boo has a customizable syntax, is mature and is open source.  However, it’s syntax is possibly over-flexible, to the extent that it can be very hard to figure out what a DSL does without reading its source code.  You can mitigate this by writing decent documentation, but typically DSLs don’t come with much.

Summary

The iterator and interpreter patterns are both terminology that ought to be retired.  This is not to say they’re bad patterns, it’s just that it’s not useful to name the concepts anymore.  The term “interpreter” is best used simply to denote the same concept it represented in the 1960s: runtime evaluation of a programming language.  The proxy pattern is something you’re highly unlikely to need to implement yourself, but it’s extremely important you understand the concept it represents and when your code is using proxies.  Decorator is just a proxy that modifies behaviour.  You’re actually quite likely to implement your own decorators, though.

UPDATE:  The text about decorators has been revised.  The original text can be found here.

Gang of Four Patterns

I’m about to give a talk on Gang of Four patterns.  I’ve got to admit, I’d rather have been talking about the seminal post-punk band.  For one thing, if people disagree with my opinions (“Entertainment” is genius, for the record…) they’re unlikely to take it personally.  The thing is, everyone treats the book as being something akin to the Bible in the 16th century:

  • It’s incredibly important
  • It’s full of useful ideas
  • It’s hugely respected
  • But no-one’s read it
  • And a fair number of those that do don’t understand it, and take it out context.

None of these are actually problems with the book per se, but misinterpretation is annoyingly common.  You hear people boasting of how many different patterns they managed to implement in their code base, as if increased complexity were something of which to be proud.  You see people shoehorning patterns into problems which don’t match the use cases.  Personally, I wish more people bothered to read Chapter 1, especially the section on favouring composition over inheritance.

Taking Another Look

I have to admit, these attitudes coloured my own stance on the book for years.  I was leery of developers who espoused patterns because it seemed that use of patterns was more important to them than delivering solutions.  I’m hardly the first person to say this

Like the Bible, it’s better when you have a modern translation, since frankly 15 years is a long time in software development.  To give you an idea, Java was released a year later.  Some were a stupid idea, some just aren’t as important anymore, some are special cases of more general ideas, some people use all the time and the only real benefit is terminology.  And some…

…well actually, some are so important that you really, really, need to understand them.  So, I decided to write a skeptic’s guide to design patterns.  You’re almost certainly going to disagree with me, but for the record, the patterns I think are still relevant and unobvious today are:

  • Factory / Abstract Factory
  • Command
  • Chain of Responsibility
  • State

Sorry, that’s it.  Don’t worry, I’m wearing asbestos.

Initial Observations

Going through the book again, a couple of themes keep cropping up:

  • Unlike most modern patterns, the use cases often overlap.  Because the focus is on low-level programming constructs, there’s often more than one way to do something.
  • The design patterns are, contrary to popular belief, extremely language dependent.  Iterator is irrelevant in C#, Visitor is irrelevant in JavaScript.
  • The patterns are often special cases of more general concepts and techniques.

You’re not going to find any diagrams in this stuff.  Frankly, I think that UML is a positive hindrance to understanding what’s going on in most of these patterns.

  • For one, I don’t regard the presence or absence of an abstract interface as fundamentally changing a design, it’s just a refinement (one that you should pretty much always be using).
  • For another, the difference between composition and inheritance is significant, but I’d argue doesn’t actually change a pattern.  Hence, I’d argue that Template and Strategy are actually the same.
Technorati Tags: ,

Retlang 0.4

Retlang 0.4 has been out for quite a while, but I’ve never written about it.  Worse, my example code doesn’t work in it, which has garnered complaints (in my defence, the Retlang wiki is out of date as well).  The version is again a restructuring that you shouldn’t apply to your own code without a bit of thought, but it’s added a killer feature: the ability to interact with WinForms.  Or WPF if you’re that way inclined.

Anyway, I’ve drawn up a new version of the spider, but it differs quite a bit from the previous versions:

  • It now has something resembling an architecture.
  • Keeping track of progress is now handled separately from keeping track of which URLs have been encountered.
  • I’ve used the ability to throw a command directly onto a fiber.  (Note for old users:  where you used to say “Context” or “Queue”, you now say “Fiber”)
  • I’ve abstracted out the basic graph-walking functionality from the URL reading functionality.  It’s not clear to me that it’s more readable this way, although the advantages of abstraction tend to grow with scale.
  • If you pass an argument of “interactive” in, it will show a progress bar.

I still haven’t gone with Mike Rettig’s suggestion to group channels together into service classes, which are then passed into the constructors of their consumers.  Instead, I’ve mostly gone for a single top-level routine that sets up the whole routing.  However, this ran into trouble when dealing with the new feature, the ability to switch on a progress bar.

Basically, UI fibers look the same in Retlang as threads, but ultimately they’re not.  So the main set up routine needed access to the particular fiber.  I achieved that by actually making the fiber a property of the object.  At one point in the design (yes, there is some design…) this produced a chicken-and-egg problem. 

  • I wanted the form to have a fiber property
  • I wanted to pass that in in the constructor to the form
  • But the fiber itself wanted the form in its constructor

This looked like a serious problem until I realized that there was a better design, which separated out the job of tracking progress from reporting progress.  This is reflective of a more general fact about retlang: it really punishes you sometimes if your design isn’t SOLID.  This isn’t a criticism, in fact it’s one of the best features of Retlang: it pushes you towards better designs.

Anyway, enough rambling and on with the code.  Feedback on whether or not this is better at illustrating principles than the old version will be appreciated.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Net;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using Retlang.Channels;
using Retlang.Core;
using Retlang.Fibers;

delegate IEnumerable<TNode> NodeWalker<TNode>(TNode root);

interface IProgressCounter<TNode> {
    void NodeQueued(TNode node);
    void NodeCompleted(TNode node);

    IFiber Fiber { get; }

    void WaitUntilComplete();
}

interface IGraphListener<TNode>
{
    bool HasEncounteredNode(TNode node);

    void ProcessNode(TNode node);
}

class GeneralGraphListener<TNode> : IGraphListener<TNode>
{
    private readonly HashSet<TNode> alreadyProcessed;

    public GeneralGraphListener(IEqualityComparer<TNode> comparer)
    {
        alreadyProcessed = new HashSet<TNode>(comparer);
    }

    public virtual bool HasEncounteredNode(TNode node)
    {
        return alreadyProcessed.Contains(node);
    }

    public virtual void ProcessNode(TNode node)
    {
        alreadyProcessed.Add(node);
    }

    public IEnumerable<TNode> NodesEncountered
    {
        get { return alreadyProcessed; }
    }
}

static class RetlangMacros
{
    internal static Action<TValue> Distribute<TValue>(Func<Action<TValue>> processorFactory, int numberOfProcessors)
    {
        var distributeChannel = new QueueChannel<TValue>();
        for (int index = 0; index < numberOfProcessors; index++) {
            var processor = processorFactory();
            var queue = new ThreadFiber();
            queue.Start();
            distributeChannel.Subscribe(queue, processor);
        }
        return distributeChannel.Publish;
    }

    internal static IPublisher<TNode> CreateGraphWalker<TNode>(
        Func<NodeWalker<TNode>> nodeWalkerFactory, 
        int numberOfProcessors, 
        IGraphListener<TNode> listener,
        IProgressCounter<TNode> progressCounter)
    {
        var foundNodeChannel = new Channel<TNode>();
        var enqueuedNodeChannel = new Channel<TNode>();
        var finishedNodeChannel = new Channel<TNode>();

        Func<Action<TNode>> nodeProcessorFactory = () => {
            var walker = nodeWalkerFactory();
            return node => {
                foreach (TNode child in walker(node)) {
                    foundNodeChannel.Publish(child);
                }
                finishedNodeChannel.Publish(node);
            };
        };
        var walkChildren = Distribute(nodeProcessorFactory, numberOfProcessors);
        var trackerQueue = new PoolFiber();
        trackerQueue.Start();
        enqueuedNodeChannel.Subscribe(progressCounter.Fiber, progressCounter.NodeQueued);
        finishedNodeChannel.Subscribe(progressCounter.Fiber, progressCounter.NodeCompleted);
        foundNodeChannel.Subscribe(trackerQueue, node =>
        {
            if (!listener.HasEncounteredNode(node)) {
                listener.ProcessNode(node);
                enqueuedNodeChannel.Publish(node);
                walkChildren(node);
            }
        });

        return foundNodeChannel;
    }
}


class ProgressCounter<TNode> : IProgressCounter<TNode>
{
    private readonly IFiber fiber;
    private readonly IProgressReporter reporter;
    private readonly AutoResetEvent waitHandle;
    int nodesEncountered;
    int nodesProcessed;
    

    internal ProgressCounter(AutoResetEvent waitHandle, IFiber fiber, IProgressReporter reporter)
    {
        this.waitHandle = waitHandle;
        this.fiber = fiber;
        this.reporter = reporter;
    }

    public IFiber Fiber
    {
        get { return fiber; }
    }

    public virtual void NodeQueued(TNode node)
    {
        nodesEncountered++;
    }

    public virtual void NodeCompleted(TNode node) {
        nodesProcessed++;
        reporter.Report(nodesProcessed, nodesEncountered);
        if (nodesProcessed == nodesEncountered) {
            waitHandle.Set();
        }
    }

    ///NOTE that this routine is called on a separate fiber from the other functions in
    ///this class.  All other classes stick to their fibers.
    public virtual void WaitUntilComplete() {
        waitHandle.WaitOne();
    }
}

interface IProgressReporter : IDisposable
{
    void Report(int nodesProcessed, int nodesEncountered);
}

class ConsoleProgressReporter : IProgressReporter
{
    public void Report(int nodesProcessed, int nodesEncountered)
    {
        Console.WriteLine(string.Format("{0}/{1}", nodesProcessed, nodesEncountered));
    }

    public void Dispose()
    {
        // Not needed
    }
}

class FormProgressReporter : Form, IProgressReporter {
    private readonly ProgressBar progressBar;

    public FormProgressReporter()
    {
        progressBar = new ProgressBar();
        SuspendLayout();
        progressBar.Dock = DockStyle.Fill;
        progressBar.Location = new System.Drawing.Point(0, 0);
        progressBar.Name = "progressBar";
        progressBar.Size = new System.Drawing.Size(292, 266);
        progressBar.TabIndex = 0;
        Controls.Add(progressBar);
        Height = 75;
        Width = 600;
        ResumeLayout();
    }

    public void Report(int nodesProcessed, int nodesEncountered)
    {
        Text = string.Format("{0}/{1}", nodesProcessed, nodesEncountered);
        SuspendLayout();
        progressBar.Maximum = nodesEncountered;
        progressBar.Value = nodesProcessed;
        ResumeLayout();
    }
}

class Program
{
    static void Main(string[] args)
    {
        string baseUrl = "http://www.yourwebsite.xyzzy/";
        int spiderThreadsCount = 15;
        bool hasUI = args.Length > 0;
        if (hasUI)
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
        }
        
        var waitHandle = new AutoResetEvent(false);
        var reporter = hasUI
            ? (IProgressReporter)new FormProgressReporter()
            : new ConsoleProgressReporter();
        var form = reporter as FormProgressReporter;
        if (form != null) {
            new Thread(() => Application.Run(form)).Start();
        }
        using (var fiber = hasUI 
            ? new FormFiber(form, new BatchAndSingleExecutor())
            : (IFiber) new PoolFiber())
        {
            fiber.Add(reporter);
            var progressCounter = new ProgressCounter<string>(
                waitHandle, fiber, reporter);
            var listener = new GeneralGraphListener<string>(
                StringComparer.InvariantCultureIgnoreCase);
            progressCounter.Fiber.Start();
            var walker = RetlangMacros.CreateGraphWalker(
                () => new Spider(baseUrl).FindReferencedUrls,
                spiderThreadsCount,
                listener,
                progressCounter
            );
            walker.Publish(baseUrl);
            progressCounter.WaitUntilComplete();
            foreach (string url in listener.NodesEncountered.OrderBy(url => url)) {
                Console.WriteLine(url);
            }
            Console.ReadLine();
            fiber.Enqueue(reporter.Dispose);
        }
    }

    class Spider
    {
        string _baseUrl;

        public Spider(string baseUrl)
        {
            _baseUrl = baseUrl.ToLowerInvariant();
        }

        public IEnumerable<string> FindReferencedUrls(string pageUrl) {
            if (Path.GetExtension(pageUrl) == "css")
            {
                return new string[0];
            }
            string content = GetContent(pageUrl);
            return from url in Urls(content, "href='(?<Url>[^'<>]+)'")
                            .Union(Urls(content, "href="(?<Url>[^"<>]+)""))
                            .Union(Urls(content, "href=(?<Url>[^'" <>]+)"))
                       where url != null && url.Length > 0
                            && IsInternalLink(url) && url[0] != '#'
                            && !url.Contains("&lt")
                            && !url.Contains("[")
                            && !url.Contains("\")
                            && !url.EndsWith(".css")
                            && !url.Contains("css.axd")
                       select ToAbsoluteUrl(pageUrl, url);
        }

        static int BaseUrlIndex(string url)
        {
            // This finds the first / after //
            return url.IndexOf('/', url.IndexOf("//") + 2);
        }

        string ToAbsoluteUrl(string url, string relativeUrl)
        {
            int hashIndex = relativeUrl.IndexOf('#');
            if (hashIndex >= 0) {
                relativeUrl = relativeUrl.Substring(0, hashIndex);
            }
            if (relativeUrl.Contains("//"))
            {
                return relativeUrl;
            }
            if (relativeUrl.Length > 0)
            {
                bool isRoot = relativeUrl.StartsWith("/");
                int index = isRoot 
                    ? BaseUrlIndex(url) 
                    : url.LastIndexOf('/') + 1;
                if (index < 0) {
                    throw new ArgumentException(string.Format("The url {0} is not correctly formatted.", url));
                }
                var result = url.Substring(0, index) + relativeUrl;
                return result;
            }
            return null;
        }

        bool IsInternalLink(string url)
        {
            url = url.ToLowerInvariant();
            if (url.StartsWith(_baseUrl))
            {
                return true;
            }
            if (url.StartsWith("http") || url.StartsWith("ftp") || url.StartsWith("javascript"))
            {
                return false;
            }
            if (url.Contains("javascript-error"))
            {
                return false;
            }
            return true;
        }

        static IEnumerable<string> Urls(string content, string pattern)
        {
            var regex = new Regex(pattern);
            // Why exactly doesn't MatchCollection implement IEnumerable<Match> ?
            return from match in regex.Matches(content).Cast<Match>()
                   select match.Groups["Url"].Value;
        }

        static string GetContent(string url)
        {
            var request = WebRequest.Create(url);
            request.Proxy = WebRequest.DefaultWebProxy;
            try {
                using (var response = request.GetResponse()) {
                    using (var reader = new StreamReader(response.GetResponseStream())) {
                        return reader.ReadToEnd();
                    }
                }
            } catch (WebException ex) {
                Console.Error.WriteLine("Problem reading url {0}, message {1}.", url, ex.Message);
                return "";
            }
        }
    }
}

 

Technorati Tags: ,

Fluent NHibernate: A great project

I have to admit, I stopped lurking to the Fluent NHibernate mailing list a while ago. Ironically, it wasn’t because I thought nothing was going on, simply that the sheer volume of emails was producing massive amounts of noise in my inbox.  The unfortunate aspect of this is that often with .NET projects, there’s very little evidence of life outside of their mailing lists (for example, a lot of activity on the Castle project is focusing on Mono and Silverlight, try finding that information on their web site).

Now, I know from personal experience just quite how painful it is to produce a patch for an open source project, never mind actually maintain one.  The people doing this are typically doing it because they find the end product useful in its own right.  End users, who don’t contribute to the improvement of the project, are necessarily second class citizens in amateur open source projects.

Now, take a look at this bug report and comments #4 and #5.  #4 was me in a pretty bad mood, I’d just lost a day trying to work out what was going on.  #5 is a completely reasonable response from someone who has put a lot of work in to the project.  It does two things

  • It explains the current priorities and why the issue is not fixed.
  • It reassures the end user that his concerns are appreciated.

As I say, no-one forces people to work on amateur open source projects, and trawling through bug lists is definitely pretty far down most developers list of favourite things to do.  That’s what I mean when I say that FH is a great project.  (The code’s quite useful too…)

The aspect that I haven’t mentioned is that projects that don’t take end users seriously tend to wither, if only because they run out of new contributors.  Whereas I’m not qualified to help with the code, I can produce a decent bug report.  I’m going to go do that right now…

Technorati Tags:

Doing a self join with Fluent NHibernate AutoMapping

This is definitely in the category of posts “write it down before you stop understanding the solution”.  Let’s say that you’re trying to track your servers.  Servers are related to other servers.  So, for instance, a live server has a corresponding DR server and a corresponding UAT server.  Let’s say also you have a simple table with two foreign key references that implements this relationship.  You can implement this in fairly short order:

mapping.HasManyToMany(s => s.RelatedSites)
    .Cascade.All()
    .WithTableName("RelatedSite")
    .WithChildKeyColumn("RelatedSiteId")
    .WithParentKeyColumn("LiveSiteId")
    .Inverse()
    .FetchType.Join();
mapping.IgnoreProperty(s => s.RelatedSites);

The only problem with this is that it doesn’t work.  Now, if you automatically export your mapping files (and you should) you’ll see that it’s ignoring the key columns you specify.  The automatic configuration is doing its own thing.

The problem is that you also added a foreign key convention by using the helper.  Take a look at the code that implements this.  You’ll see that the Accept code looks a bit dodgy when you compare it to the Apply method.  Instead, you can try the following code:

class ForeignKey : ForeignKeyConvention, IRelationshipConvention
{
    private readonly Func<PropertyInfo, Type, string> standardRule;

    public ForeignKey(Func<PropertyInfo, Type, string> standardRule)
    {
        this.standardRule = standardRule;
    }

    protected override string GetKeyName(PropertyInfo property, Type type)
    {
        return standardRule(property, type);
    }

    public bool Accept(IRelationship target)
    {
        if (target is IManyToManyPart) return base.Accept((IManyToManyPart)target);
        return true;
    }

    public void Apply(IRelationship target)
    {
        if (target is IOneToManyPart) base.Apply((IOneToManyPart)target);
        if (target is IManyToManyPart) base.Apply((IManyToManyPart)target);
        if (target is IManyToOnePart) base.Apply((IManyToOnePart)target);
    }
}

This code fixes the problem.

Anatomy of a Bug

This is a fix that raises as many questions as it answers.  One is why Accept still doesn’t do the obvious thing, the other is why I’m not going to submit this as a patch.  The second is pretty easy to answer: this is nothing like a solution to the underlying problem.  The first takes a bit longer…

If you make Accept do the obvious thing, it stops applying your foreign key rules anywhere.  The problem is that the rules for one to many and many to many check to see if they’ve had their keys set already.  And they already have, by the factory foreign key convention.  So the user rule does the wrong thing in order to make up for that.  So two wrongs nearly make a right, until you introduce a many to many part.  The fix I’ve described above fixes it for me, but it’s far from obvious that the underlying problem is fixable.

This is the second time I’ve found the factory conventions broke my code through no fault of my own (the other is the well documented, but still present, nullable enum bug) and I have to admit that I’m starting to wonder if the conventions code is more trouble than it’s worth.  Certainly the interaction between the unremovable factory conventions and your own conventions is at best hard to understand and at worst an unsolvable problem.  Well, I’m still learning…

Technorati Tags:

AutoGen: Extending the Convention Approach to Event Wiring

I couldn’t quite leave this code alone.  I have to admit, the whole reason I wrote the AutoGen stuff in the first place was out of frustration at the amount of plumbing factories I was having to write in a recent project.  Well, the plumbing of event wiring was getting at me as well, so I decided to do something about that as well.

Let me explain the problem I wanted to solve, first.  I recently had to modify a program that took one fix connection to handle one or two, depending on the deployment scenario.  Now, obviously, handling forty is pretty much like handling two from an API perspective, but going from one to two tends to involve refactoring.  The annoyance was, in this particular case, it was absolutely obvious what I wanted to do.  I wanted both to open, close and reset at the same time.  This was done through the obvious interface.

interface IFixConnection {
    void Open();
    void Close();
    void Reset();
}

Now, here, there’s no complex API.  It’s just a series of commands.  All I want is for it to pass the commands on to the implementors of the interface.  So, I wanted to be able to write.

container.Register(Component.For<IFixConnection>().Named("AggregateConnection").AutoWire("principalConnection", "controlConnection"));

and for it to “just work”.  Actually, I wanted to go further than that.  Large parts of my system need to know when a reset occurs, but I didn’t have to have to wire them up by hand.  So actually the interface looked like this:

internal interface IResettable {
    void Reset();
}
interface IFixConnection2 : IResettable {
    void Open();
    void Close();
}

Where quite a lot of objects implemented IResettable.  Now, I wanted the following:

  • The controller object shouldn’t need to know that some people only implemented part of the interface.
  • I shouldn’t have to wire up the objects to the AutoWire aggregate by hand.
  • It should keep track of creation and release.

So, I added in the following syntax:

container.Register(Component.For<IFixConnection2>().Named("AggregateConnection").AutoWire(s => s.WithCurrentObjects().UseWeakReferences()));

This supports the above behaviour.  It also has the advantage of requiring the minimum rewiring for different deployment scenarios.  The linkage works on the basis of whether or not the interface is implemented, not whether it is exposed.  This is a deliberate design decision to sacrifice a small amount of control for ease of use.  It certainly didn’t simplify the implementation.  Finally, the aggregate object exposes an IBroadcaster interface, defined as follows:

public interface IBroadcaster {
    void Add(object listener);
    bool Remove(object listener);
    void Clear();
    IEnumerable<object> GetListeners();
}

which can be used to dynamically modify the list at run-time.  It also implements a chain of responsibility pattern if the target interface method returns bool or a class.  Finally, it’s worth noting that the AutoWire does the opposite of AutoGen when presented with a Dispose method.  A dispose method clears the listeners, it doesn’t dispose of the listeners.  This is a special rule, but I think a useful one.  Anyone who really did want to dispose of the listeners can always get the list through GetListeners.

Anyway, it’s on the patch list in donjon.

Technorati Tags: ,

TFS API: How to break an abstraction

I’ve been trying without success for the last hour to limit the results of a TFS query.  It would be, on the face of it, relatively simple: I already know how to get all of the builds of a certain type, I just want to limit it to the last week.  You might think this was achievable using LINQ, and it would be if the problem you were trying to solve was anything other than a timeout.  Instead you find yourself falling down a rabbit hole.

Basically, in order to perform such a query, you need to pass in an implementation of IBuildDetailSpec.  This, in turn references, IBuildDefinitionSpec.  They’re both great big DTOs wrapped in an interface.  You might be wondering at this point why the interface has so many set properties, but Resharper cuts the implementation work down.  However, there’s a nasty shock waiting for you: an invalid array cast exception.  You see, TFS doesn’t really expect an IBuildDetailSpec, it expects a BuildDetailSpec.  Which is an internal sealed class.  You’re actually expected to create this object through the store’s own factory.

Seriously, what benefit is there to exposing an interface when only one implementation could ever possibly work?  I understand Microsoft has different priorities from open source developers, but I genuinely can’t think of an angle in which wrapping a DTO in these layers helps.

Technorati Tags:

Building Fluent NHibernate

The Castle project has recently got an awful lot better at actually being buildable from SVN.  It used to be a nightmare.  Since Fluent NHibernate doesn’t have a recognized built version, you’ve pretty much got to use the source.  So you’d hope it was pretty easy.  Sadly, it’s not.  It’s another nightmare.  Most of the problem comes from their decision to use rake.

Now, don’t get me wrong, I love rake.  It is 100% the right idea for a build tool, but the story on windows sucks.  For one thing, you’ve got to get ruby working on your machine.  Good luck with that, since most of the installs don’t include the required files.  Secondly, rake doesn’t have any extensions to deal with .NET code, which means that you end up dropping down to invoking MSBuild on the solution file anyway.  This also means that you’re prey to the standard problems of building from a solution file, including references not pointing to where you thought they were pointing.  (When I looked in October, FNh was suffering from exactly this problem.)

  • Install the Ruby 1.8.6 one-click installer.  Don’t try anything later: it probably won’t work.  (Best way to get 1.9.1 working on windows is probably to install 1.8.6 and copy across the missing DLLs to the 1.9.1 install directory)
  • Now go into your Fluent NHibnerate folder.  Don’t run build.bat.
  • Put the c:rubybin folder onto your path:  set path=c:rubybin;%path%  (I’m assuming you installed to the default location)
  • If you’ve got a proxy server, find out what its server name and port is.
  • Open installgems.bat in notepad.  Add this to every “gem install” line  –http-proxy http://<<server>&gt;:<<port>>. (obviously, 80 is the default)
  • Now run installgems.bat.
  • Type “rake” (since that’s all build.bat does anyway)
  • Hope I haven’t forgotten anything.

Anyway, Fluent NHibernate is a fabulous project, which has a project velocity the average .NET open source project would give their source repository for, so enjoy.

Technorati Tags:

Castle Windsor Configuration by Convention Proposal

Since adding convention over configuration features is the second most popular suggestion (after actually shipping) on the Castle User Voice site, I figured I’d chip in my own thoughts.  Impressive as Krzysztof’s approach is, I’d rather that we didn’t modify the runtime behaviour of Castle in order to get these kind of features.  Instead, I’d rather make the registration API more powerful.  The AllTypes code shows us a way forward on this, and the fluent NHibernate code has a good model for convention over configuration.

So, here’s a syntax that I would like to see just for auto-registration.  You’ll note it doesn’t even address the question of sub-dependency resolution, which was Krzysztof’s original focus, but I’m trying to start small here.  🙂

using System.Linq;
using System.Reflection;
using Castle.Windsor;
using NUnit.Framework;

namespace ColourCoding.ConventionConfigurationProposal {
    [TestFixture]
    public class ExampleUsage
    {
        [Test]
        public void RegisteringImplementations()
        {
            var container = new WindsorContainer();
            // Observations: we probably need some new syntax like AllTypes.  
// Sadly, we can't use AllTypes // since it's already a convention-based configuration mechanism.
var allInterfaces = Assembly.GetExecutingAssembly().GetTypes().Where(
t => t.IsInterface && !container.Kernel.HasComponent(t)); var allClasses = Assembly.GetExecutingAssembly().GetTypes(); container.Register(UseConvention .For(allInterfaces) .ImplementedBy(allClasses) ); var result = container.Resolve<ILogger>(); Assert.IsInstanceOfType(typeof(StandardLogger), result); // Convention by name Assert.IsFalse(container.Kernel.HasComponent(typeof(IService))); container.Register(UseConvention .For(allInterfaces) .ImplementedBy(allClasses) .UsingSelectionRule((i, s) => s.Name == "Default" + i.Name.Substring(1)) ); var service = container.Resolve<IService>(); Assert.IsInstanceOfType(typeof(DefaultService), service); // Multiple Registration Assert.IsFalse(container.Kernel.HasComponent(typeof(IMultipleService))); container.Register(UseConvention .For(allInterfaces) .ImplementedBy(allClasses) .AllowMultiple() ); var services = container.ResolveAll<IMultipleService>(); Assert.AreEqual(2, services.Count()); } public interface ILogger { } public class StandardLogger : ILogger { } public interface IService { } public class DefaultService : IService { } public class NonDefaultService : IService { } public interface IMultipleService { } public class Service1 : IMultipleService { } public class Service2 : IMultipleService { } } }

 

Now, there’s a couple of problems here:

  • As I’ve already said, we haven’t dealt with resolution of sub-dependencies.
  • We probably need a syntax for the allInterfaces and allClasses variables.  There’s no way you want that syntax repeated across the world.
  • We might want to create a syntax for common naming patterns as well.

You’ll note that I’ve tried to make the conventions based stuff look similar to ComponentRegistration directly.  There’s also a general hook, like in NHibernate, for intercepting the registration.  Here’s the implementation.  All of the code compiles against Castle Windsor 2.0 RTM.

using System;
using System.Collections.Generic;
using System.Linq;
using Castle.MicroKernel;
using Castle.MicroKernel.Registration;

namespace ColourCoding.ConventionConfigurationProposal
{
    public static class UseConvention {
        public static ConventionRegistration For(IEnumerable<Type> serviceTypes) {
            return new ConventionRegistration(serviceTypes);
        }
    }

    public delegate string NameRule(Type serviceType, Type implementationType);
    public delegate IEnumerable<Type> SelectionRule(Type serviceType, 
IEnumerable<Type> implementationTypeCandidates); public delegate bool SingleSelectionRule(Type serviceType, Type implementationType); public class ConventionRegistration : IRegistration { private IEnumerable<Type> serviceTypes; private IEnumerable<Type> implementationTypes; private Func<Type, Type> findImplementationRule; private NameRule nameRule; private Action<ComponentRegistration<object>> creationRules; private SelectionRule selectionRule; private SingleSelectionRule singleSelectionRule; public ConventionRegistration(IEnumerable<Type> serviceTypes) { this.serviceTypes = serviceTypes; } public IEnumerable<Type> ImplementationTypes { get { return implementationTypes; } } public IEnumerable<Type> ServiceTypes { get { return serviceTypes; } } public void Register(IKernel kernel) { var initialComponents = InitialComponents(); if (nameRule != null) { Apply(initialComponents, c => c.Named(nameRule(c.ServiceType, c.Implementation))); } if (creationRules != null) { Apply(initialComponents, creationRules); } foreach (var component in initialComponents) { kernel.Register(component); } } void Apply(IEnumerable<ComponentRegistration<object>> components,
Action<ComponentRegistration<object>> action) { foreach (var component in components) { action(component); } } IEnumerable<ComponentRegistration<object>> InitialComponents() { if (findImplementationRule == null) { return ComponentsByMatch(); } return ComponentsByFindRule(); } IEnumerable<Type> SingleOnly(Type serviceType,
IEnumerable<Type> implementationTypeCandidates) { if (implementationTypeCandidates.Count() == 1) { return implementationTypeCandidates; } return new Type[0]; } private IEnumerable<ComponentRegistration<object>> ComponentsByMatch() { var actualSelectionRule = selectionRule ?? SingleOnly; var filter = singleSelectionRule ?? new SingleSelectionRule((s, i) => true); // Yes, this code could be faster... return from serviceType in serviceTypes from implementationType in ImplementationTypes where serviceType.IsAssignableFrom(implementationType) && filter(serviceType, implementationType) group implementationType by serviceType into candidates from selectedImplementationType in actualSelectionRule(candidates.Key, candidates) select Component.For(candidates.Key)
.ImplementedBy(selectedImplementationType); } IEnumerable<ComponentRegistration<object>> ComponentsByFindRule() { foreach (var serviceType in ServiceTypes) { var implementation = findImplementationRule(serviceType); if (implementation != null) { yield return Component.For(serviceType)
.ImplementedBy(findImplementationRule(serviceType)); } } } public ConventionRegistration ImplementedBy(Func<Type, Type> findImplementation) { this.findImplementationRule = findImplementation; return this; } public ConventionRegistration ImplementedBy(IEnumerable<Type> implementationTypes) { this.implementationTypes = implementationTypes.Where(t => !t.IsInterface); return this; } public ConventionRegistration With(Action<ComponentRegistration<object>> creationRule) { this.creationRules += creationRule; return this; } public ConventionRegistration Named(NameRule nameRule) { this.nameRule = nameRule; return this; } public ConventionRegistration UsingSelectionRule(SelectionRule selection) { this.selectionRule = selection; return this; } public ConventionRegistration AllowMultiple() { if (selectionRule == null) { selectionRule = (serviceType, candidates) => candidates; } return this; } public ConventionRegistration UsingSelectionRule(SingleSelectionRule selection) { this.singleSelectionRule = selection; return this; } } }

 

Anyway, I hope this is a useful contribution to the discussion. 

Technorati Tags: