<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>.net alternatives</title>
        <link>http://geekswithblogs.net/alternativedotnet/Default.aspx</link>
        <description>by Michel Grootjans</description>
        <language>en-US</language>
        <copyright>Michel Grootjans</copyright>
        <managingEditor>michel.grootjans@gmail.com</managingEditor>
        <generator>Subtext Version 0.0.0.0</generator>
        <image>
            <title>.net alternatives</title>
            <url>http://geekswithblogs.net/images/RSS2Image.gif</url>
            <link>http://geekswithblogs.net/alternativedotnet/Default.aspx</link>
            <width>77</width>
            <height>60</height>
        </image>
        <item>
            <title>Quo vadis .net community?</title>
            <category>.net</category>
            <link>http://geekswithblogs.net/alternativedotnet/archive/2011/09/20/146964.aspx</link>
            <description>&lt;p&gt;Originally posted on: &lt;a href='http://geekswithblogs.net/alternativedotnet/archive/2011/09/20/146964.aspx'&gt;http://geekswithblogs.net/alternativedotnet/archive/2011/09/20/146964.aspx&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Are you passionate about your job? Do you enjoy programming? Do you think you're any good at it?&lt;br /&gt;
&lt;br /&gt;
One of the things that make me productive as a developer are the tools and products I use. However, these tools seem to try and grab all my attention. When I go to a conference, or read a blog entry, I'm bombarded with them: Windows 8, Visual Studio 11, TFS, WCF, Silverlight, MEF, OData, Lightswitch, LabManagement, NuGet, ... it just doesn't stop, and I know I will never be able to keep up with all of them. And I really don't need to. Most of them will be obsolete in a few years. Some of them will pass the test of time, and those will get my full attention ... in a few years.&lt;br /&gt;
&lt;br /&gt;
On the other hand, if you care about your craft, you know that the things that make you  good are the principles, the practices and the patterns you've learned over  the years. You're also painfully aware of the gaps in your own  knowledge, and that's why you're continuously on the lookout for  like-minded colleagues to exchange war stories, experiences and  practices.&lt;br /&gt;
&lt;br /&gt;
An &lt;a href="http://www.agileminds.be/event/5"&gt;upcoming event in Ghent&lt;/a&gt; is going to focus on that side of our developers life: agile minds is trying to bring .net professionals together to share their stories. And you know what: &lt;a href="http://www.agileminds.be/event/5/registration"&gt;there are still tickets available&lt;/a&gt;. I'd like to advise all professional .net developers who are passionate about their craft, to seriously consider joining in this new initiative. If you contact me personally, I can get you a EUR 50.00 discount.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;The Agile .Net Europe is a community platform for people who care about writing the right thing in the right way. &lt;/b&gt;&lt;/p&gt; &lt;img src="http://geekswithblogs.net/alternativedotnet/aggbug/146964.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Michel Grootjans</dc:creator>
            <guid>http://geekswithblogs.net/alternativedotnet/archive/2011/09/20/146964.aspx</guid>
            <pubDate>Tue, 20 Sep 2011 19:59:53 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/alternativedotnet/comments/146964.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/alternativedotnet/archive/2011/09/20/146964.aspx#feedback</comments>
            <wfw:commentRss>http://geekswithblogs.net/alternativedotnet/comments/commentRss/146964.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/alternativedotnet/services/trackbacks/146964.aspx</trackback:ping>
        </item>
        <item>
            <title>Is focusing on quality stealing from the customer?</title>
            <category>design</category>
            <category>Personal</category>
            <link>http://geekswithblogs.net/alternativedotnet/archive/2011/05/15/145348.aspx</link>
            <description>&lt;p&gt;Originally posted on: &lt;a href='http://geekswithblogs.net/alternativedotnet/archive/2011/05/15/145348.aspx'&gt;http://geekswithblogs.net/alternativedotnet/archive/2011/05/15/145348.aspx&lt;/a&gt;&lt;/p&gt;&lt;p&gt;We had a crisis in our team last week. One of our teammates left.&lt;br /&gt;
&lt;br /&gt;
It all started off with a discussion while pairing on a task with John (not his real name). I found a method did not belong in a certain class, while John didn't care, but didn't want to change it. We started a discussion that ended up into a heated debate about code quality. The two positions were:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;having readable code leads to a higher velocity&lt;/li&gt;
    &lt;li&gt;checking in code that just works gets us to the deadline&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;During the sprint retrospective, this event got a lot of attention, and we decided to see if we could modify our &lt;a href="http://www.scrumalliance.org/articles/105-what-is-definition-of-done-dod"&gt;Definition of Done&lt;/a&gt; to ease this kind of discussions. We tried to come up with a short description of an activity that would not be too constraining, while keeping the focus we wanted.&lt;/p&gt;
&lt;blockquote&gt;"Commit code that is readable enough for three pair of eyes"&lt;br /&gt;
&lt;/blockquote&gt;
&lt;p&gt;John found that this activity did not belong in the DoD.&lt;br /&gt;
John's argument can be summed up as this. When code works, the customer is happy. The customer doesn't see the "quality" of the code, and he doesn't care. Code quality is subjective. Beauty is in the eye of the beholder. We have deadlines to meet, and these should be our first priority. Refactor code when you have time. On a Friday afternoon after a retrospective, when you're not in a hurry to jump into the next traffic jam. So if the code is not looking good enough, so be it. Move on.&lt;br /&gt;
&lt;br /&gt;
The team voted to add this activity to the DoD of a user story. &lt;br /&gt;
The team's point of view is that a story is not done until it is refactored well enough. This implicitly means that a story that &lt;i&gt;works&lt;/i&gt;, but whose code is &lt;i&gt;not good enough&lt;/i&gt;, will not get released and its points will not be added to the sprint's story points. This story will be taken to the next sprint, just to clean it up.&lt;br /&gt;
&lt;br /&gt;
This is the point where John decided he could not function properly in a team that held such a point of view.&lt;br /&gt;
&lt;br /&gt;
I find it amazing that a professional would quit for this reason. People usually quit because they want something better than what their current position has to offer. What is this 'better' John is looking for? Maybe this was some kind of &lt;a href="http://www.acidlabs.org/wp-content/uploads/2008/01/401556761_48e0ee0d88.jpg"&gt;resistance to change&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
I have seen plenty of projects slowing down month after month, just because of poor code quality. But I have yet to see a project fail because too much attention has been given to code quality.&lt;br /&gt;
&lt;br /&gt;
"The only way to go fast is to go well" -- &lt;a href="http://programmer.97things.oreilly.com/wiki/index.php/Speed_Kills"&gt;Bob Martin&lt;/a&gt;.&lt;/p&gt; &lt;img src="http://geekswithblogs.net/alternativedotnet/aggbug/145348.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Michel Grootjans</dc:creator>
            <guid>http://geekswithblogs.net/alternativedotnet/archive/2011/05/15/145348.aspx</guid>
            <pubDate>Sun, 15 May 2011 10:21:07 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/alternativedotnet/comments/145348.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/alternativedotnet/archive/2011/05/15/145348.aspx#feedback</comments>
            <slash:comments>7</slash:comments>
            <wfw:commentRss>http://geekswithblogs.net/alternativedotnet/comments/commentRss/145348.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/alternativedotnet/services/trackbacks/145348.aspx</trackback:ping>
        </item>
        <item>
            <title>Disable pasting in a textbox using jQuery</title>
            <category>.net</category>
            <category>design</category>
            <link>http://geekswithblogs.net/alternativedotnet/archive/2011/01/27/143662.aspx</link>
            <description>&lt;p&gt;Originally posted on: &lt;a href='http://geekswithblogs.net/alternativedotnet/archive/2011/01/27/143662.aspx'&gt;http://geekswithblogs.net/alternativedotnet/archive/2011/01/27/143662.aspx&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I had fun writing this one&lt;br /&gt;
&lt;br /&gt;
My current client asked me to allow users to paste text into textboxes/textareas, but that the pasted text should be cleaned from '&amp;lt;...&amp;gt;' tags. Here's what we came up with:&lt;/p&gt;
&lt;pre&gt;
    $(":input").bind('paste', function(e) {
        var el = $(this);
        setTimeout(function() {
            var text = $(el).val();
            $(el).val(text.replace(/&amp;lt;(.*?)&amp;gt;/gi, ''));
        }, 100);
    })
;
&lt;/pre&gt;
&lt;p&gt;This is so simple, I'm amazed. The first part just binds a function to the paste operation applied to any &lt;em&gt;input&lt;/em&gt;  declared on the page.&lt;/p&gt;
&lt;pre&gt;
$(":input").bind('paste', function(e) {...});&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;
In the first line, I just capture the element. Then wait for 100ms&lt;/p&gt;
&lt;pre&gt;
setTimeout(function() {....}, 100);&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;
then get the actual value from the textbox, and replace it with a regular expression that basically means replace everything that looks like '&amp;lt;{0}&amp;gt;' with ''. gi at the end are regex arguments in javascript.&lt;/p&gt;
&lt;pre&gt;
/&amp;lt;(.*?)&amp;gt;/gi&lt;/pre&gt; &lt;img src="http://geekswithblogs.net/alternativedotnet/aggbug/143662.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Michel Grootjans</dc:creator>
            <guid>http://geekswithblogs.net/alternativedotnet/archive/2011/01/27/143662.aspx</guid>
            <pubDate>Thu, 27 Jan 2011 16:35:23 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/alternativedotnet/comments/143662.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/alternativedotnet/archive/2011/01/27/143662.aspx#feedback</comments>
            <slash:comments>4</slash:comments>
            <wfw:commentRss>http://geekswithblogs.net/alternativedotnet/comments/commentRss/143662.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/alternativedotnet/services/trackbacks/143662.aspx</trackback:ping>
        </item>
        <item>
            <title>From Call of Duty to reading code like a poem...</title>
            <category>design</category>
            <category>Personal</category>
            <link>http://geekswithblogs.net/alternativedotnet/archive/2010/11/17/142749.aspx</link>
            <description>&lt;p&gt;Originally posted on: &lt;a href='http://geekswithblogs.net/alternativedotnet/archive/2010/11/17/142749.aspx'&gt;http://geekswithblogs.net/alternativedotnet/archive/2010/11/17/142749.aspx&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I recently bought &lt;a href="http://www.callofduty.com/blackops"&gt;Call Of Duty: Black Ops&lt;/a&gt; for the PC. It's a really realistic and challenging game, and my kids love it. However, if you want to share a gaming experience, you want to have different profiles for each player in the family. No luck with CoD:BO though. The game doesn't support mutliple profiles.&lt;br /&gt;
