Sunday, 31 May 2009

Internal DSLs, method chaining and discoverability

Paul says “The whole .NET space has gone fluent interface crazy”, and he is quite right. Everybody has their own fluent interfaces, and unless I’m missing the bigger picture, most of them seem to be about productivity over discoverability. The intent is clear, write more intent-revealing code in less time.

More often than not however, you multiply the entry points needed to be known by developers. Let’s take an example with the criteria API in nHibernate.

return Session.CreateCriteria(typeof(FundingCategory), "fc")
   
.CreateCriteria("FundingPrograms", "fp")
   
.CreateCriteria("Projects", "p", JoinType.LeftOuterJoin)
   
.Add(Restrictions.Disjunction()
       
.Add(Restrictions.Eq("fp.Recipient.Id", recipientId))
       
.Add(Restrictions.Eq("p.Recipient.Id", recipientId))
   
)
   
.SetProjection(Projections.ProjectionList()
       
.Add(Projections.GroupProperty("fc.Name"), "fcn")
       
.Add(Projections.Sum("fp.ObligatedAmount"), "fpo")
       
.Add(Projections.Sum("p.ObligatedAmount"), "po")
   
)
   
.AddOrder(Order.Desc("fpo"))
   
.AddOrder(Order.Desc("po"))
   
.AddOrder(Order.Asc("fcn"))
   
.List<object[]>();
[nitpicker corner: no one ever said the criteria api was a fluent api, it’s at most method chaining.]

I’ve highlighted in red those entry points. Each of those method usually takes an instance of an interface. A static method is then used to create those objects. What’s the issue with that?

It all comes down to discoverability. One of the biggest issue I’ve always had with the criteria API is the low discoverability of those types. Take the ICriterion interface, for which the Expression class provides the simple criterions. The only way, once in a method, for me to know that where it expects ICriterion I could use Expression is by going to the documentation. This is for me a massive discoverability failure.

