Tuesday, 26 February 2008

Live.com dead?

image

Is it just me?

[Update 18:08: it's back!]

Wednesday, 20 February 2008

The MVP presentation code

Last night, I've made some progress towards my long-overdue MVP series of articles, by rewriting what I had to adopt the same format as the presentation I did yesterday at the London .net user group.

As promised, here's the code from last night. Stay tuned for the articles.

Thanks to the surprisingly large audience, and thanks to those that came to me to say they were reading this blog. I still get quite shocked when people tell me they saw a specific article I've written.

To be fair I still get shocked when people remember my name the second time they see me, as I'm sadly quite the opposite and have a lot of trouble remembering people by name.

Anyway, enjoy the code in its roughest form, nearly no comments in there, and still no powerpoint slides :)

File iconCaffeineIT.ShoppingList.zip

MacBook Air and Windows Vista x64

For the masochists amongst you, two tips when installing Vista 64bits on a MacBook Air:

  • The mouse drivers don't work initially. Just rollback to the microsoft drivers and execute the multitouch install manually from the apple folder (the 64 one!)
  • The video drivers need to be downloaded from Intel. The latest GMA drivers will do.
  • The wireless network card is wrongly recognized. Go and download Broadcom's drivers from HP at http://h10025.www1.hp.com/ewfrf/wc/softwareDownloadIndex?softwareitem=ob-53245-1&lc=en&cc=us&dlc=en&product=3185028&os=228&lang=en
    You need to extract the files, and do a manual installation (Let me select... and Choose a location in the wizzard) and *ignore* the warning about windows not being able to match the driver to your hardware. It's the right one (select the 802.11n draft version of the driver in the list)

And now some pictures of the unboxing.

IMG_0042 IMG_0043IMG_0044IMG_0045

The full installation from boot to first screen (including me typing the product key) came at a whopping 32 minutes. I'm so impressed with how snappy everything feels that I'm thinking of either replacing my main drive on the MacBook Pro by a Solid state drive (as soon as a 128G gets out) or just doing my development on the MacBook Air!

Monday, 18 February 2008

PowerShell one-liners for svn