&lt;br /&gt;
I started looking around on the internet for known solutions and stumbled upon &lt;a href="http://mel-green.com/2010/11/call-of-duty-black-ops-multiple-profiles/"&gt;this guy&lt;/a&gt; who made his own multi-profile CoD:BO launcher. I was quick to notice that it was a .net 3.5 app, probably WPF. I quickly scanned through it with Reflecor to see if there were no obvious &lt;i&gt;virus&lt;/i&gt;-y or &lt;i&gt;phone-home&lt;/i&gt;-y hacks in it, and judged it to be OK.&lt;br /&gt;
&lt;br /&gt;
This morning, I boasted to my kids about how great their dad is: I just '&lt;i&gt;modified&lt;/i&gt;' CoD:BO to have multiple profiles. Their jaws dropped. You did what? Woooow, coool. I gotta tell this to my friends!&lt;br /&gt;
&lt;br /&gt;
That's when I realized I should stop this lie instantly. I told them I found this tool online, and that I checked the code to see if it was nothing dangerous. I even commented that it was good looking code, well written and understandable. My son turned to me with a big smile and said: &lt;/p&gt;
&lt;blockquote&gt;"Dad, you talk about code like you would about a poem"&lt;br /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;br /&gt;
Did I? Is that the way I sound to the uninitiated? Should code even read like a poem? Lets look at some online explanations, shall we ;-)&lt;br /&gt;
From: &lt;a href="http://www.poets.org/viewmedia.php/prmMID/19882"&gt;How to read a poem&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;Reading poetry well is part attitude and part technique. Curiosity is a  useful attitude, especially when it’s free of preconceived ideas about  what poetry is or should be. Effective technique directs your curiosity  into asking questions, drawing you into a conversation with the poem.&lt;br /&gt;
&lt;/blockquote&gt;
&lt;p&gt;Up until here, I think we could draw the parallel with code. Read the previous quote again, replacing &lt;i&gt;poetry&lt;/i&gt; and &lt;i&gt;poem&lt;/i&gt; with &lt;i&gt;code&lt;/i&gt;. I kinda like the sound of it.&lt;/p&gt;
&lt;blockquote&gt;... Most readers make three false assumptions when addressing an unfamiliar  poem. The first is assuming that they should understand what they  encounter on the first reading, and if they don’t, that something is  wrong with them or with the poem. The second is assuming that the poem  is a kind of code, that each detail corresponds to one, and only one,  thing, and unless they can crack this code, they’ve missed the point.  The third is assuming that the poem can mean anything readers want it to mean...&lt;br /&gt;
&lt;/blockquote&gt;
&lt;p&gt;Wow, stop. The parallel between code and poetry goes only skin deep. Code should be unambiguous and instantly understandable. Poems should invite you to read a second time, and a third time, discovering new details and meanings on each consecutive read. Maybe we should try drawing parallels between poems and requirements ;-)&lt;br /&gt;
&lt;br /&gt;
The bottom line for me is: Today, I went to work with a happy feeling inside.&lt;/p&gt; &lt;img src="http://geekswithblogs.net/alternativedotnet/aggbug/142749.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Michel Grootjans</dc:creator>
            <guid>http://geekswithblogs.net/alternativedotnet/archive/2010/11/17/142749.aspx</guid>
            <pubDate>Wed, 17 Nov 2010 21:08:08 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/alternativedotnet/comments/142749.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/alternativedotnet/archive/2010/11/17/142749.aspx#feedback</comments>
            <slash:comments>2</slash:comments>
            <wfw:commentRss>http://geekswithblogs.net/alternativedotnet/comments/commentRss/142749.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/alternativedotnet/services/trackbacks/142749.aspx</trackback:ping>
        </item>
        <item>
            <title>Ruby vs C#: hard data</title>
            <category>.net</category>
            <category>Ruby on Rails</category>
            <link>http://geekswithblogs.net/alternativedotnet/archive/2010/09/28/142016.aspx</link>
            <description>&lt;p&gt;Originally posted on: &lt;a href='http://geekswithblogs.net/alternativedotnet/archive/2010/09/28/142016.aspx'&gt;http://geekswithblogs.net/alternativedotnet/archive/2010/09/28/142016.aspx&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Have you ever tried &lt;a href="http://www.google.com/trends"&gt;google trends&lt;/a&gt;? It's a fun utility to see trends in search keywords typed in google. You can go as far back as 2004, so there's plenty of data available. You can even compare different trends.&lt;br /&gt;
&lt;br /&gt;
One of these interesting trends &lt;a href="http://pascalmestdach.blogspot.com/"&gt;Pascal&lt;/a&gt; once pointed out is c# vs ruby. Back then, this is what it looked like (c#, ruby)&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.google.com/trends?q=c%23%2C+ruby&amp;amp;ctab=0&amp;amp;geo=all&amp;amp;date=2008-11&amp;amp;sort=0"&gt;&lt;img src="http://gwb.blob.core.windows.net/alternativedotnet/moz-screenshot-1.png" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
The blue line is c#, the red line is ruby. And what do you think the regular dips are? WEEKENDS!&lt;br /&gt;
And what's more, the ruby line is close to the c# line in the weekends. Does this mean that there are almost as many ruby developers as there are &lt;i&gt;passionate&lt;/i&gt; c# developers? Maybe. It certainly seems to be a trend, but let's not be hasty about such conclusions. After all, I'm not looking for a flame war here.&lt;br /&gt;
&lt;br /&gt;
Lets look at the current trend for the same keywords:&lt;br /&gt;
&lt;a href="http://www.google.com/trends?q=c%23%2C+ruby&amp;amp;ctab=0&amp;amp;geo=all&amp;amp;date=2010-9&amp;amp;sort=0"&gt;&lt;img src="http://gwb.blob.core.windows.net/alternativedotnet/moz-screenshot-2.png" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;
 Aha, now ruby is perceptibly more popular than c# in the weekend. This data supports what I've been suspecting for a while now: Ruby is on the rise worldwide. I quite like this idea.&lt;br /&gt;
&lt;br /&gt;
Lets see what this means in our small country - Belgium:&lt;br /&gt;
&lt;a href="http://www.google.be/trends?q=c%23%2C+ruby&amp;amp;ctab=0&amp;amp;geo=be&amp;amp;date=2010-9&amp;amp;sort=0"&gt;&lt;img src="http://gwb.blob.core.windows.net/alternativedotnet/moz-screenshot-3.png" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;
Wow: 0 hits for ruby? Ok, that can't be right. Probably because searches in Belgium go through www.google.be. Tried the same on google.be =&amp;gt; same result. That probably means that the search terms for c# are WAY out of the league of Ruby in our small country. Does this mean it is time to jump on the Ruby bandwagon, because Belgium will be catching on, and now is the time to build expertise in it?&lt;br /&gt;
&lt;br /&gt;
All in all, a fun aside in trying to decipher what these numbers and graphs mean, with maybe a little confirmation bias on my part.&lt;/p&gt; &lt;img src="http://geekswithblogs.net/alternativedotnet/aggbug/142016.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Michel Grootjans</dc:creator>
            <guid>http://geekswithblogs.net/alternativedotnet/archive/2010/09/28/142016.aspx</guid>
            <pubDate>Tue, 28 Sep 2010 20:52:18 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/alternativedotnet/comments/142016.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/alternativedotnet/archive/2010/09/28/142016.aspx#feedback</comments>
            <slash:comments>6</slash:comments>
            <wfw:commentRss>http://geekswithblogs.net/alternativedotnet/comments/commentRss/142016.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/alternativedotnet/services/trackbacks/142016.aspx</trackback:ping>
        </item>
        <item>
            <title>Using NU for the first time</title>
            <category>design</category>
            <category>.net</category>
            <link>http://geekswithblogs.net/alternativedotnet/archive/2010/08/16/141338.aspx</link>
            <description>&lt;p&gt;Originally posted on: &lt;a href='http://geekswithblogs.net/alternativedotnet/archive/2010/08/16/141338.aspx'&gt;http://geekswithblogs.net/alternativedotnet/archive/2010/08/16/141338.aspx&lt;/a&gt;&lt;/p&gt;&lt;p&gt;While preparing the code for &lt;a href="http://geekswithblogs.net/alternativedotnet/archive/2010/08/16/141310.aspx"&gt;my previous post&lt;/a&gt;, I decided to try NU to get the OSS I needed for the demo. I must say it was a blast.  Ruby is required to run NU. For those who don’t have ruby on their machine, &lt;a target="_blank" href="http://rubyinstaller.org/"&gt;get the ruby installer&lt;/a&gt;. It won’t slow your system down or pollute it in any way. It’s just creating a directory of your choice for ruby, and adds a system path pointing to it.&lt;/p&gt;
