<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6675534776398892468</id><updated>2011-12-29T18:25:06.778+01:00</updated><category term='ruby'/><category term='dependency injection'/><category term='reflections'/><category term='continuous integration'/><category term='koans'/><category term='php'/><category term='books'/><category term='altnerddinner'/><category term='recruiting'/><category term='autotest'/><category term='nant'/><category term='deadline driven development'/><category term='oop'/><category term='rvm'/><category term='msbuild'/><category term='philosophy'/><category term='wtf'/><category term='bash'/><category term='teams'/><category term='git started'/><category term='leadership'/><category term='katas'/><category term='software development'/><category term='mvc'/><category term='c#'/><category term='reminder'/><category term='rspec'/><category term='agile'/><category term='git'/><category term='good practices'/><category term='tips'/><category term='bits'/><category term='project automation'/><category term='asp.net'/><category term='tdd'/><category term='quality'/><category term='.net'/><category term='symfony'/><category term='project management'/><category term='analogic life'/><category term='convention over configuration'/><category term='bdd'/><category term='work'/><category term='nhibernate'/><category term='svn'/><title type='text'>sharp bites</title><subtitle type='html'>Standing on the shoulders of giants</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.sharpbites.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>64</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-8947309100441685561</id><published>2011-11-06T23:43:00.000+01:00</published><updated>2011-11-06T23:43:11.968+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git started'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='svn'/><title type='text'>git started #1. Using git with a svn server</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;So, you already know that &lt;a href="http://www.sharpbites.com/2008/09/why-svn-sucks.html"&gt;svn sucks&lt;/a&gt; and you want to switch to git because you know it's awesome, but you are stuck in a team environment of svn-zombies.&lt;br /&gt;&lt;br /&gt;What can you do? You can try to convert all the non-deads at once... or you can use git-svn and get them into git one by one.&lt;br /&gt;&lt;br /&gt;git-svn let's you interact with a svn server using git as your client.&amp;nbsp;Some git GUIs support git svn. On Mac OSX you can use &lt;a href="http://gitx.laullon.com/"&gt;GitX(L)&lt;/a&gt;&amp;nbsp;or &lt;a href="http://www.sourcetreeapp.com/"&gt;SourceTree&lt;/a&gt;. Here is how to do it using the commandline.&lt;br /&gt;&lt;br /&gt;To get a copy of your svn repo (assuming you have the de facto standard structure of trunk, branches and tags dirs) do:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;git svn init -s http://path/to/your/svn/project&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;From here, use your local repo as usually, i.e. do some hacking, add your files and commit them. Rinse, repeat. &lt;br /&gt;&lt;br /&gt;&lt;code&gt;git add somefile&amp;nbsp;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;git commit&lt;/code&gt;&lt;br /&gt;&lt;code&gt;...&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;When you are ready to commit your changes, get the changes from the svn repo:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;git svn rebase&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;and commit your changes:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;git svn dcommit&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;That's it!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-8947309100441685561?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/8947309100441685561/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=8947309100441685561' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/8947309100441685561'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/8947309100441685561'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2011/11/git-started-1-using-git-with-svn-server.html' title='git started #1. Using git with a svn server'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-575299784194383880</id><published>2011-10-23T21:35:00.000+02:00</published><updated>2011-10-23T21:35:14.338+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='philosophy'/><category scheme='http://www.blogger.com/atom/ns#' term='leadership'/><title type='text'>Change</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;blockquote&gt;“You never change things by ﬁghting the existing reality. To change something, build a new model that makes the existing model obsolete.” &lt;cite&gt;— R. Buckminster Fuller&lt;/cite&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-575299784194383880?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/575299784194383880/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=575299784194383880' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/575299784194383880'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/575299784194383880'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2011/10/change.html' title='Change'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-5754229482299703454</id><published>2011-04-15T22:10:00.000+02:00</published><updated>2011-04-15T22:10:11.327+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='project management'/><category scheme='http://www.blogger.com/atom/ns#' term='leadership'/><title type='text'>Becoming an Agile Manager: Transforming the Three Dysfunctions of Management</title><content type='html'>A terrific talk by Diana Larsen on &lt;a href="http://www.infoq.com/presentations/Managing-Agile"&gt;how to overcome 3 dysfunctional management traps&lt;/a&gt;:&amp;nbsp;magical thinking, illusion of control and individual blame using Agile.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-5754229482299703454?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/5754229482299703454/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=5754229482299703454' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/5754229482299703454'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/5754229482299703454'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2011/04/becoming-agile-manager-transforming.html' title='Becoming an Agile Manager: Transforming the Three Dysfunctions of Management'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-2609807773710534966</id><published>2011-01-29T23:02:00.000+01:00</published><updated>2011-01-29T23:02:02.757+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rspec'/><category scheme='http://www.blogger.com/atom/ns#' term='autotest'/><category scheme='http://www.blogger.com/atom/ns#' term='tdd'/><category scheme='http://www.blogger.com/atom/ns#' term='rvm'/><title type='text'>Setting up a ruby testing environment on Linux</title><content type='html'>Now that &lt;a href="http://www.sharpbites.com/2011/01/setting-up-your-ruby-environment-on.html"&gt;we have setup our ruby environment on Linux&lt;/a&gt;,&amp;nbsp;we are going to create a setup for testing purposes by adding some useful gems.&lt;br /&gt;&lt;br /&gt;For that, we will use a feature from &lt;a href="http://rvm.beginrescueend.com/"&gt;rvm&lt;/a&gt; called&amp;nbsp;&lt;a href="http://rvm.beginrescueend.com/gemsets/basics/"&gt;gemsets&lt;/a&gt;. A gemset is an independent setup for your environment. That means you can have many environments with a different set of gems (hence the name) installed independently on each one (even with different ruby versions).&lt;br /&gt;&lt;br /&gt;Usually, when working on a project, you would create a gemset specific for that project, but in this case, we are going to create a gemset for practicing tdd, doing katas, coderetreats, etc. If you plan to use rvm in a serious project (which you should), please read first about &lt;a href="http://rvm.beginrescueend.com/rvm/best-practices/"&gt;rvm best practices&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;A brief introduction to gemsets&lt;/span&gt;&lt;br /&gt;For each version of ruby, rvm creates two gemsets, the default, empty gemset and the global gemset. You can list your gemsets with:&lt;br /&gt;&lt;blockquote&gt;rvm gemset list&lt;/blockquote&gt;Gems that are installed to the @global gemset are shared to all other gemset for that ruby. We won't install anything here. Instead we will create our own gemset and put everything there.&lt;br /&gt;&lt;br /&gt;Create a tdd gemset:&lt;br /&gt;&lt;blockquote&gt;rvm gemset create tdd&lt;/blockquote&gt;Switch to that gemset:&lt;br /&gt;&lt;blockquote&gt;rvm use gemset 1.9.2@tdd&lt;/blockquote&gt;If you want to make this your default gemset (the one that will be loaded by default) you can do that by doing:&lt;br /&gt;&lt;blockquote&gt;rvm use gemset 1.9.2@tdd --default&lt;/blockquote&gt;Verify you are on the new gemset:&lt;br /&gt;&lt;blockquote&gt;rvm gemset name&lt;/blockquote&gt;You should get:&lt;br /&gt;&lt;blockquote&gt;tdd&lt;/blockquote&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Gems for testing that rock&lt;/span&gt;&lt;br /&gt;You can install gems &lt;b&gt;for your current gemset&lt;/b&gt; using:&lt;br /&gt;&lt;blockquote&gt;gem install&lt;/blockquote&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;To do unit testing in ruby, &lt;a href="http://relishapp.com/rspec"&gt;rspec&lt;/a&gt; is a great choice.&lt;br /&gt;&lt;blockquote&gt;gem install&amp;nbsp;rspec&lt;/blockquote&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;To start using it, create an rspec file, like example_spec.rb inside a spec folder on the root of your project:&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;span class="Apple-style-span" style="color: #222222; font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif; font-size: 14px; line-height: 21px;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;pre style="background-color: #e0f8e0; border-bottom-width: 1px; border-color: initial; border-left-color: rgb(8, 138, 8); border-left-width: 1px; border-right-color: rgb(8, 138, 8); border-right-width: 1px; border-style: initial; border-top-color: rgb(8, 138, 8); border-top-style: solid; border-top-width: 1px; font-family: inherit; font-style: inherit; font-weight: inherit; margin-bottom: 8px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 2px; padding-left: 5px; padding-right: 5px; padding-top: 2px; vertical-align: baseline; white-space: pre;"&gt;&lt;span class="Apple-style-span" style="color: #222222; font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif; font-size: 14px; line-height: 21px;"&gt;describe "something" do&lt;br /&gt;  it "does something that passes" do&lt;br /&gt;    5.should eq(5)&lt;br /&gt;  end&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;You can then execute it by running:&lt;/div&gt;&lt;blockquote&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;rspec spec/&lt;/div&gt;&lt;/blockquote&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;For a nicer, colored output, pass in the --colour flag to rspec&lt;/div&gt;&lt;blockquote&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;rspec spec/ --colour&amp;nbsp;&lt;/div&gt;&lt;/blockquote&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;Or create a .rspec config file&amp;nbsp;on your project root (or in your home dir if you want to always use it), to tell rspec to use the colored output by default&lt;/div&gt;&lt;blockquote&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;echo "--colour" &amp;gt;&amp;gt; .rspec&lt;/div&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;Excecuting rspec by hand all the time gets boring quickly, and it turns out computers are quite good at doing tasks repeteadly, so you can instead use &lt;a href="http://ph7spot.com/musings/getting-started-with-autotest"&gt;autotest&lt;/a&gt;, a cool gem from the &lt;a href="http://www.zenspider.com/ZSS/Products/ZenTest/"&gt;ZenTest suite&lt;/a&gt;&amp;nbsp;that will automagically execute your tests when you save your files.&lt;/div&gt;&lt;blockquote&gt;gem install autotest&lt;/blockquote&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;Execute it from your project root.&lt;/div&gt;&lt;blockquote&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;autotest --style rspec2 --quiet&lt;/div&gt;&lt;/blockquote&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;The --style flag tells autotest to look for rspec kind of tests. The --quiet flag removes a bit of noise you probably don't care about.&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;If you have created the .rpec file on your project root, you can omit the style flag and autotest will still find the tests.&lt;/div&gt;&lt;blockquote&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;autotest --quiet&lt;/div&gt;&lt;/blockquote&gt;If you are really lazy like me, you can instruct autotest to be quiet by default by creating a .autotest file in your home:&lt;br /&gt;&lt;blockquote&gt;echo "Autotest.options[:quiet] = true" &amp;gt;&amp;gt; ~/.autotest&lt;/blockquote&gt;So whatever option you want to use, let's try it.&amp;nbsp;Modify your rspec file and save it. Awesome, isn't it? But wait,&amp;nbsp;there is more!&lt;br /&gt;&lt;br /&gt;We'll add a nice gem called &lt;a href="https://github.com/fnando/test_notifier"&gt;test_notifier&lt;/a&gt;.&amp;nbsp;This is the topping of the cake. It will notify your OS with the result of your tests.&lt;br /&gt;&lt;br /&gt;In order to it on GNOME, we will need to install libnotify:&lt;br /&gt;&lt;/div&gt;&lt;blockquote&gt;sudo apt-get install libnotify-bin&lt;/blockquote&gt;&lt;blockquote&gt;gem install test_notifier&lt;/blockquote&gt;Configure autotest to use test_notifier:&lt;br /&gt;&lt;blockquote&gt;echo 'require "test_notifier/runner/autotest"' &amp;gt;&amp;gt; .autotest&lt;/blockquote&gt;Or add the following to your rspec/spec_helper file if you want to use it directly with rspec:&lt;br /&gt;&lt;blockquote&gt;require "test_notifier/runner/spec"&lt;/blockquote&gt;Now you should get a nice notification when you save your file.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_kQ7iivKjVno/TUSNLUgyTcI/AAAAAAAAARA/zA_zkMV45dk/s1600/test_notifier.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="138" src="http://1.bp.blogspot.com/_kQ7iivKjVno/TUSNLUgyTcI/AAAAAAAAARA/zA_zkMV45dk/s320/test_notifier.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-2609807773710534966?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/2609807773710534966/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=2609807773710534966' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/2609807773710534966'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/2609807773710534966'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2011/01/setting-up-ruby-testing-environment-on.html' title='Setting up a ruby testing environment on Linux'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_kQ7iivKjVno/TUSNLUgyTcI/AAAAAAAAARA/zA_zkMV45dk/s72-c/test_notifier.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-3730907429777424061</id><published>2011-01-25T21:41:00.002+01:00</published><updated>2011-01-25T21:45:17.385+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rvm'/><title type='text'>Setting up your ruby environment on Linux</title><content type='html'>Here are the instructions on how to set up a ruby environment for Linux, in case you want to start playing with it.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;NOTE:&lt;/b&gt; Don't use the packages from your distribution. They are outdated and will cause more harm than good. Use one of the methods below.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;The quick and easy way&lt;/span&gt;&lt;br /&gt;If you are planning to use Rails anyways, you can use the script from &lt;a href="https://github.com/joshfng/railsready"&gt;railsready&lt;/a&gt;.&lt;br /&gt;It will install rails, passenger, and a shitload dependencies it need for everything to work smoothly.&lt;br /&gt;You can install it by running:&lt;br /&gt;&lt;blockquote&gt;sudo wget --no-check-certificate https://github.com/joshfng/railsready/raw/master/railsready.sh &amp;amp;&amp;amp; bash railsready.sh&lt;/blockquote&gt;The script will ask if you want to build Ruby from source or install RVM.&amp;nbsp;Choose RVM.&lt;br /&gt;&lt;br /&gt;It will download around 50MB of libraries from the repositories and then download and compile rvm, ruby and download again some other gems, so it will take some time. Don't worry, you don't have to do anything, just wait.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;The almost-as-quick, almost-as-easy way&lt;/span&gt;&lt;br /&gt;If you don't intend to use rails and don't feel like installing all that stuff, use the following method. It's basically doing the same thing as the previous script, except you don't need so many dependencies, and you won't install rails or passenger.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Installing RVM&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://rvm.beginrescueend.com/"&gt;RVM&lt;/a&gt; (Ruby Version Manager)&amp;nbsp;is a tool which allows us to easily install, manage and work with multiple ruby environments (interpreters and gems) on the same machine. This means we can create different environments with distincts versions, of ruby, rails, or whatever gem we want, without any headaches.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;In order to install rvm, you'll need curl, git and some compiler tools. We can get them with the following command:&lt;/div&gt;&lt;blockquote&gt;sudo apt-get install git-core curl build-essential&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;To install rvm execute:&lt;/div&gt;&lt;blockquote&gt;bash &amp;lt; &amp;lt;( curl http://rvm.beginrescueend.com/releases/rvm-install-head )&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;This command will install rvm in your home directory.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;You need to include a line at the end of the .bashrc file to tell it to load rvm.&lt;/div&gt;&lt;div&gt;Follow carefuly the instructions on your terminal, specially the part about converting the return to an if statement&lt;/div&gt;&lt;blockquote&gt;"[ -z "$PS1" ] &amp;amp;&amp;amp; return"&lt;/blockquote&gt;&lt;div&gt;&lt;b&gt;NOTE:&lt;/b&gt; The railsready script doesn't do this, and just appends the line loading rvm at the end of the file. RVM maintainers recommend otherwise, so you better do it their way.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you find any problems, check &lt;a href="http://rvm.beginrescueend.com/rvm/install/"&gt;rvm site troubleshooting information&lt;/a&gt;&amp;nbsp;(section 'Trhoubleshooting your install')&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Finally reload your envirnonment executing:&lt;/div&gt;&lt;blockquote&gt;source ~/.bashrc&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Installing ruby&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Now you have rvm installed and running, you can proceed to install ruby. You'll need some packages first, the following command will tell you which:&lt;/div&gt;&lt;blockquote&gt;rvm notes&lt;/blockquote&gt;&lt;/div&gt;In my case, these were:&lt;br /&gt;# For Ruby (MRI &amp;amp; ree) &amp;nbsp;you should install the following OS dependencies:&lt;br /&gt;&lt;blockquote&gt;sudo apt-get install build-essential bison openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf&lt;/blockquote&gt;&lt;div&gt;&lt;div&gt;Now, we can install ruby 1.9.2:&lt;/div&gt;&lt;blockquote&gt;rvm install 1.9.2&lt;/blockquote&gt;&lt;div&gt;This will take a while, since it is dowloading ruby sources and compiling them.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can check ruby is all fine and dandy by running&lt;/div&gt;&lt;blockquote&gt;ruby -v&lt;/blockquote&gt;&lt;div&gt;You should get something similar to:&lt;/div&gt;&lt;blockquote&gt;ruby 1.9.2p136 (2010-12-25 revision 30365) [x86_64-linux]&lt;/blockquote&gt;On the next post I will explain how to setup your environment for testing using rvm.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-3730907429777424061?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/3730907429777424061/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=3730907429777424061' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/3730907429777424061'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/3730907429777424061'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2011/01/setting-up-your-ruby-environment-on.html' title='Setting up your ruby environment on Linux'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-1769708688548565746</id><published>2011-01-01T21:29:00.000+01:00</published><updated>2011-01-01T21:29:30.323+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='katas'/><title type='text'>12 months, 12 katas: January. String calculator</title><content type='html'>As recommended by &lt;a href="http://www.twitter.com/plagelao"&gt;@plagelao&lt;/a&gt; on twitter, the kata for January will be &lt;a href="http://www.osherove.com/tdd-kata-1/"&gt;String Calculator&lt;/a&gt;.&lt;br /&gt;Here are the specs:&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #0a0606; font-family: Tahoma, Arial, Helvetica, Geneva, sans-serif; font-size: 14px; line-height: 18px;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Create a simple String calculator with a method&amp;nbsp;&lt;strong&gt;int Add(string numbers)&lt;/strong&gt;&lt;ol&gt;&lt;li&gt;The method can take 0, 1 or 2 numbers, and will return their sum (for an empty string it will return 0) for example&lt;strong&gt;&amp;nbsp;“” or “1” or “1,2”&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Start with the simplest test case of an empty string and move to 1 and two numbers&lt;/li&gt;&lt;li&gt;Remember to solve things as simply as possible so that you force yourself to write tests you did not think about&lt;/li&gt;&lt;li&gt;Remember to refactor after each passing test&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;Allow the Add method to handle an unknown amount of numbers&lt;/li&gt;&lt;li&gt;Allow the Add method to handle new lines between numbers (instead of commas).&lt;ol&gt;&lt;li&gt;the following input is ok:&amp;nbsp; “1\n2,3”&amp;nbsp; (will equal 6)&lt;/li&gt;&lt;li&gt;the following input is NOT&amp;nbsp;ok:&amp;nbsp; “1,\n”&amp;nbsp;&lt;/li&gt;&lt;li&gt;Make sure you only test for correct inputs. there is no need to test for invalid inputs for these katas&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;Allow the Add method to handle a different delimiter:&lt;ol&gt;&lt;li&gt;to change a delimiter, the beginning of the string will contain a separate line that looks like this:&amp;nbsp;&amp;nbsp; “//[delimiter]\n[numbers…]” for example “//;\n1;2” should return three where the default delimiter is ‘;’ .&lt;/li&gt;&lt;li&gt;the first line is optional. all existing scenarios should still be supported&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;Calling Add with a negative number will throw an exception “negatives not allowed” - and the negative that was passed.if there are multiple negatives, show all of them in the exception message&lt;hr /&gt;&lt;strong&gt;stop here if you are a beginner&lt;/strong&gt;. Continue if you can finish the steps so far in less than 30 minutes.&lt;hr /&gt;&lt;/li&gt;&lt;li&gt;Numbers bigger than 1000 should be ignored, so adding 2 + 1001 &amp;nbsp;= 2&lt;/li&gt;&lt;li&gt;Delimiters can be of any length with the following format:&amp;nbsp; “//[delimiter]\n” for example: “//[***]\n1***2***3” should return 6&lt;/li&gt;&lt;li&gt;Allow multiple delimiters like this:&amp;nbsp; “//[delim1][delim2]\n” for example “//[*][%]\n1*2%3” should return 6.&lt;/li&gt;&lt;li&gt;make sure you can also handle multiple delimiters with length longer than one char&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-1769708688548565746?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/1769708688548565746/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=1769708688548565746' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/1769708688548565746'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/1769708688548565746'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2011/01/12-months-12-katas-january-string.html' title='12 months, 12 katas: January. String calculator'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-4662344939069917715</id><published>2011-01-01T20:45:00.003+01:00</published><updated>2011-01-01T21:37:18.859+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='analogic life'/><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='reflections'/><category scheme='http://www.blogger.com/atom/ns#' term='katas'/><title type='text'>New Year resolutions</title><content type='html'>Here are my resolutions for the present year:&lt;br /&gt;- Read LESS. Yes, less reading, more doing.&lt;br /&gt;- Keep learning ruby.&lt;br /&gt;- Practice! I'm resolved to do a kata EVERY day, one kata each month. Wanna join? Use the hashtag&amp;nbsp;&lt;a href="http://search.twitter.com/search?q=12months12katas"&gt;#12months12katas&lt;/a&gt;.&lt;br /&gt;- Rediscover enjoyment, on many aspects. This is a tough one, since I&amp;nbsp;first&amp;nbsp;need to find direction, then courage to act in consequence.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-4662344939069917715?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/4662344939069917715/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=4662344939069917715' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/4662344939069917715'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/4662344939069917715'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2011/01/new-year-resolutions.html' title='New Year resolutions'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-9194067060613791214</id><published>2010-12-20T02:10:00.004+01:00</published><updated>2010-12-20T02:50:05.120+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='koans'/><title type='text'>Greed game koan</title><content type='html'>&lt;a href="http://twitter.com/jjballano"&gt;@jjballano&lt;/a&gt;&amp;nbsp;recently&amp;nbsp;&lt;a href="https://gist.github.com/736614"&gt;posted&lt;/a&gt;&amp;nbsp;his version of the &lt;a href="http://en.wikipedia.org/wiki/Greed_(dice_game)"&gt;Greed game&lt;/a&gt;, as part of his learning experience with &lt;a href="http://rubykoans.com/"&gt;Ruby Koans&lt;/a&gt;. As I am following that very same path, I thought it could also be worth for me to share &lt;a href="https://gist.github.com/747881"&gt;my implementation of Greed&lt;/a&gt; for people to comment on it.&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;The code could surely be much prettier since I am still trying to get my head around ruby block-passing, among others, so comments (and patches!) are welcome.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/747881.js?file=score.rb"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;UPDATE: The code seems to update automatically to the latest version on github, you can find the original &lt;a href="https://gist.github.com/747881/3b8cb77970b0b22b2265904b3c02acf7bae84a3f#file_score.rb"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-9194067060613791214?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/9194067060613791214/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=9194067060613791214' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/9194067060613791214'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/9194067060613791214'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2010/12/greed-game-koan.html' title='Greed game koan'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-7952304080954308185</id><published>2010-11-30T00:12:00.000+01:00</published><updated>2010-11-30T00:12:05.164+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='good practices'/><category scheme='http://www.blogger.com/atom/ns#' term='oop'/><title type='text'>Writing Better Object Oriented Code</title><content type='html'>&lt;a href="http://twitter.com/#!/gregyoung"&gt;Greg Young&lt;/a&gt; did a great presentation at &lt;a href="http://www.oredev.org/"&gt;Oredev&lt;/a&gt; about &lt;a href="http://vimeo.com/17151526"&gt;writing Object Oriented code the right way&lt;/a&gt;. It's so full of good stuff I could not bother to make a summary out of it. Go watch the original video. Now.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-7952304080954308185?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/7952304080954308185/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=7952304080954308185' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/7952304080954308185'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/7952304080954308185'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2010/11/writing-better-object-oriented-code.html' title='Writing Better Object Oriented Code'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-7536755303523040957</id><published>2010-11-26T18:32:00.001+01:00</published><updated>2010-11-26T20:06:54.093+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='teams'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='work'/><category scheme='http://www.blogger.com/atom/ns#' term='project management'/><category scheme='http://www.blogger.com/atom/ns#' term='philosophy'/><category scheme='http://www.blogger.com/atom/ns#' term='books'/><category scheme='http://www.blogger.com/atom/ns#' term='recruiting'/><title type='text'>I've read: Peopleware</title><content type='html'>'Peopleware' is one of those classic books of our profession, a must-read. Unfortunately, it's not easy to grab a copy of it on the stores (it may have been discontinued, I'm not sure).&amp;nbsp;After a failed attempt to borrow it from &lt;a href="http://twitter.com/jmbeas"&gt;Jose Manuel Beas&lt;/a&gt;,&amp;nbsp;a few weeks ago, I finally got the chance to read it (thanks &lt;a href="http://twitter.com/rubenbpv"&gt;Rubén&lt;/a&gt;!).&lt;br /&gt;&lt;br /&gt;All I can say is, if you have the chance, read it! Just so you can have a glimpse at it, here are some notes I&amp;nbsp;took from it. Most are direct quotes,&amp;nbsp;although&amp;nbsp;I reworded a few to&amp;nbsp;synthesize.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Productivity&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;As long as workers are crowded into noisy, disruptive space, it's not worth improving anything but the workspace.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Experiments showed projects without deadlines had the best productivity.&lt;br /&gt;Better performance can be explained entirely by more effective ways of handling people, modifying the workplace and corporate culture.&lt;br /&gt;Developers main work is human communication to organize the user's expressions of needs into formal procedure.&lt;br /&gt;People won't work better under a lot of pressure.&lt;br /&gt;The manager's function is not to make people work, but to make it possible for people to work.&lt;br /&gt;Best people outperform the worst by 10 and the median performer by 2.5.&lt;br /&gt;Years of experience are not correlated to productivity.&lt;br /&gt;Interrupting flow not only causes disruption but frustration.&lt;br /&gt;There are two types of work: Individual work is noise sensitive and needs flow.&amp;nbsp;Group work is noise producing. Adapt your workspace to make both kinds of work possible.&lt;br /&gt;Measure and try to maximize flow time, but don't let managers access to data.&lt;br /&gt;Ignoring the phone must be accepted by corporate policy.&lt;br /&gt;Ask people about their workspace conditions, what affects their productivity.&lt;br /&gt;Listening to music uses the right part of the braing, which is responsible for creativity.&lt;br /&gt;Encourage teams to customize their space.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;People&lt;/span&gt;&lt;br /&gt;People who work for you will be more or less the same at the end as they were at the beginning, so they better be right for the job from the start.&lt;br /&gt;Find the right people, make them happy, turn them loose.&lt;br /&gt;Success or failure is in the cards from the moment the team is formed and the initial directions set out.&lt;br /&gt;Corporate pressure is pushing towards the company average, encouraging you to hire people that look, sound and think like everybody else.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Hiring&lt;/span&gt;&lt;br /&gt;(Tell about hiring a juggler) 'Don't you want to see me juggle?'&lt;br /&gt;Make people bring their code portfolio for interviews.&lt;br /&gt;Make candidates prepare an audition with the team 10-to-15 minute presentation on some aspect of past work.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Good organizations&lt;/span&gt;&lt;br /&gt;Late promotion is a sign of health.&lt;br /&gt;With a low and flat hierarchy, people at the lowest level have, on average more years of experience.&lt;br /&gt;Strive to be the best&lt;br /&gt;Grow a community feeling.&lt;br /&gt;Focus on long term benefits.&lt;br /&gt;Widespread sense that you are expected to stay&lt;br /&gt;Invest in personal growth&lt;br /&gt;Retrain your people&lt;br /&gt;When you automate a system, you make it deterministic, so it looses its self-healing ability. A&amp;nbsp;&lt;b&gt;M&lt;/b&gt;ethodology (capital 'M' here) can produce the same results on you organization.&lt;br /&gt;To achieve convergence of methods, use training, tools and peer review.&lt;br /&gt;Don't declare something a standard until it is a de facto standard.&lt;br /&gt;Hawtorne effect (experiment of raising and lowering the light) People perform better when they are trying something new.&lt;br /&gt;You have to make non-standard approaches to the rule. Whatever standard there is should be brief and gentle.&lt;br /&gt;Let a hundred flowers blossom and let a hundred schools of thought contend. (Mao Tse-tung)&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Jelled teams&lt;/span&gt;&lt;br /&gt;Productive teams = challenge + team interaction&lt;br /&gt;They have momentum.&lt;br /&gt;They have a goal&lt;br /&gt;The purpose of a team is not goal attainment but goal achievement.&lt;br /&gt;People on jelled teams are often so involved you have to remind them&amp;nbsp;that what they are trying to accomplish is not winning a war.&lt;br /&gt;Jelled teams have low turnover and strong sense of identity.&lt;br /&gt;Money, status and position for advance matter a lot less. Enjoyment is an obvious sign.&lt;br /&gt;You can't make teams jell, just act to improve the odds.&lt;br /&gt;Teamicide techniques:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Defensive management&lt;/li&gt;&lt;li&gt;Bureaucracy&lt;/li&gt;&lt;li&gt;Physical&amp;nbsp;separation&lt;/li&gt;&lt;li&gt;Fragmentation of people's time&lt;/li&gt;&lt;li&gt;Quality reduction&lt;/li&gt;&lt;li&gt;Phony deadlines&lt;/li&gt;&lt;li&gt;Clique control&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Good managers provide opportunities for the team to succeed together. The best success is the one in which there is no evident management. The best boss is the one who can manage without the team knowing they've been managed.&lt;br /&gt;&lt;br /&gt;Growing jelled teams:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Give people autonomy and responsibility&lt;/li&gt;&lt;li&gt;Let them work alone, without constant supervision&lt;/li&gt;&lt;li&gt;They break the rules when they believe in it&lt;/li&gt;&lt;li&gt;Let them choose mates and projects&lt;/li&gt;&lt;li&gt;Let them exercise their natural authority in their area of expertise.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Chemistry for team formation:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Make a cult of quality&lt;/li&gt;&lt;li&gt;Provide satisfying confirmation&lt;/li&gt;&lt;li&gt;Build a sense of eliteness&lt;/li&gt;&lt;li&gt;Allow and encourage heterogeneity&lt;/li&gt;&lt;li&gt;Preserve and protect successful teams.&lt;/li&gt;&lt;li&gt;Provide strategic but not tactical direction&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Chaos (it is not that bad!)&lt;/span&gt;&lt;br /&gt;Small amounts of disorder are benefitial&lt;br /&gt;Pilot projects, war games, brainstorming, provocative training experiences, training, trips, conferences, celebrations, retreats,...&lt;br /&gt;&lt;br /&gt;If your corporation is fortunate enough to have a self-motivated superachiever on-board, it's enough to say "Define your own job"&lt;br /&gt;"Free electrons" have a strong role in choosing their own orbits.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Being a Change Agent&lt;/span&gt;&lt;br /&gt;Focus on one thing to change. Raise people's consciousness of it, so they help you change it.&lt;br /&gt;Be careful with motivational posters, they can have the opposite effect.&lt;br /&gt;Fuck overtime.&lt;br /&gt;Competition inhibits coaching.&lt;br /&gt;Any action that rewards team members differently is likely to foster competition.&lt;br /&gt;The success of the individual should be tied to the success of the whole.&lt;br /&gt;People hate change. Any change.&lt;br /&gt;Your enemies are blindly loyals and militantly opposed to change.&lt;br /&gt;The fundamental response to change is not logical, but emotional.&lt;br /&gt;Celebrate the old as a way to help make change happen.&lt;br /&gt;Be aware that chaos is an integral part of change. Otherwise, you mistake it for the new status quo and will want to change back.&lt;br /&gt;Change always involves chaos, it is necessary and can't be shortcut. The more painful the chaos, the greater the perceived value of the new status quo.&lt;br /&gt;Change won't even get started unless people feel safe when they know they won't be demeaned for proposing or trying a change.&lt;br /&gt;Change only has a chance of&amp;nbsp;succeeding&amp;nbsp;if failure is also&amp;nbsp;OK.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Organizational learning&lt;/span&gt;&lt;br /&gt;Learning is limited by an organization's ability to keep its people.&lt;br /&gt;If the retrained people leave, investment is lost and learning is gone.&lt;br /&gt;Successful&amp;nbsp;learning organizations are always characterized by strong middle management. In order for a vital learning center to form, middle managers must communicate with each other and learn to work together in effective harmony.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Waste&lt;/span&gt;&lt;br /&gt;The ultimate management sin is wasting people's time.&lt;br /&gt;Organizations have need of ceremony.&lt;br /&gt;Ceremony is good when it fulfills a need for appreciation by the team.&lt;br /&gt;Early&amp;nbsp;over-staffing&amp;nbsp;is waste.&lt;br /&gt;Fragmented time is waste, it breaks flow.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Community&lt;/span&gt;&lt;br /&gt;Building a community makes a difference, but requires talent, courage and creativity. And an enormous invest of time, to be, at best, the catalyst.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-7536755303523040957?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/7536755303523040957/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=7536755303523040957' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/7536755303523040957'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/7536755303523040957'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2010/11/ive-read-peopleware.html' title='I&apos;ve read: Peopleware'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-8970130574201855675</id><published>2010-02-27T17:01:00.000+01:00</published><updated>2010-02-27T17:01:02.033+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='symfony'/><category scheme='http://www.blogger.com/atom/ns#' term='bash'/><title type='text'>Bash completion for symfony</title><content type='html'>&lt;a href="http://www.tatai.es/"&gt;Fran&lt;/a&gt;&amp;nbsp;(a.k.a. tatai), one of my teammates at Biko, was kind enough to make us a nice (and unreadable) script to get &lt;a href="http://github.com/biko2/symfony_complete"&gt;symfony bash completion&lt;/a&gt;. Get it while it's hot!&lt;br /&gt;&lt;br /&gt;You can read more about the script on &lt;a href="http://www.tatai.es/2010/02/26/bash-completion-for-symfony/"&gt;tatai's blog&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Kudos @tatai for your work!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-8970130574201855675?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/8970130574201855675/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=8970130574201855675' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/8970130574201855675'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/8970130574201855675'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2010/02/bash-completion-for-symfony.html' title='Bash completion for symfony'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-2750932543022742863</id><published>2009-11-08T02:23:00.000+01:00</published><updated>2009-11-08T02:23:25.626+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='analogic life'/><category scheme='http://www.blogger.com/atom/ns#' term='work'/><category scheme='http://www.blogger.com/atom/ns#' term='php'/><title type='text'>Sometimes You Have To Take A Step Back Before You Can Move Forward</title><content type='html'>Or how I am moving to a PHP team to free myself from WebForms.&lt;br /&gt;&lt;br /&gt;So expect to find some stuff (probably including some rants) here about PHP from now on.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-2750932543022742863?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/2750932543022742863/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=2750932543022742863' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/2750932543022742863'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/2750932543022742863'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2009/11/sometimes-you-have-to-take-step-back.html' title='Sometimes You Have To Take A Step Back Before You Can Move Forward'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-2630109774270324437</id><published>2009-10-19T21:14:00.001+02:00</published><updated>2009-10-19T21:14:46.263+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='altnerddinner'/><category scheme='http://www.blogger.com/atom/ns#' term='dependency injection'/><category scheme='http://www.blogger.com/atom/ns#' term='nhibernate'/><title type='text'>AltNerDinner: Part 4. Introducing NHibernate. Because POCO is enough</title><content type='html'>&lt;p&gt;It's time already to introduce a proper persistence solution. NHibernate can be a little intimidating at first for a new-comer, but I undoubtedly think it's the way to go. And it's not really more difficult than the other contenders anymore. Its two major drawbacks (hand writing all that XMhelL mapping and not strongly typed queries) are solved (or in serious process of it) by Fluent NHibernate and NHibernate.Linq.&lt;/p&gt;  &lt;p&gt;Other than that, the only difficulty relies in learning a few concepts inherent to OR/Ms. Most notably the &lt;a href="http://martinfowler.com/eaaCatalog/unitOfWork.html"&gt;Unit of Work&lt;/a&gt; pattern and &lt;a href="http://martinfowler.com/eaaCatalog/lazyLoad.html"&gt;Lazy Loading&lt;/a&gt;, and all the stuff around them (namely repositories, query objects, persistence ignorance, POCOs, DTOs, entities/value objects and equality, inheritance mapping, dynamic proxies, caching, anemic domains, active record, transactions, concurrency, session lifetime, unit testing, select n+1 problems and other pitfalls to avoid,&amp;#160; ...). [NOTE: If you need more info on this topics I'd recommend you to visit the &lt;a href="http://nhforge.org/"&gt;official nhibernate site&lt;/a&gt;.]&lt;/p&gt;  &lt;p&gt;Sounds scary? It might seem using an OR/M brings in more problems that the ones it solves, but I don't think it is the case, except for maybe the most trivial apps (like AltNerdDinner, hehe, I know). Even if you are writing a relatively simple app, you can still greatly benefit from using NHibernate (or Active Record on top of it). If your app has inherent complexity, well, of course you'll have to do your homework and learn a few concepts, but that's not your OR/M's fault. Using a hand-rolled DAL won't make your problems go away (quite the opposite, I'd dare to say).&lt;/p&gt;  &lt;p&gt;As I said, most (if not all) of this problems exist in all OR/M, it's just that some of them somehow try to hide this complexity in one or another way. The problem is, this is a can of worms that can lead to very bad practices and slap on your face at any moment. And this is were I think this is were NHibernate excels at, its flexibility. It gets out of your way.&lt;/p&gt;  &lt;h4&gt;Ok, enough talking! Show me the code!&lt;/h4&gt;  &lt;p&gt;To use NHibernate and NH.Linq we need to add a reference in our project to the following dll's: NHibernate, NHibernate.Linq, FluentNHibernate (if we hadn't already) and lastly NHibernate.ByteCode.Castle if we want to use Castle's dynamic proxy as our proxy generator of choice.&lt;/p&gt;  &lt;p&gt;Here is the code for my DinnerRepository implementation using NHibernate:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;NhDinnerRepository &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;IDinnerRepository&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    &lt;span style="color: blue"&gt;private readonly &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ISession &lt;/span&gt;_session;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: blue"&gt;public &lt;/span&gt;NhDinnerRepository(&lt;span style="color: #2b91af"&gt;ISession &lt;/span&gt;session)&lt;br /&gt;    {&lt;br /&gt;        _session = session;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: blue"&gt;private &lt;/span&gt;&lt;span style="color: #2b91af"&gt;INHibernateQueryable&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Dinner&lt;/span&gt;&amp;gt; GetDbContext()&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: blue"&gt;return &lt;/span&gt;_session.Linq&amp;lt;&lt;span style="color: #2b91af"&gt;Dinner&lt;/span&gt;&amp;gt;();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IQueryable&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Dinner&lt;/span&gt;&amp;gt; FindAllDinners()&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: blue"&gt;return &lt;/span&gt;GetDbContext().AsQueryable();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IQueryable&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Dinner&lt;/span&gt;&amp;gt; FindByLocation(&lt;span style="color: blue"&gt;float &lt;/span&gt;latitude, &lt;span style="color: blue"&gt;float &lt;/span&gt;longitude)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: blue"&gt;return &lt;/span&gt;GetDbContext().Where(d =&amp;gt; d.Distance(latitude, longitude) &amp;lt; 100).AsQueryable();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IQueryable&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Dinner&lt;/span&gt;&amp;gt; FindUpcomingDinners()&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: blue"&gt;return from &lt;/span&gt;dinner &lt;span style="color: blue"&gt;in &lt;/span&gt;GetDbContext()&lt;br /&gt;               &lt;span style="color: blue"&gt;where &lt;/span&gt;dinner.EventDate &amp;gt; &lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;.Now&lt;br /&gt;               &lt;span style="color: blue"&gt;orderby &lt;/span&gt;dinner.EventDate&lt;br /&gt;               &lt;span style="color: blue"&gt;select &lt;/span&gt;dinner;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Dinner &lt;/span&gt;GetDinner(&lt;span style="color: blue"&gt;int &lt;/span&gt;id)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: blue"&gt;return &lt;/span&gt;GetDbContext().SingleOrDefault(d =&amp;gt; d.DinnerID == id);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: blue"&gt;public void &lt;/span&gt;Save(&lt;span style="color: #2b91af"&gt;Dinner &lt;/span&gt;dinner)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: blue"&gt;if &lt;/span&gt;(!dinner.IsValid)&lt;br /&gt;        {&lt;br /&gt;            &lt;span style="color: blue"&gt;throw new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ApplicationException&lt;/span&gt;(&lt;span style="color: #a31515"&gt;&amp;quot;Rule violations&amp;quot;&lt;/span&gt;);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        _session.SaveOrUpdate(dinner);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: blue"&gt;public void &lt;/span&gt;Delete(&lt;span style="color: #2b91af"&gt;Dinner &lt;/span&gt;dinner)&lt;br /&gt;    {&lt;br /&gt;        _session.Delete(dinner);&lt;br /&gt;    }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;As you see, I am returning IQueryable&amp;lt;Dinner&amp;gt; instead of traditional .NET collections. Some people think &lt;a href="http://mikehadlow.blogspot.com/2009/01/should-my-repository-expose-iqueryable.html"&gt;IQueryable is the best thing since slice bread&lt;/a&gt;, others are &lt;a href="http://ayende.com/Blog/archive/2009/04/17/repository-is-the-new-singleton.aspx"&gt;ditching repositories entirely&lt;/a&gt;, some prefer &lt;a href="http://www.udidahan.com/2007/03/28/query-objects-vs-methods-on-a-repository/"&gt;using query objects&lt;/a&gt;, others advocate for &lt;a href="http://codebetter.com/blogs/gregyoung/archive/2009/01/16/ddd-the-generic-repository.aspx"&gt;explicit repositories&lt;/a&gt;, some use &lt;a href="http://serialseb.blogspot.com/2009/08/nhibernate-repository-that-oren-wont.html"&gt;generic ones&lt;/a&gt; and I just don't know yet, but decided to go at least with repositories because I want to take &lt;a href="http://www.udidahan.com/2008/02/15/from-crud-to-domain-driven-fluency/"&gt;control of how entities are persisted&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;To instantiate my NHibernate repository, I need to supply it with an ISession. I &lt;a href="http://ayende.com/Blog/archive/2008/07/24/How-to-review-NHibernate-application.aspx"&gt;don't create the ISession inside the repository&lt;/a&gt;, since this is considered a bad practice. Instead, I create a new Session per request. To do that, I expected I would have some infrastructure in place in MvcContrib, but that was not the case. &lt;a href="http://jeffreypalermo.com"&gt;Jeffrey Palermo&lt;/a&gt; posted a &lt;a href="http://jeffreypalermo.com/blog/use-this-nhibernate-wrapper-to-keep-your-repository-classes-simple/"&gt;NHibernate wrapper to manage ISession&lt;/a&gt;, but I thought that class had too many responsibilities, so I separated it in the following.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SessionFactoryBuilder&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    &lt;span style="color: blue"&gt;private static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ISessionFactory &lt;/span&gt;_sessionFactory;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: blue"&gt;private readonly &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IPersistenceConfigurer &lt;/span&gt;_dbConfiguration;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: blue"&gt;public &lt;/span&gt;SessionFactoryBuilder(&lt;span style="color: #2b91af"&gt;IPersistenceConfigurer &lt;/span&gt;dbConfiguration)&lt;br /&gt;    {&lt;br /&gt;        _dbConfiguration = dbConfiguration;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ISessionFactory &lt;/span&gt;Build()&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: blue"&gt;if &lt;/span&gt;(_sessionFactory == &lt;span style="color: blue"&gt;null&lt;/span&gt;)&lt;br /&gt;        {&lt;br /&gt;            _sessionFactory  = GetDbConfiguration().BuildSessionFactory();   &lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span style="color: blue"&gt;return &lt;/span&gt;_sessionFactory;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Configuration &lt;/span&gt;GetDbConfiguration()&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: blue"&gt;return &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Fluently&lt;/span&gt;.Configure()&lt;br /&gt;                .Mappings(m =&amp;gt; m.FluentMappings.AddFromAssemblyOf&amp;lt;&lt;span style="color: #2b91af"&gt;Dinner&lt;/span&gt;&amp;gt;())&lt;br /&gt;                .Database(_dbConfiguration)                    &lt;br /&gt;                .BuildConfiguration();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;This builds the session factory and also returns the configuration (useful to create the schema). It needs an IPersistenceConfigurer, which I supply from the constructor, in order to be able to switch between different configurations (i.e. MSSQL and SQLite), as shown below:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MsSqlPersistenceConfigurerFactory &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;IPersistenceConfigurerFactory&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    &lt;span style="color: blue"&gt;private string &lt;/span&gt;_connectionString;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: blue"&gt;public &lt;/span&gt;MsSqlPersistenceConfigurerFactory(&lt;span style="color: blue"&gt;string &lt;/span&gt;connectionString)&lt;br /&gt;    {&lt;br /&gt;        _connectionString = connectionString;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IPersistenceConfigurer &lt;/span&gt;GetPersistenceConfigurer()&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: blue"&gt;return &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MsSqlConfiguration&lt;/span&gt;.MsSql2005&lt;br /&gt;                .ConnectionString(c =&amp;gt; c.Is(_connectionString))&lt;br /&gt;                .ShowSql()&lt;br /&gt;                .FormatSql()&lt;br /&gt;                .ProxyFactoryFactory&amp;lt;&lt;span style="color: #2b91af"&gt;ProxyFactoryFactory&lt;/span&gt;&amp;gt;();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Life of a Session&lt;/h4&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;We need to create the aforementioned ISession somehow. In Web applications, it's generally a good practice to create a new Session on every request. For that, Ayende recently &lt;a href="http://ayende.com/Blog/archive/2009/08/05/do-you-need-a-framework.aspx"&gt;suggested&lt;/a&gt; to just stick it in the global.asax, but I prefer to put it in a separate&amp;#160; IHttpModule.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;NhSessionPerRequestModule &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;IHttpModule&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    &lt;span style="color: blue"&gt;private readonly &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ISessionFactory &lt;/span&gt;_sessionFactory;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: blue"&gt;public &lt;/span&gt;NhSessionPerRequestModule(&lt;span style="color: #2b91af"&gt;ISessionFactory &lt;/span&gt;sessionFactory)&lt;br /&gt;    {&lt;br /&gt;        _sessionFactory = sessionFactory;&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color: blue"&gt;public void &lt;/span&gt;Init(&lt;span style="color: #2b91af"&gt;HttpApplication &lt;/span&gt;application)&lt;br /&gt;    {&lt;br /&gt;        application.BeginRequest += &lt;span style="color: blue"&gt;delegate&lt;br /&gt;                                    &lt;/span&gt;{&lt;br /&gt;                                        CurrentSession = _sessionFactory.OpenSession();&lt;br /&gt;                                    };&lt;br /&gt;&lt;br /&gt;        application.EndRequest += &lt;span style="color: blue"&gt;delegate&lt;br /&gt;                                  &lt;/span&gt;{&lt;br /&gt;                                      &lt;span style="color: blue"&gt;if &lt;/span&gt;(CurrentSession != &lt;span style="color: blue"&gt;null&lt;/span&gt;)&lt;br /&gt;                                      {&lt;br /&gt;                                          CurrentSession.Dispose();&lt;br /&gt;                                      }&lt;br /&gt;                                  };&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: blue"&gt;public static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ISession &lt;/span&gt;CurrentSession&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: blue"&gt;get &lt;/span&gt;{ &lt;span style="color: blue"&gt;return &lt;/span&gt;(&lt;span style="color: #2b91af"&gt;ISession&lt;/span&gt;)&lt;span style="color: #2b91af"&gt;HttpContext&lt;/span&gt;.Current.Items[&lt;span style="color: #a31515"&gt;&amp;quot;current.session&amp;quot;&lt;/span&gt;]; }&lt;br /&gt;        &lt;span style="color: blue"&gt;private set &lt;/span&gt;{ &lt;span style="color: #2b91af"&gt;HttpContext&lt;/span&gt;.Current.Items[&lt;span style="color: #a31515"&gt;&amp;quot;current.session&amp;quot;&lt;/span&gt;] = &lt;span style="color: blue"&gt;value&lt;/span&gt;; }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: blue"&gt;public void &lt;/span&gt;Dispose()&lt;br /&gt;    {        &lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;In my Global.asax, I configure it as follows:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private static readonly &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ISessionFactory &lt;/span&gt;SessionFactory = CreateSessionFactory();&lt;br /&gt;&lt;span style="color: blue"&gt;private static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IWindsorContainer &lt;/span&gt;_container;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: blue"&gt;private static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ISessionFactory &lt;/span&gt;CreateSessionFactory()&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: blue"&gt;string &lt;/span&gt;connString = &lt;span style="color: #2b91af"&gt;ConfigurationManager&lt;/span&gt;.ConnectionStrings[&lt;span style="color: #a31515"&gt;&amp;quot;AltNerdDinner&amp;quot;&lt;/span&gt;].ConnectionString;&lt;br /&gt;    &lt;span style="color: blue"&gt;return new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;SessionFactoryBuilder&lt;/span&gt;(&lt;br /&gt;            &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MsSqlPersistenceConfigurerFactory&lt;/span&gt;(connString)&lt;br /&gt;                    .GetPersistenceConfigurer())&lt;br /&gt;            .Build();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: blue"&gt;private readonly &lt;/span&gt;&lt;span style="color: #2b91af"&gt;NhSessionLifetimeModule &lt;/span&gt;_nhSessionLifetimeModule =&lt;br /&gt;        &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;NhSessionLifetimeModule&lt;/span&gt;(SessionFactory);&lt;br /&gt;&lt;br /&gt;&lt;span style="color: blue"&gt;public override void &lt;/span&gt;Init()&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: blue"&gt;base&lt;/span&gt;.Init();&lt;br /&gt;    _nhSessionLifetimeModule.Init(&lt;span style="color: blue"&gt;this&lt;/span&gt;);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Lastly, this is my current configuration of the container in order to register the components:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private void &lt;/span&gt;RegisterComponents()&lt;br /&gt; {&lt;br /&gt;     _container = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;WindsorContainer&lt;/span&gt;();&lt;br /&gt;     _container.AddFacility&amp;lt;&lt;span style="color: #2b91af"&gt;FactorySupportFacility&lt;/span&gt;&amp;gt;();&lt;br /&gt;&lt;br /&gt;     &lt;span style="color: #2b91af"&gt;ControllerBuilder&lt;/span&gt;.Current.SetControllerFactory(&lt;br /&gt;         &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;WindsorControllerFactory&lt;/span&gt;(_container));&lt;br /&gt;&lt;br /&gt;     _container.Register(&lt;br /&gt;             &lt;span style="color: #2b91af"&gt;Component&lt;/span&gt;.For&amp;lt;&lt;span style="color: #2b91af"&gt;ISession&lt;/span&gt;&amp;gt;()&lt;br /&gt;                     .UsingFactoryMethod(() =&amp;gt; &lt;span style="color: #2b91af"&gt;NhSessionLifetimeModule&lt;/span&gt;.CurrentSession)&lt;br /&gt;                     .LifeStyle.Transient);&lt;br /&gt;  &lt;br /&gt;     _container.Register(&lt;br /&gt;             &lt;span style="color: #2b91af"&gt;Component&lt;/span&gt;.For&amp;lt;&lt;span style="color: #2b91af"&gt;IDinnerRepository&lt;/span&gt;&amp;gt;()&lt;br /&gt;                     .ImplementedBy&amp;lt;&lt;span style="color: #2b91af"&gt;NhDinnerRepository&lt;/span&gt;&amp;gt;().LifeStyle.Transient);&lt;br /&gt;&lt;br /&gt;     _container.RegisterControllers(&lt;span style="color: #2b91af"&gt;Assembly&lt;/span&gt;.GetExecutingAssembly());&lt;br /&gt; }&lt;/pre&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-2630109774270324437?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/2630109774270324437/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=2630109774270324437' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/2630109774270324437'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/2630109774270324437'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2009/10/altnerdinner-part-4-introducing.html' title='AltNerDinner: Part 4. Introducing NHibernate. Because POCO is enough'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-5361056737775209402</id><published>2009-10-16T17:34:00.001+02:00</published><updated>2009-10-16T17:34:44.460+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><category scheme='http://www.blogger.com/atom/ns#' term='wtf'/><category scheme='http://www.blogger.com/atom/ns#' term='convention over configuration'/><title type='text'>Java and (the lack of) CoC</title><content type='html'>&lt;blockquote&gt;   &lt;p&gt;&amp;quot;Java is a DSL to transform big Xml documents into long exception stack traces.&amp;quot;&lt;/p&gt;   &lt;cite&gt;-- Scott Bellware&lt;/cite&gt;&lt;/blockquote&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-5361056737775209402?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/5361056737775209402/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=5361056737775209402' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/5361056737775209402'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/5361056737775209402'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2009/10/java-and-lack-of-coc.html' title='Java and (the lack of) CoC'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-3235742071083678195</id><published>2009-10-14T23:02:00.001+02:00</published><updated>2009-10-14T23:19:48.589+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='altnerddinner'/><category scheme='http://www.blogger.com/atom/ns#' term='nhibernate'/><title type='text'>AltNerdDinner: Part 3. Introducing Fluent NHibernate. Mapping, the easy way</title><content type='html'>&lt;p&gt;&lt;em&gt;This is part 3 of the &lt;a href="http://sharpbites.blogspot.com/2009/08/introducing-altnerddinner.html"&gt;AltNerdDinner&lt;/a&gt; Series.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;One of the things I always disliked the most when exploring NHibernate was the need of declaring all the mappings in XMhelL. And don't know about you, but that's not something I want to be spending my time creating, modifying, hand-refactoring or debugging tedious tons of this crap.&lt;/p&gt;  &lt;p&gt;Fast forward to 2008 and say hello to &lt;a href="http://fluentnhibernate.org/"&gt;Fluent NHibernate&lt;/a&gt;. (And don't forget to thank &lt;a href="http://codebetter.com/blogs/jeremy.miller/"&gt;Jeremy Miller&lt;/a&gt;, &lt;a href="http://blog.jagregory.com/"&gt;James Gregory&lt;/a&gt; &lt;a href="http://code.google.com/p/fluent-nhibernate/people/list"&gt;&lt;em&gt;et al&lt;/em&gt;&lt;/a&gt;!). It is basically a way to programmatically declare the mappings, allowing you to go from this:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color: #a31515"&gt;xml &lt;/span&gt;&lt;span style="color: red"&gt;version&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;1.0&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;encoding&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;utf-8&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;?&amp;gt;  &lt;br /&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;hibernate-mapping &lt;/span&gt;&lt;span style="color: red"&gt;xmlns&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;urn:nhibernate-mapping-2.2&lt;/span&gt;&amp;quot;  &lt;br /&gt;  &lt;span style="color: red"&gt;namespace&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;QuickStart&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;assembly&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;QuickStart&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;&amp;gt;  &lt;br /&gt; &lt;br /&gt;  &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;class &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Cat&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;table&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Cat&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;&amp;gt;  &lt;br /&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;id &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Id&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;&amp;gt;  &lt;br /&gt;      &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;generator &lt;/span&gt;&lt;span style="color: red"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;identity&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;  &lt;br /&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;  &lt;br /&gt; &lt;br /&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;property &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Name&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;&amp;gt;  &lt;br /&gt;      &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;column &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Name&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;length&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;16&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;not-null&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;true&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;  &lt;br /&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;property&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;  &lt;br /&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;property &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Sex&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;  &lt;br /&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;many-to-one &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Mate&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;  &lt;br /&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;bag &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Kittens&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;&amp;gt;  &lt;br /&gt;      &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;key &lt;/span&gt;&lt;span style="color: red"&gt;column&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;mother_id&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;  &lt;br /&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;one-to-many &lt;/span&gt;&lt;span style="color: red"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Cat&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;  &lt;br /&gt;      &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;bag&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;  &lt;br /&gt;  &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;class&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;  &lt;br /&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;hibernate-mapping&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;To this:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;CatMap &lt;/span&gt;: ClassMap&amp;lt;Cat&amp;gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: blue"&gt;public &lt;/span&gt;CatMap()&lt;br /&gt;    {&lt;br /&gt;        Id(x =&amp;gt; x.Id);&lt;br /&gt;        Map(x =&amp;gt; x.Name)&lt;br /&gt;          .Length(16)&lt;br /&gt;          .Not.Nullable();&lt;br /&gt;        Map(x =&amp;gt; x.Sex);&lt;br /&gt;        References(x =&amp;gt; x.Mate);&lt;br /&gt;        HasMany(x =&amp;gt; x.Kittens);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;What it gives you, you may ask? Compile-time checks and refactoring support, for a start.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;But wait, there is more!&lt;/h4&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Fluent NHibernate is built with &lt;a href="http://en.wikipedia.org/wiki/Convention_over_Configuration"&gt;Convention over Configuration&lt;/a&gt; in mind. So, if you adhere to it, you can greatly reduce the amount of mapping needed, by virtue of &lt;a href="http://wiki.fluentnhibernate.org/Auto_mapping"&gt;auto mapping&lt;/a&gt;. And you can combine that with explicit ClassMap mappings, like the one above, they are not mutually exclusive.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Mapping your domain can be as simple as:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;AutoMap.AssemblyOf&amp;lt;Product&amp;gt;();&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;And if you call within the next 5 minutes we throw in Conventions for free!&lt;/h4&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&amp;quot;Ok, that might be great for a greenfield project, but I am working in a big brown piece of ... code&amp;quot;, I hear you saying. So you may not have the choice to call your Id's &amp;quot;Id&amp;quot; or name your tables exactly after your classes. &lt;a href="http://wiki.fluentnhibernate.org/Conventions"&gt;Conventions&lt;/a&gt; can greatly help here, allowing you to define your own conventions. That is, if your database naming follows any convention at all, and wasn't defined by a bunch of monkeys typing at random.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;For further info, check the &lt;a href="http://fluentnhibernate.org/"&gt;site&lt;/a&gt;, &lt;a href="http://wiki.fluentnhibernate.org/"&gt;wiki&lt;/a&gt; and &lt;a href="http://groups.google.com/group/fluent-nhibernate"&gt;mailing list&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;AltNerdDinner's mappings&lt;/h4&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Here are the mapping files for AltNerdDinner.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DinnerMap &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;ClassMap&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Dinner&lt;/span&gt;&amp;gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: blue"&gt;public &lt;/span&gt;DinnerMap()&lt;br /&gt;    {&lt;br /&gt;        Id(x =&amp;gt; x.DinnerID);&lt;br /&gt;        Map(x =&amp;gt; x.Address).Not.Nullable();&lt;br /&gt;        Map(x =&amp;gt; x.ContactPhone).Not.Nullable();&lt;br /&gt;        Map(x =&amp;gt; x.Country).Not.Nullable();&lt;br /&gt;        Map(x =&amp;gt; x.Description).Not.Nullable();&lt;br /&gt;        Map(x =&amp;gt; x.EventDate).Not.Nullable();&lt;br /&gt;        Map(x =&amp;gt; x.HostedBy).Not.Nullable();&lt;br /&gt;        Map(x =&amp;gt; x.Latitude).Not.Nullable();&lt;br /&gt;        Map(x =&amp;gt; x.Longitude).Not.Nullable();&lt;br /&gt;        Map(x =&amp;gt; x.Title).Not.Nullable();&lt;br /&gt;        HasMany(x =&amp;gt; x.RSVPs).Cascade.AllDeleteOrphan();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;RSVPMap &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;ClassMap&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;RSVP&lt;/span&gt;&amp;gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: blue"&gt;public &lt;/span&gt;RSVPMap()&lt;br /&gt;    {&lt;br /&gt;        Id(x =&amp;gt; x.RsvpId);&lt;br /&gt;        Map(x =&amp;gt; x.AttendeeName).Not.Nullable();&lt;br /&gt;        References(r =&amp;gt; r.Dinner).&lt;strong&gt;Nullable()&lt;/strong&gt;;            &lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;One gotcha that had me fiddling around for a while was that Nullable part on the Dinner reference in RSVPMap. If you don't set it to nullable, you'll get an exception when trying to persist the entities. And even if you set it to nullable, you'll find out, NHibernate executes two queries to insert the RSVP.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; INSERT INTO&amp;#160; [RSVP] (AttendeeName, Dinner_id) VALUES (@p0, @p1); &lt;br /&gt;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; select SCOPE_IDENTITY(); &lt;br /&gt;&lt;br /&gt;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; @p0 = 'alberto', &lt;br /&gt;&lt;br /&gt;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; @p1 = 9 &lt;br /&gt;&lt;br /&gt;    &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; UPDATE [RSVP] SET Dinner_id = @p0 WHERE RsvpId = @p1; @p0 = 9, @p1 = 21&lt;/p&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;You can find &lt;a href="http://nhforge.org/doc/nh/en/index.html#example-parentchild-bidir"&gt;more info&lt;/a&gt; about this behavior in the &lt;a href="http://nhforge.org/"&gt;official nhibernate site&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;So, what I have done instead is to set the RSVP as the managing part of the relationship, changing it back to not nullable and using Inverse() on the Dinner's mapping side.&lt;/p&gt;&lt;br /&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;It is not possible to make the &amp;quot;many part&amp;quot; responsible for this. What this means is that we have to persist our entities calling:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;span style="color: #2b91af"&gt;Dinner &lt;/span&gt;dinner = _dinnerRepository.GetDinner(id);&lt;br /&gt;&lt;span style="color: blue"&gt;var &lt;/span&gt;rsvp = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;RSVP&lt;/span&gt;{ AttendeeName = username };&lt;br /&gt;rsvp.Dinner = dinner;&lt;br /&gt;dinner.Rsvps.Add(rsvp);&lt;br /&gt;_dinnerRepository.Save(dinner);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;That's not very ideal, so I have included an AddRsvp() method in Dinner to handle that. Now I have:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;span style="color: #2b91af"&gt;Dinner &lt;/span&gt;dinner = _dinnerRepository.GetDinner(id);&lt;br /&gt;dinner.AddRsvp(&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;RSVP&lt;/span&gt;{ AttendeeName = User.Identity.Name });&lt;br /&gt;_dinnerRepository.Save(dinner);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Much cleaner! In order to avoid confusion when adding an RSVO, I have changed the type of the collection to an IEnumerable&amp;lt;RSVP&amp;gt;, so that the collection cannot be modified directly, but only by means of Dinner (which is a good practice if you want to follow DDD, anyway). Because of that, I had to modified the DinnerMap to use a backing field for it. In the future I might revisit this relationship to include the User in the domain again and change it to a less CRUD-y style. You can read more on &lt;a href="http://www.udidahan.com/2008/02/15/from-crud-to-domain-driven-fluency/"&gt;Domain-Driven fluency&lt;/a&gt; from &lt;a href="http://www.udidahan.com/2008/02/15/from-crud-to-domain-driven-fluency/"&gt;Udi Dahan&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Anyway, here is the final mapping I have come up with:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;RSVPMap &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;ClassMap&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;RSVP&lt;/span&gt;&amp;gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: blue"&gt;public &lt;/span&gt;RSVPMap()&lt;br /&gt;    {&lt;br /&gt;        Id(x =&amp;gt; x.RsvpId);&lt;br /&gt;        Map(x =&amp;gt; x.AttendeeName).Not.Nullable();&lt;br /&gt;        References(r =&amp;gt; r.Dinner).Not.Nullable();            &lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DinnerMap &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;ClassMap&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Dinner&lt;/span&gt;&amp;gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: blue"&gt;public &lt;/span&gt;DinnerMap()&lt;br /&gt;    {&lt;br /&gt;        Id(x =&amp;gt; x.DinnerID);&lt;br /&gt;        Map(x =&amp;gt; x.Address).Not.Nullable();&lt;br /&gt;        Map(x =&amp;gt; x.ContactPhone).Not.Nullable();&lt;br /&gt;        Map(x =&amp;gt; x.Country).Not.Nullable();&lt;br /&gt;        Map(x =&amp;gt; x.Description).Not.Nullable();&lt;br /&gt;        Map(x =&amp;gt; x.EventDate).Not.Nullable();&lt;br /&gt;        Map(x =&amp;gt; x.HostedBy).Not.Nullable();&lt;br /&gt;        Map(x =&amp;gt; x.Latitude).Not.Nullable();&lt;br /&gt;        Map(x =&amp;gt; x.Longitude).Not.Nullable();&lt;br /&gt;        Map(x =&amp;gt; x.Title).Not.Nullable();&lt;br /&gt;        HasMany(x =&amp;gt; x.Rsvps).Access.CamelCaseField(&lt;span style="color: #2b91af"&gt;Prefix&lt;/span&gt;.Underscore)&lt;br /&gt;            .Inverse().Cascade.AllDeleteOrphan();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-3235742071083678195?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/3235742071083678195/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=3235742071083678195' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/3235742071083678195'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/3235742071083678195'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2009/10/altnerddinner-part-3-introducing-fluent.html' title='AltNerdDinner: Part 3. Introducing Fluent NHibernate. Mapping, the easy way'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-6720675466522579576</id><published>2009-10-06T21:02:00.001+02:00</published><updated>2009-10-06T21:02:25.642+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='altnerddinner'/><category scheme='http://www.blogger.com/atom/ns#' term='dependency injection'/><category scheme='http://www.blogger.com/atom/ns#' term='good practices'/><title type='text'>AltNerdDinner: Part 2. Rich Man's Dependency Injection</title><content type='html'>&lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;This is part 2 of the &lt;a href="http://sharpbites.blogspot.com/2009/08/introducing-altnerddinner.html"&gt;AltNerdDinner&lt;/a&gt; Series.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;The classes in &lt;a href="http://nerddinner.codeplex.com/"&gt;NerdDinner&lt;/a&gt; use &lt;a href="http://martinfowler.com/articles/injection.html"&gt;dependency injection&lt;/a&gt; (&lt;a href="http://martinfowler.com/articles/injection.html#ConstructorInjectionWithPicocontainer"&gt;constructor injection&lt;/a&gt;, to be more precise), which is a form of &lt;a href="http://martinfowler.com/bliki/InversionOfControl.html"&gt;Inversion of Control&lt;/a&gt; that allows you to break the dependencies between classes, minimizing coupling (i.e. a Good Thing &amp;#8482;). Instead having classes with direct dependencies&amp;#160; on other classes, and instantiating them directly, classes are dependent on interfaces, and the concrete implementation is injected via the constructor, in this case, or via a setter in the case of &lt;a href="http://martinfowler.com/articles/injection.html#SetterInjectionWithSpring"&gt;setter injection&lt;/a&gt;. Constructor injection is preferred for required dependencies, as it makes dependencies more explicit, and setter injection is usually reserved for optional dependencies.&lt;/p&gt;  &lt;p&gt;Using this technique, the responsibility of providing the dependencies is delegated to the calling object (hence the term Inversion of Control).&lt;/p&gt;  &lt;h4&gt;Poor Man's Dependency Injection&lt;/h4&gt;  &lt;p&gt;The problem with the NerdDinner codebase is that, besides the constructor that accepts the required dependencies, they added a default constructor that news up those dependencies. Here is an example:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public &lt;/span&gt;DinnersController() : &lt;span style="color: blue"&gt;this&lt;/span&gt;(&lt;span style="color: blue"&gt;new &lt;/span&gt;DinnerRepository())&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: blue"&gt;public &lt;/span&gt;DinnersController(&lt;span style="color: #2b91af"&gt;IDinnerRepository &lt;/span&gt;repository) {&lt;br /&gt;    dinnerRepository = repository;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;This may look like a good compromise. You get the decoupling needed to run your tests (by means of the constructor accepting parameters) and you are also able to instantiate you classes calling the default constructor, without the added complexity of an IoC container. However this technique is considered an &lt;a href="http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/07/03/how-not-to-do-dependency-injection-in-nerddinner.aspx"&gt;anti-pattern&lt;/a&gt; (although &lt;a href="http://devlicio.us/blogs/tim_barcz/archive/2009/07/12/why-there-s-nothing-wrong-with-dependency-injection-in-nerddinner.aspx"&gt;not everybody agrees&lt;/a&gt;) &lt;a href="http://www.lostechies.com/blogs/chad_myers/archive/2009/07/14/the-usual-result-of-poor-man-s-dependency-injection.aspx"&gt;leading to many headaches&lt;/a&gt;. By adding this constructor we're almost at square one again. Our classes are still coupled, and if we need to add new dependencies, we'll have to go hunting around to fix all the constructor calls.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;If I were a rich man&lt;/h4&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;So now you are convinced to use an IoC container, you can have a look this &lt;a href="http://www.lostechies.com/blogs/jimmy_bogard/archive/2008/09/12/some-ioc-container-guidelines.aspx"&gt;container guidelines&lt;/a&gt; by &lt;a href="http://www.lostechies.com/blogs/jimmy_bogard/default.aspx"&gt;Jimmy Bogard&lt;/a&gt;. He may not consider his recommendations as best practices, but I do (and so should you, IMHO). I picked &lt;a href="http://www.castleproject.org/container/gettingstarted/index.html"&gt;Castle Windsor&lt;/a&gt; as my framework of choice. As usual, &lt;a href="http://structuremap.sourceforge.net/"&gt;there&lt;/a&gt; &lt;a href="http://code.google.com/p/autofac/"&gt;are&lt;/a&gt; &lt;a href="http://ninject.org/"&gt;plenty&lt;/a&gt;&amp;#160;&lt;a href="http://www.spring.net/"&gt;of&lt;/a&gt; &lt;a href="http://www.codeplex.com/unity"&gt;alternatives&lt;/a&gt;. Even though the API is not the cleanest of all the frameworks, I favored Windsor because it is very mature, is widely adopted, it also supports .NET 2.0, and has good integration with NHibernate. It also is the container used in &lt;a href="http://code.google.com/p/sharp-architecture/"&gt;S#arp Architecture&lt;/a&gt;, which is something I will probably end up using. Otherwise, my choice would be &lt;a href="http://structuremap.sourceforge.net/"&gt;StructureMap&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;In order to use Windsor, you have to reference on your project &lt;em&gt;Castle.Core&lt;/em&gt;, &lt;em&gt;Castle.MicroKernel&lt;/em&gt; and &lt;em&gt;Castle.Windsor&lt;/em&gt;. To ease the configuration of the container, I also downloaded &lt;a href="http://www.codeplex.com/MVCContrib"&gt;MvcContrib&lt;/a&gt; (which I was planning to use anyway) and added a reference to &lt;em&gt;MvcContrib.Castle&lt;/em&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;This is the code needed to register the controllers and the Repository.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private void &lt;/span&gt;RegisterComponents()&lt;br /&gt;{&lt;br /&gt;    _container = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;WindsorContainer&lt;/span&gt;();&lt;br /&gt;    &lt;span style="color: #2b91af"&gt;ControllerBuilder&lt;/span&gt;.Current.SetControllerFactory(&lt;br /&gt;        &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;WindsorControllerFactory&lt;/span&gt;(_container));&lt;br /&gt;    _container.RegisterControllers(&lt;span style="color: #2b91af"&gt;Assembly&lt;/span&gt;.GetExecutingAssembly());&lt;br /&gt;    _container.Register(&lt;br /&gt;            &lt;span style="color: #2b91af"&gt;Component&lt;/span&gt;.For&amp;lt;&lt;span style="color: #2b91af"&gt;IDinnerRepository&lt;/span&gt;&amp;gt;()&lt;br /&gt;            .ImplementedBy&amp;lt;&lt;span style="color: #2b91af"&gt;InMemoryDinnerRepository&lt;/span&gt;&amp;gt;());&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;To allow the creation of the controllers by the MVC framework, you need to supply a ControllerFactory that can instantiate them, as they now take dependencies on their constructors. MvcContrib provides one for Windsor, as well as the method RegisterControllers to, guess what, registering all the controllers in a specified assembly. I also registered my DinnerRepository, so that Windsor can resolve the references to it.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-6720675466522579576?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/6720675466522579576/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=6720675466522579576' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/6720675466522579576'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/6720675466522579576'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2009/10/altnerddinner-part-2-rich-man.html' title='AltNerdDinner: Part 2. Rich Man&amp;#39;s Dependency Injection'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-463388537583013388</id><published>2009-10-03T18:56:00.001+02:00</published><updated>2009-10-03T18:56:16.244+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='altnerddinner'/><title type='text'>AltNerdDinner: Part 1. Removing unwanted dependencies</title><content type='html'>&lt;p&gt;The first thing I have done is to set up the project on &lt;a href="http://github.com/"&gt;github&lt;/a&gt;, so if you want to have a look at the code, check the &lt;a href="http://github.com/alberto/altnerddinner"&gt;AltNerdDinner repository&lt;/a&gt;. Then I set up the project following the guidelines of my series &lt;a href="http://sharpbites.blogspot.com/2009/09/road-to-continuous-integration.html"&gt;Continuous Integration series&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Now we are set, there is some stuff I don't want in AltNerdDinner, so I am mercilessly going to get rid of it.&lt;/p&gt;  &lt;h4&gt;Bye, MSTest&lt;/h4&gt;  &lt;p&gt;MSTest gives nothing useful beyond integration in VS (for which I prefer ReSharper's Test Runner or TDD.NET). I won't say it sucks, but &lt;a href="http://haacked.com/archive/2007/09/04/should-microsoft-really-bundle-open-source-software.aspx"&gt;Phil Haack did&lt;/a&gt;. It's just there to satisfy MS-Only shops. It's slow, and it evolves slowly too. It lags behind &lt;a href="http://www.nunit.org/index.php"&gt;the&lt;/a&gt;&amp;#160;&lt;a href="http://www.gallio.org/"&gt;alternative&lt;/a&gt; &lt;a href="http://www.codeplex.com/xunit"&gt;frameworks&lt;/a&gt;. Oh, and it requires VS to be installed on your build server (crazy!), and... &lt;/p&gt;  &lt;p&gt;So I replaced it with good ol'&amp;#160; &lt;a href="http://www.nunit.org/index.php"&gt;NUnit&lt;/a&gt;. It basically involves replacing:&lt;/p&gt;  &lt;p&gt;using Microsoft.VisualStudio.TestTools.UnitTesting; by using NUnit.Framework;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;[TestClass] and [TestMethod] by [TestFixture],&amp;#160; and [Test]&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;and a bunch of calls to Assert.IsInstanceOfType(object, type); by Assert.IsInstanceOf(type, object); (pay attention to the signature change!).&lt;/p&gt;  &lt;h4&gt;We don't need no membership provider&lt;/h4&gt;  &lt;p&gt;Right now I don't want to deal with membership provider. I think it's bloated and I don't want to have to mess with the authentication right now, so I am going to replace it with a FakeMembershipService for the moment and leave the decision of whether revisiting it or completely replacing it (probably the latter) for a later time.&lt;/p&gt;  &lt;h4&gt;LINQ to SQL is dead, long live NHibernate&lt;/h4&gt;  &lt;p&gt;L2S is probably a decent option for this kind of simple app, and it's very easy to quickly duct-tape a simple app. It has some goodies, like the visual designer and of course Linq. But it's not the best option if your app gets bigger and you need some more advanced ORM features, like different mapping capabilities or different databases support. It's not a bad tool, but it has &lt;a href="http://codebetter.com/blogs/ian_cooper/archive/2008/07/01/architecting-linq-to-sql-part-10.aspx"&gt;some limitations&lt;/a&gt; that need to be addressed and, unfortunately, the fact that &lt;a href="http://www.infoq.com/news/2008/11/DLINQ-Future"&gt;L2S is being killed&lt;/a&gt; means you are better not investing hard into it.&lt;/p&gt;  &lt;p&gt;So I am planning to replace it with NHibernate, a mature and tested product&amp;#160; that fits my needs. But just not yet. Right now, I will simply remove the L2S stuff and work with POCOs and an InMemoryRepository implementation (which is basically the FakeDinnerRepository present in the Tests project).&lt;/p&gt;  &lt;h5&gt;The model&lt;/h5&gt;  &lt;p&gt;As we can see on the picture of the original model, the domain is quite simple.&lt;a href="http://lh3.ggpht.com/_kQ7iivKjVno/SseCJ_ZEG0I/AAAAAAAAAMQ/ehF8shEf9Dg/s1600-h/image11.png"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" border="0" alt="image" src="http://lh3.ggpht.com/_kQ7iivKjVno/SseCKvw9G1I/AAAAAAAAAMU/ft6vs8PlB_0/image_thumb9.png?imgmax=800" width="488" height="259" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;I have simply created POCO classes replacing the L2S generated ones.&lt;/p&gt;  &lt;p&gt;After all the changes, we run all the tests and...&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_kQ7iivKjVno/SseCLKN9WMI/AAAAAAAAAMY/KpeLlk_F18c/s1600-h/testsgreen2.jpg"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" border="0" alt="tests-green" src="http://lh5.ggpht.com/_kQ7iivKjVno/SseCL4M-ONI/AAAAAAAAAMc/Nr3Jv3PFVPc/testsgreen_thumb.jpg?imgmax=800" width="184" height="34" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;We're done!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-463388537583013388?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/463388537583013388/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=463388537583013388' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/463388537583013388'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/463388537583013388'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2009/10/altnerddinner-part-1-removing-unwanted.html' title='AltNerdDinner: Part 1. Removing unwanted dependencies'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_kQ7iivKjVno/SseCKvw9G1I/AAAAAAAAAMU/ft6vs8PlB_0/s72-c/image_thumb9.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-3255220909010797137</id><published>2009-09-28T21:03:00.003+02:00</published><updated>2009-09-28T21:15:15.914+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='project automation'/><category scheme='http://www.blogger.com/atom/ns#' term='project management'/><category scheme='http://www.blogger.com/atom/ns#' term='continuous integration'/><title type='text'>The road to Continuous Integration. Part 3: Script it, build it, test it, break it, fix it. Commit it.</title><content type='html'>Ideally, any new developer in your team should be able to build your project with a single command or double-click. To accomplish that, we are going to use a build script.  &lt;br /&gt;You can also &lt;a href="http://nant.sourceforge.net/"&gt;pick&lt;/a&gt; &lt;a href="http://msdn.microsoft.com/en-us/library/0k6kkbsd.aspx"&gt;your&lt;/a&gt; &lt;a href="http://rake.rubyforge.org/"&gt;poison&lt;/a&gt; here, too. I am going to stick with nant for the moment, because it's the most mature and broadly used, and the one I know better, despite of the &lt;i&gt;XMHell&lt;/i&gt; that is the angle-bracket orgy it imposes. &lt;a href="http://codebetter.com/blogs/david_laribee/archive/2008/08/25/omg-rake.aspx"&gt;Rake seems nice&lt;/a&gt;, and has less noise than the others, but I don't like the fact that I have to install ruby and rake separately. As I said, I like all of my dependencies being included in source control, so that my projects are self-contained (there are some efforts to get &lt;a href="http://www.stephenbalkum.com/archive/2009/06/09/when-all-you-need-is-a-rake.aspx"&gt;ruby and rake as a single executable&lt;/a&gt;, though). If you are hesitating between msbuild and nant, you can check out a &lt;a href="http://sharpbites.blogspot.com/2008/09/nant-vs-msbuild.html"&gt;comparison between nant and msbuild&lt;/a&gt; I did a while ago.  &lt;br /&gt;&lt;a href="http://lh5.ggpht.com/_kQ7iivKjVno/SsEIh_i4iCI/AAAAAAAAAME/oexhq-gr7N4/s1600-h/projectstructure10.jpg"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" border="0" alt="project-structure" align="left" src="http://lh6.ggpht.com/_kQ7iivKjVno/SsEIiowefII/AAAAAAAAAMI/TuxGRy-ffPI/projectstructure_thumb8.jpg?imgmax=800" width="155" height="244" /&gt;&lt;/a&gt;  &lt;br /&gt;As you can see on the picture, I have added two build scripts to the root of &lt;a href="http://github.com/alberto/altnerddinner"&gt;AltNerdDinner&lt;/a&gt;. &lt;i&gt;&lt;a href="http://github.com/alberto/altnerddinner/blob/master/common-targets.build"&gt;common-targets.build&lt;/a&gt;&lt;/i&gt; has, you know, common nant targets. It's a script I reuse between projects and it has all the tasks I usually execute (compile, recompile, publish or package the project, run the tests, analyze the code or binaries, etc). &lt;i&gt;&lt;a href="http://github.com/alberto/altnerddinner/blob/master/AltNerdDinner.build"&gt;AltNerdDinner.build&lt;/a&gt;&lt;/i&gt; is the specific script for this project. By virtue of &lt;a href="http://en.wikipedia.org/wiki/Convention_over_configuration"&gt;Convention over Configuration&lt;/a&gt; on the project structure and directory and file names, we can remove a lot of unnecessary noise. By adhering to conventions, we just have to set up a couple of properties and simply delegate on common-targets.build for most (if not all) of the tasks, just defining the dependencies between tasks and passing parameters to configure the task where needed.  &lt;br /&gt;  &lt;br /&gt;You can see below how simple it gets, with only 16 lines of code:  &lt;br /&gt;  &lt;br /&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color: #a31515"&gt;xml &lt;/span&gt;&lt;span style="color: red"&gt;version&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;1.0&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;?&amp;gt;&lt;br /&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;project &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;AltNerdDinner&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;default&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;compile&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;&amp;gt;&lt;br /&gt;  &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;property &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;dir.root&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;value&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;${path::get-full-path('.')}&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;&lt;br /&gt;  &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;include &lt;/span&gt;&lt;span style="color: red"&gt;buildfile&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;${dir.root}/common-targets.build&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;&lt;br /&gt;  &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;property &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;file.solution&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;value&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;${dir.root}/NerdDinner.sln&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;&lt;br /&gt;  &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;property &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;file.project&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;value&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;${dir.root}/src/NerdDinner/NerdDinner.csproj&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;&lt;br /&gt;  &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;property &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;assembly.tests&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;value&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;NerdDinner.Tests.dll&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;target &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;compile&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;depends&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;common.clean, common.init, common.compile&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;&lt;br /&gt;  &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;target &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;test&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;depends&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;compile, common.test&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;&lt;br /&gt;  &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;target &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;publish&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;depends&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;test, common.publish&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;&lt;br /&gt;  &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;target &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;zip&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;depends&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;publish, common.zip&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;&lt;br /&gt;  &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;target &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;analyze&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;depends&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;publish, common.stylecop, common.ndepend&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;&lt;br /&gt;  &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;target &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;build&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;depends&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;publish, analyze&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;&lt;br /&gt;  &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;target &lt;/span&gt;&lt;span style="color: red"&gt;name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;build-full&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;depends&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;publish, analyze, zip&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;&lt;br /&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;project&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;There is also a &lt;a href="http://github.com/alberto/altnerddinner/blob/master/go.bat"&gt;go.bat&lt;/a&gt; script, which just calls nant, passing AltNerdDinner.build as the build file. As a side note, notice that my solution file is in the root of the project instead of in src. I like to keep it there so that I can easily refer to the root of the project from it (useful if you want to dome some pre/post build stuff on Visual Studio or for other tools than reference your solution).&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-3255220909010797137?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/3255220909010797137/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=3255220909010797137' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/3255220909010797137'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/3255220909010797137'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2009/09/road-to-continuous-integration-part-3.html' title='The road to Continuous Integration. Part 3: Script it, build it, test it, break it, fix it. Commit it.'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_kQ7iivKjVno/SsEIiowefII/AAAAAAAAAMI/TuxGRy-ffPI/s72-c/projectstructure_thumb8.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-7426619163897805663</id><published>2009-09-15T11:33:00.002+02:00</published><updated>2009-09-15T11:34:59.466+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wtf'/><title type='text'>What do you see on the picture?</title><content type='html'>&lt;div class="separator" style="clear: both; float: left; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_kQ7iivKjVno/Sq9dG5dZPCI/AAAAAAAAAL8/Z4vqxop7-cY/s1600-h/monofinger.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_kQ7iivKjVno/Sq9dG5dZPCI/AAAAAAAAAL8/Z4vqxop7-cY/s320/monofinger.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;a href="http://monotouch.net/"&gt;Monotouch&lt;/a&gt; 1.0 was released today. I was quite shocked when I saw the logo. Look at it for a second. What do you see there?&lt;br /&gt;It might be my perturbated mind, but I was quite shocked when I felt it was "showing me the finger". It actually took me a minute (I said I was shocked) to realize it was not &lt;i&gt;that &lt;/i&gt;finger. Still, maybe that logo deserves a revamp. Just making clear the first finger is a thumb will suffice.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-7426619163897805663?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/7426619163897805663/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=7426619163897805663' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/7426619163897805663'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/7426619163897805663'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2009/09/what-do-you-see-on-picture.html' title='What do you see on the picture?'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_kQ7iivKjVno/Sq9dG5dZPCI/AAAAAAAAAL8/Z4vqxop7-cY/s72-c/monofinger.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-6331902920249328748</id><published>2009-09-13T20:11:00.001+02:00</published><updated>2009-09-13T20:11:17.785+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='project automation'/><category scheme='http://www.blogger.com/atom/ns#' term='continuous integration'/><title type='text'>The road to Continuous Integration. Part 2: Shake your tree</title><content type='html'>&lt;p&gt;As I stated in the &lt;a href="http://sharpbites.blogspot.com/2009/09/road-to-continuous-integration-part-1.html"&gt;first part&lt;/a&gt; of this &lt;a href="http://sharpbites.blogspot.com/2009/09/road-to-continuous-integration.html"&gt;Continuous Integration series&lt;/a&gt;, one of the aims of storing your stuff under source control is being able to build your project from a fresh checkout, without needing to manually install or configure anything.&lt;/p&gt;  &lt;p&gt;To accomplish this, it is always useful to use a standardized tree structure. You can have a look at some of the popular open source projects you use and love to get ideas on how to organize things. Now that your have &lt;a href="http://sharpbites.blogspot.com/2009/09/road-to-continuous-integration-part-1.html"&gt;everything under source control&lt;/a&gt; (don't you?), we can start moving a few things around.&lt;/p&gt;  &lt;p&gt;&lt;img align="right" src="http://4.bp.blogspot.com/_kQ7iivKjVno/SpghIOjZSzI/AAAAAAAAALc/SkfsSCTd74E/s400/project-structure.jpg" /&gt; On the picture you can see a very typical structure for a project.&lt;/p&gt;  &lt;p&gt;The &lt;strong&gt;src&lt;/strong&gt; folder contains the different projects in their respective folders.     &lt;br /&gt;The &lt;strong&gt;lib&lt;/strong&gt; folder will contain any third-party library needed to run our project. This is, any dependency that has to be deployed with our project (e.g. NHibernate, Windsor, etc).     &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;The &lt;strong&gt;tools&lt;/strong&gt; folders will contain any tools needed to build our project. It will contain tools like nant, nunit or fxcop, which we will use but won't distribute with our application.     &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;The &lt;strong&gt;build&lt;/strong&gt; folder will hold the artifacts of the build.&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;Again, the purpose of putting all these libraries and frameworks under source control is to make EVERITHING needed to build and run your project available. Any new developer getting into your team should then be able to checkout your code and build it successfully, without needing to download and/or install anything from the Internet or hunt down any other dependencies your project builds upon. &lt;/p&gt;  &lt;p&gt;If you need further info, I would recommend you to watch &lt;a href="http://www.dimecasts.net/Casts/CastDetails/16"&gt;this screencast&lt;/a&gt; by &lt;a href="http://codebetter.com/blogs/kyle.baley/"&gt;Kyle &amp;quot;Dissociative identity disorder&amp;quot; Baley&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-6331902920249328748?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/6331902920249328748/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=6331902920249328748' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/6331902920249328748'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/6331902920249328748'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2009/09/road-to-continuous-integration-part-2.html' title='The road to Continuous Integration. Part 2: Shake your tree'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_kQ7iivKjVno/SpghIOjZSzI/AAAAAAAAALc/SkfsSCTd74E/s72-c/project-structure.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-8714907535387450764</id><published>2009-09-11T22:44:00.001+02:00</published><updated>2009-09-11T22:44:39.386+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quality'/><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='project automation'/><category scheme='http://www.blogger.com/atom/ns#' term='project management'/><category scheme='http://www.blogger.com/atom/ns#' term='continuous integration'/><title type='text'>The road to Continuous Integration. Part 1: Get your source under control!</title><content type='html'>&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_kQ7iivKjVno/Sqq2s0-EiHI/AAAAAAAAAL0/DFQJE0sWIhc/s1600-h/timemachine6.jpg"&gt;&lt;img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" border="0" alt="time-machine" align="right" src="http://lh3.ggpht.com/_kQ7iivKjVno/Sqq2tpkGKTI/AAAAAAAAAL4/g1pf0RP_k7Q/timemachine_thumb6.jpg?imgmax=800" width="115" height="115" /&gt;&lt;/a&gt; If you are not already doing so, put your stuff under source control. Right now. It doesn't matter how small your project is or whether you are working alone. If it's worth your time, it's worth putting it under source control. &lt;/p&gt;  &lt;h4&gt;What is Source Control?&lt;/h4&gt;  &lt;p&gt;Source control, often referred to as VCS (Version Control System) or SCM (Source Code Management) is the management of changes in files. It's a time machine that lets you see how your project looked like at any given point in time.&lt;/p&gt;  &lt;p&gt;For a more detailed introduction, see &lt;a href="http://www.ericsink.com/scm/source_control.html"&gt;Eric Sink's Source Control HOWTO&lt;/a&gt; or the &lt;a href="http://svnbook.red-bean.com/nightly/en/index.html"&gt;SVN book&lt;/a&gt;.&lt;/p&gt;  &lt;h4&gt;Why you should use a SCM tool&lt;/h4&gt;  &lt;p&gt;It gives you an infinite undo-button. No matter how much you have screwed up, you can always go back to a stable point.&lt;/p&gt;  &lt;p&gt;You can share code with other people.&lt;/p&gt;  &lt;p&gt;You can keep track of your changes over time. This allows you to know who changed what, when and (luckily, if you use meaningful comments) why.&lt;/p&gt;  &lt;p&gt;You can maintain multiple code bases of your software. Even if you only have one active version at a time, it's useful to start new development independently.&lt;/p&gt;  &lt;h4&gt;What should you store?&lt;/h4&gt;  &lt;p&gt;Everything you need to build your product. That includes your sources, of course, but also any libraries your projects depends on (avoid referencing GAC'ed or installed libraries), any tools you use and any scripts that you need as part of the process. Nothing should be dependent of your machine installation.&lt;/p&gt;  &lt;p&gt;The goal is to be able to get into a clean machine, get a copy of the codebase from your source repository, build it (automatically) and voil&amp;#224;, you are done and ready to start working!&lt;/p&gt;  &lt;h4&gt;WHICH SCM ARE YOU?&lt;/h4&gt;  &lt;p&gt;&lt;a href="http://subversion.tigris.org/"&gt;There&lt;/a&gt; &lt;a href="http://www.git-scm.org/"&gt;are&lt;/a&gt; &lt;a href="http://www.selenic.com/mercurial/"&gt;many&lt;/a&gt; &lt;a href="http://bazaar-vcs.org/"&gt;alternatives&lt;/a&gt;, just pick one, (oh well, &lt;a href="http://www.codinghorror.com/blog/archives/000660.html"&gt;not THAT one&lt;/a&gt;). If you don't want to set up and maintain a server, you can use &lt;a href="http://code.google.com/"&gt;one&lt;/a&gt; &lt;a href="http://sourceforge.net"&gt;of&lt;/a&gt; &lt;a href="http://www.assembla.com"&gt;the&lt;/a&gt; &lt;a href="http://github.com/"&gt;many&lt;/a&gt; &lt;a href="http://bitbucket.org/"&gt;online&lt;/a&gt; &lt;a href="http://www.launchpad.net"&gt;services&lt;/a&gt; &lt;a href="http://www.codeplex.com"&gt;available&lt;/a&gt; (some of them are just for open source projects, and some have free and paid plans). Which one is best will depend on your specific needs:&lt;/p&gt;  &lt;h5&gt;If you...&lt;/h5&gt;  &lt;ul&gt;   &lt;li&gt;want an easy to install, easy to start tool -&amp;gt; svn &lt;/li&gt;    &lt;li&gt;want a powerful tool, at the expense of a bit steeper learning curve -&amp;gt; git, mercurial, bazaar &lt;/li&gt;    &lt;li&gt;need to use a mature GUI/integration with Visual Studio -&amp;gt; svn, tfs &lt;/li&gt;    &lt;li&gt;need good branching and merging support -&amp;gt; git, mercurial, bazaar &lt;/li&gt;    &lt;li&gt;need an all-in-one tool (source control, bug tracking system, continuous integration) completely integrated, even if the individual tools are not-so-great for the -&amp;gt; tfs &lt;/li&gt;    &lt;li&gt;are a Microsoft-only shop -&amp;gt; tfs &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;For the clients there are also a myriad of tools available for all platforms. You have command-line interfaces, standalone GUI tools (&lt;a href="http://tortoisesvn.net/"&gt;tortoisesvn&lt;/a&gt;, &lt;a href="http://bitbucket.org/tortoisehg/stable/wiki/Home"&gt;tortoisehg&lt;/a&gt;, &lt;a href="http://code.google.com/p/tortoisegit/"&gt;tortoisegit&lt;/a&gt;) and IDE integrated (&lt;a href="http://www.visualsvn.com/"&gt;VisualSVN&lt;/a&gt;, &lt;a href="http://ankhsvn.open.collab.net/"&gt;AnhkSVN&lt;/a&gt;, &lt;a href="http://code.google.com/p/gitextensions/"&gt;Git Extensions&lt;/a&gt;).&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-8714907535387450764?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/8714907535387450764/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=8714907535387450764' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/8714907535387450764'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/8714907535387450764'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2009/09/road-to-continuous-integration-part-1.html' title='The road to Continuous Integration. Part 1: Get your source under control!'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_kQ7iivKjVno/Sqq2tpkGKTI/AAAAAAAAAL4/g1pf0RP_k7Q/s72-c/timemachine_thumb6.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-2007036761059099750</id><published>2009-09-08T20:38:00.002+02:00</published><updated>2009-09-08T21:05:10.382+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='work'/><category scheme='http://www.blogger.com/atom/ns#' term='philosophy'/><category scheme='http://www.blogger.com/atom/ns#' term='recruiting'/><title type='text'>Agile enterprise culture</title><content type='html'>&lt;div style="width:425px;text-align:left" id="__ss_1798664"&gt;&lt;a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/reed2001/culture-1798664" title="Culture"&gt;Culture&lt;/a&gt;&lt;object style="margin:0px" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=culture9-090801103430-phpapp02&amp;rel=0&amp;stripped_title=culture-1798664" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=culture9-090801103430-phpapp02&amp;rel=0&amp;stripped_title=culture-1798664" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;"&gt;View more &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/reed2001"&gt;Reed Hastings&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;Some highlights:&lt;br /&gt;&lt;blockquote&gt;"The real company values, as opposed to the nice-sounding values, are shown by who gets rewarded, promoted or let-go"&lt;/blockquote&gt;&lt;blockquote&gt;"The Keeper Test: 'Which of my people, if they told me they were leaving in two months for a similar job at a peer company, would I fight hard to keep?'"&lt;/blockquote&gt;&lt;blockquote&gt;"You should periodically ask your manager: 'If I told you I were leaving, how hard would you work to change my mind?'"&lt;/blockquote&gt;&lt;blockquote&gt;"In procedural work, the best are 2x better than the average."&lt;/blockquote&gt;&lt;blockquote&gt;"In creative work, the best are 10x better than the average, so huge premium on creating effective teams of the best"&lt;/blockquote&gt;&lt;blockquote&gt;"Vacation policy and Tracking: there is no policy or tracking"&lt;/blockquote&gt;&lt;blockquote&gt;"One outstanding employee gets more done and costs less than two adequate employees"&lt;/blockquote&gt;&lt;blockquote&gt;"It is a good idea, not a traitorous idea, to understand what other firms would pay you, by interviewing and talking to peers at other companies"&lt;/blockquote&gt;&lt;blockquote&gt;Three Tests for Top of Market for a Person:&lt;br /&gt;1. What could person get elsewhere?&lt;br /&gt;2. What would we pay for replacement?&lt;br /&gt;3. What would we pay to keep person?&lt;br /&gt;&lt;/blockquote&gt;&lt;blockquote&gt;"We should celebrate someone leaving for a bigger job that we didn't have available to offer them"&lt;/blockquote&gt;&lt;blockquote&gt;"If manager would promote employee to keep them [...], manager should promote him now, and not wait"&lt;/blockquote&gt;&lt;blockquote&gt;"Mediocre colleagues and unchallenging work is what kills progress of a person's skills"&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-2007036761059099750?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/2007036761059099750/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=2007036761059099750' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/2007036761059099750'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/2007036761059099750'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2009/09/agile-enterprise-culture.html' title='Agile enterprise culture'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-7228160131340565306</id><published>2009-09-01T19:54:00.002+02:00</published><updated>2009-10-03T17:58:31.563+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='continuous integration'/><title type='text'>The road to continuous integration</title><content type='html'>&lt;p&gt;&lt;img style="border-bottom: 0px; border-left: 0px; border-top: 0px; border-right: 0px" border="0" alt="road" align="right" src="http://lh6.ggpht.com/_kQ7iivKjVno/Ssd0pucIX_I/AAAAAAAAAMM/KxJlsxekJj8/carretera%5B1%5D.jpg?imgmax=800" width="244" height="177" /&gt; After my introductory post in the &lt;a href="http://sharpbites.blogspot.com/2009/08/introducing-altnerddinner.html"&gt;AltNerdDinner&lt;/a&gt; series, I thought it would be a good idea to roll out an independent series of posts about the things I have learnt in the past two years on setting up a code base for continuous integration. Nothing really new under the sun, but it might help a few people to get started.    &lt;br /&gt;I will update this post with links backs to each element of the series.    &lt;br /&gt;&lt;a href="http://sharpbites.blogspot.com/2009/09/road-to-continuous-integration-part-1.html"&gt;Part 1: Get your source under control&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://sharpbites.blogspot.com/2009/09/road-to-continuous-integration-part-2.html"&gt;Part 2: Shake your tree&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://sharpbites.blogspot.com/2009/09/road-to-continuous-integration-part-3.html"&gt;Part 3: Script it, build it, test it, break it, fix it. Commit it&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-7228160131340565306?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/7228160131340565306/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=7228160131340565306' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/7228160131340565306'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/7228160131340565306'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2009/09/road-to-continuous-integration.html' title='The road to continuous integration'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_kQ7iivKjVno/Ssd0pucIX_I/AAAAAAAAAMM/KxJlsxekJj8/s72-c/carretera%5B1%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-143013625843200762</id><published>2009-08-27T19:49:00.004+02:00</published><updated>2009-10-19T21:19:37.785+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='altnerddinner'/><title type='text'>Introducing AltNerdDinner</title><content type='html'>&lt;p&gt;This is the first in a series of posts in my quest to get my hands dirty with ASP.NET MVC framework, MVCContrib, Spark, NHibernate, FluentNhibernate, Linq2NHibernate, Windsor and a whatnot. For that, I have decided to take &lt;a href="http://nerddinner.codeplex.com/"&gt;NerdDinner&lt;/a&gt; for a spin (not extremely original, I know), replacing what I think could be better and extending from there. If you are interested, you can have a look at the &lt;a href="http://github.com/alberto/altnerddinner"&gt;AltNerdDinner repository&lt;/a&gt; on github.&lt;/p&gt;  &lt;p&gt;Here is a list of the posts published so far:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://sharpbites.blogspot.com/2009/10/altnerddinner-part-1-removing-unwanted.html"&gt;Part 1: Removing unwanted dependencies&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://sharpbites.blogspot.com/2009/10/altnerddinner-part-2-rich-man.html"&gt;Part 2: Rich Man's Dependency Injection&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://sharpbites.blogspot.com/2009/10/altnerddinner-part-3-introducing-fluent.html"&gt;Part 3: Introducing Fluent NHibernate. Mapping, the easy way&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://sharpbites.blogspot.com/2009/10/altnerdinner-part-4-introducing.html"&gt;Part 4: Introducing NHibernate. Because POCO is enough&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-143013625843200762?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/143013625843200762/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=143013625843200762' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/143013625843200762'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/143013625843200762'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2009/08/introducing-altnerddinner.html' title='Introducing AltNerdDinner'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-5849871751148410741</id><published>2009-08-26T20:38:00.003+02:00</published><updated>2009-08-27T19:49:02.678+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tdd'/><title type='text'>TDD Masterclass</title><content type='html'>&lt;p&gt;Roy Osherove is giving an hands-on TDD Masterclass in the UK, September 21-25. Roy is author of "The Art of Unit Testing" (&lt;a href="http://www.artofunittesting.com/"&gt;http://www.artofunittesting.com/&lt;/a&gt;), a leading tdd &amp;amp; unit testing book; he maintains a blog at &lt;a href="http://iserializable.com"&gt;http://iserializable.com&lt;/a&gt; (which amoung other things has critiqued tests written by Microsoft for &lt;a href="http://asp.net"&gt;asp.net&lt;/a&gt; MVC - check out the testreviews category) and has recently been on the Scott Hanselman podcast (&lt;a href="http://bit.ly/psgYO"&gt;http://bit.ly/psgYO&lt;/a&gt;) where he educated Scott on best practices in Unit Testing techniques. For a further insight into Roy's style, be sure to also check out Roy's talk at the recent Norwegian Developer's Conference (&lt;a href="http://bit.ly/NuJVa"&gt;http://bit.ly/NuJVa&lt;/a&gt;).  &lt;/p&gt;  &lt;p&gt;Full Details here: &lt;a href="http://bbits.co.uk/tddmasterclass"&gt;http://bbits.co.uk/tddmasterclass&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;bbits are holding a raffle for a free ticket for the event. To be eligible to win the ticket (worth £2395!) you MUST paste this text, including all links, into your blog and email &lt;a href="mailto:Ian@bbits.co.uk"&gt;Ian@bbits.co.uk&lt;/a&gt; with the url to the blog entry.  The draw will be made on September 1st and the winner informed by email and on &lt;a href="http://bbits.co.uk/blog"&gt;bbits.co.uk/blog&lt;/a&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-5849871751148410741?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/5849871751148410741/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=5849871751148410741' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/5849871751148410741'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/5849871751148410741'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2009/08/tdd-masterclass.html' title='TDD Masterclass'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-9130050944998521521</id><published>2009-08-15T20:04:00.004+02:00</published><updated>2009-08-15T20:10:54.643+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quality'/><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='work'/><category scheme='http://www.blogger.com/atom/ns#' term='project management'/><category scheme='http://www.blogger.com/atom/ns#' term='philosophy'/><category scheme='http://www.blogger.com/atom/ns#' term='recruiting'/><title type='text'>It's the people, stupid!</title><content type='html'>&lt;blockquote&gt;You need people who are passionate about what they do. People who care about their craft — and actually think of it as a craft. People who take pride in their work, regardless of the monetary reward involved. People who sweat the details even if 95% of folks don't know the difference. People who want to build something great and won't settle for less. [...]Anyhow, when you find those people, hold onto them. In the end, the folks on your team will make or break your project — and your company.&lt;br /&gt;&lt;cite&gt;-- &lt;a href="http://gettingreal.37signals.com/"&gt;Getting Real&lt;/a&gt;, &lt;a href="http://www.37signals.com/"&gt;37signals&lt;/a&gt;&lt;/cite&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-9130050944998521521?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/9130050944998521521/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=9130050944998521521' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/9130050944998521521'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/9130050944998521521'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2009/08/its-people-stupid.html' title='It&apos;s the people, stupid!'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-2326612763605213066</id><published>2009-05-08T21:08:00.000+02:00</published><updated>2009-05-08T21:11:38.711+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quality'/><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><category scheme='http://www.blogger.com/atom/ns#' term='philosophy'/><title type='text'>Excellence</title><content type='html'>&lt;blockquote&gt;We are what we repeatedly do. Excellence, then, is not an act, but a habit.&lt;br /&gt;&lt;cite&gt;-- Aristotle&lt;/cite&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-2326612763605213066?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/2326612763605213066/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=2326612763605213066' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/2326612763605213066'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/2326612763605213066'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2009/05/excellence.html' title='Excellence'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-3545936206328924571</id><published>2009-05-01T20:51:00.006+02:00</published><updated>2009-05-01T21:07:17.593+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='project management'/><title type='text'>The role of the Scrum Sensei</title><content type='html'>&lt;blockquote&gt;When you need me, but do not want me, then I will stay.&lt;br /&gt;When you want me, but do not need me, then I have to go.&lt;br /&gt;&lt;br /&gt;&lt;cite&gt;-- Nanny McPhee, &lt;a href="http://blog.jayway.com/2008/12/17/scrum-shock-therapy-part-2/"&gt;via&lt;/a&gt; &lt;a href="http://blog.jayway.com/author/bjorngranvik/"&gt;Björn Granvik&lt;/a&gt;&lt;/cite&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-3545936206328924571?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/3545936206328924571/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=3545936206328924571' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/3545936206328924571'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/3545936206328924571'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2009/05/role-of-scrum-sensei.html' title='The role of the Scrum Sensei'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-5049695300289449332</id><published>2009-04-27T23:50:00.004+02:00</published><updated>2009-04-27T23:57:21.771+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.net'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>On value types vs reference types and premature optimization</title><content type='html'>Eric Lippert, wrote a great post about value types vs reference types, and how, many times, the discussion is shifted to the-heap-and-the-stack, when it should really be about the differences when those types are passed (by value) as parameters.&lt;br /&gt;&lt;br /&gt;He nails it when he says:&lt;br /&gt;&lt;blockquote&gt;Making the nano-optimization of making a type that really should be a ref type into a value type for a few nanoseconds of perf gain is probably not worth it. I would only be making that choice if profiling data showed that there was a large, real-world-customer-impacting performance problem directly mitigated by using value types. Absent such data, I’d always make the choice of value type vs reference type based on whether the type is semantically representing a value or semantically a reference to something.&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-5049695300289449332?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/5049695300289449332/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=5049695300289449332' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/5049695300289449332'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/5049695300289449332'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2009/04/on-value-types-vs-reference-types-and.html' title='On value types vs reference types and premature optimization'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-4196294956640410616</id><published>2009-03-14T21:18:00.002+01:00</published><updated>2009-03-14T21:21:24.913+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><category scheme='http://www.blogger.com/atom/ns#' term='project management'/><title type='text'>To plan or not to plan</title><content type='html'>&lt;blockquote&gt;In preparing for battle I have always found that plans are useless, but planning is indispensable.&lt;/blockquote&gt;&lt;cite&gt;-- Dwight D. Eisenhower&lt;/cite&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-4196294956640410616?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/4196294956640410616/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=4196294956640410616' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/4196294956640410616'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/4196294956640410616'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2009/03/to-plan-or-not-to-plan.html' title='To plan or not to plan'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-1385828474376140835</id><published>2009-03-12T17:20:00.001+01:00</published><updated>2009-03-12T17:23:25.050+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quality'/><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><title type='text'>The price of change</title><content type='html'>&lt;blockquote&gt;Change is expensive, no question about it. However, consider the alternative—stagnation.&lt;/blockquote&gt;&lt;cite&gt;-- Jim Highsmith&lt;/cite&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-1385828474376140835?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/1385828474376140835/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=1385828474376140835' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/1385828474376140835'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/1385828474376140835'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2009/03/price-of-change.html' title='The price of change'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-2111807431828420986</id><published>2009-03-10T13:20:00.003+01:00</published><updated>2009-03-10T13:29:32.308+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='nant'/><category scheme='http://www.blogger.com/atom/ns#' term='.net'/><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='msbuild'/><category scheme='http://www.blogger.com/atom/ns#' term='continuous integration'/><title type='text'>Targetting .NET 2.0 with Nant and Visual Studio 2008</title><content type='html'>If you try to migrate a solution to VS2008 and you are using nant, you'll probably find a few problems. This is one of them I am documenting for you.&lt;br /&gt;I wanted to use VS2008 and nant, but still want target the .net 2.0 framework. I read somewhere I needed to install the .net 2.0 sdk, but I was still having issues, where msbuild was complaining it didn't recognize the format of the solution file.&lt;br /&gt;It turns out you need to change nant.settings.currentframework to "net-3.5", so that it is the version of msbuild that comes with msbuild who compiles the solution (so I am not sure anymore you need the .net 2.0 sdk). It will still target the .net 2.0 framework for your projects if you set that that way in VS, as msbuild uses that info for the target.&lt;br /&gt;&lt;br /&gt;Hope it helps someone out there.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-2111807431828420986?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/2111807431828420986/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=2111807431828420986' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/2111807431828420986'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/2111807431828420986'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2009/03/targetting-net-20-with-nant-and-visual.html' title='Targetting .NET 2.0 with Nant and Visual Studio 2008'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-2647250444581656545</id><published>2009-02-22T19:12:00.004+01:00</published><updated>2009-02-22T20:39:19.793+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quality'/><category scheme='http://www.blogger.com/atom/ns#' term='deadline driven development'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><title type='text'>Programming for the Mob sharks? No, thanks.</title><content type='html'>&lt;a href="http://c2.com/"&gt;Ward Cunniham&lt;/a&gt;, of &lt;a href="http://c2.com/cgi/wiki"&gt;Ward's Wiki&lt;/a&gt; fame, was the coiner of the term "technical debt". He made an interesting clarification in the following video:&lt;br /&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/pqeJFYwnkjE&amp;hl=es&amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/pqeJFYwnkjE&amp;hl=es&amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;According to his intention, the term is usually misused to reflect (and even encourage) the writing of sloppy code with the excuse that it will be refactored later. His original vision was more aligned with the XP style of simple design.&lt;br /&gt;&lt;br /&gt;Doing bad code with the excuse of refactoring somewhere in the future is not technical debt we are going to pay, but rather asking money from loan mob sharks at an astronomic interest rate and the expenses of losing a few body parts in the way.&lt;br /&gt;&lt;br /&gt;PS: It is funny how the metaphor was coined as an analogy that his boss could understand, but it has grown to be used and abused by everybody in the industry. Maybe that's also related to the debt culture that has drawn our uneducated society into the current situation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-2647250444581656545?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/2647250444581656545/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=2647250444581656545' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/2647250444581656545'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/2647250444581656545'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2009/02/programming-for-mob-sharks-no-thanks.html' title='Programming for the Mob sharks? No, thanks.'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-4526547592830608239</id><published>2008-12-04T23:56:00.004+01:00</published><updated>2009-01-17T17:12:31.128+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quality'/><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><category scheme='http://www.blogger.com/atom/ns#' term='deadline driven development'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><title type='text'>Quality</title><content type='html'>&lt;blockquote&gt;Quality means doing it right when no one is looking.&lt;/blockquote&gt;&lt;cite&gt;-- Henry Ford&lt;/cite&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-4526547592830608239?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/4526547592830608239/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=4526547592830608239' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/4526547592830608239'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/4526547592830608239'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2008/12/quality.html' title='Quality'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-2455655948596927098</id><published>2008-12-04T21:49:00.002+01:00</published><updated>2008-12-04T21:52:39.349+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='work'/><category scheme='http://www.blogger.com/atom/ns#' term='philosophy'/><title type='text'>Assumptions</title><content type='html'>&lt;blockquote&gt;Assumption is the mother of all screw-ups.&lt;/blockquote&gt;&lt;cite&gt;-- Wethern's Law of Suspended Judgment&lt;/cite&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-2455655948596927098?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/2455655948596927098/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=2455655948596927098' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/2455655948596927098'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/2455655948596927098'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2008/12/assumptions.html' title='Assumptions'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-6258557341930548147</id><published>2008-12-04T20:52:00.003+01:00</published><updated>2008-12-04T21:04:13.365+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><title type='text'>Achieving Mastery</title><content type='html'>&lt;blockquote&gt;First, master the fundamentals.&lt;/blockquote&gt;&lt;cite&gt;-- Larry Bird&lt;/cite&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-6258557341930548147?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/6258557341930548147/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=6258557341930548147' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/6258557341930548147'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/6258557341930548147'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2008/12/achieving-mastery.html' title='Achieving Mastery'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-4007359419529215370</id><published>2008-11-24T22:58:00.005+01:00</published><updated>2008-11-24T23:16:13.878+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tdd'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>[SPAM-LOW] Isolator for SharePoint</title><content type='html'>The Typemock guys have released a version of Typemock isolator for SharePoint. This is the announcement (which will hopefully grant me a license to try Typemock):&lt;br /&gt;&lt;br /&gt;Typemock are offering their new product for &lt;a href="http://www.typemock.com/sharepointpage.php?utm_source=sp_bb&amp;utm_medium=blog_4sp&amp;utm_campaign=sp_bb"&gt;unit testing SharePoint&lt;/a&gt; called Isolator For SharePoint, for a special introduction price. it is the only tool that allows you to &lt;a href="http://blog.typemock.com/2008/11/newisolatorforsharepointtoolforunittest.html?utm_source=typeblog&amp;utm_medium=sp_bb&amp;utm_campaign=typeblog"&gt;unit test SharePoint&lt;/a&gt; without a SharePoint server. To learn more &lt;a href="http://www.typemock.com/sharepointpage.php?utm_source=sp_bb&amp;utm_medium=blog_4sp&amp;utm_campaign=sp_bb"&gt;click here&lt;/a&gt;.&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;br /&gt;The first 50 bloggers&lt;/span&gt; who blog this text in their blog and tell us about it, will get &lt;font color="#ff0000"&gt;a Full Isolator license&lt;/font&gt;, Free. for rules and info &lt;a href="http://blog.typemock.com/2008/11/newisolatorforsharepointtoolforunittest.html"&gt;click here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-4007359419529215370?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/4007359419529215370/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=4007359419529215370' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/4007359419529215370'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/4007359419529215370'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2008/11/spam-low-isolator-for-sharepoint.html' title='[SPAM-LOW] Isolator for SharePoint'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-2476144527030000115</id><published>2008-10-15T20:54:00.001+02:00</published><updated>2008-10-15T20:54:54.053+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tips'/><category scheme='http://www.blogger.com/atom/ns#' term='reminder'/><title type='text'>Fix: Can't install updates on Windows XP after installing SP2</title><content type='html'>Just in case it happens to me (or you) again.&lt;br /&gt;&lt;br /&gt;1. Open command prompt (or use a for a &lt;a href="http://sourceforge.net/projects/console/"&gt;better console&lt;/a&gt;).&lt;br /&gt;2. net stop wuauserv&lt;br /&gt;3. regsvr32 %windir%\system32\wups2.dll (regsvr32 %windir%\syswow64\wups2.dll for win64)&lt;br /&gt;4. net start wuauserv&lt;br /&gt;5. exit&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;http://forums.cnet.com/5208-6142_102-0.html?forumID=5&amp;threadID=276886&amp;messageID=2660716&lt;br /&gt;http://support.microsoft.com/kb/943144&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-2476144527030000115?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/2476144527030000115/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=2476144527030000115' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/2476144527030000115'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/2476144527030000115'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2008/10/fix-cant-install-updates-on-windows-xp.html' title='Fix: Can&apos;t install updates on Windows XP after installing SP2'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-608336890087870765</id><published>2008-09-26T18:54:00.004+02:00</published><updated>2011-10-27T20:42:37.196+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='project management'/><category scheme='http://www.blogger.com/atom/ns#' term='wtf'/><category scheme='http://www.blogger.com/atom/ns#' term='continuous integration'/><title type='text'>Why SVN sucks</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;blockquote&gt;"A common desire is to refactor source code, especially in Java-based software projects. Files and directories are shuffled around and renamed, often causing great disruption to everyone working on the project. Sounds like a perfect case to use a branch, doesn't it? Just create a branch, shuffle things around, and then merge the branch back to the trunk, right?&lt;br /&gt;&lt;br /&gt;Alas, this scenario doesn't work so well right now and is considered one of Subversion's current weak spots."&lt;/blockquote&gt;&lt;cite&gt;-- Subversion book&lt;/cite&gt;&lt;br /&gt;&lt;br /&gt;The fact that subversion lacks a true rename operation (it is done via copy &amp;amp; delete) you can get into a lot of troubles if you rename or move files in subversion if somebody else modifies the same file meanwhile. And by troubles I mean losing data! (If you want more info about it, check &lt;a href="http://subversion.tigris.org/issues/show_bug.cgi?id=2282"&gt;this bug entry&lt;/a&gt;. You will find the detailed use cases in the attached files there.)&lt;br /&gt;&lt;br /&gt;For a fast rename (or move, which is exactly the same operation) &amp;amp; commit, there is a low probability you run into this issue (assuming the other guy also updates frequently), so things aren't so critical here. But, when working with branches, it's a whole new story. They will live much longer (from days to weeks or months) so the probability of somebody modifying a file renamed in another branch increases a lot. That effectively means you cannot rename or move files if you use branches. Yeah, you read it right. If you use branches, moving files &lt;span style="font-weight: bold;"&gt;is not safe&lt;/span&gt;. End of story.&lt;br /&gt;&lt;br /&gt;So, what svn is forcing us to do is either:&lt;br /&gt;a) Don't rename files.&lt;br /&gt;b) Don't use branches.&lt;br /&gt;c) Don't use subversion.&lt;br /&gt;&lt;br /&gt;a) is simply stupid, so let's forget it. b) might be ok for some people/enviroments. c) is what you really should be doing if b) is not an option (which makes perfect sense).&lt;br /&gt;&lt;br /&gt;If you are looking for alternatives, use git or mercurial.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-608336890087870765?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/608336890087870765/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=608336890087870765' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/608336890087870765'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/608336890087870765'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2008/09/why-svn-sucks.html' title='Why SVN sucks'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-3413618369271142266</id><published>2008-09-05T20:19:00.006+02:00</published><updated>2008-09-08T02:53:59.997+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='nant'/><category scheme='http://www.blogger.com/atom/ns#' term='project automation'/><category scheme='http://www.blogger.com/atom/ns#' term='msbuild'/><category scheme='http://www.blogger.com/atom/ns#' term='continuous integration'/><title type='text'>nant vs. msbuild</title><content type='html'>Yes, this is yet another post on &lt;a href="http://nant.sourceforge.net/"&gt;nant&lt;/a&gt; vs. &lt;a href="http://msdn.microsoft.com/en-us/library/0k6kkbsd.aspx"&gt;msbuild&lt;/a&gt;.&lt;br /&gt;I had to choose which one of the two to use at the company I work for. After doing a lot of research, it looks like there aren't many differences between them. Here are some of the pro/cons I found:&lt;br /&gt;&lt;br /&gt;- msbuild comes from Microsoft (yes, that usually matters to some (not all, like me) people)&lt;br /&gt;- msbuild is already installed in every .net developer machine (not a big deal)&lt;br /&gt;- msbuild has probably better integration with VS build process&lt;br /&gt;- msbuild supports parallel builds since .net 3.5 (not that it really matters, since you usually use msbuild from nant to build your projects, anyway).&lt;br /&gt;- msbuild evaluates filesets at startup. This seems to cause some headaches when you want to manipulate files generated during the building process.&lt;br /&gt;- you can redefine targets in msbuild. in nant you can define general targets and just make your build files call those (or create and use hooks, which is a solution I don't really like).&lt;br /&gt;- nant has more examples and better documentation&lt;br /&gt;- there is much more information about nant than about msbuild on the web, according to &lt;a href="http://www.google.es/trends?q=msbuild%2C+nant"&gt;google trends&lt;/a&gt; and google search results (both in english and spanish)&lt;br /&gt;- nant has some more tasks, but with &lt;a href="http://msbuildtasks.tigris.org/"&gt;msbuildtasks&lt;/a&gt;/&lt;a href="http://www.codeplex.com/sdctasks"&gt;sdc tasks&lt;/a&gt; it's on par with nant and &lt;a href="http://nantcontrib.sourceforge.net/"&gt;nantcontrib&lt;/a&gt;.&lt;br /&gt;- nant helper functions and expressions are better ¿?&lt;br /&gt;- I like nant syntax better.&lt;br /&gt;- nant is more mature, msbuild was born as an alternative (alt.alt.net :D) to nant for companies with ridiculous "no open source here" and Microsoft "I can't support an open source project I don't control" way of life.&lt;br /&gt;- most open source projects tend to use nant over msbuild, so there are plenty of build files and task you can make good use of or have as a reference.&lt;br /&gt;- I have already played with nant a little, so I know it's syntax better.&lt;br /&gt;- I have started to use nant to automatically generate config files from templates for the different enviroments, and didn't find the way to do so in msbuild.&lt;br /&gt;- nant is open source, so people can contribute to it.&lt;br /&gt;- nant is not tied to microsoft release cycle, msbuild is.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;There isn't any strong reason in itself to pick one, but adding them up, things favoured significantly nant over msbuild, so I ended up choosing the former.&lt;br /&gt;&lt;br /&gt;If you want to read more on the subject, here are some of the links I used in my research (in no particular order):&lt;br /&gt;http://ayende.com/Blog/archive/2008/02/25/Zero-Friction-and-why-Defaults-Matters.aspx&lt;br /&gt;http://www.winterdom.com/weblog/2007/09/21/MSBuildVsNAnt.aspx&lt;br /&gt;http://www.paraesthesia.com/archive/2008/01/08/why-nant-is-better-than-msbuild.aspx&lt;br /&gt;http://www.innoq.com/blog/hw/2007/09/24/msbuild_vs_nant.html&lt;br /&gt;http://www.codeproject.com/KB/books/msbuild.aspx&lt;br /&gt;http://brandonbyars.com/blog/articles/2008/01/10/Managing-Config-Files&lt;br /&gt;http://www.paraesthesia.com/archive/2008/01/08/why-nant-is-better-than-msbuild.aspx&lt;br /&gt;http://kentb.blogspot.com/2008/02/fail-early-with-full-builds-from-within.html&lt;br /&gt;http://weblogs.asp.net/rosherove/archive/2008/01/18/trying-out-team-city-looks-promising.aspx&lt;br /&gt;http://codebetter.com/blogs/jeremy.miller/archive/2007/09/20/is-there-a-good-reason-to-switch-to-msbuild.aspx&lt;br /&gt;http://codebetter.com/blogs/jeffrey.palermo/archive/2007/09/25/demo-on-automating-your-build-with-nant-and-ccnet.aspx&lt;br /&gt;http://www.distribucon.com/blog/WhyMSBuildSucks.aspx&lt;br /&gt;http://www.tkachenko.com/blog/archives/000643.html&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-3413618369271142266?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/3413618369271142266/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=3413618369271142266' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/3413618369271142266'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/3413618369271142266'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2008/09/nant-vs-msbuild.html' title='nant vs. msbuild'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-562623484367208646</id><published>2008-07-20T12:49:00.003+02:00</published><updated>2008-07-20T12:52:27.785+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='analogic life'/><title type='text'>Back from holydays</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_kQ7iivKjVno/SIMYnCtkH5I/AAAAAAAAAGU/KKTZAgii9cA/s1600-h/unread.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_kQ7iivKjVno/SIMYnCtkH5I/AAAAAAAAAGU/KKTZAgii9cA/s400/unread.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5225047051701854098" /&gt;&lt;/a&gt;&lt;br /&gt;Oh, my.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-562623484367208646?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/562623484367208646/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=562623484367208646' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/562623484367208646'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/562623484367208646'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2008/07/back-from-holydays.html' title='Back from holydays'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_kQ7iivKjVno/SIMYnCtkH5I/AAAAAAAAAGU/KKTZAgii9cA/s72-c/unread.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-4477242460330845516</id><published>2008-06-18T21:07:00.004+02:00</published><updated>2008-06-18T21:14:20.912+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><category scheme='http://www.blogger.com/atom/ns#' term='deadline driven development'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='project management'/><title type='text'>How does a project get to be a year behind schedule?</title><content type='html'>&lt;blockquote&gt;One day at a time.&lt;br /&gt;&lt;cite&gt;-- &lt;a href="http://www.cs.unc.edu/~brooks/"&gt;Fred Brooks&lt;/a&gt;, &lt;a href="http://www.amazon.com/Mythical-Man-Month-Software-Engineering-Anniversary/dp/0201835959"&gt;The Mythical Man-Month&lt;/a&gt;.&lt;/cite&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-4477242460330845516?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/4477242460330845516/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=4477242460330845516' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/4477242460330845516'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/4477242460330845516'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2008/06/how-does-project-get-to-be-year-behind.html' title='How does a project get to be a year behind schedule?'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-4065884893909142646</id><published>2008-06-18T20:54:00.007+02:00</published><updated>2008-06-18T21:06:30.790+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='project management'/><title type='text'>Fix Time and Budget, Flex Scope</title><content type='html'>&lt;blockquote&gt;Here's an easy way to launch on time and on budget: keep them fixed. Never throw more time or money at a problem, just scale back the scope.&lt;br /&gt;[...]&lt;br /&gt;If you can't fit everything in within the time and budget allotted then don't expand the time and budget. Instead, pull back the scope. There's always time to add stuff later — later is eternal, now is fleeting.&lt;cite&gt;-- &lt;a href="http://www.37signals.com/"&gt;37signals&lt;/a&gt;, &lt;a href="http://gettingreal.37signals.com/ch02_Fix_Time_and_Budget_Flex_Scope.php"&gt;Getting Real&lt;/a&gt;.&lt;/cite&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-4065884893909142646?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/4065884893909142646/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=4065884893909142646' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/4065884893909142646'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/4065884893909142646'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2008/06/fix-time-and-budget-flex-scope.html' title='Fix Time and Budget, Flex Scope'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-3607650612062281160</id><published>2008-06-15T18:24:00.003+02:00</published><updated>2008-06-15T18:32:31.071+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><category scheme='http://www.blogger.com/atom/ns#' term='analogic life'/><category scheme='http://www.blogger.com/atom/ns#' term='philosophy'/><title type='text'>Experience</title><content type='html'>&lt;blockquote&gt;Experience is what you get when you don't get what you want.&lt;/blockquote&gt;&lt;cite&gt;-- Dan Stanford&lt;/cite&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-3607650612062281160?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/3607650612062281160/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=3607650612062281160' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/3607650612062281160'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/3607650612062281160'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2008/06/experience.html' title='Experience'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-8713952570313249243</id><published>2008-06-01T19:28:00.006+02:00</published><updated>2008-06-01T19:47:59.534+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.net'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>Exce(r)ptions</title><content type='html'>Just a few notes on exceptions to remind, from &lt;a href="http://codebetter.com/blogs/karlseguin/default.aspx"&gt;Karl Seguin&lt;/a&gt;.&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Handling exceptions&lt;/span&gt;&lt;br /&gt;1 - Only handle exceptions that you can actually do something about, and&lt;br /&gt;2 - You can't do anything about the vast majority of exceptions&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Logging&lt;/span&gt;&lt;br /&gt;You should log every exception. Ideally you'll centralize your logging - an HttpModule's OnError event is your best choice for an ASP.NET application or web service.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Handling database access (and its possible exceptions):&lt;/span&gt;&lt;br /&gt;&lt;code&gt;using (SqlConnection connection = new SqlConnection(FROM_CONFIGURATION))  &lt;br /&gt;using (SqlCommand command = new SqlCommand("SomeSQL", connection))  &lt;br /&gt;{  &lt;br /&gt;   connection.Open();  &lt;br /&gt;   command.ExecuteNonQuery();  &lt;br /&gt;} &lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;throw vs. throw ex&lt;/span&gt;&lt;br /&gt;On occasion you'll need to rethrow an exception because, while you can't handle the exception, you still need to execute some code when an exception occurs. In this case you should use &lt;span style="font-weight:bold;"&gt;throw&lt;/span&gt; to preserve the full exception stack. Contrary, if you find yourself in a situation where you think you want to rethrow an exception with your handler as the source, a better approach is to use a nested exception:&lt;br /&gt;&lt;code&gt;catch (HibernateException ex)&lt;br /&gt;{&lt;br /&gt;  if (transaction != null) { transaction.Rollback(); }&lt;br /&gt;  throw new Exception("Email already in use", ex);&lt;br /&gt;}&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;When to throw&lt;/span&gt;&lt;br /&gt;A method should throw when it wasn't able to do what it was suppossed to do.&lt;br /&gt;&lt;br /&gt;If you want a more in-depth explanation on the subject, I recommend you go and read the &lt;a href="http://codebetter.com/blogs/karlseguin/archive/2008/05/29/foundations-of-programming-pt-8-back-to-basics-exceptions.aspx"&gt;article&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-8713952570313249243?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/8713952570313249243/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=8713952570313249243' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/8713952570313249243'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/8713952570313249243'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2008/06/exceptions.html' title='Exce(r)ptions'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-1084188314983576973</id><published>2008-06-01T11:38:00.001+02:00</published><updated>2008-06-01T11:39:49.913+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='work'/><category scheme='http://www.blogger.com/atom/ns#' term='philosophy'/><title type='text'>The key to success</title><content type='html'>&lt;blockquote&gt;I don't know the key to success, but the key to failure is trying to please everybody.&lt;/blockquote&gt;&lt;cite&gt;-- Bill Cosby&lt;/cite&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-1084188314983576973?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/1084188314983576973/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=1084188314983576973' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/1084188314983576973'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/1084188314983576973'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2008/06/key-to-success.html' title='The key to success'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-8606875089151810326</id><published>2008-05-11T22:05:00.004+02:00</published><updated>2008-05-11T22:29:24.652+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><category scheme='http://www.blogger.com/atom/ns#' term='analogic life'/><category scheme='http://www.blogger.com/atom/ns#' term='philosophy'/><title type='text'>Don't let that wall stop you</title><content type='html'>&lt;blockquote&gt;Brick walls are there for a reason: they let us prove how bad we want things.&lt;/blockquote&gt;&lt;cite&gt;-- &lt;a href="http://es.youtube.com/watch?v=ji5_MqicxSo"&gt;Randy Pausch&lt;/a&gt;&lt;/cite&gt;&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="355"&gt;&lt;param name="movie" value="http://www.youtube.com/v/ji5_MqicxSo&amp;hl=es"&gt;&lt;/param&gt;&lt;param name="wmode" value="transparent"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/ji5_MqicxSo&amp;hl=es" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-8606875089151810326?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/8606875089151810326/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=8606875089151810326' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/8606875089151810326'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/8606875089151810326'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2008/05/dont-let-that-wall-stop-you.html' title='Don&apos;t let that wall stop you'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-5746900383778539992</id><published>2008-04-14T21:14:00.004+02:00</published><updated>2008-04-14T21:57:46.632+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='recruiting'/><title type='text'>Ayende's Challenge #2: The directory tree</title><content type='html'>Here comes a new challenge.&lt;br /&gt;&lt;blockquote&gt;Given a set of versioned file, you need to cache them locally. Note that IPersistentCache semantics means that if you put a value in it, is is always going to remain there.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;I'm glad this one wasn't on a real interview, it took me quite some time to get this right, I guess I wouldn't have get the job this time. xD&lt;br /&gt;&lt;br /&gt;You can download the source from &lt;a href="http://www.assembla.com/spaces/sand-box/documents/aMV1tEcLGr3zM9ab7jnrAJ/download?filename=Ayende%27s+Challenge+%232%3A+The+directory+Tree.zip"&gt;here&lt;/a&gt; or see it below. :)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;}??\fs20     \cf3 public\cf0  \cf3 interface\cf0  \cf4 IPersistentCache\par ??\cf0     \{\par ??        \cf3 void\cf0  Set(\cf3 string\cf0  key, \cf3 params\cf0  \cf3 string\cf0 [] items);\par ??        \cf3 string\cf0 [] Get(\cf3 string\cf0  key);\par ??        \cf4 ICollection\cf0 &amp;lt;\cf3 string\cf0 &amp;gt; Keys();\par ??    \}\par ??\par ??    \cf3 public\cf0  \cf3 class\cf0  \cf4 PersistentCache\cf0  : \cf4 IPersistentCache\par ??\cf0     \{\par ??        \cf3 readonly\cf0  \cf4 Dictionary\cf0 &amp;lt;\cf3 string\cf0 , \cf4 List\cf0 &amp;lt;\cf3 string\cf0 &amp;gt;&amp;gt; cache = \cf3 new\cf0  \cf4 Dictionary\cf0 &amp;lt;\cf3 string\cf0 , \cf4 List\cf0 &amp;lt;\cf3 string\cf0 &amp;gt;&amp;gt;();\par ??        \cf3 public\cf0  \cf3 void\cf0  Set(\cf3 string\cf0  key, \cf3 params\cf0  \cf3 string\cf0 [] items)\par ??        \{\par ??            \cf3 if\cf0  (cache.ContainsKey(key))\par ??               cache[key].AddRange(items);\par ??            \cf3 else\par ??\cf0                cache[key] = \cf3 new\cf0  \cf4 List\cf0 &amp;lt;\cf3 string\cf0 &amp;gt;(items);\par ??        \}\par ??\par ??        \cf3 public\cf0  \cf3 string\cf0 [] Get(\cf3 string\cf0  key)\par ??        \{\par ??            \cf3 if\cf0  (!cache.ContainsKey(key))\par ??                \cf3 return\cf0  \cf3 null\cf0 ;\par ??            \cf3 return\cf0  cache[key].ToArray();\par ??        \}\par ??\par ??        \cf3 public\cf0  \cf4 ICollection\cf0 &amp;lt;\cf3 string\cf0 &amp;gt; Keys()\par ??        \{\par ??            \cf3 return\cf0  cache.Keys;\par ??        \}\par ??    \}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;interface&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;IPersistentCache&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Set(&lt;span style="color: blue;"&gt;string&lt;/span&gt; key, &lt;span style="color: blue;"&gt;params&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt;[] items);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;string&lt;/span&gt;[] Get(&lt;span style="color: blue;"&gt;string&lt;/span&gt; key);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;ICollection&lt;/span&gt;&amp;lt;&lt;span style="color: blue;"&gt;string&lt;/span&gt;&amp;gt; Keys();&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;PersistentCache&lt;/span&gt; : &lt;span style="color: #2b91af;"&gt;IPersistentCache&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;readonly&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Dictionary&lt;/span&gt;&amp;lt;&lt;span style="color: blue;"&gt;string&lt;/span&gt;, &lt;span style="color: #2b91af;"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue;"&gt;string&lt;/span&gt;&amp;gt;&amp;gt; cache = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Dictionary&lt;/span&gt;&amp;lt;&lt;span style="color: blue;"&gt;string&lt;/span&gt;, &lt;span style="color: #2b91af;"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue;"&gt;string&lt;/span&gt;&amp;gt;&amp;gt;();&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Set(&lt;span style="color: blue;"&gt;string&lt;/span&gt; key, &lt;span style="color: blue;"&gt;params&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt;[] items)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (cache.ContainsKey(key))&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; cache[key].AddRange(items);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;else&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; cache[key] = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue;"&gt;string&lt;/span&gt;&amp;gt;(items);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt;[] Get(&lt;span style="color: blue;"&gt;string&lt;/span&gt; key)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (!cache.ContainsKey(key))&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: blue;"&gt;null&lt;/span&gt;;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; cache[key].ToArray();&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;ICollection&lt;/span&gt;&amp;lt;&lt;span style="color: blue;"&gt;string&lt;/span&gt;&amp;gt; Keys()&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; cache.Keys;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red163\green21\blue21;}??\fs20     \cf3 public\cf0  \cf3 class\cf0  \cf4 VersionedFile\par ??\cf0     \{\par ??        \cf3 public\cf0  \cf3 int\cf0  Version \{ \cf3 get\cf0 ; \cf3 set\cf0 ; \}\par ??        \cf3 public\cf0  \cf3 string\cf0  Name \{ \cf3 get\cf0 ; \cf3 set\cf0 ; \}\par ??\par ??        \cf3 public\cf0  \cf3 override\cf0  \cf3 string\cf0   ToString()\par ??        \{\par ??            \cf3 return\cf0  Name + \cf5 ";"\cf0  + Version;\par ??        \}\par ??\par ??        \cf3 public\cf0  \cf3 static\cf0  \cf4 VersionedFile\cf0  FromString(\cf3 string\cf0  versionedFileString)\par ??        \{\par ??            \cf3 string\cf0 [] nameAndVersion = versionedFileString.Split(\cf5 ';'\cf0 );\par ??            \cf3 return\cf0  \cf3 new\cf0  \cf4 VersionedFile\par ??\cf0                        \{\par ??                           Name = nameAndVersion[0],\par ??                           Version = \cf3 int\cf0 .Parse(nameAndVersion[1])\par ??                       \};\par ??        \}\par ??\par ??        \cf3 public\cf0  \cf3 string\cf0  GetParent()\par ??        \{\par ??            \cf3 int\cf0  index = Name.LastIndexOf(\cf5 "/"\cf0 );\par ??            \cf3 if\cf0  (index &amp;gt; 0)\par ??                \cf3 return\cf0  Name.Substring(0, index);\par ??            \cf3 if\cf0  (index == 0 &amp;amp;&amp;amp; Name.Length &amp;gt; 1)\par ??                \cf3 return\cf0  \cf5 "/"\cf0 ;\par ??            \cf3 return\cf0  \cf3 null\cf0 ;\par ??        \}\par ??    \}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;VersionedFile&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; Version { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Name { &lt;span style="color: blue;"&gt;get&lt;/span&gt;; &lt;span style="color: blue;"&gt;set&lt;/span&gt;; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;override&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt;&amp;nbsp; ToString()&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; Name + &lt;span style="color: #a31515;"&gt;";"&lt;/span&gt; + Version;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;VersionedFile&lt;/span&gt; FromString(&lt;span style="color: blue;"&gt;string&lt;/span&gt; versionedFileString)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;string&lt;/span&gt;[] nameAndVersion = versionedFileString.Split(&lt;span style="color: #a31515;"&gt;';'&lt;/span&gt;);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;VersionedFile&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; Name = nameAndVersion[0],&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; Version = &lt;span style="color: blue;"&gt;int&lt;/span&gt;.Parse(nameAndVersion[1])&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; };&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; GetParent()&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;int&lt;/span&gt; index = Name.LastIndexOf(&lt;span style="color: #a31515;"&gt;"/"&lt;/span&gt;);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (index &amp;gt; 0)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; Name.Substring(0, index);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (index == 0 &amp;amp;&amp;amp; Name.Length &amp;gt; 1)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: #a31515;"&gt;"/"&lt;/span&gt;;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: blue;"&gt;null&lt;/span&gt;;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;}??\fs20     \cf3 public\cf0  \cf3 enum\cf0  \cf4 Recursion\par ??\cf0     \{\par ??        None,\par ??        OneLevel,\par ??        Full\par ??    \}\par ??\par ??    \cf3 public\cf0  \cf3 interface\cf0  \cf4 IFileSystemCache\par ??\cf0     \{\par ??        \cf3 void\cf0  Add(\cf4 VersionedFile\cf0 [] versionedFiles);\par ??        \cf3 string\cf0 [] ListFilesAndFolders(\cf3 string\cf0  root, \cf3 int\cf0  version, \cf4 Recursion\cf0  recursion);\par ??    \}\par ??\par ??    \cf3 public\cf0  \cf3 class\cf0  \cf4 FileSystemCache\cf0  : \cf4 IFileSystemCache\par ??\cf0     \{\par ??        \cf3 readonly\cf0  \cf4 IPersistentCache\cf0  cache;\par ??\par ??        \cf3 public\cf0  FileSystemCache(\cf4 IPersistentCache\cf0  cache)\par ??        \{\par ??            \cf3 this\cf0 .cache = cache;\par ??        \}\par ??\par ??        \cf3 private\cf0  \cf3 void\cf0  WriteToPersistentCache(\cf4 VersionedFile\cf0  file)\par ??        \{\par ??           WriteToPersistentCache(file.Name, file);\par ??        \}\par ??\par ??        \cf3 private\cf0  \cf3 void\cf0  WriteToPersistentCache(\cf3 string\cf0  key, \cf4 VersionedFile\cf0  file)\par ??        \{\par ??            cache.Set(key, file.ToString());\par ??        \}\par ??\par ??        \cf3 public\cf0  \cf3 void\cf0  Add(\cf4 VersionedFile\cf0 [] versionedFiles)\par ??        \{\par ??            \cf3 foreach\cf0  (\cf4 VersionedFile\cf0  file \cf3 in\cf0  versionedFiles)\par ??            \{\par ??                WriteToPersistentCache(file);\par ??                \cf3 string\cf0  parent = file.GetParent();\par ??                \cf3 if\cf0  (parent != \cf3 null\cf0 )\par ??                    WriteToPersistentCache(parent, file);\par ??            \}\par ??        \}\par ??\par ??        \cf3 public\cf0  \cf3 string\cf0 [] ListFilesAndFolders(\cf3 string\cf0  root, \cf3 int\cf0  version, \cf4 Recursion\cf0  recursion)\par ??        \{\par ??            \cf3 switch\cf0  (recursion)\par ??            \{\par ??                \cf3 case\cf0  \cf4 Recursion\cf0 .None:\par ??                    \cf3 return\cf0  GetFolder(root, version);\par ??                \cf3 case\cf0  \cf4 Recursion\cf0 .OneLevel:\par ??                    \cf3 return\cf0  GetFilesAndFolder(root, version);\par ??                \cf3 case\cf0  \cf4 Recursion\cf0 .Full:\par ??                    \cf3 return\cf0  GetAllFilesAndFoldersIn(root, version, \cf3 false\cf0 );\par ??                \cf3 default\cf0 :\par ??                    \cf3 return\cf0  \cf3 null\cf0 ;\par ??            \}\par ??        \}\par ??\par ??\par ??        \cf3 private\cf0  \cf3 static\cf0  \cf3 string\cf0 [] FilterByVersion(\cf3 string\cf0 [] strings, \cf3 int\cf0  version)\par ??        \{\par ??            \cf3 var\cf0  versionedfiles = \cf3 new\cf0  \cf4 List\cf0 &amp;lt;\cf3 string\cf0 &amp;gt;();\par ??            \cf3 foreach\cf0  (\cf3 string\cf0  s \cf3 in\cf0  strings)\par ??            \{\par ??                \cf3 var\cf0  versionedFile = \cf4 VersionedFile\cf0 .FromString(s);\par ??                \cf3 if\cf0  (versionedFile.Version == version)\par ??                    versionedfiles.Add(versionedFile.Name);\par ??            \}\par ??            \cf3 return\cf0  versionedfiles.ToArray();\par ??        \}\par ??\par ??        \cf3 private\cf0  \cf3 string\cf0 [] GetFilesAndFolder(\cf3 string\cf0  folderPath, \cf3 int\cf0  version)\par ??        \{\par ??            \cf3 return\cf0  FilterByVersion(cache.Get(folderPath), version);\par ??        \}\par ??\par ??        \cf3 private\cf0  \cf3 string\cf0 [] GetFolder(\cf3 string\cf0  folderPath, \cf3 int\cf0  version)\par ??        \{\par ??            \cf3 var\cf0  files = GetFilesAndFolder(folderPath, version);\par ??            \cf3 if\cf0  (files == \cf3 null\cf0 )\par ??               \cf3 return\cf0  \cf3 null\cf0 ;\par ??            \cf3 foreach\cf0  (\cf3 string\cf0  file \cf3 in\cf0  files)\par ??            \{\par ??                \cf3 if\cf0  (file == folderPath)\par ??                \{\par ??                    \cf3 return\cf0  \cf3 new\cf0  []\{folderPath\};\par ??                \}\par ??            \}\par ??            \cf3 return\cf0  \cf3 null\cf0 ;\par ??        \}\par ??\par ??        \cf3 private\cf0  \cf3 string\cf0 [] GetAllFilesAndFoldersIn(\cf3 string\cf0  folderPath, \cf3 int\cf0  version, \cf3 bool\cf0  rootIncluded)\par ??        \{\par ??            \cf3 var\cf0  allFiles = \cf3 new\cf0  \cf4 List\cf0 &amp;lt;\cf3 string\cf0 &amp;gt;();\par ??            \cf3 var\cf0  files = GetFilesAndFolder(folderPath, version);\par ??            \cf3 foreach\cf0  (\cf3 string\cf0  file \cf3 in\cf0  files)\par ??            \{\par ??                \cf3 if\cf0  (file != folderPath)\par ??                \{\par ??                    allFiles.AddRange(GetAllFilesAndFoldersIn(file, version, \cf3 true\cf0 ));\par ??                    allFiles.Add(file);\par ??                \}\par ??                \cf3 else\cf0  \cf3 if\cf0  (!rootIncluded)\par ??                    allFiles.Add(file);\par ??            \}\par ??            \cf3 return\cf0  allFiles.ToArray();\par ??        \}\par ??    \}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;enum&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Recursion&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; None,&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; OneLevel,&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Full&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;interface&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;IFileSystemCache&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Add(&lt;span style="color: #2b91af;"&gt;VersionedFile&lt;/span&gt;[] versionedFiles);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;string&lt;/span&gt;[] ListFilesAndFolders(&lt;span style="color: blue;"&gt;string&lt;/span&gt; root, &lt;span style="color: blue;"&gt;int&lt;/span&gt; version, &lt;span style="color: #2b91af;"&gt;Recursion&lt;/span&gt; recursion);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;FileSystemCache&lt;/span&gt; : &lt;span style="color: #2b91af;"&gt;IFileSystemCache&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;readonly&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;IPersistentCache&lt;/span&gt; cache;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; FileSystemCache(&lt;span style="color: #2b91af;"&gt;IPersistentCache&lt;/span&gt; cache)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;this&lt;/span&gt;.cache = cache;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; WriteToPersistentCache(&lt;span style="color: #2b91af;"&gt;VersionedFile&lt;/span&gt; file)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; WriteToPersistentCache(file.Name, file);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; WriteToPersistentCache(&lt;span style="color: blue;"&gt;string&lt;/span&gt; key, &lt;span style="color: #2b91af;"&gt;VersionedFile&lt;/span&gt; file)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; cache.Set(key, file.ToString());&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Add(&lt;span style="color: #2b91af;"&gt;VersionedFile&lt;/span&gt;[] versionedFiles)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;foreach&lt;/span&gt; (&lt;span style="color: #2b91af;"&gt;VersionedFile&lt;/span&gt; file &lt;span style="color: blue;"&gt;in&lt;/span&gt; versionedFiles)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; WriteToPersistentCache(file);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;string&lt;/span&gt; parent = file.GetParent();&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (parent != &lt;span style="color: blue;"&gt;null&lt;/span&gt;)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; WriteToPersistentCache(parent, file);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt;[] ListFilesAndFolders(&lt;span style="color: blue;"&gt;string&lt;/span&gt; root, &lt;span style="color: blue;"&gt;int&lt;/span&gt; version, &lt;span style="color: #2b91af;"&gt;Recursion&lt;/span&gt; recursion)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;switch&lt;/span&gt; (recursion)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;case&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Recursion&lt;/span&gt;.None:&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; GetFolder(root, version);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;case&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Recursion&lt;/span&gt;.OneLevel:&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; GetFilesAndFolder(root, version);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;case&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Recursion&lt;/span&gt;.Full:&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; GetAllFilesAndFoldersIn(root, version, &lt;span style="color: blue;"&gt;false&lt;/span&gt;);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;default&lt;/span&gt;:&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: blue;"&gt;null&lt;/span&gt;;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt;[] FilterByVersion(&lt;span style="color: blue;"&gt;string&lt;/span&gt;[] strings, &lt;span style="color: blue;"&gt;int&lt;/span&gt; version)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;var&lt;/span&gt; versionedfiles = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue;"&gt;string&lt;/span&gt;&amp;gt;();&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;foreach&lt;/span&gt; (&lt;span style="color: blue;"&gt;string&lt;/span&gt; s &lt;span style="color: blue;"&gt;in&lt;/span&gt; strings)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;var&lt;/span&gt; versionedFile = &lt;span style="color: #2b91af;"&gt;VersionedFile&lt;/span&gt;.FromString(s);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (versionedFile.Version == version)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; versionedfiles.Add(versionedFile.Name);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; versionedfiles.ToArray();&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt;[] GetFilesAndFolder(&lt;span style="color: blue;"&gt;string&lt;/span&gt; folderPath, &lt;span style="color: blue;"&gt;int&lt;/span&gt; version)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; FilterByVersion(cache.Get(folderPath), version);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt;[] GetFolder(&lt;span style="color: blue;"&gt;string&lt;/span&gt; folderPath, &lt;span style="color: blue;"&gt;int&lt;/span&gt; version)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;var&lt;/span&gt; files = GetFilesAndFolder(folderPath, version);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (files == &lt;span style="color: blue;"&gt;null&lt;/span&gt;)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: blue;"&gt;null&lt;/span&gt;;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;foreach&lt;/span&gt; (&lt;span style="color: blue;"&gt;string&lt;/span&gt; file &lt;span style="color: blue;"&gt;in&lt;/span&gt; files)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (file == folderPath)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: blue;"&gt;new&lt;/span&gt; []{folderPath};&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: blue;"&gt;null&lt;/span&gt;;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt;[] GetAllFilesAndFoldersIn(&lt;span style="color: blue;"&gt;string&lt;/span&gt; folderPath, &lt;span style="color: blue;"&gt;int&lt;/span&gt; version, &lt;span style="color: blue;"&gt;bool&lt;/span&gt; rootIncluded)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;var&lt;/span&gt; allFiles = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue;"&gt;string&lt;/span&gt;&amp;gt;();&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;var&lt;/span&gt; files = GetFilesAndFolder(folderPath, version);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;foreach&lt;/span&gt; (&lt;span style="color: blue;"&gt;string&lt;/span&gt; file &lt;span style="color: blue;"&gt;in&lt;/span&gt; files)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (file != folderPath)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; allFiles.AddRange(GetAllFilesAndFoldersIn(file, version, &lt;span style="color: blue;"&gt;true&lt;/span&gt;));&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; allFiles.Add(file);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;else&lt;/span&gt; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (!rootIncluded)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; allFiles.Add(file);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; allFiles.ToArray();&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;And there are a few tests too, just to make sure everything works as intended. ;)&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red43\green145\blue175;\red0\green0\blue255;\red163\green21\blue21;}??\fs20         [\cf3 Test\cf0 ]\par ??        \cf4 public\cf0  \cf4 void\cf0  get__should_return_the_files__when_key_exists()\par ??        \{\par ??            \cf4 var\cf0  target = \cf4 new\cf0  \cf3 PersistentCache\cf0 ();\par ??            \cf4 var\cf0  key = \cf5 "/"\cf0 ;\par ??            \cf4 string\cf0 [] values = \{ \cf5 "/"\cf0 , \cf5 "/foo"\cf0  \};\par ??            target.Set(key, values);\par ??\par ??            \cf4 string\cf0 [] actual = target.Get(key);\par ??            \cf3 Assert\cf0 .IsTrue(ContainsAllIn(actual, values));\par ??        \}\par ??\par ??        [\cf3 Test\cf0 ]\par ??        \cf4 public\cf0  \cf4 void\cf0  old_values__should_persist__when_adding_new_ones()\par ??        \{\par ??            \cf4 var\cf0  target = \cf4 new\cf0  \cf3 PersistentCache\cf0 ();\par ??            \cf4 var\cf0  key = \cf5 "/"\cf0 ;\par ??            \cf4 string\cf0 [] values = \{ \cf5 "/"\cf0 , \cf5 "/foo"\cf0  \};\par ??            target.Set(key, values);\par ??\par ??            \cf4 string\cf0 [] otherValues = \{\cf5 "/foo/bar"\cf0 , \cf5 "/test.txt"\cf0 \};\par ??            target.Set(key, otherValues);\par ??            \cf4 string\cf0 [] actual = target.Get(key);\par ??            \cf3 Assert\cf0 .IsTrue(ContainsAllIn(actual, values));\par ??            \cf3 Assert\cf0 .IsTrue(ContainsAllIn(actual, otherValues));\par ??        \}\par ??\par ??        [\cf3 Test\cf0 ]\par ??        \cf4 public\cf0  \cf4 void\cf0  get__should_return_empty_array__when_key_does_not_exist()\par ??        \{\par ??            \cf4 var\cf0  target = \cf4 new\cf0  \cf3 PersistentCache\cf0 ();\par ??            \cf4 var\cf0  key = \cf5 "/"\cf0 ;\par ??            \cf4 string\cf0 [] values = \{ \cf5 "/"\cf0 , \cf5 "/foo"\cf0  \}; \par ??            target.Set(key, values);\par ??            \cf4 var\cf0  key2 = \cf5 "boo"\cf0 ;\par ??            \cf3 Assert\cf0 .IsNull((target.Get(key2)));\par ??        \}\par ??\par ??        \cf4 public\cf0  \cf4 static\cf0  \cf4 bool\cf0  ContainsAllIn(\cf4 string\cf0 [] actual, \cf4 string\cf0 [] array)\par ??        \{\par ??            \cf4 var\cf0  actualValues = \cf4 new\cf0  \cf3 List\cf0 &amp;lt;\cf4 string\cf0 &amp;gt;(actual);\par ??            \cf4 foreach\cf0  (\cf4 string\cf0  s \cf4 in\cf0  array)\par ??            \{\par ??                \cf4 if\cf0  (!actualValues.Contains(s))\par ??                    \cf4 return\cf0  \cf4 false\cf0 ;\par ??            \}\par ??            \cf4 return\cf0  \cf4 true\cf0 ;\par ??        \}\par ??\par ??    \}\par ??}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;Test&lt;/span&gt;]&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; get__should_return_the_files__when_key_exists()&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;var&lt;/span&gt; target = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;PersistentCache&lt;/span&gt;();&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;var&lt;/span&gt; key = &lt;span style="color: #a31515;"&gt;"/"&lt;/span&gt;;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;string&lt;/span&gt;[] values = { &lt;span style="color: #a31515;"&gt;"/"&lt;/span&gt;, &lt;span style="color: #a31515;"&gt;"/foo"&lt;/span&gt; };&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; target.Set(key, values);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;string&lt;/span&gt;[] actual = target.Get(key);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Assert&lt;/span&gt;.IsTrue(ContainsAllIn(actual, values));&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;Test&lt;/span&gt;]&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; old_values__should_persist__when_adding_new_ones()&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;var&lt;/span&gt; target = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;PersistentCache&lt;/span&gt;();&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;var&lt;/span&gt; key = &lt;span style="color: #a31515;"&gt;"/"&lt;/span&gt;;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;string&lt;/span&gt;[] values = { &lt;span style="color: #a31515;"&gt;"/"&lt;/span&gt;, &lt;span style="color: #a31515;"&gt;"/foo"&lt;/span&gt; };&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; target.Set(key, values);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;string&lt;/span&gt;[] otherValues = {&lt;span style="color: #a31515;"&gt;"/foo/bar"&lt;/span&gt;, &lt;span style="color: #a31515;"&gt;"/test.txt"&lt;/span&gt;};&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; target.Set(key, otherValues);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;string&lt;/span&gt;[] actual = target.Get(key);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Assert&lt;/span&gt;.IsTrue(ContainsAllIn(actual, values));&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Assert&lt;/span&gt;.IsTrue(ContainsAllIn(actual, otherValues));&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;Test&lt;/span&gt;]&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; get__should_return_empty_array__when_key_does_not_exist()&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;var&lt;/span&gt; target = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;PersistentCache&lt;/span&gt;();&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;var&lt;/span&gt; key = &lt;span style="color: #a31515;"&gt;"/"&lt;/span&gt;;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;string&lt;/span&gt;[] values = { &lt;span style="color: #a31515;"&gt;"/"&lt;/span&gt;, &lt;span style="color: #a31515;"&gt;"/foo"&lt;/span&gt; }; &lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; target.Set(key, values);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;var&lt;/span&gt; key2 = &lt;span style="color: #a31515;"&gt;"boo"&lt;/span&gt;;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Assert&lt;/span&gt;.IsNull((target.Get(key2)));&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;bool&lt;/span&gt; ContainsAllIn(&lt;span style="color: blue;"&gt;string&lt;/span&gt;[] actual, &lt;span style="color: blue;"&gt;string&lt;/span&gt;[] array)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;var&lt;/span&gt; actualValues = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue;"&gt;string&lt;/span&gt;&amp;gt;(actual);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;foreach&lt;/span&gt; (&lt;span style="color: blue;"&gt;string&lt;/span&gt; s &lt;span style="color: blue;"&gt;in&lt;/span&gt; array)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (!actualValues.Contains(s))&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: blue;"&gt;false&lt;/span&gt;;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: blue;"&gt;true&lt;/span&gt;;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red43\green145\blue175;\red0\green0\blue255;\red163\green21\blue21;}??\fs20     [\cf3 TestFixture\cf0 ]\par ??    \cf4 public\cf0  \cf4 class\cf0  \cf3 FileSystemCacheTests\par ??\cf0     \{\par ??        \cf4 readonly\cf0  \cf3 PersistentCache\cf0  cache = \cf4 new\cf0  \cf3 PersistentCache\cf0 ();\par ??        \cf4 private\cf0  \cf3 FileSystemCache\cf0  fsc;\par ??\par ??        [\cf3 SetUp\cf0 ]\par ??        \cf4 public\cf0  \cf4 void\cf0  SetUp()\par ??        \{\par ??            fsc = \cf4 new\cf0  \cf3 FileSystemCache\cf0 (cache);\par ??            fsc.Add(\cf4 new\cf0 []\par ??                        \{\par ??                            \cf4 new\cf0  \cf3 VersionedFile\cf0  \{Version = 1, Name = \cf5 "/"\cf0 \},\par ??                            \cf4 new\cf0  \cf3 VersionedFile\cf0  \{Version = 1, Name = \cf5 "/foo"\cf0 \},\par ??                            \cf4 new\cf0  \cf3 VersionedFile\cf0  \{Version = 1, Name = \cf5 "/foo/bar"\cf0 \},\par ??                            \cf4 new\cf0  \cf3 VersionedFile\cf0  \{Version = 1, Name = \cf5 "/foo/bar/text.txt"\cf0 \},\par ??                        \});\par ??            fsc.Add(\cf4 new\cf0 []\par ??                        \{\par ??                            \cf4 new\cf0  \cf3 VersionedFile\cf0  \{Version = 2, Name = \cf5 "/"\cf0 \},\par ??                            \cf4 new\cf0  \cf3 VersionedFile\cf0  \{Version = 2, Name = \cf5 "/foo"\cf0 \},\par ??                            \cf4 new\cf0  \cf3 VersionedFile\cf0  \{Version = 2, Name = \cf5 "/foo/bar"\cf0 \},\par ??                            \cf4 new\cf0  \cf3 VersionedFile\cf0  \{Version = 2, Name = \cf5 "/foo/bar/text.txt"\cf0 \},\par ??                            \cf4 new\cf0  \cf3 VersionedFile\cf0  \{Version = 2, Name = \cf5 "/test.txt"\cf0 \},\par ??                        \});\par ??        \}\par ??\par ??        [\cf3 Test\cf0 ]\par ??        \cf4 public\cf0  \cf4 void\cf0  should_be_able_to_get_files__without_recursion()\par ??        \{\par ??            \cf4 var\cf0  actual = fsc.ListFilesAndFolders(\cf5 "/"\cf0 , 1, \cf3 Recursion\cf0 .None);\par ??            \cf3 Assert\cf0 .IsTrue(\cf3 PersistentCacheTest\cf0 .ContainsAllIn(actual, \cf4 new\cf0  [] \{ \cf5 "/"\cf0  \}));\par ??        \}\par ??\par ??        [\cf3 Test\cf0 ]\par ??        \cf4 public\cf0  \cf4 void\cf0  should_be_able_to_get_files__with_one_level_recursion()\par ??        \{\par ??            \cf4 var\cf0  actual = fsc.ListFilesAndFolders(\cf5 "/"\cf0 , 1, \cf3 Recursion\cf0 .OneLevel);\par ??            \cf3 Assert\cf0 .IsTrue(\cf3 PersistentCacheTest\cf0 .ContainsAllIn(actual, \cf4 new\cf0  [] \{ \cf5 "/"\cf0 , \cf5 "/foo"\cf0  \}));\par ??        \}\par ??\par ??\par ??\par ??        [\cf3 Test\cf0 ]\par ??        \cf4 public\cf0  \cf4 void\cf0  should_be_able_to_get_files__with_full_recursion()\par ??        \{\par ??            \cf4 var\cf0  actual = fsc.ListFilesAndFolders(\cf5 "/"\cf0 , 1, \cf3 Recursion\cf0 .Full);\par ??            \cf4 var\cf0  expected = \cf4 new\cf0 [] \{\cf5 "/"\cf0 , \cf5 "/foo"\cf0 , \cf5 "/foo/bar"\cf0 , \cf5 "/foo/bar/text.txt"\cf0 \};\par ??            \cf3 Assert\cf0 .IsTrue(\cf3 PersistentCacheTest\cf0 .ContainsAllIn(actual, expected));\par ??            expected = \cf4 new\cf0 [] \{ \cf5 "/"\cf0 , \cf5 "/foo"\cf0 , \};\par ??            actual = fsc.ListFilesAndFolders(\cf5 "/"\cf0 , 1, \cf3 Recursion\cf0 .OneLevel);\par ??            \cf3 Assert\cf0 .IsTrue(\cf3 PersistentCacheTest\cf0 .ContainsAllIn(actual, expected));\par ??            actual = fsc.ListFilesAndFolders(\cf5 "/"\cf0 , 2, \cf3 Recursion\cf0 .OneLevel);\par ??            expected = \cf4 new\cf0 [] \{ \cf5 "/"\cf0 , \cf5 "/foo"\cf0 , \cf5 "/test.txt"\cf0  \};\par ??            \cf3 Assert\cf0 .IsTrue(\cf3 PersistentCacheTest\cf0 .ContainsAllIn(actual, expected));\par ??        \}\par ??    \}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;TestFixture&lt;/span&gt;]&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;FileSystemCacheTests&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;readonly&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;PersistentCache&lt;/span&gt; cache = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;PersistentCache&lt;/span&gt;();&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;FileSystemCache&lt;/span&gt; fsc;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;SetUp&lt;/span&gt;]&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; SetUp()&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; fsc = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;FileSystemCache&lt;/span&gt;(cache);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; fsc.Add(&lt;span style="color: blue;"&gt;new&lt;/span&gt;[]&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;VersionedFile&lt;/span&gt; {Version = 1, Name = &lt;span style="color: #a31515;"&gt;"/"&lt;/span&gt;},&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;VersionedFile&lt;/span&gt; {Version = 1, Name = &lt;span style="color: #a31515;"&gt;"/foo"&lt;/span&gt;},&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;VersionedFile&lt;/span&gt; {Version = 1, Name = &lt;span style="color: #a31515;"&gt;"/foo/bar"&lt;/span&gt;},&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;VersionedFile&lt;/span&gt; {Version = 1, Name = &lt;span style="color: #a31515;"&gt;"/foo/bar/text.txt"&lt;/span&gt;},&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; });&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; fsc.Add(&lt;span style="color: blue;"&gt;new&lt;/span&gt;[]&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;VersionedFile&lt;/span&gt; {Version = 2, Name = &lt;span style="color: #a31515;"&gt;"/"&lt;/span&gt;},&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;VersionedFile&lt;/span&gt; {Version = 2, Name = &lt;span style="color: #a31515;"&gt;"/foo"&lt;/span&gt;},&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;VersionedFile&lt;/span&gt; {Version = 2, Name = &lt;span style="color: #a31515;"&gt;"/foo/bar"&lt;/span&gt;},&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;VersionedFile&lt;/span&gt; {Version = 2, Name = &lt;span style="color: #a31515;"&gt;"/foo/bar/text.txt"&lt;/span&gt;},&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;VersionedFile&lt;/span&gt; {Version = 2, Name = &lt;span style="color: #a31515;"&gt;"/test.txt"&lt;/span&gt;},&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; });&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;Test&lt;/span&gt;]&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; should_be_able_to_get_files__without_recursion()&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;var&lt;/span&gt; actual = fsc.ListFilesAndFolders(&lt;span style="color: #a31515;"&gt;"/"&lt;/span&gt;, 1, &lt;span style="color: #2b91af;"&gt;Recursion&lt;/span&gt;.None);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Assert&lt;/span&gt;.IsTrue(&lt;span style="color: #2b91af;"&gt;PersistentCacheTest&lt;/span&gt;.ContainsAllIn(actual, &lt;span style="color: blue;"&gt;new&lt;/span&gt; [] { &lt;span style="color: #a31515;"&gt;"/"&lt;/span&gt; }));&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;Test&lt;/span&gt;]&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; should_be_able_to_get_files__with_one_level_recursion()&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;var&lt;/span&gt; actual = fsc.ListFilesAndFolders(&lt;span style="color: #a31515;"&gt;"/"&lt;/span&gt;, 1, &lt;span style="color: #2b91af;"&gt;Recursion&lt;/span&gt;.OneLevel);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Assert&lt;/span&gt;.IsTrue(&lt;span style="color: #2b91af;"&gt;PersistentCacheTest&lt;/span&gt;.ContainsAllIn(actual, &lt;span style="color: blue;"&gt;new&lt;/span&gt; [] { &lt;span style="color: #a31515;"&gt;"/"&lt;/span&gt;, &lt;span style="color: #a31515;"&gt;"/foo"&lt;/span&gt; }));&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;Test&lt;/span&gt;]&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; should_be_able_to_get_files__with_full_recursion()&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;var&lt;/span&gt; actual = fsc.ListFilesAndFolders(&lt;span style="color: #a31515;"&gt;"/"&lt;/span&gt;, 1, &lt;span style="color: #2b91af;"&gt;Recursion&lt;/span&gt;.Full);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;var&lt;/span&gt; expected = &lt;span style="color: blue;"&gt;new&lt;/span&gt;[] {&lt;span style="color: #a31515;"&gt;"/"&lt;/span&gt;, &lt;span style="color: #a31515;"&gt;"/foo"&lt;/span&gt;, &lt;span style="color: #a31515;"&gt;"/foo/bar"&lt;/span&gt;, &lt;span style="color: #a31515;"&gt;"/foo/bar/text.txt"&lt;/span&gt;};&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Assert&lt;/span&gt;.IsTrue(&lt;span style="color: #2b91af;"&gt;PersistentCacheTest&lt;/span&gt;.ContainsAllIn(actual, expected));&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; expected = &lt;span style="color: blue;"&gt;new&lt;/span&gt;[] { &lt;span style="color: #a31515;"&gt;"/"&lt;/span&gt;, &lt;span style="color: #a31515;"&gt;"/foo"&lt;/span&gt;, };&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; actual = fsc.ListFilesAndFolders(&lt;span style="color: #a31515;"&gt;"/"&lt;/span&gt;, 1, &lt;span style="color: #2b91af;"&gt;Recursion&lt;/span&gt;.OneLevel);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Assert&lt;/span&gt;.IsTrue(&lt;span style="color: #2b91af;"&gt;PersistentCacheTest&lt;/span&gt;.ContainsAllIn(actual, expected));&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; actual = fsc.ListFilesAndFolders(&lt;span style="color: #a31515;"&gt;"/"&lt;/span&gt;, 2, &lt;span style="color: #2b91af;"&gt;Recursion&lt;/span&gt;.OneLevel);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; expected = &lt;span style="color: blue;"&gt;new&lt;/span&gt;[] { &lt;span style="color: #a31515;"&gt;"/"&lt;/span&gt;, &lt;span style="color: #a31515;"&gt;"/foo"&lt;/span&gt;, &lt;span style="color: #a31515;"&gt;"/test.txt"&lt;/span&gt; };&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Assert&lt;/span&gt;.IsTrue(&lt;span style="color: #2b91af;"&gt;PersistentCacheTest&lt;/span&gt;.ContainsAllIn(actual, expected));&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-5746900383778539992?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/5746900383778539992/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=5746900383778539992' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/5746900383778539992'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/5746900383778539992'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2008/04/ayendes-challenge-2-directory-tree.html' title='Ayende&apos;s Challenge #2: The directory tree'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-9192749109284626533</id><published>2008-04-09T22:36:00.008+02:00</published><updated>2008-04-09T22:53:50.668+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='recruiting'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>Ayende's Challenge</title><content type='html'>&lt;a href="http://www.ayende.com/"&gt;Ayende&lt;/a&gt; &lt;a href="http://www.ayende.com/Blog/archive/2008/04/09/A-challenge-Getting-a-list-of-products.aspx"&gt;challenged&lt;/a&gt; the whole intarweb to resolve a problem similar to the ones he uses in his job interviews. It goes like this:&lt;br /&gt;&lt;blockquote&gt;The task is listing the first 10 products that we can sell to a customer. The UI is console application, and the database design and data access method are whatever you want.&lt;/blockquote&gt;&lt;br /&gt;Additionally you have to filter those products according to some arguments given as input parameters to the application (representing different categorizations of products).&lt;br /&gt;&lt;br /&gt;Now, my solution. :)&lt;br /&gt;&lt;pre name="code" class="c-sharp"&gt;&lt;br /&gt;    public enum Category&lt;br /&gt;    {&lt;br /&gt;        PG13,&lt;br /&gt;        Vegetarian&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public class Product&lt;br /&gt;    {&lt;br /&gt;        public string Name { get; set; }&lt;br /&gt;        public decimal Price { get; set; }&lt;br /&gt;        public IList&lt;Category&gt; Categories { get; set;}&lt;br /&gt;&lt;br /&gt;        public override string ToString()&lt;br /&gt;        {&lt;br /&gt;            return string.Format("{0}\t{1}", Name, Price);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public class Filter&lt;br /&gt;    {&lt;br /&gt;        public static IEnumerable&lt;Product&gt; ApplyFilter(IEnumerable&lt;Product&gt; products, Category category)&lt;br /&gt;        {&lt;br /&gt;            return from p in products where p.Categories.Contains(category) select p; &lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    class Program&lt;br /&gt;    {&lt;br /&gt;        static void Main(string[] args)&lt;br /&gt;        {&lt;br /&gt;            var categoryMapper = new Dictionary&lt;string, Category&gt;&lt;br /&gt;                                     {&lt;br /&gt;                                         {"-pg13", Category.PG13},&lt;br /&gt;                                         {"-vegetarian", Category.Vegetarian}&lt;br /&gt;                                     };&lt;br /&gt;&lt;br /&gt;            var products = new List&lt;Product&gt;&lt;br /&gt;                               {&lt;br /&gt;                                   new Product {Name = "Milk", Price = 1.0M, &lt;br /&gt;                                       Categories = new List&lt;Category&gt; {Category.PG13, Category.Vegetarian}}, &lt;br /&gt;                                   new Product {Name = "Bread", Price = 1.3M, &lt;br /&gt;                                       Categories = new List&lt;Category&gt; {Category.PG13, Category.Vegetarian}},&lt;br /&gt;                                   new Product {Name = "Sausage", Price = 2.5M, &lt;br /&gt;                                       Categories = new List&lt;Category&gt; {Category.PG13}},&lt;br /&gt;                                   new Product {Name = "Horror Movie", Price = 5.0M, &lt;br /&gt;                                       Categories = new List&lt;Category&gt; {Category.Vegetarian}}&lt;br /&gt;                               };&lt;br /&gt;&lt;br /&gt;            var filteredResults = (IEnumerable&lt;Product&gt;) products;&lt;br /&gt;            foreach (string arg in args)&lt;br /&gt;            {&lt;br /&gt;                if (categoryMapper.ContainsKey(arg))&lt;br /&gt;                {&lt;br /&gt;                    filteredResults = Filter.ApplyFilter(filteredResults, categoryMapper[arg]);&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            filteredResults = filteredResults.Take(10);&lt;br /&gt;&lt;br /&gt;            foreach (Product product in filteredResults)&lt;br /&gt;            {&lt;br /&gt;                Console.Out.WriteLine(product);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-9192749109284626533?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/9192749109284626533/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=9192749109284626533' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/9192749109284626533'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/9192749109284626533'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2008/04/ayendes-challenge.html' title='Ayende&apos;s Challenge'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-542670051482189022</id><published>2008-04-06T19:52:00.002+02:00</published><updated>2008-04-06T20:01:13.149+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><category scheme='http://www.blogger.com/atom/ns#' term='continuous integration'/><title type='text'>You better don't break the build</title><content type='html'>&lt;blockquote&gt;/trunk must compile and pass regression tests at all times. Committers who violate this rule are publically humiliated.&lt;/blockquote&gt;&lt;cite&gt;-- &lt;a href="http://svn.collab.net/repos/svn/trunk/doc/user/svn-best-practices.html"&gt;svn best practices&lt;/a&gt;&lt;/cite&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-542670051482189022?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/542670051482189022/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=542670051482189022' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/542670051482189022'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/542670051482189022'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2008/04/you-better-dont-break-build.html' title='You better don&apos;t break the build'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-1621199619857656550</id><published>2008-02-18T21:53:00.006+01:00</published><updated>2008-06-18T21:05:28.696+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><title type='text'>I Know What You Coded Last Summer</title><content type='html'>&lt;blockquote&gt;At all times, I want to produce code that is readable, maintainable and simple. [...]                   [I]t is considered polite to do this in a manner that would make sense to the next developer that would have to touch this code. [...] A good suggestion that I take to heart is to assume that the next developer to touch your code is an axe murderer that knows where you live, and has a very short fuse.&lt;/blockquote&gt;&lt;cite&gt;-- &lt;a href="http://www.ayende.com"&gt;Ayende&lt;/a&gt;, &lt;a href="http://www.manning.com/rahien/"&gt;Building Domain Specific Languages in Boo&lt;/a&gt;&lt;/cite&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-1621199619857656550?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/1621199619857656550/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=1621199619857656550' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/1621199619857656550'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/1621199619857656550'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2008/02/i-know-what-you-coded-last-summer.html' title='I Know What You Coded Last Summer'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-6921538265722797611</id><published>2008-01-24T21:57:00.000+01:00</published><updated>2008-01-24T22:18:34.622+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='.net'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>Returning null vs. Empty Collection/Default Object</title><content type='html'>In a nice thread on the &lt;a href="http://tech.groups.yahoo.com/group/cli_dev/message/9849"&gt;cli_dev list (formerly altdotnet)&lt;/a&gt; they discuss whether you should return null or an Empty Collection/Default Object when a query returns no results.&lt;br /&gt;&lt;br /&gt;There is a more or less common approach I agree with of returning a null collection when your query yields no results, like in GetUsers(), being therefore able to iterate it with a foreach(User user in GetUsers()) witout having to use safe-guards.&lt;br /&gt;&lt;br /&gt;I think Luke Breuer makes a good point too in &lt;a href="http://tech.groups.yahoo.com/group/cli_dev/message/9855"&gt;this post&lt;/a&gt; when talking about retrieving a particular result:&lt;br /&gt;&lt;blockquote&gt;I like null checks to actually have significant meaning.  I've actually adopted a convention -- GetAwesomeObject will return a valid object or throw; FindAwesomeObject might return null.  The idea is that a NullReferenceException means you really screwed up somewhere -- you have a glaring logic error, because you didn't account for possible emptiness. &lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-6921538265722797611?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/6921538265722797611/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=6921538265722797611' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/6921538265722797611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/6921538265722797611'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2008/01/returning-null-vs-empty.html' title='Returning null vs. Empty Collection/Default Object'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-9091025201360723000</id><published>2008-01-12T13:29:00.000+01:00</published><updated>2008-01-12T13:48:58.802+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='mvc'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net'/><category scheme='http://www.blogger.com/atom/ns#' term='tdd'/><title type='text'>2008 will be the year of...</title><content type='html'>Linux.&lt;br /&gt;Hehe, I'm kidding. I think 2008 will be the year of &lt;a href="http://www.agiledata.org/essays/tdd.html"&gt;Test Driven &lt;span style="font-weight:bold;"&gt;Design&lt;/span&gt;&lt;/a&gt;. I know it has been already there for a long time already, but I hope that it will become mainstream with the final release of the &lt;a href="http://weblogs.asp.net/scottgu/archive/2007/10/14/asp-net-mvc-framework.aspx"&gt;ASP.NET MVC&lt;/a&gt; framework Microsoft is releasing this year.&lt;br /&gt;&lt;br /&gt;Well, in fact, depending how long it takes for them to ship it, it may actually take a bit longer to be widely used tough, but I'm happy this is going to be finally adopted for web development.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-9091025201360723000?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/9091025201360723000/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=9091025201360723000' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/9091025201360723000'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/9091025201360723000'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2008/01/2008-will-be-year-of.html' title='2008 will be the year of...'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-1000125542909956878</id><published>2008-01-10T17:55:00.000+01:00</published><updated>2008-01-12T13:45:56.145+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asp.net'/><title type='text'>ASP.NET 2.0 Page Life Cycle</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_kQ7iivKjVno/R4ZOtzG4SNI/AAAAAAAAAD8/QeztqpeQpvs/s1600-h/Asp.Net2.0LifecycleBIG.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_kQ7iivKjVno/R4ZOtzG4SNI/AAAAAAAAAD8/QeztqpeQpvs/s400/Asp.Net2.0LifecycleBIG.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5153893372292253906" /&gt;&lt;/a&gt;&lt;br /&gt;Geez, I better move onto ASP.Mvc than learn the inner tricks of all that stuff. Seriously.&lt;br /&gt;&lt;br /&gt;Via &lt;a href="http://spietrek.blogspot.com/2006/07/aspnet-20-page-life-cycle.html"&gt;Steve Pietrek&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-1000125542909956878?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/1000125542909956878/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=1000125542909956878' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/1000125542909956878'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/1000125542909956878'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2008/01/aspnet-20-page-life-cycle.html' title='ASP.NET 2.0 Page Life Cycle'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_kQ7iivKjVno/R4ZOtzG4SNI/AAAAAAAAAD8/QeztqpeQpvs/s72-c/Asp.Net2.0LifecycleBIG.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-3337455388825050393</id><published>2007-12-12T21:26:00.000+01:00</published><updated>2007-12-12T22:13:04.103+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.net'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>Nullable Types and the Coallescence Operator</title><content type='html'>I'm going to talk a bit about a couple of nice features introduced in &lt;span style="font-weight:bold;"&gt;.NET 2.0&lt;/span&gt;. It's nothing new, but it's sweet anyway.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Nullable Types&lt;/span&gt;&lt;br /&gt;Nullable types address the scenario where you want to be able to have a primitive type with a null (or unknown) value. This is common in database scenarios, but is also useful in other situations. This is a PITA to deal with in .NET 1.1, and you have to do some boxing or wrapping to get along with it.&lt;br /&gt;&lt;br /&gt;Since .NET 2.0 we have Nullable Types, a much cleaner way to do it.&lt;br /&gt;Nullable Types are declared either as:&lt;br /&gt;&lt;code&gt;System.Nullable&lt;T&gt; variable&lt;/code&gt;&lt;br /&gt;or the simpler way:&lt;br /&gt;&lt;code&gt;T? variable&lt;/code&gt;&lt;br /&gt;where  T is the underlying type of the nullable type. T can be any value type including struct; it cannot be a reference type.&lt;br /&gt;&lt;br /&gt;Examples of Nullable Types:&lt;br /&gt;&lt;code&gt;int? i = 10;&lt;br /&gt;double? d1 = 3.14;&lt;br /&gt;bool? flag = null;&lt;br /&gt;char? letter = 'a';&lt;br /&gt;int?[] arr = new int?[10];&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;To do a null check we could write:&lt;br /&gt;&lt;code&gt;if (i.HasValue) {...}&lt;/code&gt;&lt;br /&gt;but again we can just simplify it to:&lt;br /&gt;&lt;code&gt;if (i != null) {...}&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Nevertheless, there are a few things to consider when dealing with nullable types:&lt;br /&gt;&lt;br /&gt;Exceptions:&lt;br /&gt;&lt;code&gt;int? n = null;&lt;br /&gt;//int m1 = n;      // Will not compile.&lt;br /&gt;int m2 = (int)n;   // Compiles, but will create an exception if x is null.&lt;br /&gt;int m3 = n.Value;  // Compiles, but will create an exception if x is null.&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Operators:&lt;br /&gt;&lt;code&gt;int? a = 10;&lt;br /&gt;int? b = null;&lt;br /&gt;a++;         // Increment by 1, now a is 11.&lt;br /&gt;a = a * 10;  // Multiply by 10, now a is 110.&lt;br /&gt;a = a + b;   // Add b, now a is null.&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Comparisons: If one of the nullable types is null, the comparison evaluates to false&lt;br /&gt;&lt;code&gt;int? num1 = 10;&lt;br /&gt;int? num2 = null;&lt;br /&gt;if (num1 &gt;= num2)&lt;br /&gt;{&lt;br /&gt;    System.Console.WriteLine("num1 is greater than or equal to num1");&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;    // num1 is NOT less than num2. --&gt; WRONG ASSUMPTION!!! &lt;br /&gt;}&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The bool? nullable type can contain three different values: true, false and null. As such, the cannot be used in conditionals such as with if, for, or while. It would give a compilation error.&lt;br /&gt;&lt;code&gt;bool? b = null;&lt;br /&gt;if (b) // Error CS0266.&lt;br /&gt;{&lt;br /&gt;}&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;The ?? (Coalescence) Operator&lt;/span&gt;&lt;br /&gt;The ?? operator defines a default value that is returned when a nullable type is assigned to a non-nullable type.&lt;br /&gt;&lt;code&gt;int? c = null;&lt;br /&gt;// d = c, unless c is null, in which case d = -1.&lt;br /&gt;int d = c ?? -1;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This operator can also be used with multiple nullable types. For example:&lt;br /&gt;&lt;code&gt;int? e = null;&lt;br /&gt;int? f = null;&lt;br /&gt;// g = e or f, unless e and f are both null, in which case g = -1.&lt;br /&gt;int g = e ?? f ?? -1;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-3337455388825050393?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/3337455388825050393/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=3337455388825050393' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/3337455388825050393'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/3337455388825050393'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2007/12/nullable-types-and-coallescence.html' title='Nullable Types and the Coallescence Operator'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-4513507521629867217</id><published>2007-12-12T19:08:00.000+01:00</published><updated>2007-12-12T21:24:26.336+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='work'/><title type='text'>Don't fear the unknown</title><content type='html'>&lt;blockquote&gt;"If we only code to what the lowest-common-denominator can do then we're never going to get anywhere."&lt;/blockquote&gt;&lt;cite&gt;&lt;a href="http://blog.jagregory.com/"&gt;James Gregory&lt;/a&gt;&lt;/cite&gt;&lt;br /&gt;&lt;br /&gt;In other words. If the problem is the coders, not the code, change the coders, let the code alone.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-4513507521629867217?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/4513507521629867217/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=4513507521629867217' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/4513507521629867217'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/4513507521629867217'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2007/12/dont-fear-unknown.html' title='Don&apos;t fear the unknown'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-6418230373808790856</id><published>2007-12-12T11:23:00.000+01:00</published><updated>2007-12-12T11:31:14.263+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><category scheme='http://www.blogger.com/atom/ns#' term='continuous integration'/><title type='text'>Get a Build Server and Keep it Clean</title><content type='html'>&lt;a href="http://codebetter.com/blogs/jeremy.miller/archive/2007/04/26/get-a-build-server-and-keep-it-clean.aspx"&gt;One goog tip from Jeremy Miller on continuous integration&lt;/a&gt; is to generate your builds in a separate server to detect early problems with dependencies with libraries from Visual Studio, some third-party or whatever you might have in the GAC.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-6418230373808790856?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/6418230373808790856/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=6418230373808790856' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/6418230373808790856'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/6418230373808790856'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2007/12/get-build-server-and-keep-it-clean.html' title='Get a Build Server and Keep it Clean'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-1909521847510589260</id><published>2007-12-12T01:13:00.000+01:00</published><updated>2007-12-12T11:22:54.118+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.net'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>Public fields vs. Public properties</title><content type='html'>ScottGu  blogged some time ago, among other interesting things, about the &lt;a href="http://weblogs.asp.net/scottgu/archive/2007/03/08/new-c-orcas-language-features-automatic-properties-object-initializers-and-collection-initializers.aspx"&gt;difference between public fields and public properties&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I had always seen comments about the convenience of using public properties instead of public fields, but I hadn't seen a real explanation until now. I tought, "why should I bother writing a getter and a setter? If I just use a public Foo field, I can refactor it into a Property if it turns out I have to." It seems &lt;a href="http://www.codinghorror.com/blog/archives/000654.html"&gt;I wan't the only one that thought this very same thing&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;But it turns out there are some differences:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You can't databind against a variable. &lt;/li&gt;&lt;li&gt;Changing a variable to a property is &lt;a href="http://blogs.msdn.com/abhinaba/archive/2006/04/11/572694.aspx"&gt;a breaking change&lt;/a&gt;. &lt;strong style="font-weight: normal;"&gt;When you change a field to a property you need to re-build all code that used that field.&lt;/strong&gt;  &lt;/li&gt;&lt;li&gt;Reflection works differently on variables vs. properties, so if you rely on reflection, it's easier to use all properties.&lt;/li&gt;&lt;/ul&gt;There are some other relevant points in both posts.&lt;br /&gt;From Jeff's:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Distinguishing public and private using only case is an accident waiting to happen. I still don't have a clear view if I should be using  _bar = bar or this.bar = bar.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Is it a property or a method? A property should do less work-- a &lt;i&gt;lot&lt;/i&gt; less work-- than a method. Properties should be lightweight. If your property incurs significant effort, it should be refactored into an explicit method.&lt;/li&gt;&lt;/ul&gt;From Scott's, there is some &lt;span style="font-size:100%;"&gt;syntactic &lt;/span&gt;sugar for C#3 (or is it 3.5?):&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Automatic Properties&lt;/span&gt;&lt;br /&gt;This cleans up our classes from all the innecesary private fields.&lt;/span&gt;&lt;br /&gt;&lt;pre name="code" class="c-sharp"&gt;public class Person {&lt;br /&gt;public string FirstName { get; set; }&lt;br /&gt;   public string LastName { get; set; } &lt;br /&gt;   public int Age { get; set; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Object initializers&lt;/span&gt;&lt;br /&gt;Allow you to atomically initialize an object lacking an appropiate constructor. &lt;a href="http://community.bartdesmet.net/blogs/bart/archive/2006/12/04/C_2300_-3.0-Feature-Focus-_2D00_-Part-2-_2D00_-Object-Initializers.aspx"&gt;More on this.&lt;/a&gt;&lt;br /&gt;&lt;pre name="code" class="c-sharp"&gt;Person person = new Person { FirstName="Scott", LastName="Guthrie", Age=32 };&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight: bold;"&gt;Collection initializers&lt;/span&gt;&lt;br /&gt;Same annonymous methods, but applied to collections.&lt;br /&gt;&lt;pre name="code" class="c-sharp"&gt;   List&lt;person&gt; people = new List&lt;person&gt; {&lt;br /&gt;    new Person { FirstName = "Scott", LastName = "Guthrie", Age = 32 },&lt;br /&gt;    new Person { FirstName = "Bill", LastName = "Gates", Age = 50 },&lt;br /&gt;    new Person { FirstName = "Susanne", LastName = "Guthrie", Age = 32 }&lt;br /&gt; };&lt;br /&gt;&lt;/person&gt;&lt;/person&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-1909521847510589260?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/1909521847510589260/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=1909521847510589260' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/1909521847510589260'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/1909521847510589260'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2007/12/public-fields-vs-public-properties.html' title='Public fields vs. Public properties'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-1449984214965729892</id><published>2007-12-10T19:44:00.000+01:00</published><updated>2007-12-10T20:04:26.709+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='tdd'/><category scheme='http://www.blogger.com/atom/ns#' term='bdd'/><title type='text'>Write your test first... because adding them later sucks</title><content type='html'>So true. As &lt;a href="http://www.jasonbock.net/JB/Default.aspx?blog=entry.a44b94d177ed4c139029e8cca6efe90f"&gt;jason&lt;/a&gt; points out:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It's boring. Write the obvious tests. Check code coverage - what did I miss? Write more tests capturing more edge cases. Wash, rinse, repeat. Ugh.&lt;/li&gt;&lt;li&gt;It's not trivial. I'm trying to put tests around code that was created months ago, and trying to capture the mental state of the coder and what he was doing is damn near impossible.&lt;/li&gt;&lt;/ul&gt;If you write the test first, you get all the benefits of TDD.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You don't get just unit testing, but instead you let your design lead your development.&lt;/li&gt;&lt;li&gt;As you are writing the minimum code necessary to achieve the &lt;span style="font-weight: bold;"&gt;behaviour &lt;/span&gt;your test is checking, you end up with full code coverage.&lt;/li&gt;&lt;li&gt;You can refactor as you test-and-code (and test, and code,...), and you have your tests to cover your ass as you go. If you need to refactor when it's all finished, poor you. You are just left out in the wild.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-1449984214965729892?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='enclosure' type='' href='http://www.jasonbock.net/JB/Default.aspx?blog=entry.a44b94d177ed4c139029e8cca6efe90f' length='0'/><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/1449984214965729892/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=1449984214965729892' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/1449984214965729892'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/1449984214965729892'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2007/12/write-your-test-first-because-adding.html' title='Write your test first... because adding them later sucks'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-5655763739796799950</id><published>2007-12-09T16:18:00.000+01:00</published><updated>2007-12-09T16:58:02.028+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><category scheme='http://www.blogger.com/atom/ns#' term='work'/><category scheme='http://www.blogger.com/atom/ns#' term='philosophy'/><category scheme='http://www.blogger.com/atom/ns#' term='recruiting'/><title type='text'>The Peter Principle</title><content type='html'>&lt;blockquote&gt;"In a hierarchy every employee tends to rise to his level of incompetence."&lt;/blockquote&gt;&lt;cite&gt;-- Laurence J. Peter. &lt;a href="http://www.amazon.com/gp/product/B000EECRH6/"&gt;'The Peter Principle'&lt;/a&gt;, (1969).&lt;/cite&gt;&lt;br /&gt;&lt;br /&gt;This principle states that in any company or organization, people who do their job right get promoted to higher responsibility jobs repeteadly, until they end up in a job they are incompetents for.&lt;br /&gt;&lt;br /&gt;The logic behind this theory is that recruiting people for a new vacancy look first for the people already working in the organization. If an employee is performing well in his current duties, they feel he deserves to be promoted and deduce he will be equally efective in the new role. So, this employee will keep promoting while he is competent, and therefore he will eventually end up in a post he is no longer apt for, and he will get stuck in it.&lt;br /&gt;&lt;br /&gt;As a consecuence, we can infer that many high-end positions are occupied by people who don't have enough qualifications for their jobs, and this leads to big mistakes in the decision being made by people leading those organizations.&lt;br /&gt;&lt;br /&gt;Thus, the Peter Principle is a big warning for people involved in the recruiting process. The requirements for the new job must be defined clearly, and when analyzing the aptitudes of existing employees for the vacancy, those people should be treated as any other applicant, despite of their efficiency at their current tasks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-5655763739796799950?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/5655763739796799950/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=5655763739796799950' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/5655763739796799950'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/5655763739796799950'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2007/12/peter-principle.html' title='The Peter Principle'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-3989021516591808335</id><published>2007-12-09T16:03:00.000+01:00</published><updated>2007-12-09T16:12:18.594+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='continuous integration'/><title type='text'>Handling library dependendancies</title><content type='html'>It seems &lt;a href="http://www.jpboodhoo.com/blog/Handling3rdPartyDependenciesIncludingYourOwn.aspx"&gt;some smart people&lt;/a&gt; is taking the same approach I have ended up with in my projects. I still don't like it very much, but it seems the only way to go until we have a complete continous integration environment, fully backed-up by TDD, a consistent versioning policy and a tool like &lt;a href="http://maven.apache.org/"&gt;Maven&lt;/a&gt; to handle those dependencies for us.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-3989021516591808335?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/3989021516591808335/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=3989021516591808335' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/3989021516591808335'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/3989021516591808335'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2007/12/handling-library-dependendancies.html' title='Handling library dependendancies'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-4725992378576153933</id><published>2007-12-07T03:49:00.000+01:00</published><updated>2007-12-07T04:27:58.995+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><title type='text'>Software is art</title><content type='html'>&lt;blockquote&gt;"Software design is an art, and like any art it cannot be taught and &lt;br /&gt;learned as a precise science, by means of theorems and formulas."&lt;/blockquote&gt;&lt;cite&gt;-- Domain-Driven Design Quickly, by Abel Avram &amp; Floyd Marinescu&lt;/cite&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-4725992378576153933?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/4725992378576153933/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=4725992378576153933' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/4725992378576153933'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/4725992378576153933'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2007/12/software-is-art.html' title='Software is art'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-5760930616366478259</id><published>2007-12-04T08:01:00.000+01:00</published><updated>2007-12-07T04:29:08.209+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><category scheme='http://www.blogger.com/atom/ns#' term='deadline driven development'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><title type='text'>Did you think your shit didn't stink?</title><content type='html'>&lt;blockquote&gt;"No matter how good the code you write is, it’s crap to another developer."&lt;br /&gt;&lt;/blockquote&gt;&lt;cite&gt;-- &lt;a href="http://haacked.com/archive/2007/10/07/the-greatest-compliment-a-developer-can-receive.aspx"&gt;Phil Haack&lt;/a&gt;&lt;/cite&gt;&lt;br /&gt;&lt;br /&gt;Next time I am honored with some unmanageable code, before I start swearing, I'll try to remeber all the crap I endep up doing under deadline pressures.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-5760930616366478259?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/5760930616366478259/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=5760930616366478259' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/5760930616366478259'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/5760930616366478259'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2007/12/did-you-think-your-shit-didnt-stink.html' title='Did you think your shit didn&apos;t stink?'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6675534776398892468.post-3824188139830335821</id><published>2007-12-04T01:05:00.000+01:00</published><updated>2007-12-07T04:29:57.905+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bits'/><category scheme='http://www.blogger.com/atom/ns#' term='tdd'/><category scheme='http://www.blogger.com/atom/ns#' term='bdd'/><title type='text'>What tests are for</title><content type='html'>&lt;blockquote&gt;"Tests are absolutely not for checking to see if things went wrong. They are for articulating what code should do, and proving that code does it."&lt;/blockquote&gt;&lt;cite&gt;-- &lt;a href="http://gilesbowkett.blogspot.com/2007/10/debugger-support-considered-harmful.html"&gt;Giles Bowkett&lt;/a&gt;&lt;/cite&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6675534776398892468-3824188139830335821?l=www.sharpbites.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sharpbites.com/feeds/3824188139830335821/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6675534776398892468&amp;postID=3824188139830335821' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/3824188139830335821'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6675534776398892468/posts/default/3824188139830335821'/><link rel='alternate' type='text/html' href='http://www.sharpbites.com/2007/12/what-tests-are-for.html' title='What tests are for'/><author><name>alberto</name><uri>http://www.blogger.com/profile/03053589431434029905</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