A bit of CLI love (and I'm sure my readers will correct me fairly quickly with something much smaller and better!), for those like me that wish they never had to use tortoise.

Adding all files that are not in the repository

svn st | %{ if ($_ -match "\?\s+(.*)") { svn add $matches[1] } }

Removing the dreaded bin and obj folders if you did an add by accident

ls -i bin,obj -recurse | % { svn revert $_ -R }

And to exclude all the stuff you put in your .svnignore (and that one works with any shell)

svn propset svn:external . -F .svnignore -R

Enjoy!

Wednesday, 13 February 2008

A life-saver for one-button developers

http://codebetter.com/blogs/jean-paul_boodhoo/archive/2008/02/12/another-handy-shortcut-combination-shift-f10.aspx

I got used to use the menu system with the keyboard to compensate for the trackpad on my macbook pro not having a usable right click (the double tap behavior is erratic at best and unusable). Shift-F10 is going to make my life so much easier!

[Update: I just realized this shortcut works for any application. I should really increase my keyboard shortcut proficiency, especially as I don't seem to have enough space for my mouse anymore in the office...]

Thursday, 7 February 2008

Follow-up on the OnXxx anti-pattern

[Started updating the previous entry, but the reply is chunky enough to go in its own post]

One person on the dotnet-clr mailing list has highlighted, quite accurately, that the RaiseXxxEvent method should really take EventArgs as a parameter instead of a string to ensure it can be swapped with a class inheriting from EventArgs. If you want that kind of extensibility, then yes, put an EventArgs as a parameter. I should update the sample.

A second person in the comments vehemently disagree with my point, so let's go for a simple rebuttal, as I do not believe the arguments to be accurate.

The first part is that the pattern, to be deemed acceptable, should be OnXxx(object src, EventArgs ea).  I have nothing else to say but to point with every single of my examples as none of them seems to "get" the right way of declaring OnXxx. As for this way to be the right way, I've not found any other reference to support Peter's argument.

The Design Guidelines for Developing Class Libraries does mention the void delegateType(object source, eventargs e) signature for event handlers, not for event raisers. As for event raisers, here's a big quote from the same source.

Do use a protected virtual method to raise each event. This is applicable only to non-static events on unsealed classes, not to structures, sealed classes, or static events.

Complying with this guideline allows derived classes to handle a base class event by overriding the protected method. The name of the protected virtual (Overridable in Visual Basic) method should be the same as the event name prefixed with On. For example, the protected virtual method for an event named "TimeChanged" is named "OnTimeChanged".

Important Note:

Derived classes that override the protected virtual method are not required to call the base class implementation. The base class must continue to work correctly even if its implementation is not called.

Do use a parameter that is typed as the event argument class to the protected method that raises an event. The parameter should be named e.

Let's see:

  • protected virtual method for non-static events on unsealed classes: Checked
  • the virtual method *should* be prefixed by On. This is non normative, so I'm still within the guideline: Checked
  • The last bit is quite clear: to be within the guideline, the raise method would be Raise(EventArgs e), and not take an object as the first argument: Checked (after having updated the previous post)

Indeed, the second part talks about passing a string instead of an EventArg, this came from typing quickly an example rather than the focus of the pattern, but point taken and resolved.

The third part is interesting. The reader is oblivious to the fact that the event raising method is called RaiseXxxEvent. Missing the italics is an easy mistake to make so let's move on. Apparently OnClear is a rat hole because it doesn't follow the right pattern (neither do the others as said before, and worst, neither does the design guideline...) OnClear with any other argument can mean anything but OnClear(object, EventArgs) can only mean one thing. So in this case, using On can have several meanings and it's fine, but in the case of Raise, you may never know if someone cannot confuse RaiseTheMountain and RaiseGoingUpEvent, so it's not acceptable. I'll assume the whole diatribe is based on the EventArgs confusion and the use of a string, and the missing Event suffix, so I think the point is clear.

So I'll summarize the argument I made extensively: OnXxx is implemented widely but implemented widely wrongly across mscorlib, asp.net, winforms and WPF. It has a double meaning as either raising (as per the design guidelines) or handling (as per people's use of it). The examples in the previous post show that without . Furthermore, the asp.net language use OnXxx to autowire events to event handlers, just like html events.

The confusion is enough that I choose to split the pattern in two methods with clear intent: HandleXEvent to handle an event, RaiseXEvent to raise an event. And even by doing so, I still adhere to the design guidelines issued by Microsoft. If you find this more confusing than OnXxx, I'm just lost for words.

Making the case against OnXxx

[Updated the code sample for the raising event method. See my response to the comments that were made.]

Some people, like Jeremy, really don't like events. I have to admit having a nearly-fanatic interest in good event patterns. One of such patterns I've seen used and misused continuously is the OnXxx pattern. Let's have a quick look at what the MSDN gods have to say about this.

You raise the event by calling the protected OnEventName method in the class that defined the event, or in a derived class. The OnEventName method raises the event by invoking the delegates, passing in any event-specific data. The delegate methods for the event can perform actions for the event or process the event-specific data.

Note:
The protected OnEventName method also allows derived classes to override the event without attaching a delegate to it. A derived class must always call the OnEventName method of the base class to ensure that registered delegates receive the event.

When you want to handle events raised in another class, you add delegate methods to the event.

So far so good. Let's open reflector and check how well is this pattern implemented. First candidate (selected through my advanced AI randomisation algorythm called click until you find a class with an OnXxx patern), FileSystemWatcher.

protected void OnChanged(FileSystemEventArgs e)

{

    FileSystemEventHandler onChangedHandler = this.onChangedHandler;

    if (onChangedHandler != null)

    {

        if ((this.SynchronizingObject != null) && this.SynchronizingObject.InvokeRequired)

        {

            this.SynchronizingObject.BeginInvoke(onChangedHandler, new object[] { this, e });

        }

        else

        {

            onChangedHandler(this, e);

        }

    }

}

So far so good. Let's stay within mscorlib (just in case the pattern was team specific), and have a look at DictionaryBase.

protected virtual void OnClear()

{

}

Oh. Where's the event call? Let's see what the method is described as doing.

Performs additional custom processes before clearing the contents of the DictionaryBase instance.

Wait a second, I thought we were supposed to use OnXxx for raising events, not to change stuff. Ok, let's move on to the ado.net team, and have a look at DataSet, and for the same price I give you not one but two methods.

protected internal void RaisePropertyChanging(string name)

{

    this.OnPropertyChanging(new PropertyChangedEventArgs(name));

}

protected virtual void OnPropertyChanging(PropertyChangedEventArgs pcevent)

{

    if (this.onPropertyChangingDelegate != null)

    {

        this.onPropertyChangingDelegate(this, pcevent);

    }

}

Alright... Now I'm getting quite confused. I can call RaiseXxx(name) which in turns call the proper OnXxx pattern that calls the event. This is now getting quite messy. Let's see what the guys in the asp.net team do with the DataSourceControl.

protected virtual void RaiseDataSourceChangedEvent(EventArgs e)

{

    this.OnDataSourceChangedInternal(e);

    this.OnDataSourceChanged(e);

}

Note that both OnXxx are now private methods... At least in DataSet you have two ways to do the same thing, one legal and one not legal (again, according to the msdn documentation). Not convinced yet? Ok, let's see what the Winforms guy have been doing and have a look at Control. I'll point to two examples.

[EditorBrowsable(EditorBrowsableState.Advanced)]

protected virtual void OnNotifyMessage(Message m)

{

}

And example 2.

[EditorBrowsable(EditorBrowsableState.Advanced)]

protected void RaisePaintEvent(object key, PaintEventArgs e)

{

    PaintEventHandler handler = (PaintEventHandler)base.Events[EventPaint];

    if (handler != null)

    {

        handler(this, e);

    }

}

Note that the OnPaint event exists and does mostly the same thing. Isn't it great to have that much flexibility? Ok, last but not least, let's see what the latest greatest brings us with WPF's UIElement.

public void RaiseEvent(RoutedEventArgs e)

{

    if (e == null)

    {

        throw new ArgumentNullException("e");

    }

    e.ClearUserInitiated();

    this.RaiseEventImpl(e);

}

protected virtual void OnMouseLeave(MouseEventArgs e)

{

}

Can you make any sense of the OnXxx notation? No? Me neither, neither do my developers. So I hereby propose (again) to just get done with it already and *aknowledge* that OnXxx is an anti-pattern used either for raising or for handling events, is overused and misused, and should die a long and painful death. I propose the simpler and more semantically correct syntax:

public class DoingEventsProperly

{

    public DoingEventsProperly()

    {

        this.SomethingChanged += HandleSomethingChangedEvent;

    }

    public event EventHandler<PropertyChangedEventArgs> SomethingChanged = (src, ea) => { };

 

    protected virtual void RaiseSomethingChangedEvent(PropertyChangedEventArgs e) { SomethingChanged(this, e); }

 

    protected virtual void HandleSomethingChangedEvent(object src, PropertyChangedEventArgs ea) { }

}

What this class achieves is covering all the scenarios we just encountered.

  • The event handler is defaulted to an empty anonymous method, so it cannot be null, which means RaiseSomethingChangedEvent doesn't need to check for null.
  • The semantic of the RaiseXxxEvent method is simple: It raises the event. Want to cancel the event? Override RaiseXxxEvent.
  • The semantic of HandleXxxEvent is simple: It aint raising the event! Want to do some stuff in your class when the event is raised, override that method.

And it's also easy to explain: Call it Raise when you're Raising an event and call it Handle if you're handling an event. I think the semantic complexity is achievable.

I may go into the other patterns such as explicitly cancelable events for consumers and explicitly cancelable by contract for inheritance cancellation another day.

And remember: The best way to combat an anti-pattern is to stop using it.

Monday, 4 February 2008

alt.net - Some comments and ideas

[Updated: Toned down a few sentences as they were more emotional than necessary.]

I've been holding back from commenting as there's been a lot happening and I probably need a few more days before my mind is set, both on the technicalities we discussed, on the process, and on the ideas. For today I'll focus on the alt.net movement, and on the conference. I'l leave the technical stuff for later.

Communities, user groups and is the existing structure working for alt.net

There's been strong suggestions that user groups are enough to cover the scope of alt.net. The concepts behind alt.net have been up for discussion, but by their nature, they need a small kernel of focused people discussing what is doable, what the state of affairs are and how to convince people to take the alternative route of innovation. We need people to challenge, and for that they need to have a forum in which they can progress and advance ideas.

The wider communities existing today seems to me a perfect place to distill those ideas, but maybe they're not the right place for defining them. Doing that necessitate people knowing about the subject, the technologies and the commercial realities to break the all <insert your favourite software vendor> approach. Only from those reflections can it be distilled to user groups, in the more typical presentation style that is common to those groups.

The good

This conference had good less good sessions. The good sessions were the ones where people sat down and discussed in an open format each subject. Having Roy Osherove in a room discussing why mocks are not always a good idea and can lead to brittle tests, and question the constraints imposed on testing because of the first generation of mocking frameworks was fantastic. But what was fantastic was not having someone taking over the room to present his own agenda or switch the room into demonstration mode, where an individual does most of the talking. The spirit was very much a relaxed opened session where everyone contributed what they had to say.

The bad

The REST discussion was interesting, but dragged on longer than necessary. The discussion was very much focused on one presenter doing most of the talks, and I felt that by the time others had the opportunity to discuss their solutions, the room was tired, and people started leaving. To a certain extent I guess I can only blame myself for not having prepared material and moving the discussion more towards the points I was interested in, so I can't blame anyone, but it felt more like a presentation or an ask the expert session than the discussion that happened in other sessions.

Overall, I think the demonstrations that were done didn't add anything to the talk, as I do not believe most of the room saw the light of content type negotiation through yet another wiki demo. That said, I aplaud Alan for pushing this part of the HTTP spec, something that I've also been trying to get through for quite a few years. Other people had stuff to show and by then it was too late. Maybe those demonstrations should overall be discouraged to keep the focus on the discussion.

The ugly

As for the ugly, in the becoming a better developer, the discussion became quite wide on the challenges we face. I discussed, maybe too much, a recent case where one of my clients revoked my contract for a wide range of reasons. I highlighted the fact, during that session, that having a forum where developers can explain their worst experiences, share them with others, is probably a good idea to relief that feeling you get that you're the only one it happened to. Getting fired or being the scapegoat on a project happened to most contractors. Hence why the suggestion was made that maybe AA-like meetings for us guys to talk about the struggles we face in a safe haven would be good therapy.

The issue there is that maybe some people have over-inflated egos and refuse to talk about it, because it would tarnish their carefully crafted image. I assumed this session was a safe haven into which I could have those kind of discussions, without fearing consequences.

Only a few hours later  at the pub, we were discussing my inbox email filtering policy. I may blog about it in more details later on, but I filter email based on recipients, to/cc lists, if its a reply or not, and split those incoming emails in sub folders. The lowest priority I read when I have time at the end of the day, the medium is read when i have time (usually lunch), and only the very few emails getting straight to my inbox get read immediately and treated in a GTD way.

However, one of the person present during that session, I hope fuelled by the copious amount of beer that was consumed by all parties involved, saw fit to reply to me, after a couple of exchanges explaining that my email policy couldn't work, that my views on emails maybe were why I got fired. This is low. Furthermore, it made me wonder if that person had to resort to mentions of my previous failures because they ran out of arguments or because they were making a point. Maybe repeating the same thing three times is not an argument anyway. But more than that, this breaks the safe haven I talked about a few paragraphs earlier. Explaining my struggles with some clients should never come back to bite me back, especially not by an organizer that is supposed to help IT people deal with those issues.

I for one will know to avoid discussing those issues if I don't have the guarantee of a safe haven. I did express my complete dismay at his comments and that it was quite out of order, and got an apology for hurting my feelings. I accepted the apology even though my feelings in this matter are nearly as irrelevant as the comment that was made. Moving on.

Maybe the relevant point in all this is the reflection on why the situation got that bad. I think it may all come down to learning how to let go. Maybe as a contractor sometimes I should not push so hard when I see a project failing, and let it fail the way the manager wants it to fail. Maybe the constant push against decisions I deem bound to failure are not my place to take. Overall, when bad decisions are taken continuously, I should learn to quit and either get on with it, or more likely break my contract and find a client that wants to listen to what I have to say.

The question still pending is, what is the right forum to discuss failures? I find that contractors are especially frisky when talking about their mistakes and their failures, maybe by fear for their public image, or maybe because they've had the situation I just encountered and it hit them back. Who knows. It shouldn't be this complicated when we're all in the same boat. And personality conflicts are not going to help us much.

Conclusion

I'll focus on the technical discussions that happened as I try to remember them this week. There's been very good points raised that each should have their own entries, and the first will probably be about REST and my open implementation of UriTemplate for .net 2. I've learnt from others and their views, and have questioned my own views. I wish the conference would've spanned two days.

I'd like to thank the people that came, the organizers for their hard work (always nice to see Z and Ian, and I'm going to follow up on my promise to come to the london .net user group.) Thank to Conchango and Redgate (special mention to Michelle for always making sure I had a beer, for better or worse, and to Ben for such a lovely evening on Friday, and hope he recovered from that hangover). It's been a great experience.