&lt;p&gt;I wanted fluent Nhibernate with all it’s &lt;em&gt;compatible&lt;/em&gt; dependencies: NHibernate, Castle.core, … To get all these dependencies, all I had to do is this:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Open the command prompt&lt;/li&gt;
    &lt;li&gt;Install NU: &lt;font face="Courier New"&gt;gem install nu &lt;/font&gt;(you only need to do this once, obviously)&lt;/li&gt;
    &lt;li&gt;Navigate to the project folder: &lt;font face="Courier New"&gt;cd I:\projects\RepositoryExperiments&lt;/font&gt;&lt;/li&gt;
    &lt;li&gt;Get FluentNH and all its dependencies: &lt;font face="Courier New"&gt;nu install fluentnhibernate&lt;/font&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That’s it. My project directory now has a &lt;font face="Courier New"&gt;lib&lt;/font&gt; folder containing:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;castle.core&lt;/li&gt;
    &lt;li&gt;castle.dynamicproxy2&lt;/li&gt;
    &lt;li&gt;fluentnhibernate&lt;/li&gt;
    &lt;li&gt;log4net&lt;/li&gt;
    &lt;li&gt;nhibernate&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And it took me about 30 seconds to set this up.&lt;/p&gt;
&lt;p&gt;Way to go NU! These are the packages currently available with NU: &lt;a href="http://nu.wikispot.org/Current_Packages" title="http://nu.wikispot.org/Current_Packages"&gt;http://nu.wikispot.org/Current_Packages&lt;/a&gt;&lt;/p&gt; &lt;img src="http://geekswithblogs.net/alternativedotnet/aggbug/141338.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Michel Grootjans</dc:creator>
            <guid>http://geekswithblogs.net/alternativedotnet/archive/2010/08/16/141338.aspx</guid>
            <pubDate>Mon, 16 Aug 2010 19:23:04 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/alternativedotnet/comments/141338.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/alternativedotnet/archive/2010/08/16/141338.aspx#feedback</comments>
            <wfw:commentRss>http://geekswithblogs.net/alternativedotnet/comments/commentRss/141338.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/alternativedotnet/services/trackbacks/141338.aspx</trackback:ping>
        </item>
        <item>
            <title>An alternative repository</title>
            <category>.net</category>
            <category>design</category>
            <link>http://geekswithblogs.net/alternativedotnet/archive/2010/08/16/141310.aspx</link>
            <description>&lt;p&gt;Originally posted on: &lt;a href='http://geekswithblogs.net/alternativedotnet/archive/2010/08/16/141310.aspx'&gt;http://geekswithblogs.net/alternativedotnet/archive/2010/08/16/141310.aspx&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Since I published the state of my project goals, I got a few questions about my repository implementation, so here goes…&lt;/p&gt;  &lt;p&gt;The ‘classic’ repository interface looks like this:&lt;/p&gt;  &lt;div&gt;   &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;interface&lt;/span&gt; IRepository&amp;lt;T&amp;gt;
{
    T GetById(&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; id);
    IEnumerable&amp;lt;T&amp;gt; GetAll();
    T SaveOrUpdate(T entity);
    &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Delete(T entity);
    &lt;span style="color: #008000"&gt;//...&lt;/span&gt;
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This interface has some issues to me. First of all, it’s data-centric. I know that’s the whole point of a repository, but bear with me. Second, it exposes far too many methods. One method in particular scares me: &lt;font face="Courier New"&gt;GetAll()&lt;/font&gt;! This is the one method you REALLY don’t want to execute in production when you have massive amounts of data. And if you’re lucky, you will have a few eager fetches with a nice SELECT N+1. Yikes.&lt;/p&gt;

&lt;p&gt;The implementations of this interface tend to become a long list of different queries.&lt;/p&gt;

&lt;div&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; CustomerRepository : IRepository&amp;lt;Customer&amp;gt;
{
    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Customer GetById(&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; id) {...}
    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IEnumerable&amp;lt;Customer&amp;gt; GetAll(){...}
    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Customer SaveOrUpdate(Customer entity){...}
    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Delete(Customer entity){...}

    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IEnumerable&amp;lt;Customer&amp;gt; GetByName(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; customerName){...}
    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IEnumerable&amp;lt;Customer&amp;gt; GetByTotalOrderAmount(&lt;span style="color: #0000ff"&gt;double&lt;/span&gt; orderAmount){...}
    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IEnumerable&amp;lt;Customer&amp;gt; GetByCity(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; zipCode){...}
    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IEnumerable&amp;lt;Customer&amp;gt; GetNewCustomersSince(DateTime date){...}
    ...
}&lt;/pre&gt;
&lt;/div&gt;

&lt;h1&gt;An alternative&lt;/h1&gt;

&lt;p&gt;I’ve been looking for an alternative to this. The goals I had in mind are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;I want an easy interface to interact with the database &lt;/li&gt;

  &lt;li&gt;Every time I need a new query, I don’t want to have to add a new method to an existing object. I want a new object that encapsulates the query. &lt;/li&gt;

  &lt;li&gt;I want to be free to choose which query API call I make against NHibernate: LINQ, criteria or hql. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;A single IRepository&lt;/h2&gt;

&lt;p&gt;My &lt;font face="Courier New"&gt;IRepository&lt;/font&gt; interface is a simple one:&lt;/p&gt;

&lt;div&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;interface&lt;/span&gt; IRepository
{
    &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Add&amp;lt;T&amp;gt;(T entity);
    &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Remove&amp;lt;T&amp;gt;(T entity);
    IQueryResult&amp;lt;T&amp;gt; Query&amp;lt;T&amp;gt;(IQuery&amp;lt;T&amp;gt; query);
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;font face="Courier New"&gt;Add()&lt;/font&gt; and &lt;font face="Courier New"&gt;Remove()&lt;/font&gt; just look and feel like standard collection methods, and the implied behavior is simply forwarded to the database. Since I’m using NHibernate under the hood, there’s no need to have a &lt;font face="Courier New"&gt;Save()&lt;/font&gt; or an &lt;font face="Courier New"&gt;Update()&lt;/font&gt; statement, NHibernate’s autoflush will take care of this.&lt;/p&gt;

&lt;p&gt;The interesting part is the last method: &lt;font face="Courier New"&gt;Query()&lt;/font&gt;. This method takes a query object, and returns a query result object. When you call this method, you can do this:&lt;/p&gt;

&lt;div&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;var customer = repository.Query(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; GetCustomerByName(&lt;span style="color: #006080"&gt;"ALFKI"&lt;/span&gt;))
                         .UniqueResult();&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Lets take a closer look at the repository implementation:&lt;/p&gt;

&lt;div&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; NHibernateRepository : IRepository
{
    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Add&amp;lt;T&amp;gt;(T entity)
    {
        CurrentSession.Save(entity);
    }

    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Remove&amp;lt;T&amp;gt;(T entity)
    {
        CurrentSession.Delete(entity);
    }

    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IQueryResult&amp;lt;T&amp;gt; Query&amp;lt;T&amp;gt;(IQuery&amp;lt;T&amp;gt; query)
    {
        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; query.Execute(CurrentSession);
    }

    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; ISession CurrentSession
    {
        &lt;span style="color: #008000"&gt;// use whatever suits you ... out of scope of this post&lt;/span&gt;
    }
}&lt;/pre&gt;
&lt;/div&gt;

&lt;h2&gt;IQuery&amp;lt;T&amp;gt;&lt;/h2&gt;

&lt;p&gt;The query object can use the NHibernate query, criteria or LINQ, the repository doesn’t care. This offers several advantages:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;You only need one repository (or DAO, or whatever you want to name it) &lt;/li&gt;

  &lt;li&gt;The repository implementation doesn’t have to change every time you need a new query &lt;/li&gt;

  &lt;li&gt;You can test each query object in isolation &lt;/li&gt;

  &lt;li&gt;Your services have to reference only one repository &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lets go and take a look at what a query object implementation looks like:&lt;/p&gt;

&lt;div&gt; &lt;/div&gt;

&lt;div&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; GetCustomerByName : IQuery&amp;lt;Customer&amp;gt;
{
    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; name;

    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; GetCustomerByName(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; name)
    {
        &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.name = name;
    }

    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IQueryResult&amp;lt;Customer&amp;gt; Execute(ISession session)
    {
        var query = session.CreateQuery(&lt;span style="color: #006080"&gt;"from Customer where Name=:name"&lt;/span&gt;)
            .SetString(&lt;span style="color: #006080"&gt;"name"&lt;/span&gt;, name);
        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; QueryResult&amp;lt;Customer&amp;gt;(query);
    }
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Again, for someone familiar with NHibernate, no magical tricks here. This is where you can choose what NHibernate API you want to use. Her goes the criteria API:&lt;/p&gt;

&lt;div&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IQueryResult&amp;lt;Customer&amp;gt; Execute(ISession session)
{
    var criteria = session.CreateCriteria&amp;lt;Customer&amp;gt;().Add(Restrictions.Eq(&lt;span style="color: #006080"&gt;"Name"&lt;/span&gt;, name));
    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; CriteriaResult&amp;lt;Customer&amp;gt;(criteria);
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;And the LINQ API:&lt;/p&gt;

&lt;div&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IQueryResult&amp;lt;Customer&amp;gt; Execute(ISession session)
{
    var query = session.Linq&amp;lt;Customer&amp;gt;().Where(c =&amp;gt; c.Name == name);
    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; LinqResult&amp;lt;Customer&amp;gt;(query);
}&lt;/pre&gt;
&lt;/div&gt;

&lt;h2&gt;IQueryResult&amp;lt;T&amp;gt;&lt;/h2&gt;

&lt;p&gt;The IQueryResult&amp;lt;T&amp;gt; interface should speak for itself. Once you have performed a query against the repository, you can either get its unique result, or a list of results.&lt;/p&gt;

&lt;div&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;interface&lt;/span&gt; IQueryResult&amp;lt;T&amp;gt;
{
    T UniqueResult();
    IEnumerable&amp;lt;T&amp;gt; List();
}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;At this time of writing, you only need three implementations of IQueryResult&amp;lt;T&amp;gt;: QueryResult&amp;lt;T&amp;gt;, CriteriaResult&amp;lt;T&amp;gt; and LinqResult&amp;lt;T&amp;gt;. The implementation you choose to use is free and the decision is made inside the query object, exactly where you choose which query type you want to make.&lt;/p&gt;

&lt;div&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; QueryResult&amp;lt;T&amp;gt; : IQueryResult&amp;lt;T&amp;gt;
{
    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; IQuery query;

    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; QueryResult(IQuery query)
    {
        &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.query = query;
    }

    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; T UniqueResult()
    {
        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; query.UniqueResult&amp;lt;T&amp;gt;();
    }

    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; List()
    {
        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; query.List&amp;lt;T&amp;gt;();
    }
}

&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; CriteriaResult&amp;lt;T&amp;gt; : IQueryResult&amp;lt;T&amp;gt;
{
    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; ICriteria criteria;

    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; CriteriaResult(ICriteria criteria)
    {
        &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.criteria = criteria;
    }

    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; T UniqueResult()
    {
        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; criteria.UniqueResult&amp;lt;T&amp;gt;();
    }

    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; List()
    {
        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; criteria.List&amp;lt;T&amp;gt;();
    }
}

&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; LinqResult&amp;lt;T&amp;gt; : IQueryResult&amp;lt;T&amp;gt;
{
    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; IQueryable&amp;lt;T&amp;gt; query;

    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; LinqResult(IQueryable&amp;lt;T&amp;gt; query)
    {
        &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.query = query;
    }

    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; T UniqueResult()
    {
        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; query.First();
    }

    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; List()
    {
        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; query;
    }
}&lt;/pre&gt;
&lt;/div&gt;

&lt;h1&gt;Drawbacks of this implementation&lt;/h1&gt;

&lt;p&gt;Maybe I could split the IRepository in two: one interface for data-modifying methods (as in command - &lt;strong&gt;&lt;em&gt;C&lt;/em&gt;&lt;/strong&gt;QS), and a second interface for querying (as in Query - C&lt;strong&gt;&lt;em&gt;Q&lt;/em&gt;&lt;/strong&gt;S). At this moment I don’t see the need to do this, but it’s an idea I keep in the back of my head.&lt;/p&gt;

&lt;p&gt;One drawback to this implementation that I’m aware of: the &lt;font face="Courier New"&gt;ISession&lt;/font&gt; interface of NHibernate leaks out of the declared interfaces. And you know what: I don’t care. Don’t kid yourself, NHibernate has a huge impact on the design and architecture of the application. I’m on Ayende’s side on this one: &lt;a href="http://ayende.com/Blog/archive/2010/07/30/the-false-myth-of-encapsulating-data-access-in-the-dal.aspx" target="_blank"&gt;don’t try to abstract your DAL&lt;/a&gt;, it doesn’t work and you’ll find out too late.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Another design issue as it is implemented right now, the services querying the repository have to know the implementation of the query objects. I’m not sure this is a real drawback. Any ideas are welcome.&lt;/p&gt;

&lt;h1&gt;Code available for download&lt;/h1&gt;

&lt;p&gt;Since the whole point of this blog post was showing you some code, I posted it in a small &lt;a href="http://code.google.com/p/grootjansrepositorypattern/" target="_blank"&gt;google project&lt;/a&gt;. You can download it and run it, it works fine with SQLite in memory, no install necessary, no database required. I have a felling some of you running 64-bit might run into some problems with SQLite. Contact me if this happens.&lt;/p&gt; &lt;img src="http://geekswithblogs.net/alternativedotnet/aggbug/141310.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Michel Grootjans</dc:creator>
            <guid>http://geekswithblogs.net/alternativedotnet/archive/2010/08/16/141310.aspx</guid>
            <pubDate>Mon, 16 Aug 2010 06:00:00 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/alternativedotnet/comments/141310.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/alternativedotnet/archive/2010/08/16/141310.aspx#feedback</comments>
            <slash:comments>6</slash:comments>
            <wfw:commentRss>http://geekswithblogs.net/alternativedotnet/comments/commentRss/141310.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/alternativedotnet/services/trackbacks/141310.aspx</trackback:ping>
        </item>
        <item>
            <title>Finshed the new project</title>
            <link>http://geekswithblogs.net/alternativedotnet/archive/2010/07/26/141073.aspx</link>
            <description>&lt;p&gt;Originally posted on: &lt;a href='http://geekswithblogs.net/alternativedotnet/archive/2010/07/26/141073.aspx'&gt;http://geekswithblogs.net/alternativedotnet/archive/2010/07/26/141073.aspx&lt;/a&gt;&lt;/p&gt;Time for me to evaluate the progress on the original goals of our project. In januari, I started on a new project and set myself/the project a few goals. These goals were explicitly written down &lt;a href="http://geekswithblogs.net/alternativedotnet/archive/2010/01/27/137666.aspx"&gt;in a previous post&lt;/a&gt;. We've now finished phase 1 of the project, and I took the time to see what's left of my new year's resolutions.&lt;br /&gt;&lt;h3&gt;What's the point?&lt;/h3&gt;I believe that you can only improve and learn new things when you deliberately set yourself explicit goals. Publishing these goals for all to see has been a major incentive for me to follow them up.&lt;br /&gt;&lt;br /&gt;These are the goals I set for the project:&lt;br /&gt;&lt;h3&gt;Overall&lt;/h3&gt;&lt;blockquote&gt;- readable, intent revealing software&lt;br /&gt;- DRY, YAGNI, BOYSCOUT et all...&lt;br /&gt;&lt;/blockquote&gt;All in all, I think we've achieved this. What's even better, the team members started criticizing existing 'smelly' code with these principles in mind. I believe I planted a few good ideas that everyone will take to future projects&lt;br /&gt;&lt;h3&gt;Entities&lt;/h3&gt;&lt;blockquote&gt;- Aggregate roots have an explicit &lt;font face="monospace"&gt;interface&lt;br /&gt;&lt;/font&gt;- No ID (I'm not sure if I can pull this one off with NHibernate)&lt;br /&gt;- No (public) setters except for things like name, description, ...&lt;br /&gt;- State based tests&lt;br /&gt;- Testdata: take a look at &lt;a href="http://nbuilder.org/"&gt;NBuilder&lt;/a&gt;&lt;br /&gt;&lt;/blockquote&gt;No ID for entities was a challenge. At first all went well. Later on, NHibernate started complaining during specific queries that certain entities didn't contain an Id property. We didn't go into detail as to why that was. I intend to investigate this further, because I really liked the no-Id approach. We didn't get around to it yet.&lt;br /&gt;&lt;br /&gt;No setter in properties caused a disturbance in the team. This meant that we needed a method each time an entity had to change state. I believe this effort has paid off, because our objects encapsulate their data and behavior much better this way (go look up the 'law' of Demeter for more info). Of course, as always, 'No setters' becomes 'Almost no setters'.&lt;br /&gt;&lt;br /&gt;And we didn't get around to using NBuilder for test data. I'm not sure why, but we didn't. In the meantime, I met kilfour from &lt;a href="http://code.google.com/p/quicknet/"&gt;QuickNet&lt;/a&gt;. I think QuickNet might be a good candidate to include in our test&lt;h3&gt;Services&lt;/h3&gt;&lt;blockquote&gt;- almost no logic&lt;br /&gt;- infrastructure: queries, mapping, ...&lt;br /&gt;- hosted in spring.net&lt;br /&gt;- Behaviour based tests&lt;br /&gt;&lt;/blockquote&gt;Services in this case were WCF services. Check on all four goals. Lucky for me 'almost no logic' contained 'almost'. It's always good to set goals, but if the goal is too expensive when there is an easier alternative that doesn't '&lt;a href="http://en.wikipedia.org/wiki/Code_smell"&gt;smell&lt;/a&gt;', I apply the &lt;a href="http://en.wikipedia.org/wiki/KISS_principle"&gt;KISS&lt;/a&gt; principle.&lt;br /&gt;&lt;h3&gt;Controllers&lt;/h3&gt;&lt;blockquote&gt;- no logic&lt;br /&gt;- only view concerns&lt;br /&gt;- choice of view to render&lt;br /&gt;- navigation (redirect)&lt;br /&gt;- forward call to service&lt;br /&gt;- Behavior based tests&lt;br /&gt;- hosted in spring.net&lt;br /&gt;&lt;/blockquote&gt;Only a part of our application has a UI. The main part is web services, with a relatively small administration web site, built on &lt;a href="http://www.asp.net/mvc"&gt;asp.net mvc 2&lt;/a&gt;. Check on all goals here too. I might add that each view got it's own viewmodel. Thanks to &lt;a href="http://automapper.codeplex.com/"&gt;automapper&lt;/a&gt; for making this so easy.&lt;br /&gt;&lt;h3&gt;Repository&lt;/h3&gt;&lt;blockquote&gt;- only handles aggregate roots&lt;br /&gt;- only the following methods: add/remove/query&lt;br /&gt;&lt;/blockquote&gt;Yep, only 1 repository, not 1 per aggregate root or (god forbid) 1 per entity. This repository contains only three methods: &lt;br /&gt;&lt;font face="monospace"&gt;void Add&amp;lt;T&amp;gt;(T t);&lt;br /&gt;void Remove&amp;lt;T&amp;gt;(T t);&lt;br /&gt;IQueryResult&amp;lt;T&amp;gt; Query(IQuery&amp;lt;T&amp;gt; query); &lt;br /&gt;&lt;/font&gt;&lt;br /&gt;Add and Remove only accept IAggregateRoot entities.&lt;br /&gt;Query() accepts only query objects.&lt;br /&gt;&lt;h3&gt;Queries&lt;/h3&gt;&lt;blockquote&gt;- Separate query objects that get passed in the 'query' method of repository&lt;br /&gt;- Preference in this order: LinqToNH, Criteria, HQL. Each query object can use any querying alternative from NHibernate&lt;br /&gt;- Integration tested&lt;/blockquote&gt;Having separate query objects is something I'll try to apply on all upcoming projects. This way, we can have individual objects for each query that can be  tested in isolation.&lt;br /&gt;&lt;h3&gt;Security&lt;/h3&gt;&lt;blockquote&gt;- RhinoSecurity?&lt;br /&gt;&lt;/blockquote&gt;Nope, not needed at the moment. Security was not that big a concern... yet. This is phase 1 after all. That means phase 2 is coming up.&lt;br /&gt;&lt;h3&gt;WCF&lt;/h3&gt;&lt;blockquote&gt;- Service hosting in Spring&lt;/blockquote&gt;Works OOB with spring.net.&lt;br /&gt;&lt;h3&gt;Testing&lt;/h3&gt;&lt;blockquote&gt;- Heavy emphasis on readability&lt;br /&gt;- Intent (test) Driven Development&lt;br /&gt;- Fitnesse first (red), then unit test(R=&amp;gt;G=&amp;gt;R), integration test (R=&amp;gt;G=&amp;gt;R), Fitnesse green.&lt;/blockquote&gt;Check on all three goals. FitNesse first was a challenge, but it added a clarity to what we really wanted to accomplish in each story. In my opinion, FitNesse is a time saver when you're not sure how a feature should behave. It removes any ambiguity in the requirements before the implementation.&lt;br /&gt;&lt;br /&gt;My original goal was to have the Product Owner write at least one FitNesse test per story to guide the team. This didn't work because the PO's workload didn't allow this. As a team, we decided to continue doing FitNesse up front.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Summary&lt;/h3&gt;First of all, we had a happy customer. In my opinion, this is what matters most. The customer was happy, because this design allowed us to have a flexible system which can easily adapt to changing requirements. &lt;br /&gt;&lt;br /&gt;The team was happy too. We only had a small team of 4 people. Two of them had never heard of TDD, IoC, ORM, MVC, ... After a few weeks both became fans of this non-MSDN way of working. Retrospectives rule!&lt;br /&gt; &lt;img src="http://geekswithblogs.net/alternativedotnet/aggbug/141073.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Michel Grootjans</dc:creator>
            <guid>http://geekswithblogs.net/alternativedotnet/archive/2010/07/26/141073.aspx</guid>
            <pubDate>Mon, 26 Jul 2010 08:46:07 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/alternativedotnet/comments/141073.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/alternativedotnet/archive/2010/07/26/141073.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://geekswithblogs.net/alternativedotnet/comments/commentRss/141073.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/alternativedotnet/services/trackbacks/141073.aspx</trackback:ping>
        </item>
        <item>
            <title>Bye bye Quicksilver, hello Alfred</title>
            <category>Personal</category>
            <link>http://geekswithblogs.net/alternativedotnet/archive/2010/07/20/141004.aspx</link>
            <description>&lt;p&gt;Originally posted on: &lt;a href='http://geekswithblogs.net/alternativedotnet/archive/2010/07/20/141004.aspx'&gt;http://geekswithblogs.net/alternativedotnet/archive/2010/07/20/141004.aspx&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I've been using the application launcher &lt;a href="http://docs.blacktree.com/quicksilver/what_is_quicksilver"&gt;Quicksilver&lt;/a&gt; on my Mac for about a year and a half now. It was the first app I installed. However, with &lt;a href="http://docs.blacktree.com/quicksilver/what_is_quicksilver"&gt;Quicksilver&lt;/a&gt;, I've never been able to go further than the  basic launching of applications. Maybe it's because I didn't put much  effort in learning the tool. Maybe it's because I'm too used to the windows-based &lt;a href="http://www.launchy.net/"&gt;Launchy&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
A few days ago, I stumbled upon &lt;a href="http://www.makeuseof.com/tag/access-quicker-alfred-mac/"&gt;a review&lt;/a&gt; of an alternative launcher: &lt;a href="http://www.alfredapp.com/"&gt;Alfred&lt;/a&gt;. I downloaded and installed it. I have been using it for about a week now, and I really like it. For basic application launching, it's exactly the same keystrokes as with &lt;a href="http://docs.blacktree.com/quicksilver/what_is_quicksilver"&gt;Quiksilver&lt;/a&gt;. However, the ease of use for extra tasks is what I like about it.&lt;br /&gt;
&lt;br /&gt;
I'm ditching Quicksilver, welcome &lt;a href="http://www.alfredapp.com/"&gt;Alfred&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &lt;/p&gt; &lt;img src="http://geekswithblogs.net/alternativedotnet/aggbug/141004.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Michel Grootjans</dc:creator>
            <guid>http://geekswithblogs.net/alternativedotnet/archive/2010/07/20/141004.aspx</guid>
            <pubDate>Tue, 20 Jul 2010 10:29:08 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/alternativedotnet/comments/141004.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/alternativedotnet/archive/2010/07/20/141004.aspx#feedback</comments>
            <slash:comments>2</slash:comments>
            <wfw:commentRss>http://geekswithblogs.net/alternativedotnet/comments/commentRss/141004.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/alternativedotnet/services/trackbacks/141004.aspx</trackback:ping>
        </item>
        <item>
            <title>Teaching Principles, Patterns and Practices in .net</title>
            <category>.net</category>
            <category>Personal</category>
            <link>http://geekswithblogs.net/alternativedotnet/archive/2010/06/28/140662.aspx</link>
            <description>&lt;p&gt;Originally posted on: &lt;a href='http://geekswithblogs.net/alternativedotnet/archive/2010/06/28/140662.aspx'&gt;http://geekswithblogs.net/alternativedotnet/archive/2010/06/28/140662.aspx&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I recently got the opportunity to teach a 3 day course on the subject of "Principles, Patterns and Practices in .net". I must say it was a fun and enriching experience. I have never taught a course before, so I decided to go off the beaten path and do a little experiment in format. No need to copy existing formats that can be found everywhere else in Belgium.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;Format&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://gwb.blob.core.windows.net/alternativedotnet/23062010.jpg"&gt;&lt;img align="right" src="http://gwb.blob.core.windows.net/alternativedotnet/23062010.jpg" style="max-width: 400px;" alt="" /&gt;&lt;/a&gt;I took the excellent &lt;a href="http://www.amazon.com/First-Design-Patterns-Elisabeth-Freeman/dp/0596007124/"&gt;Head First Design Patterns&lt;/a&gt; as a guide to run through each pattern in the same way: - show an existing implementation without using a pattern; discuss the problems with the current design - a change in the requirement is introduced that will be hard to implement - refactor the existing implementation to a pattern - apply the change in requirement - discuss the applied solution - explore some alternatives - try to give an appropriate name to the applied solution  After each pattern was explained, shown and discussed, I drew a summary of the pattern on a flip-chart. These were then hung to the wall as information radiators. During later discussions, each pattern could be compared to other patterns, because easy reminders were constantly visible. A nice tool for this is 3M's &lt;a href="http://www.amazon.com/Post-Self-Stick-Easel-Inches-30-Sheet/dp/B00006IA9F/"&gt;self-stick flip-charts&lt;/a&gt;. You just draw, and hang them on the wall.  During the explaining phase, the same principles kept coming up (depend upon abstractions, encapsulate what varies, open/closed, ...). These were also added to a list on the wall as they came up. Every time we looked at a new design, these principles were used to criticize code.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;Content&lt;/h2&gt;
&lt;p&gt;The subject of design patterns is a vast one. I had to limit the content of the course, since I had only three days. You must also take into account that the human brain has not been made to absorb a lot of knowledge in a small amount of time after you graduate ;-). So I decided not only to show the most important design patterns, but to add a few related exercises to allow everyone to take on a more active role from time to time.  The first day, after lunch, we did a &lt;a href="http://codingdojo.org/"&gt;coding dojo&lt;/a&gt; for about an hour. The subject I choose was &lt;a href="http://butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata"&gt;the bowling game kata&lt;/a&gt;. This small exercise during a course on design patterns was a deliberate choice. First of all, a coding dojo loosens the atmosphere by being more informal and fun. Second, every participant got five minutes to add a significant part to the code. So no one was able to fall asleep. Third, this exercise got the message across that you don't have to reach for patterns to have a good solution. The best solution is almost always the easiest one.  The second day, after lunch, I showed the team a demo of how IoC containers and AoP can solve some of the problems they're having right now. Since I seem to be a .net dinosaur, I still use spring.net, and that's exactly what I demoed.  The third day, I tried a refactoring exercise. Lets look at a piece of existing code, criticize it and try to make it better. The choice of the example was easy. &lt;a href="http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672/"&gt;Martin Fowler's book on refactoring&lt;/a&gt; has a great one. Small enough to keep the timing, large enough to introduce a few more common refactorings.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;Source code&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://gwb.blob.core.windows.net/alternativedotnet/23062010%28001%29.jpg"&gt;&lt;img align="right" src="http://gwb.blob.core.windows.net/alternativedotnet/23062010%28001%29.jpg" style="max-width: 200px;" alt="" /&gt;&lt;/a&gt;Since everyone on the team was already using SVN for source control, I decided to host the course code on google projects. I made a trunk where all the unmodified code is stored, and a branch with all the modifications/refactorings we made during the course. Before each break, I committed the current state of the code. This allows every participant to review each piece of code &lt;a href="http://attentiappp.googlecode.com/svn/trunk/"&gt;"before"&lt;/a&gt; and &lt;a href="http://attentiappp.googlecode.com/svn/branches/Session"&gt;"after"&lt;/a&gt; patternization whenever they have time for it.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;Course material&lt;/h2&gt;
&lt;p&gt;An issue I discussed with the customer prior to starting the course was documentation. What will the participants take away from these three days? I could have written a bunch of word documents explaining each and every design patter in detail, together with diagrams and examples. I explained that this would be a pointless exercise for me, and a useless tool for the participants. I proposed to just buy the Head First book, as this is a course material of much higher value than anything I could ever produce.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;Evaluation of progress&lt;/h2&gt;
&lt;p&gt;Being an agilist, I couldn't refrain from applying agile ideas to this course. On the first day, I let the team enumerate all the patterns they had ever heard of. Lucky for me, these were all patterns that I prepared. I wrote them all down on yellow stickies, and put them in the "ToDo" section of the whiteboard. I counted the number of patterns hanging there and drew a burndown: 3 days on the x-axis, 13 patterns to go on the y-axis. Every time that a pattern was over, I moved the pattern to the "Done" section. At every break, I updated the burndown.  This allowed us to evaluate our progress, and decide to touch on particular problems the team was having with existing projects.  At the end of each day, we also held a small retrospective. This allowed me  to fine-tune my teaching method or speed.   All in all, it was a great experience. I enjoyed it tremendously, and I believe the participants did too.&lt;/p&gt; &lt;img src="http://geekswithblogs.net/alternativedotnet/aggbug/140662.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Michel Grootjans</dc:creator>
            <guid>http://geekswithblogs.net/alternativedotnet/archive/2010/06/28/140662.aspx</guid>
            <pubDate>Mon, 28 Jun 2010 21:03:40 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/alternativedotnet/comments/140662.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/alternativedotnet/archive/2010/06/28/140662.aspx#feedback</comments>
            <slash:comments>2</slash:comments>
            <wfw:commentRss>http://geekswithblogs.net/alternativedotnet/comments/commentRss/140662.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/alternativedotnet/services/trackbacks/140662.aspx</trackback:ping>
        </item>
        <item>
            <title>The theory of evolution applied to software</title>
            <category>design</category>
            <link>http://geekswithblogs.net/alternativedotnet/archive/2010/05/11/139762.aspx</link>
            <description>&lt;p&gt;Originally posted on: &lt;a href='http://geekswithblogs.net/alternativedotnet/archive/2010/05/11/139762.aspx'&gt;http://geekswithblogs.net/alternativedotnet/archive/2010/05/11/139762.aspx&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I recently realized the many parallels you can draw between the theory of evolution and evolving software.&lt;/p&gt;
&lt;p&gt;Evolution is not the proverbial million monkeys typing on a million typewriters, where one of them comes up with the complete works of Shakespeare. We would have noticed by now, since the proverbial monkeys are now blogging on the Internet ;-)&lt;/p&gt;
&lt;p&gt;One of the main ideas of the theory of evolution is the balance between random mutations and natural selection. Random mutations happen all the time: millions of mutations over millions of years. Most of them are totally useless. Some of them are beneficial to the evolved species. Natural selection favors the beneficially mutated species. Less beneficial mutations die off. The mutated rabbit doesn't have to be faster than the fox. It just has to be faster than the other rabbits.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;table border="1"&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td&gt;&lt;strong&gt;Theory of evolution&lt;/strong&gt;&lt;/td&gt;
            &lt;td&gt;&lt;strong&gt;Evolving software&lt;/strong&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Random mutations happen all the time. Most of these mutations are so bad, the new species dies off, or cannot reproduce.&lt;/td&gt;
            &lt;td&gt;Developers write new code all the time. New ideas come up during the act of writing software. The really bad ones don't get past the stage of &lt;em&gt;idea&lt;/em&gt;. The bad ones don't get committed to source control.&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Natural selection favors the beneficial mutated species&lt;/td&gt;
            &lt;td&gt;Good ideas and new code gets discussed in group during informal peer review. Less than good code gets refactored. Enhanced code makes it more readable, maintainable...&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;A good set of traits makes the species superior to others. It becomes widespread&lt;/td&gt;
            &lt;td&gt;A good design tends to make it easier to add new features, easier to understand the current implementations, easier to optimize for performance...thus superior.          &lt;br /&gt;
            The best designs get carried over from project to project. They appear in blogs, articles and books about principles, patterns and practices.&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Of course the act of writing software is deliberate. This can hardly be called &lt;em&gt;random mutations&lt;/em&gt;. Though it sometimes might seem that code evolves through a will of its own ;-)&lt;/p&gt;
&lt;p&gt;Does this mean that evolving software (evolution) is better than a big design up front (creationism)? Not necessarily. It's a false idea to think that a project starts from scratch and everything evolves from there. Everyone carries his experience of what works and what doesn't. Up front design is necessary, but is best kept simple and minimal, just enough to get you started. Let the good experiences and ideas help to drive the process, whether they come from you or from others, from past experience or from the most junior developer on your team.&lt;/p&gt;
&lt;p&gt;Once again, balance is the keyword. Balance design up front with evolution on a daily basis. How do you know what balance is right? Through your own experience of what worked and what didn't (here's evolution again).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Notes:&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The evolution of software can quickly degenerate without discipline. TDD is a discipline that leaves little to chance on that part. Write your test to describe the new behavior. Write just enough code to make it behave as specified. Refactor to evolve the code to a higher standard.&lt;/p&gt;
&lt;p&gt;The responsibility of good design rests continuously on each developers' shoulders. Promiscuous pair programming helps quickly spreading the design to the whole team.&lt;/p&gt; &lt;img src="http://geekswithblogs.net/alternativedotnet/aggbug/139762.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Michel Grootjans</dc:creator>
            <guid>http://geekswithblogs.net/alternativedotnet/archive/2010/05/11/139762.aspx</guid>
            <pubDate>Tue, 11 May 2010 19:59:25 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/alternativedotnet/comments/139762.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/alternativedotnet/archive/2010/05/11/139762.aspx#feedback</comments>
            <slash:comments>2</slash:comments>
            <wfw:commentRss>http://geekswithblogs.net/alternativedotnet/comments/commentRss/139762.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/alternativedotnet/services/trackbacks/139762.aspx</trackback:ping>
        </item>
        <item>
            <title>Third coding dojo</title>
            <category>Ruby on Rails</category>
            <link>http://geekswithblogs.net/alternativedotnet/archive/2010/03/03/138315.aspx</link>
            <description>&lt;p&gt;Originally posted on: &lt;a href='http://geekswithblogs.net/alternativedotnet/archive/2010/03/03/138315.aspx'&gt;http://geekswithblogs.net/alternativedotnet/archive/2010/03/03/138315.aspx&lt;/a&gt;&lt;/p&gt;&lt;p&gt;We just did our third coding dojo today. Just to keep things interesting, we did it in Ruby this time. The whole thing has been done on a Mac with TextMate.&lt;br /&gt;
