Sunday 8 April 2012

The Use Case for Event Monitoring

I'm revisiting my KenKen project, it's time for a little performance tuning - my unit tests take about 14 seconds to run, which is too long. One of the immediate fixes I need to make is remove the arbitrary limit of 10 calculation iterations, and swap it with some logic to decide if another iteration is likely to be useful.

The logic runs something like this

  10 if grid solved then quit
  20 if iterations >= 10 then guess a square, reset iterations and goto 10
  30 iterations++
  40 start an iteration, calculating as many squares as possible
  50 goto 10

After 10 iterations, the grid is unlikely to be solved using the rules I've created; what usually happens is that by iteration 4 there are no squares left that can be calculated using my rules, so iterations 5-10 are pointless. This is an example of some tracing that illustrates the point:
The logic I needed to implement goes more like this:

  10 if grid solved then quit
  20 if previous iteration resulted in no work then guess a square and goto 10
  30 start an iteration, calculating as many squares as possible
  40 goto 10


This set me on my way to investigating the Event Monitor, the story of which can be found here, The C# Event Monitor using Reflection

UPDATE
You're possibly the only person reading this, so thanks. I implemented the changes outlined above and it's shaved 1-1.5 seconds off the tests, so I'm happy. New tracing looks like this:

C# Event Monitor using Reflection

Objective

I needed a component that will hook into any event raised on any objects, to keep track of the number of events raised. Simple, huh?

Hardwired Proof of Concept

My first attempt was in the constructor of the observed object, that registered its events to be handled by a CountEvent method in an EventMonitor object.
It worked:

But it seriously ignored SRP in that the observed object shouldn't care how its events are handled.

Refactor I - The EventHandler Parameter

With SRP in mind, I created a RegisterEvent method to accept the object's event, so that the monitor could add its own handler - there still needed to be knowledge of observer and observed, but that could be handled in a builder object so no harm there. A nice side effect of this is that the method that actually handled the event (CountEvent) could be made private. This is the EventMonitor code:
Lovely. Next, time to implement the new RegisterEvent in the client:
Easy. Now, time to run it:
Hmm. I'm not entirely sure what happened there, but it appears that you can't just go passing events around like that as it doesn't give you access to the Add and Remove handlers that you need to call (using the += and -= syntax). Note to self: Jon Skeet will know.

The ref Keyword is Your Friend

However, a quick addition of the ref keyword seemed to work:


The Builder

Excellent. Next, I wanted to totally remove the responsibility of event registration from the observed object. Enter, the builder object:

You'll notice that the event passed as the argument to RegisterEvent is in an error state. The error that this produced is "The event 'ObservedObject.ObservedEvent' can only appear on the left hand side of += or -= (except when used from within the type 'ObservedObject')"

What a shame. I can't access the event outside of the class itself except to add or remove a handler. I did want to use the add handler, honest, but just not inside the builder. Ok, that clearly wasn't going to work so I changed tack, and added the event handler directly from inside the builder.
It worked

What's That Smell?

Lets revisit the objective of the exercise: I need a component that will hook into any event raised on any objects, to keep track of the number of events raised.
Clearly I didn't have this yet - I'd merely abstracted the construction of one object into a builder class. All good, but a long, long way from any event on any object.

Reflection

As we know, nothing is really safe from prying eyes in the .Net world; every object is available to be decomposed via reflection. And if you can't beat them, join them... I found an article on MSDN, How to: Hook Up a Delegate Using Reflection. This explained how to use reflection to discover an object's events, and crucially how to create a delegate and use it to handle the object's events.
Here's the final code for the event monitor:
Here's an extended ObservedObject, with a standard and custom eventhandler:
And the builder. Note, this just passes the ObservedObject through to the EventMonitor, ensuring that if the ObservedObject changes by adding events, its builder doesn't need to.

GitHub

The final version of the EventMonitor example is available to inspect here on GitHub

Saturday 7 April 2012

Visual Studio item templates

I feel like I've come too late to the party and everyone's got dressed and sobered up, but I've created a Visual Studio 2010 template.

This is a step-by-step guide to creating my NUnit Test Fixture template, available on github.

Objective

95% of the time, when I create a class in Visual Studio, I create a corresponding test class. The class ends up looking something like this:

To get to this from a standard "new class", it's approximately 100 keystrokes. As there's a finite number of keystrokes you can make before you die (see Scott Hanselmans evidence), it's important to cut down the number of keys you press as it will eventually kill you - unless I've deliberately misread the angle of Mr Hanselman's blog post. Anyway, what I needed is a VS template that gives me the above code.

Create The Content

The first step to creating a template is to write the code that you want to end up with - for me, that's the code as shown above. I saved this in a file called NUnitTestFixture.cs.

Define The Template

Next step is to create the mechanism for telling Visual Studio about your template. This is done via an XML definition of your template, saved as a file with a .vstemplate extension. This is the XML definition of the NUnitTestFixture template:
This is what the important parts of this file defines:

  • Lines 3 - 9 <TemplateData> defines how the item will appear in the VS "Add new item" dialog.
  • Lines 4 - 8 define the individual items of information, displayed in the dialog as shown:

  • Lines 10-12 <TemplateContent> define the items that will be added to the VS project when this item is selected.
  • Line 11 defines the single item of this template, the code template. I'll show later how to package the template so that these files are available to Visual Studio. The TemplateContent element defines a file that makes up part of the template - in this example there's just one element for the code file NUnitTestFixture.cs. If there was e.g. a help file, a resource file, a designer etc, these would each have a separate TemplateContent element. In the element in the example, the ReplaceParameters attribute indicates that placeholders in the file can be replaced with variables.

Replace Parameters

When a NUnitTestFixture class is required in a project, there will be details that are only known when the item is created, for example the default namespace of the project, and the name of the class as input by the user:

Templates are able to be parameterised so that at the time of creation, placeholders can be replaced with their correct values. There are several built-in parameters available to use, see the MSDN documentation for a full list.
For the variables shown above, the built in parameters that are needed are rootnamespace and itemnamerootnamespace is the default namespace for the project the item is being added to, and itemname is the name of the file as input by the user on the "Add new item" dialog. The convention for defining placeholders is to wrap the parameter name in $ characters, so NUnitTestFixture.cs needs to look like this


Package The Template

For Visual Studio to make the template available, it needs to have all the files supplied in the form of a ZIP archive. For the example here, the files to include are

  • the code file, NUnitTestFixture.cs
  • the 48x48 pixel icon file, M_J_O_N_E_S.ico
  • the template definition file, NUnitTestFixture.vstemplate
Put these files in the same folder, and add them to a ZIP file - the easiest way is to select the files, right click and choose Send To -> Compressed (zipped) Folder. The resulting ZIP file needs to be copied to Visual Studio's Item Templates folder, and will then be available on the "Add new item" list.
Tip: to find out where your Item Tempate folder is, go to Tools -> Options -> Projects and Solutions -> General.

Further possibilities

I've barely scratched the surface with this template and there is far more configuration available than this blog post shows. There's a heap more to read about this topic on MSDN.