Technorati Tags: ,,

Saturday, 2 February 2008

alt.net Conference day 1

My hotmail is back apparently... we'll never know what happened. At the alt.net conference this morning... Early start after a very late evening. There are damn smart people in here, very uplifting.

Here's the sessions I'm going to attend:

  • REST / SOAP / MVC and what it all means for services
  • Mocking, is it a good idea? (you know it's one of my pet peeves)
  • How to become a better developer and spread the alt.net ideas
  • DSL and fluent interfaces...

They're the bits I proposed in each of the topic-based subjects that are being grouped together...

It's my opinion that we should've had probably less topics proposed, and the decision on what stays and what doesn't should've been taken by the people that are here rather than pre-organized. It makes people passively vote for sessions with less self-organization. But maybe British people are just less proactive and expansive than our American counterparts.

Technorati Tags: ,,

Friday, 1 February 2008

Apparently I'm a spammer - Hotmail closes my account!

[Update: Hotmail reactivated the account within 24 hours. I do like a bit of drama...]

My hotmail account has been suspended... If you've tried to reach me on seb@serialseb.com from this morning, I'm in the hands of some sort of automatic processing that believes I'm a spammer... My account has been closed!

Considering the only emails I send are to my family, my work and the alt.net community, and that's at most 20 emails a day, you start wondering what the heck is going on!

I'll keep you posted. If anyone is working at hotmail, a bit of help would be appreciated!

Oh well, I'll have some road stories for the alt.net conference in a few hours. For the Londoners see you there!

Thursday, 31 January 2008

Comparing serializations, or why Flash Remoting is not as efficient as some would imply

[Updated: Added reference to which classes were being used. The DataContractJsonSerializer is part of the .net 3.5 release.]

There's been a few discussions recently about the cost of using JSON against using Flash Remoting. Its a fact of life to have to discuss those issues when you work with a lot of Adobe people, especially when you're the Microsoft guys.

One of the discussions is around the performance of JSON and Flash Remoting. There is the BlazeBench application that would imply AMF wins hands down in every configuration. BlazeDS is a Java server that Adobe is apparently open-sourcing, but me being an asp.net guy, I wanted to see for myself what all this meant.

You see, in terms of architecture, you will always have a service layer, be it in the shape of a REST api, SOAP endpoints or a flash remoting object that pulls DTOs for display by the application. The difference between each of those solutions is going to be in the serialization mechanism you use. So I wrote a small application that compares the time it takes to serialize objects using the following:

I've not done anything special to optimise any scenario and the object graph is the same. I serialize 1,000, 10,000 and 100,000 graphs with each of the serializers, everything is built first before running the test, everything is serialized to a MemoryStream.

This is what i get.

image

The big surprise for me was the binary serialization using BinaryFormatter, which is nearly as slow as the XmlSerializer.

More important for this study, the serialization cost of the WCF JSON serializer is only 300 milliseconds, for 100,000 objects.

With those results in hand, I will argue that there is no real performance gaps between WCF JSON, Flash AMF and XML DataContracts. Even with the asp.net AJAX extensions JSON serializer, the cost of serializing your graph is probably going to be a fraction of the cost of retrieving such an object graph from a database.

If anyone wants the source code, I'll be more than happy to publish it, provided my client allows it.

Wednesday, 30 January 2008

PowerShell: Opening explorer in the current directory

[Update again]
As a reminder that my readers are usually much more skilled than I am, two anonymous commenter points out the obvious:

ii .

or

ii $pwd

Never thought of that. It's just beautiful. Thanks! The second commenter has been chatting with me through the messenger control, and points out that Start-Process is only available if you have PowerShell Commnity Extensions... A fact I missed completely. I stand twice corrected.

I've not blogged any PowerShell scripts for a while... I very often navigate around in PowerShell, but sometimes you want to switch to a graphical view. That's exactly what this script does (note it only works on the file system though...)

function Open-Explorer { Start-Process $(get-location) }

Enjoy!

Technorati Tags: ,,

Thursday, 24 January 2008

Software that sucks #2: How to not write a patch

Most of you have probably already tried using the source server support in vs2008 for the .net framework code ScottGu announced (it was, after all, 8 days ago...) In it, it's recommended to add a hotfix.

When you try installing it, you get an installation failed notification. If you view the report (generated as a local html document with scripts, running from the local drive, and as such with script deactivated by default, stupid thing number 1), you see the following:

Returning IDOK. INSTALLMESSAGE_ERROR [Error [1].An installation package for the product [2] cannot be found. Try the installation again using a valid copy of the installation package '[3]'.: 1706Microsoft Visual Studio 2008 Professional Edition - ENU]

As a guess, the valid copy of the installation package has the same name as the download from MSDN from which my copy of visual studio comes from. A message in the forums confirms the need for the physical media (or iso) to be present.

So there, my second award for software that sucks comes to the hotfix installer. Next time, a review on how badly the Hotmail outlook add-in sucks.

Thursday, 17 January 2008

The latest in the family...

http://www.apple.com/macbookair/

Ordered. Because I need an ultra lightweight to test the battery life and solid state drive implications for Windows development. And because I had to. Tried resisting all week, and today I failed.

Wednesday, 26 December 2007

An article on writing templated WPF custom controls

This is something that we had to discover with reflector when I wrote the Excel-like control we used for the National Express WPF application, so it's good to see people writing about it, especially when it's Charles Petzold in msdn magazine.

An additional thing you might want to do is have properties defining the templates for different sub-elements used by defining a dependency property of type DataTemplate. You may also want to create new sub-controls, e.g. a CellPresenter, that you can add to the template to define where in the template other components of your control will get injected.

That should probably be an article in its own right. Maybe this weekend if I recover from my sore throat.

Tuesday, 25 December 2007

Merry Christmas

While some would consider Christmas as a catholic feast, I'll consider myself the Santa Claus, Christmas tree, tinsels, balls, presents and big dinners as having no fundamental Christian ties. It's a pagan feast and as such, merry Christmas to all men on earth, whatever their religion.

Friday, 21 December 2007

XamlPadX V3.0

Lester just announced (well, on Wednesday but I have a big backlog because I spend my time reading the alt.net chat) XamlPadX 3.0. I know we didn't use the tool on my previous WPF projects, but I think it's the only XAML quick and easy tool that has seen an update recently. Will need to have a play during the festive season!

Thursday, 20 December 2007

As a follow-up on the mocking issue

Over there on CodeBetter.com, David Hayden has posted something about Model-View-Presenter that is a typical example of the confusion I was talking about in my post on why mock frameworks suck.

The interface wasn't mocked, what David did was to create a test double (a fake or a stub depending on how you look at it, but not a mock!) using a mock framework. Again, I don't object on the use of the mock framework (see my previous entry as to where my objection is), but I think we're muddying the water for everybody if we don't get the semantics correct.

Or am I really the only one thinking you should use the right tool for the right job?

Sunday, 16 December 2007

Why Mock frameworks rock

Ayende just commented on my post about writing delegate-based test doubles. He  rightfully highlights that through the method I've described, it becomes clunky to write interaction testing. I'll quote my previous post.

To sum it up, mocks are used when you want to test how your object interacts with another object, that's interaction testing, whereas all the others are used when you want to actually test your object's functionality

Let's forget the discussion about the value of interaction testing and mocks in general for a second. If you do decide to test how your object interacts with one of its dependencies, you're writing a mock and then using a mock framework makes sense. The API used will let you test the interaction conditions much faster than writing code. For example, making sure Initialize() is called only one, you'd have to write a fake using the following.

[Test]

public void InitializeIsCalledOnce()

{

    FakeConfigurationProvider provider = new FakeConfigurationProvider();

    int callCount = 0;

    provider.Initialize = () => { callCount++; };

 

    ClassThatDoesSomething obj = new ClassThatDoesSomething(provider);

    Assert.AreEqual(1, callCount);

}

As you can see, it's entirely doable, but it's starting to get a bit clunky.

The only reason why you wouldn't want to use a mock framework to do such interaction testing is when your dependency is provided by someone that provided a test harness.

Maybe that's where one day we'll be, with developers of a component providing you with a pre-written fake that, based on configuration, will throw at you any possible error combination, and check in which order and how often you called methods for each use-case you have. We're not there yet (or at all) but providing a component and a test harness for the users of that component seems to me a more long-term solution.

There is the question of the intrinsic value of interaction-based testing. In some cases, it is a requirement, in others it's not. Let's say my component has an Initialize() method. What is its behavior when you call it twice? It could be that the object is reinitialized transparently (if it has no side efects), or it could be that the object throws when initialization has already been done. In the second case you don't need a mock. In the first one your tests will catch any introduced error for any non-trivial task (lost a transaction, file handle gone). You could check that an Insert method only calls the repository class twice. But if you test a select after an insert and you get back two objects, you have a failing test.

The interesting question is, what if you don't detect an error, and the Insert method is idempotent. I'd have a tendency to think that those conditions, where you use an object in the wrong way and obtain the right results are probably of lower priorities than other tests. I'd never suggest you shouldn't test that, I'd suggest that writing those tests have probably lower priority than tests in the rest of the system.

Finally, in my last post I highlight the fact that writing your double using delegates, you can provide a default implementation that reacts the way you want, and you can replace the call with specific code on a per-test basis. I'd argue that in those conditions Mock frameworks will have a harder time providing the same level of features. Do you really want to redefine your mock every time? Do you really just want your mock to throw or return a simple value?

The point of my previous post was to suggest that Mock frameworks are over-used and not leveraged for what they are really good at. And they really shine when the objects you depend on don't have a behaviour that lets you receive errors when the caller is not respecting the documentation: done in the right order / too often, etc.

Mocks are a great tool, but shouldn't be used all the time as a general solution to writing tests. You have to pick the right tool for the right job.

Thursday, 13 December 2007

Why Mock frameworks suck, and how to write delegate-based test doubles

There is a big rift in test-oriented developers about when or how to use mocks, what the difference between a mock, a stub, a fake and a dummy is, and what mock frameworks bring to the game. I won't bore everyone with my explanation of the differences, Martin Fowler is well known for formulating patterns better than anyone else, so I'll point you to his Mocks aren't stubs article. I'll also point to Roy Osherove that has a much more simplified entry about the topic titled Mocks and stubs - The difference is in the flow of information.

To sum it up, mocks are used when you want to test how your object interacts with another object, that's interaction testing, whereas all the others are used when you want to actually test your object's functionality, which I'll consider to be unit testing. Interaction testing depends on more than one area of expertise as it involves your mock being called, and because I don't consider the mock part of the unit, I'd argue that you're not testing a unit.

In the case where you write the code from the ground up, I strongly believe there is no real reason to use mocks, as you can bake dependency injection, interfaces and fakes in your API from the ground-up. When trying to put old code under test however, mocks are a valid approach.

image The gray area is when you want to replace one of your dependencies and use a mock framework to implement a fake. Let's take an example that's quite common, abstracting configuration information. Your first step would be to implement an interface that wraps the initialisation and the property you want to retrieve, which we'll call IConfigurationProvider.

One way I often see being employed is using a Mock framework to do the heavy lifting of implementing the code. As such you'll often see code that looks like the following.

IConfigurationProvider provider = Mocks.DynamicMock<IConfigurationProvider>();
 
Expect.Call(provider.ContentLocation).PropertyBehavior();
Expect.Call(provider.Initialize()).IgnoreArguments().Throw(new ConfigurationException());

My main issue with code like this is the use of a domain language to write code. You see, what you're doing is providing an implementation of an interface, but rather than write the code, we use a mock to write... Well, code. Let's see what it takes to write a fake implementation.

public class FakeConfigurationProvider : IConfigurationProvider
{
    public string  ContentLocation
    {
        get { return null; }
    }
 
    public bool  Initialize()
    {
        throw new ConfigurationException();
    }
}

Obviously that's much more code. Or is it? Let's see a character count:

  • Mock code
    • Characters (no space): 220
    • Characters (with spaces): 260
  • Fake code
    • Characters (no spaces): 163
    • Characters (with spaces): 220

As you can see, what seems at first to be a more compact syntax is actually more verbose. Furthermore, you use an API to write code. I'd say that writing a fake using a mock framework is as useful as writing your unit tests by using reflection.

PS: I'm no Rhino expert and I expect someone to give me a more compact syntax if there's one so I can update this code.

Some people will argue that you can use the Stub<T> method with RhinoMocks to achieve the same with less code. I'd reply that creating my FakeConfigurationProvider once will ensure the same logic implementation is used in every single test that leverage the fake. To which mock fanatics will reply that you will want to change the implementation of one method for a specific test, and my way of writing fakes will create a new class for each test.

So here's my response, and the trick I use very often when writing my tests. We'll use a .net feature that doesn't get used very often, explicit interface implementation, coupled with delegates. For each of the methods in my class, I'll declare a delegate, a public property of the delegate type, together with a value (the default implementation), and finally I'll explicitly implement the interface and call the delegate property. Code speaks better than prose, so here it is.

public class FakeConfigurationProvider : IConfigurationProvider
{
    // Delegate types
    public delegate void InitializeDelegate();
    public delegate string get_ContentLocationDelegate();
 
    // Defining fields for our delegates
    public InitializeDelegate Initialize = delegate { return; };
    public get_ContentLocationDelegate get_ContentLocation = delegate { return null; };
 
    // Implementing our interface
    bool IConfigurationProvider.Initialize()
    {
        Initialize(); // calls the delegate!
    }
 
    string IConfigurationProvider.ContentLocation
    {
        get { return get_ContentLocation(); }
    }
}

Note that by default I don't do anything on Initialize. We'll inject the exception throwing later.

This fake is made up of more code, but the flexibility and clarity gains in your tests is enormous. To proove it, let's create a quick object that uses our configuration provider.

public class ClassThatDoesSomething

{

    public string ContentLocation { get; private set; }

 

    public ClassThatDoesSomething(IConfigurationProvider provider)

    {

        try

        {

            provider.Initialize();

            ContentLocation = provider.ContentLocation;

        }

        catch (ConfigurationException) { }

    }

}

And now let's write a test for the default case where everything goes according to plans in our Initialize method and nothing throws.

[Test]

public void CreatingTheClassSucceeds()

{

    FakeConfigurationProvider provider = new FakeConfigurationProvider();

    ClassThatDoesSomething obj = new ClassThatDoesSomething(provider);

    Assert.IsNotNull(obj); // will never be null anyway, keeping the Assert for more obvious expressiveness

}

As you can see if you run this test, the default implementation of my fake for that method doesn't throw. Now let's see how we can change this to throw exceptions. I've used C# 2.0 delegate notation, with the C# 3.0 notation commented out.

[Test, ExpectedException(typeof(ArgumentException))]

public void CreatingTheClassFailsWhenExceptionIsThrown()

{

    FakeConfigurationProvider provider = new FakeConfigurationProvider();

    provider.Initialize = delegate { throw new ArgumentException(); };

    // C# 3.0 Syntax is shorter:

    // provider.Initialize = () => { throw new ArgumentException(); };

 

    ClassThatDoesSomething obj = new ClassThatDoesSomething(provider);

    Assert.IsNotNull(obj); // will never be null as if something throws we won't reach the assert

}

It only took me one line of code to redefine the implementation of my method. Best of all, I use C# to implement my code rather than use the RhinoMock API. Better yet, I can reuse my default fake implementation to be a fully functional in-memory object that reacts as expected, and inject exceptions in any of the methods of my fake object, which is much more reusable. Even better yet, I'm still enjoying compile-time checks that are not applied with any mock framework.

As someone once said, when I see Mocks being used, I reach for my revolver. You've learned already that the test is written in C#, you know your documentation is (primarily) your tests, now learn that code that replaces code is better done in code!