&lt;br /&gt;
The topic we set off to implement was a game of darts. More specifically, what combination of throws gets you to win if you have to throw a 2, or a 3,  or a 4, ... &lt;br /&gt;
The constraints are:&lt;br /&gt;
- a single throw can score 1..20 singled, doubled or tripled. Center is 50.&lt;br /&gt;
- you can only throw 3 darts&lt;br /&gt;
- the last throw has to be a double or a 50&lt;br /&gt;
&lt;br /&gt;
Keep in mind that (except for me) noone had ever written any Ruby. Noone had ever programmed on a mac (that means there is no HOME, INSERT, CTRL-C/V working). Even with these limitations, within 1h30, we got a good parial solution working:&lt;br /&gt;
- single throw solutions up to 40 (double 1 for 2, double 2 for 4, double 3 for 6, ... double 20 for 40).&lt;br /&gt;
- two darts thrown with a single score on the first throw.&lt;br /&gt;
&lt;br /&gt;
These are the tests we got working.&lt;br /&gt;
&lt;font face="Courier New"&gt;A game of darts with a remainig score of 2&lt;br /&gt;
- has 1 winning combination&lt;br /&gt;
- wins with 'dubbel 1'&lt;br /&gt;
A game of darts with a remaining score of 3&lt;br /&gt;
- has 1 winning combination&lt;br /&gt;
- wins with '1, dubbel 1'&lt;br /&gt;
A game of darts with a remaining score of 4&lt;br /&gt;
- has 2 winning combinations&lt;br /&gt;
- wins with 'dubbel 2'&lt;br /&gt;
- wins with '2, dubbel 1'&lt;br /&gt;
A game of darts with a remaining score of 6&lt;br /&gt;
- has 3 winning combinations&lt;br /&gt;
- wins with '2, dubbel 2'&lt;br /&gt;
- wins with '4, dubbel 1'&lt;br /&gt;
- wins with '2, dubbel 2'&lt;br /&gt;
A game of darts with a remaining score of 40&lt;br /&gt;
- wins with 'dubbel 20'&lt;br /&gt;
A game of darts with a remaining score of 41&lt;br /&gt;
- wins with '1, dubbel 20'&lt;br /&gt;
A game of darts with a remaining score of 42&lt;br /&gt;
- wins with '2, dubbel 20'&lt;br /&gt;
A game of darts with a remaining score of 60&lt;br /&gt;
- wins with '20, dubbel 20'&lt;br /&gt;
&lt;/font&gt;&lt;br /&gt;
The tests were written in RSpec, and run with autotest. Everyone agreed that autotest is really a fun way to get instant feedback on what effect you're having on the code every time you change a tiny amount of code.&lt;br /&gt;
&lt;br /&gt;
This is what a typical test would look like:&lt;br /&gt;
&lt;font face="Courier New"&gt;describe "A game of darts" do&lt;br /&gt;
  before(:each) do&lt;br /&gt;
    @game = GameOfDarts.new&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  context "with a remainig score of 2" do&lt;br /&gt;
    before(:each) do&lt;br /&gt;
      @&lt;/font&gt;&lt;font face="Courier New"&gt;game&lt;/font&gt;&lt;font face="Courier New"&gt;.score 2&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it "has 1 winning combination" do&lt;br /&gt;
      @&lt;/font&gt;&lt;font face="Courier New"&gt;game&lt;/font&gt;&lt;font face="Courier New"&gt;.winning_combinations.length.should == 1&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    it "wins with 'dubbel 1'" do&lt;br /&gt;
      @&lt;/font&gt;&lt;font face="Courier New"&gt;game&lt;/font&gt;&lt;font face="Courier New"&gt;.winning_combinations.should include "dubbel 1"&lt;br /&gt;
    end&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