The second issue comes from the latest lambda-based APIs. Let’s have a bit of code from the original blog post from Dru that Paul was referring to.

  1.  static TestDeployment()  
  2.     {  
  3.         Define(() =>  
  4.             {  
  5.                 During(Web, (p) =>  
  6.                     {  
  7.                         p.OnServer("WebServer")  
  8.                             .IisSite("Apps")  
  9.                             .VirtualDirectory("dashboard")  
  10.                             .Verify()  
  11.                             .CreateIfItDoesntExist();  

I’ve not downloaded the code to have a play, but I assume that Define and During are actually properties on the base type. On a positive note, this does help with discoverability, at the cost of enforcing an inheritance hierarchy.

So why do I feel awkward with this syntax? The nesting of lambdas. The multiplication of p, x and other one-letter prefix make the code much less readable. The pen*s operator is not exactly my favourite addition to the C# compiler.

Here’s my checklist for what constitutes a nice usable fluent API. [nitpicker corner: OpenRasta doesn’t do it that way everywhere. You didn’t say the same thing six months ago].

  • No lambda-based chaining
  • No multi-line lambda expressions
  • At most one or two static class entry-points to discover
  • Method parameters should only be primitive types

There is a way to make a fluent API while respecting those points, but I believe the result would be better. So here’s Dru’s example rewritten using those guidelines.

using(Definition)
{
    During.Web
        .Server("WebServer")
            .Has.IisSite("Apps")
                .VirtualDirectory("dashboard")
                .Verify()
                .CreateIfItDoesntExist()
        .And
        .Server("SvrTopeka19")
            .Has.Msmsq()
                .PrivateQueueNamed("mt_subscriptions")
                .CreateIfItDoesntExist()
        .And
        .CopyFrom(@".\code_drop\dashboard\**\*.*").To(@"\\webserver\apps\dashboard\");
}

The main difference here is the introduction of scoping operators. The Server method returns two properties, And which closes the current Server scope, and Had Has which open a new service-specific scope.

I find this kind of API much more readable, and they introduce less syntax noise (aka no lambda operators or blocks). There is also no need to introduce external points of references, be them be properties or static classes, except for the original entry point. Arguably, they’re harder to write, but I think the effort is worth the benefits.

Thursday, 21 May 2009

Summer speaking schedule, AltNetBeers, the alt.net conference, oh my!

Wow, who would’ve thought the first conference season would’ve been so intense! I had an absolute blast meeting people, presenting, chatting away and drinking nice beers with so many interesting people! WebDD, DDD Scotland and DDD Belfast have been a blast!

I also realize that I’ve delivered all the talks and workshops I announced in my last schedule, so time for an update, both on my talks and on the interesting conferences and events that are being organized.

  • Thursday 28th May – London (DNUG)
    Presenting WebForms vs. MVC, with my dear friend Phil Winstanley
  • Wednesday 17th June
    Organizing AltNetBeers #8 (Glass House in Soho)
  • Tuesday 23nd June – Bracknell (VBUG)  
    Wednesday 24th June – Cork (IT@cork)  
    Thursday 25th June – Dublin (Agile Ireland)

    Presenting When agile goes bad: how to stay calm and move forward
  • Tuesday 14th July – Nuneaton (VBUG)
    Presenting When agile goes bad: how to stay calm and move forward
  • Thursday 15th July – London (Skills Matter – OpenSource.net exchange)
    Presenting What OpenRasta does other frameworks can’t
  • Friday 31st July – Sunday 2nd August
    The alt.net conference weekend with the AltNetBeers #10 – Conf edition I’m organizing
  • Monday 17th August – Coventry (NxgGenUG)
    @serialseb’s MVC Best Practices
  • Wednesday 19th August – London (The Edge User Group – formerly known as VistaSquad)
    When agile goes bad: how to stay calm and move forward

There you go. May have more to announce if things happen, or may not, but it’s going to be a busy summer!

How some agencies make it hard to trust them

I just received an email from Computer People, telling me “we agreed that I would keep in touch and update you with any further opportunities and developments around SharePoint”. I’m pretty sure that’s factually inaccurate, as I have very little interest in SharePoint development and certainly wouldn’t agree on the phone to be contacted for marketing reasons. But fair enough, if it was to help me find new clients, I wouldn’t be that bothered. But no! It’s to try and sell me sharepoint seminars! For Christ’s bullocks’ sake!

So off to my sent items, in which I keep years and years of emails (roughly since 2001), and of course I find absolutely no mention of that Dan Freshwater that just sent me an email, so emails are out.

Leaves only their website, maybe I subscribed to that and forgot to check the “do not contact me for marketing purposes” option. Although I’m very anal about always making sure I check that box, on paper forms or online, mistake is human so I may have not seen it. Or maybe it wasn’t there. Who knows.

The email goes on to try and sell me a seminar for SharePoint. So off to the website to check Computer People’s privacy policy, and here’s what I found.

You can exercise the right at any time by contacting us at Legal Services, 71 Elstree Way, Borehamwood, Hertfordshire, WD6 1WD.

What, legal services doesn’t have computers? Designing an option in your profile was too hard? Or are you making this difficult on purpose? Seeing as you lost my trust at the very beginning by saying I asked to receive marketing information about SharePoint, I’ll go for the last option.

Email was sent asking to not ever receive marketing emails again. We shall see if it has an effect, and I’ll be sure to report.

Wednesday, 6 May 2009

Yet another reason to love TestDriven.net

As I was coding some new tests for the container integration part of OpenRasta (which, since beta 2 changes, has become much more complicated…), I discovered a feature I didn’t even realize was there.

I use abstract test classes so that each container that OpenRasta supports automatically gains any new tests that verify the behaviour of the container matches OR’s expectations. In an abstract test, the test class that contains the test is marked abstract, and you inherit from that class for each specific set of tests you can run. I’ve used that trick for a long time, and was one of the main reasons why I didn’t like MSTest much, as it seems the guys in Redmond didn’t support that scenario.

So here I was, coding away in an abstract class, and frenetically executing the test as I added code (something I remapped to Ctrl+T, T). Then it dawned on me that I was attempting to execute the abstract class. But surely, an abstract class can’t be instantiated I told myself.

And then I realized what was happening. TD.net was simply executing the concrete classes inheriting from my test class. Sweet.

PS: I have no idea if it’s the runner or nunit, and have no idea either if other runners will or won’t execute this scenario. It just works and that makes me happy :)

Tuesday, 5 May 2009

My MVC Best Practices talk

I’ve given that talk in quite a few places, and always promise to post the slides on my blog. But in fact, I was secretly waiting for the VistaSquad video to be released.

Thanks to Ian Smith, you can now see it all, complete with slides and excessive arm waving.

Vista Squad: MVC Best Practices By Ian Smith
View in HD  Download Version  Visit Ian Smith's ExposureRoom Videos Page

Monday, 4 May 2009

London AltNetBeers #8 – 12th of May, Back to the pub

The next AltNetBeers is going to be on the 12th of May!

Drinks and food will be provided by our two sponsors, SkillsMatter and ThoughtWorks, big thanks to them for helping our community strive!

We’re moving venue for a while, and we’ll be organizing this one at the GlassHouse, on 55 Brewer Street.


View Larger Map

So we can plan ahead, please register for the event at http://ukdotnet.ning.com/events/london-altnetbeers-8