&lt;/font&gt;And this is what our implementation looks like (after some cleaning up):&lt;br /&gt;
&lt;font face="Courier New"&gt;class GameOfDarts&lt;br /&gt;
  def score value&lt;br /&gt;
    @score = value&lt;br /&gt;
    @combinations = []&lt;br /&gt;
    calculate_combinations&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def winning_combinations&lt;br /&gt;
    @combinations&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def calculate_combinations&lt;br /&gt;
    half_score = @score / 2&lt;br /&gt;
    (1..half_score).each{ |double_throw| add_combination_for(double_throw) }&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  def add_combination_for double_throw&lt;br /&gt;
    single_throw = @score - 2 * double_throw&lt;br /&gt;
    @combinations &amp;lt;&amp;lt; format_score(single_throw, double_throw)&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  def format_score first_throw, last_throw&lt;br /&gt;
    return "dubbel #{last_throw}" if first_throw == 0&lt;br /&gt;
    "#{first_throw}, dubbel #{last_throw}"&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;/font&gt;&lt;br /&gt;
After the dojo, we held a little retrspective. This is what came out of it:&lt;br /&gt;
&lt;u&gt;Keep doing&lt;br /&gt;
&lt;/u&gt;- Switch programmer every 5 min&lt;br /&gt;
- Test driven implementation&lt;br /&gt;
- To the audience: SHUT UP!&lt;br /&gt;
- 9 of us showed up&lt;br /&gt;
- Discovered a new feature of rspec: &lt;font face="Courier New"&gt;@&lt;/font&gt;&lt;font face="Courier New"&gt;game&lt;/font&gt;&lt;font face="Courier New"&gt;.winning_combinations.should &lt;b&gt;include&lt;/b&gt; "dubbel 1"&lt;/font&gt;&lt;br /&gt;
- booze and food were on site ;-)&lt;br /&gt;
- good location&lt;br /&gt;
- retrospective&lt;br /&gt;
&lt;br /&gt;
&lt;u&gt;Start doing&lt;br /&gt;
&lt;/u&gt;- think about the choosen algorithm BEFORE the choice. This excercise was perceived as being too hard for a dojo where both the language, the OS and the editor were new&lt;br /&gt;
- doodle the meeting before choosing a date&lt;br /&gt;
- invite aliens (java devs typically don't seem to show up)&lt;br /&gt;
- do a &lt;a href="http://codingdojo.org/cgi-bin/wiki.pl?PreparedKata"&gt;Prepared Kata&lt;/a&gt; for max 15 mins&lt;br /&gt;
- timebox the whole session to end at 20:00&lt;br /&gt;
- timebox the retrospective&lt;br /&gt;
- hand out stickies during the session to prepare retrospective remarks&lt;br /&gt;
&lt;br /&gt;
&lt;u&gt;Stop doing&lt;br /&gt;
&lt;/u&gt;- going overtime on the 5 minutes limit per developer&lt;/p&gt;
&lt;div class="zemanta-pixie"&gt;&lt;img src="http://img.zemanta.com/pixy.gif?x-id=dec5bc10-2ed1-893f-9bd1-8686a3810b21" alt="" class="zemanta-pixie-img" /&gt;&lt;/div&gt; &lt;img src="http://geekswithblogs.net/alternativedotnet/aggbug/138315.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Michel Grootjans</dc:creator>
            <guid>http://geekswithblogs.net/alternativedotnet/archive/2010/03/03/138315.aspx</guid>
            <pubDate>Wed, 03 Mar 2010 22:17:03 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/alternativedotnet/comments/138315.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/alternativedotnet/archive/2010/03/03/138315.aspx#feedback</comments>
            <wfw:commentRss>http://geekswithblogs.net/alternativedotnet/comments/commentRss/138315.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/alternativedotnet/services/trackbacks/138315.aspx</trackback:ping>
        </item>
        <item>
            <title>Learning to use slim instead of fit to run FitNesse</title>
            <category>.net</category>
            <category>FitNesse</category>
            <link>http://geekswithblogs.net/alternativedotnet/archive/2010/01/31/137726.aspx</link>
            <description>&lt;p&gt;Originally posted on: &lt;a href='http://geekswithblogs.net/alternativedotnet/archive/2010/01/31/137726.aspx'&gt;http://geekswithblogs.net/alternativedotnet/archive/2010/01/31/137726.aspx&lt;/a&gt;&lt;/p&gt;&lt;p&gt; &lt;/p&gt;
&lt;p&gt;In our new project, we've decided to use FitNesse with slilm. All in all, slim is an improvement over fit.&lt;/p&gt;
&lt;p&gt;The thing I like most is the error messages when running tests. These are now much clearer than with fit.&lt;/p&gt;
&lt;p&gt;The fixtures are now plain old objects (that's poo -- you can call them pojo, poco or even pono for all I care). So no dependency anymore on fit.&lt;/p&gt;
&lt;p&gt;Slim is also supposed to run faster, but right now our project is not really big enough to notice the difference.&lt;/p&gt;
&lt;p&gt;There's two things I don't like about slim.&lt;/p&gt;
&lt;p&gt;First, when writing scripts (the old &lt;font face="Courier New"&gt;DoFixture&lt;/font&gt;) or queries (the old &lt;font face="Courier New"&gt;RowFixture&lt;/font&gt;), you have to tell that to the wiki by prefixing the table with the corresponding keyword (&lt;font face="Courier New"&gt;|script|&lt;/font&gt; or &lt;font face="Courier New"&gt;|query|&lt;/font&gt;). This adds a technical touch to a wiki page that should be customer facing. I like to think about the wiki pages as requirements that are being elaborated by examples and scenario's. These keywords are technical cruft that get in the way of getting the functional message across. There's a little trick to hide the first row of each table however. Just add a # in front of the row, and all these technical details are gone.&lt;/p&gt;
&lt;p&gt;The second thing I don't like bothers me more. The query fixture is now harder to implement than the previous &lt;font face="Courier New"&gt;RowFixture&lt;/font&gt;. In fit, you could return a list of any arbitrary objects, the column names would magically match any property or field for the items in the list. Now you have to do that work yourself by providing a list of objects. Each item then has to hold a list of properties, which in turn are lists of two items: column name and string value.&lt;/p&gt;
&lt;p&gt;After looking around, my co-presenter &lt;a target="_blank" href="http://pascalmestdach.blogspot.com/"&gt;Pascal&lt;/a&gt; found an &lt;a target="_blank" href="http://rhjensen.com/wiki/index.php?title=SimpleReflectionQuery"&gt;alternative that uses reflection&lt;/a&gt;. This is the API to use this utility.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; font-family: consolas,'Courier New',courier,monospace; color: black; font-size: 8pt;"&gt;
var people = ...&lt;span style="color: rgb(0, 128, 0);"&gt;//get the list of results for the queryList&amp;lt;object&amp;gt; results = new List&amp;lt;object&amp;gt;();&lt;/span&gt;
&lt;span style="color: rgb(0, 0, 255);"&gt;foreach&lt;/span&gt; (var person &lt;span style="color: rgb(0, 0, 255);"&gt;in&lt;/span&gt; people)
{
    results.Add(AddObjectToQueryResult(person));
}
&lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt; results;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Being the geek that I am, I couldn't resist the urge to try to improve this. I ended up with something like this: &lt;/p&gt;
&lt;div&gt;
&lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; font-family: consolas,'Courier New',courier,monospace; color: black; font-size: 8pt;"&gt;
var people = ...&lt;span style="color: rgb(0, 128, 0);"&gt;//get the list of results for the queryList&amp;lt;object&amp;gt; results = new List&amp;lt;object&amp;gt;();&lt;/span&gt;
&lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt; people.CreateRowFixture()
    .AddColumn(&lt;span style="color: rgb(0, 96, 128);"&gt;"FullName"&lt;/span&gt;, dto =&amp;gt; dto.FirstName + &lt;span style="color: rgb(0, 96, 128);"&gt;" "&lt;/span&gt; + dto.LastName)
    .ToList();&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="http://agileacceptancetesting.googlecode.com/files/SlimUtilities.zip"&gt;Here is a link to the full code with tests on google code&lt;/a&gt;.&lt;/p&gt; &lt;img src="http://geekswithblogs.net/alternativedotnet/aggbug/137726.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Michel Grootjans</dc:creator>
            <guid>http://geekswithblogs.net/alternativedotnet/archive/2010/01/31/137726.aspx</guid>
            <pubDate>Sun, 31 Jan 2010 16:05:14 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/alternativedotnet/comments/137726.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/alternativedotnet/archive/2010/01/31/137726.aspx#feedback</comments>
            <wfw:commentRss>http://geekswithblogs.net/alternativedotnet/comments/commentRss/137726.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/alternativedotnet/services/trackbacks/137726.aspx</trackback:ping>
        </item>
        <item>
            <title>Starting up a new project</title>
            <link>http://geekswithblogs.net/alternativedotnet/archive/2010/01/27/137666.aspx</link>
            <description>&lt;p&gt;Originally posted on: &lt;a href='http://geekswithblogs.net/alternativedotnet/archive/2010/01/27/137666.aspx'&gt;http://geekswithblogs.net/alternativedotnet/archive/2010/01/27/137666.aspx&lt;/a&gt;&lt;/p&gt;We're nearing the end of our second iteration on a new project. I started out by setting myself a few goals to explore. I'd like to write them down here, so I can come back in a few months to see what remains of them. You're welcome to comment on these goals.&lt;br /&gt;&lt;br /&gt;Overall&lt;br /&gt;- readable, intent revealing software&lt;br /&gt;- DRY, YAGNI, BOYSCOUT et all...&lt;br /&gt;&lt;br /&gt;Entities:&lt;br /&gt;- IAggregate root has interface&lt;br /&gt;- No ID (I'm not sure if I can pull this one off with NHibernate)&lt;br /&gt;- No (public) setters except for things like name, description, ...&lt;br /&gt;- State based tests&lt;br /&gt;- Testdata: take a look at &lt;a href="http://nbuilder.org/"&gt;NBuilder&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Services&lt;br /&gt;- almost no logic&lt;br /&gt;- infrastructure: queries, mapping, ...&lt;br /&gt;- hosted in spring.net&lt;br /&gt;- Behaviour based tests&lt;br /&gt;&lt;br /&gt;Controllers&lt;br /&gt;- no logic&lt;br /&gt;- only view concerns&lt;br /&gt;- choice of view to render&lt;br /&gt;- navigation (redirect)&lt;br /&gt;- forward call to service&lt;br /&gt;- Behavior based tests&lt;br /&gt;- hosted in spring.net&lt;br /&gt;&lt;br /&gt;Repository&lt;br /&gt;- only handles aggregate roots&lt;br /&gt;- only the following methods: add/remove/query&lt;br /&gt;&lt;br /&gt;Queries&lt;br /&gt;- Separate query objects that get passed in the 'query' method of repository&lt;br /&gt;- Preference in this order: LinqToNH, Criteria, HQL&lt;br /&gt;- Integration tested&lt;br /&gt;&lt;br /&gt;Security&lt;br /&gt;- RhinoSecurity?&lt;br /&gt;&lt;br /&gt;WCF&lt;br /&gt;- Service hosting in Spring&lt;br /&gt;&lt;br /&gt;Testing&lt;br /&gt;- Heavy emphasis on readability&lt;br /&gt;- Intent (test) Driven Development&lt;br /&gt;- Fitnesse first (red), then unit test(R=&amp;gt;G=&amp;gt;R), integration test (R=&amp;gt;G=&amp;gt;R), Fitnesse green&lt;br /&gt;&lt;br /&gt;&lt;div class="zemanta-pixie"&gt;&lt;img class="zemanta-pixie-img" alt="" src="http://img.zemanta.com/pixy.gif?x-id=845b7a98-9624-8c82-a74a-6f5046bae01e" /&gt;&lt;/div&gt; &lt;img src="http://geekswithblogs.net/alternativedotnet/aggbug/137666.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Michel Grootjans</dc:creator>
            <guid>http://geekswithblogs.net/alternativedotnet/archive/2010/01/27/137666.aspx</guid>
            <pubDate>Wed, 27 Jan 2010 22:58:41 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/alternativedotnet/comments/137666.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/alternativedotnet/archive/2010/01/27/137666.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://geekswithblogs.net/alternativedotnet/comments/commentRss/137666.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/alternativedotnet/services/trackbacks/137666.aspx</trackback:ping>
        </item>
        <item>
            <title>My First coding dojo</title>
            <category>.net</category>
            <link>http://geekswithblogs.net/alternativedotnet/archive/2010/01/27/137665.aspx</link>
            <description>&lt;p&gt;Originally posted on: &lt;a href='http://geekswithblogs.net/alternativedotnet/archive/2010/01/27/137665.aspx'&gt;http://geekswithblogs.net/alternativedotnet/archive/2010/01/27/137665.aspx&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Note to the one reader I have (Hi mom!): I accidently deleted this post, so this is a repost.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;I’ve just started a new initiative in our company: a &lt;a href="http://codingdojo.org/" target="_blank"&gt;coding &lt;b class="highlighted0"&gt;dojo&lt;/b&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I first saw this last week at the &lt;a href="http://www.xpday.net/Xpday2009/sessions/Setting%20Up%20a%20Dojo.html" target="_blank"&gt;XP days&lt;/a&gt;, and I loved every minute of it. &lt;a href="http://emmanuelgaillot.blogspot.com/" target="_blank"&gt;Emmanuel Gaillot&lt;/a&gt; introduced us to this idea with a simple challenge: compare poker hands. The implementation was written in Haskell from scratch, using TDD and Baby Steps. As &lt;a href="http://butunclebob.com/ArticleS.UncleBob.TheProgrammingDojo" target="_blank"&gt;Bob Martin mentioned&lt;/a&gt;: the beauty of this was that most of the attendees did not know Haskell, but they were able to follow what Emmanuel was doing, and make recommendations regarding the design. Most of us learned a little Haskell too.&lt;/p&gt;
&lt;p&gt;I contacted a few colleagues to see who would be interested in this experiment, and 9 of us turned up. I brought enough beer for the group, and we got started. We first decided by dot-voting that the coding challenge should be the ‘classic’ &lt;a href="http://butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata" target="_blank"&gt;bowling game kata&lt;/a&gt;. Each of us took turns behind the keyboard for a maximum of 5 minutes.&lt;/p&gt;
&lt;p&gt;After the exercise, we held a retrospective. This is what came out of it:&lt;/p&gt;
&lt;p&gt;What went well:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Fun environment&lt;/li&gt;
    &lt;li&gt;You have the right to fail. Tests will catch you, but no one will laugh at you.&lt;/li&gt;
    &lt;li&gt;TDD with small steps&lt;/li&gt;
    &lt;li&gt;Refactoring for readability&lt;/li&gt;
    &lt;li&gt;Learned a few shortcuts in visual studio&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What could have gone better:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Let the driver and navigator do the work. The audience can comment, but if you want to argue, stand in line to code.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What would improve the coding &lt;b class="highlighted0"&gt;dojo&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Try out new languages: java, ruby, groovy, haskell, F#, ook…&lt;/li&gt;
    &lt;li&gt;Do this on a monthly basis&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All in all this session was a success, as all participants will agree. Here’s the code we came up with. We do realize that this code isn’t perfect, but at least it works AND it’s readable.&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;
&lt;span style="font-family: Courier New;"&gt;using System;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;span style="font-family: Courier New;"&gt;namespace Dojo1&lt;br /&gt;
{&lt;br /&gt;
    public class BowlingGame&lt;br /&gt;
    {&lt;br /&gt;
        private readonly int[] rolledPins = new int[21];&lt;br /&gt;
        private int currentRoll;&lt;br /&gt;
&lt;br /&gt;
        public void Roll(int pins)&lt;br /&gt;
        {&lt;br /&gt;
            rolledPins[currentRoll] = pins;&lt;br /&gt;
            currentRoll++;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        public int GetScore()&lt;br /&gt;
        {&lt;br /&gt;
            var score = 0;&lt;br /&gt;
            var rollNumber = 0;&lt;br /&gt;
            for (var frame = 0; frame &amp;lt; 10; frame++)&lt;br /&gt;
            {&lt;br /&gt;
                if (IsStrike(rollNumber))&lt;br /&gt;
                {&lt;br /&gt;
                    score += 10 + StrikeBonus(rollNumber);&lt;br /&gt;
                    rollNumber++;&lt;br /&gt;
                }&lt;br /&gt;
                else if (IsSpare(rollNumber))&lt;br /&gt;
                {&lt;br /&gt;
                    score += 10 + SpareBonus(rollNumber);&lt;br /&gt;
                    rollNumber += 2;&lt;br /&gt;
                }&lt;br /&gt;
                else&lt;br /&gt;
                {&lt;br /&gt;
                    score += FrameScore(rollNumber);&lt;br /&gt;
                    rollNumber += 2;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return score;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        private int FrameScore(int rollNumber)&lt;br /&gt;
        {&lt;br /&gt;
            return rolledPins[rollNumber] + rolledPins[rollNumber + 1];&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        private int SpareBonus(int rollNumber)&lt;br /&gt;
        {&lt;br /&gt;
            return rolledPins[rollNumber + 2];&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        private bool IsSpare(int rollNumber)&lt;br /&gt;
        {&lt;br /&gt;
            return rolledPins[rollNumber] + rolledPins[rollNumber + 1] == 10;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        private int StrikeBonus(int rollNumber)&lt;br /&gt;
        {&lt;br /&gt;
            return rolledPins[rollNumber + 1] + rolledPins[rollNumber + 2];&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        private bool IsStrike(int rollNumber)&lt;br /&gt;
        {&lt;br /&gt;
            return rolledPins[rollNumber] == 10;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;/span&gt;&lt;/div&gt; &lt;img src="http://geekswithblogs.net/alternativedotnet/aggbug/137665.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Michel Grootjans</dc:creator>
            <guid>http://geekswithblogs.net/alternativedotnet/archive/2010/01/27/137665.aspx</guid>
            <pubDate>Wed, 27 Jan 2010 22:09:37 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/alternativedotnet/comments/137665.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/alternativedotnet/archive/2010/01/27/137665.aspx#feedback</comments>
            <wfw:commentRss>http://geekswithblogs.net/alternativedotnet/comments/commentRss/137665.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/alternativedotnet/services/trackbacks/137665.aspx</trackback:ping>
        </item>
    </channel>
</rss>