<?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/opensearch/1.1/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0' gd:etag='W/&quot;DkQHRnY6cCp7ImA9WhBaE04.&quot;' xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0"><id>tag:blogger.com,1999:blog-1165127106246535168</id><updated>2013-05-23T20:38:57.818+02:00</updated><category term='Visual Studio'/><category term='Twitter'/><category term='LOL'/><category term='Microsoft'/><category term='MVC'/><category term='Architecture'/><category term='javascript'/><category term='SQL'/><category term='Hack'/><category term='Messaging'/><category term='AJAX'/><category term='SQLServer'/><category term='Windows'/><category term='Nhibnerate'/><category term='Bookreview'/><category term='Interview'/><category term='ASP.NET MVC'/><category term='ASP.NET'/><category term='Web API'/><category term='HTTP'/><category term='Reporting'/><category term='Browsers'/><category term='RSS'/><category term='Games'/><category term='Nerddinner'/><category term='General'/><category term='Resources'/><category term='Opensource'/><category term='Travel'/><category term='ARealDeveloper'/><category term='Ramblings'/><category term='DDD'/><category term='Google Adsense'/><category term='CodeSnippets'/><category term='database'/><category term='HTML5'/><category term='E-book'/><category term='jQuery'/><category term='WebMatrix'/><category term='CSS'/><category term='REST'/><category term='Techdays'/><category term='Video review'/><category term='NoSql'/><category term='PostBroadcaster'/><category term='Windows Services'/><category term='VISUG'/><category term='Tips'/><category term='Codesnipeets'/><category term='Best Practices'/><category term='Refactoring'/><category term='industry'/><category term='Blogging'/><category term='teched'/><category term='Browser'/><category term='Telerik'/><category term='Linq'/><category term='Active Directory'/><category term='HTML'/><category term='Tools'/><category term='Hardware'/><category term='NancyFx'/><category term='Hacking'/><category term='Event'/><category term='Bing API'/><category term='Silverlight'/><category term='.NET'/><title>Jef Claes on software and life</title><subtitle type='html'>On software and life</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.jefclaes.be/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default?redirect=false&amp;v=2'/><link rel='alternate' type='text/html' href='http://www.jefclaes.be/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2'/><author><name>Jef Claes</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>289</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage>
<entry gd:etag='W/&quot;DUYBQ3o9cCp7ImA9WhBaEUk.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2013/05/validating-composite-models-with.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-2663564887384779523</id><published>2013-05-20T17:02:00.000+02:00</published><updated>2013-05-21T16:39:12.468+02:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2013-05-21T16:39:12.468+02:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='Opensource'/><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='CodeSnippets'/><category scheme='http://www.blogger.com/atom/ns#' term='HTML'/><title>Validating composite models with knockout validation</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
When you use &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://github.com/Knockout-Contrib/Knockout-Validation&quot;&gt;knockout validation&lt;/a&gt; to extend observables with validation rules, it will add a few functions to these observables - the most important ones being; error and isValid. You can use these functions to verify if any of the validation rules were violated, and to extract an error message.
&lt;br&gt;

&lt;br&gt;
To extract all of the error messages out of a composite model, you can use a grouping function.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;function BookingModel() {      
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; self = &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;;
   
    self.contact = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ContactModel();
    self.departure = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; DepartureModel();
   
    self.isValid = function() {
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; self.contact.isValid() &amp;amp;&amp;amp; self.departure.isValid();
    };
   
    self.validate = function() {                           
        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (!self.isValid()) {
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; errors = ko.validation.group(self);                           
            errors.showAllMessages();
        
            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;;          
        }
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;;
    };                    
}
function DepartureModel() {
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.street = ko.observable(&lt;span class=&quot;str&quot;&gt;&apos;&apos;&lt;/span&gt;).extend({ required: &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt; });
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.houseNumber = ko.observable(&lt;span class=&quot;str&quot;&gt;&apos;&apos;&lt;/span&gt;).extend({ required: &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt; });
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.city = ko.observable(&lt;span class=&quot;str&quot;&gt;&apos;&apos;&lt;/span&gt;).extend({ required: &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt; });
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.time = ko.observable(&lt;span class=&quot;str&quot;&gt;&apos;&apos;&lt;/span&gt;).extend({ required: &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt; });            
    
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.isValid = function() {
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; 
            &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.street.isValid() &amp;amp;&amp;amp;
            &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.houseNumber.isValid() &amp;amp;&amp;amp;
            &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.city.isValid() &amp;amp;&amp;amp;
            &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.time.isValid();                
    };
}
function ContactModel() {
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.firstName = ko.observable(&lt;span class=&quot;str&quot;&gt;&apos;&apos;&lt;/span&gt;).extend({ required: &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt; });
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.lastName = ko.observable(&lt;span class=&quot;str&quot;&gt;&apos;&apos;&lt;/span&gt;).extend({ required: &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt; });
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.phoneNumber = &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.firstName = ko.observable(&lt;span class=&quot;str&quot;&gt;&apos;&apos;&lt;/span&gt;).extend({ required: &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt; });
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.email = ko.observable(&lt;span class=&quot;str&quot;&gt;&apos;&apos;&lt;/span&gt;).extend({ required: &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt; });   
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.isValid = function() {
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; 
            &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.firstName.isValid() &amp;amp;&amp;amp;
            &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.lastName.isValid() &amp;amp;&amp;amp;
            &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.phoneNumber.isValid() &amp;amp;&amp;amp;
            &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.email.isValid();                
    };    
}&lt;span style=&quot;font-family: Times New Roman;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;/pre&gt;
&lt;/div&gt;
This is what my first attempt looked like. A little later I discovered that you can get rid of these boilerplate functions on the composite model by applying the validatedObservable function instead.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;ko.applyBindings(ko.validatedObservable(&lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; BookingModel()));
ko.validatedObservable = function (initialValue) {
    &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (!exports.utils.isObject(initialValue)) { 
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; ko.observable(initialValue).extend({ validatable: &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt; }); }
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; obsv = ko.observable(initialValue);
    obsv.errors = exports.group(initialValue);
    obsv.isValid = ko.computed(function () {
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; obsv.errors().length === 0;
    });
    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; obsv;
};&lt;/pre&gt;
&lt;/div&gt;
The validatedObservable function will add an errors function to the composite model which traverses the object graph and validates each eligible property. The errors function also has a showAllMessages function that will display an error message next to each invalid element. The isValid function only asserts if there are any errors.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;function BookingModel() {      
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; self = &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;;
    
    self.contact = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ContactModel();
    self.departure = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; DepartureModel();
    self.validate = function() {                           
        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (!&lt;b&gt;&lt;span class=&quot;kwrd&quot;&gt;self&lt;/span&gt;.isValid()&lt;/b&gt;) {                                         
            &lt;b&gt;self.errors.showAllMessages();&lt;/b&gt;
        
            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;;          
        }
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;;
    };             
}   
function DepartureModel() {
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.street = ko.observable(&lt;span class=&quot;str&quot;&gt;&apos;&apos;&lt;/span&gt;).extend({ required: &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt; });
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.houseNumber = ko.observable(&lt;span class=&quot;str&quot;&gt;&apos;&apos;&lt;/span&gt;).extend({ required: &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt; });
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.city = ko.observable(&lt;span class=&quot;str&quot;&gt;&apos;&apos;&lt;/span&gt;).extend({ required: &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt; });
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.time = ko.observable(&lt;span class=&quot;str&quot;&gt;&apos;&apos;&lt;/span&gt;).extend({ required: &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt; });            
}
function ContactModel() {
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.firstName = ko.observable(&lt;span class=&quot;str&quot;&gt;&apos;&apos;&lt;/span&gt;).extend({ required: &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt; });
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.lastName = ko.observable(&lt;span class=&quot;str&quot;&gt;&apos;&apos;&lt;/span&gt;).extend({ required: &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt; });
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.phoneNumber = &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.firstName = ko.observable(&lt;span class=&quot;str&quot;&gt;&apos;&apos;&lt;/span&gt;).extend({ required: &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt; });
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.email = ko.observable(&lt;span class=&quot;str&quot;&gt;&apos;&apos;&lt;/span&gt;).extend({ required: &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt; });        
}&lt;/pre&gt;
&lt;/div&gt;

&lt;br&gt;
Removing that cruft results in less bulky, cheaper models.
&lt;br&gt;

&lt;br&gt;
If you try this example, you will notice that the model appears to be valid even though the validation rules are clearly violated. It took me a few minutes of browsing the source to figure out why this was happening. When you use the group functions to validate your model, they will by default only look at first level properties. So if you have a composite model, you need to modify the grouping validation configuration, and set the deep property to true.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;ko.validation.init({ grouping : { &lt;b&gt;deep: &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;&lt;/b&gt;, observable: &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt; } });&lt;/pre&gt;
&lt;/div&gt;
&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/41363463/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/41363463/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/41363463/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/41363463/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/41363463/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/41363463/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/41363463/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/41363463/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/2663564887384779523/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/41363463/0/jefclaes~Validating-composite-models-with-knockout-validation.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/2663564887384779523?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/2663564887384779523?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/41363463/0/jefclaes~Validating-composite-models-with-knockout-validation.html' title='Validating composite models with knockout validation'/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry>
<entry gd:etag='W/&quot;DEUCQno6fSp7ImA9WhBbE0s.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2013/05/iddd-tour-notes-22.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-7802259801796841822</id><published>2013-05-12T15:44:00.000+02:00</published><updated>2013-05-12T15:44:23.415+02:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2013-05-12T15:44:23.415+02:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='DDD'/><category scheme='http://www.blogger.com/atom/ns#' term='Ramblings'/><title>IDDD Tour notes (2/2)</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
This is the second and last part of my notes I scribbled down attending the IDDD Tour. &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2013/05/iddd-tour-notes-12.html&quot;&gt;The first part&lt;/a&gt; was published last week.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;A better model&lt;/b&gt;
&lt;br&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Even if you come up with a better model, the fact that it has been the ubiquitous language of the domain for decades proves that it works for them.&lt;/blockquote&gt;
This quote bothers me a bit. There definitely is truth to this, but modeling an existing process often presents such a great opportunity to revise and improve it. Naked models don&apos;t conceal deficiencies, inefficiencies and aberrations. Exploring alternative models free of habituation, politics and legacy is dirt cheap, while the outcome could considerably benefit all. It seems such a shame not to take advantage of this. As with most things, know when to pick your fights.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;Elegance&lt;/b&gt;
&lt;br&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Elegance is for dressing, not for delivering software.&lt;/blockquote&gt;
This is one to remember; I&apos;ll be using this one next time someone uses elegance as an argument for gold plating.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;Cultivating models&lt;/b&gt;
&lt;br&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Models grow; you will never have the best model from the start. Improve them every time you pass by.&lt;/blockquote&gt;
Your first attempt at it is hardly ever right. Don&apos;t beat yourself up over it. The best models are the result of multiple iterations. &lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;
&lt;br&gt;
In general I consider dwelling on one problem too long to be a waste of time. Settle for good enough, and allow the better solution to emerge by itself over time.
&lt;br&gt;
When I feel a design is mighty important, I might accelerate this process by iterating over it multiple times in just a few days; asking for constant feedback, carrying the problem with me everywhere I go, always challenging it, and molding it in different shapes until one sticks.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;Reuse&lt;/b&gt;
&lt;br&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Lots of people use a shared kernel just for reuse. It&apos;s often not worth it.&lt;/blockquote&gt;
People are so obsessed with the DRY principle, and the dogma of avoiding duplication, it often does more harm than good. Nonexistent concepts are introduced just to spare a few duplicate lines of code, while they will hinder and complicate autonomous evolution.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;REST and DDD&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;&lt;/b&gt;
&lt;br&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Don&apos;t expose your domain model over REST: expose use cases.&amp;nbsp;&lt;/blockquote&gt;
You want to enable relentlessly evolving your domain model without breaking clients. In practice you would post intent-revealing command resources, while hypermedia guides you in navigating to subsequent commands.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;Published language&lt;/b&gt;
&lt;br&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
How is the language agreed upon; over lunch or by a committee?&lt;/blockquote&gt;
&amp;nbsp;A great question which reveals if a language should be really considered as published.
&lt;br&gt;

&lt;br&gt;
&lt;i&gt;And that&apos;s the last of it. If you thought some of these were interesting, you should probably &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.amazon.com/gp/product/0321834577/ref=as_li_qf_sp_asin_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0321834577&amp;amp;linkCode=as2&amp;amp;tag=diofanedebyje-20&quot;&gt;get the book&lt;/a&gt;. I finished &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.amazon.com/gp/product/0321503627/ref=as_li_qf_sp_asin_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0321503627&amp;amp;linkCode=as2&amp;amp;tag=diofanedebyje-20&quot;&gt;Growing Object-Oriented Software Guided by Tests&lt;/a&gt; last week, so I finally get to read it myself after having it collect dust for two months.&lt;/i&gt;&lt;/div&gt;
&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/41071383/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/41071383/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/41071383/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/41071383/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/41071383/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/41071383/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/41071383/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/41071383/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/7802259801796841822/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/41071383/0/jefclaes~IDDD-Tour-notes.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/7802259801796841822?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/7802259801796841822?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/41071383/0/jefclaes~IDDD-Tour-notes.html' title='IDDD Tour notes (2/2)'/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry>
<entry gd:etag='W/&quot;DEEHQ3g5eCp7ImA9WhBUF0s.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2013/05/iddd-tour-notes-12.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-6214177099178109741</id><published>2013-05-05T17:10:00.000+02:00</published><updated>2013-05-05T17:10:32.620+02:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2013-05-05T17:10:32.620+02:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='DDD'/><category scheme='http://www.blogger.com/atom/ns#' term='Ramblings'/><title>IDDD Tour notes (1/2)</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Two weeks ago I got to spend four days attending the &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~idddtour.com/&quot;&gt;IDDD Tour&lt;/a&gt; by &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://twitter.com/VaughnVernon&quot;&gt;Vaughn Vernon&lt;/a&gt;. Although my book queue has only allowed me to shallowly browse &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.amazon.com/gp/product/0321834577/ref=as_li_qf_sp_asin_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0321834577&amp;amp;linkCode=as2&amp;amp;tag=diofanedebyje-20&quot;&gt;the book&lt;/a&gt;, I had high hopes for this course. I anticipated a week of getting lectured on DDD with a few practical exercises, but was blown away by the openness and interaction promoted by Vaughn and his associate &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://twitter.com/ziobrando&quot;&gt;Alberto Brandolini&lt;/a&gt;. A passionate group, engaging workshops, long days and lots of sharing made these few days exceptionally satisfying and inspirational. I&apos;m grateful to &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.corebvba.be/blog/post/IDDDtour-2013-Belgium-an-immersive-experience.aspx&quot;&gt;those who got this show on the road&lt;/a&gt;; it was more than worth your trouble.
&lt;br&gt;

&lt;br&gt;
Over these few days I scribbled down some things I thought were worth remembering or worth some more thought. Most of these are aimed at the strategic side of DDD and the softer side of software since that&apos;s where I acquired most new insights.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;Complexity&lt;/b&gt;
&lt;br&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
If we really understood the complexity of a system, we would very often make different decisions from when designing new systems.&amp;nbsp;&lt;/blockquote&gt;
Understanding the complexity of a new system is hard. Modeling can serve as the perfect tool to help you expose the hidden complexities as early as possible.
&lt;br&gt;
Often a system appears to be not much more than CRUD, to quickly evolve into something with a lot more behaviour than anticipated. Make sure you don&apos;t sabotage growing your design by picking an architecture or framework that doesn&apos;t allow you to.
&lt;br&gt;
I often start with just exposing commands and queries to my application, which encapsulate all domain logic. Behind these command- and queryhandlers is very little abstraction, just some basic building blocks; aggregates, entities and value objects. Later on I can relentlessly refactor everything behind these commands and queries without breaking application code: introduce domain services, events, separate the write- from the read model etc... 
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;Change&lt;/b&gt;
&lt;br&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
How do you bring in DDD? Gather a small cluster of motivated silent people and work on a project that has lots of potential value.&lt;/blockquote&gt;
This is my recipe for change as well. Find a few like-minded people that are confident drawing outside the lines set out by the status quo, work in the shades, working your way towards the light.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;Brown&lt;/b&gt;
&lt;br&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
There is always brown, even when it&apos;s under the green.&amp;nbsp;&lt;/blockquote&gt;
Every application has parts which are less pretty, even green fields; use proper encapsulation to contain them, and avoid them corrupting other parts of the system.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;&amp;nbsp;Another brick in the wall&lt;/b&gt;
&lt;br&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Break down that paper wall between domain experts and developers. Learn the favorite coffee of the domain expert.&lt;/blockquote&gt;
Lots of organizations still build this paper wall between domain experts and developers. But paper doesn&apos;t answer to questions, nor does it carry nuances very well. Communicating on a more personal level is key to tearing down that wall. Breaking the ice can be as easy as treating your domain expert to coffee.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;One language&lt;/b&gt;
&lt;br&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Which language do you use when naming things in code? Yours.&amp;nbsp;&lt;/blockquote&gt;
I don&apos;t think native English speakers understand just how awkward it is to write code in something other than English. Keywords, API&apos;s, documentation... it&apos;s all in English. I feel that putting these together with your own language results in a cacophony of words.
&lt;br&gt;
In my current project the business is bilingual; they use Dutch and French names for the same concept interchangeably. We tried to find middle ground by introducing English names, and have a map between these languages. Ideally there would only be one language though.
&lt;br&gt;
Someone mentioned that they use English for all globally unambiguous concepts such as account number, name... but use their mother tongue in scenarios where nuances would be lost in translation. This seems to be an attractive compromise.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;Defining a bounded context&lt;/b&gt;
&lt;br&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
A bounded context is where one ubiquitous language is consistent.&lt;/blockquote&gt;
This is by far the simplest definition of a bounded context. &lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;Bounded context relations&lt;/b&gt;
&lt;br&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
You say please, so I am upstream.&lt;/blockquote&gt;
The &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.markhneedham.com/blog/2009/03/30/ddd-recognising-relationships-between-bounded-contexts/&quot;&gt;relationship between bounded contexts&lt;/a&gt; is expressed by saying one is upstream or downstream. I thought of the quote above to be a creative expression that can aid in explaining these two concepts.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;Rewrites&lt;/b&gt;
&lt;br&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
When you rewrite an application, you have to look at the existing forces in an organization; chances are the previous team wasn&apos;t terrible either.&lt;/blockquote&gt;
Tons of factors influence the outcome of a project; it&apos;s not just about teams and their skillset. Some forces in an organization can make it close to impossible to ship good software; fear of change, lack of vision, bone-dry information streams... So don&apos;t assume your rewrite will fix everything.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;Surprise&lt;/b&gt;
&lt;br&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
Adding surprise value is often not that valuable.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;&lt;/blockquote&gt;
This seems to be related to the mantra of &apos;good enough&apos;. Sometimes we - with the best intentions - invest more time and money in solving a problem in the best possible way, than it will ever return.
&lt;br&gt;

&lt;br&gt;
&lt;i&gt;These were some notes I wrote down the first two days. I&apos;ll try to go through the other half over these next few days. I hope you found some of them valuable too.&lt;/i&gt;&lt;/div&gt;
&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/40827214/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/40827214/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/40827214/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/40827214/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/40827214/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/40827214/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/40827214/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/40827214/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/6214177099178109741/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/40827214/0/jefclaes~IDDD-Tour-notes.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/6214177099178109741?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/6214177099178109741?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/40827214/0/jefclaes~IDDD-Tour-notes.html' title='IDDD Tour notes (1/2)'/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry>
<entry gd:etag='W/&quot;AkYCQHc7eip7ImA9WhBUEUs.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2013/04/customizing-knockout-validation-message.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-1121726328435571986</id><published>2013-04-28T18:56:00.000+02:00</published><updated>2013-04-28T18:56:01.902+02:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2013-04-28T18:56:01.902+02:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='CodeSnippets'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='HTML'/><title>Customizing a knockout validation message</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://github.com/ericmbarnard/Knockout-Validation&quot;&gt;Knockout validation&lt;/a&gt; is a plugin that allows you to extend observables with validation. If you&apos;re familiar with jQuery validation, you will notice that most provided validation rules are very similar.
&lt;br&gt;

&lt;br&gt;
One of the validation rules available out-of-the-box is pattern validation. By default the error message for violating this rule doesn&apos;t mention the expected pattern. And in general, showing the expected pattern probably isn&apos;t a good idea since your users will have no idea what you&apos;re talking about. If you&apos;re building a back-end for devops purposes, it might be more acceptable though.
&lt;br&gt;

&lt;br&gt;
Instead of &quot;Invalid.&quot;, I want my error message to be &quot;I can&apos;t believe the pattern doesn&apos;t match {pattern}.&quot;.
&lt;br&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;test(&lt;span class=&quot;str&quot;&gt;&apos;1. When the object is invalid, the error message contains our formatted message.&apos;&lt;/span&gt;, 
    function () {
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; testObj = ko.observable(&lt;span class=&quot;str&quot;&gt;&apos;&apos;&lt;/span&gt;).extend({ pattern: &lt;span class=&quot;str&quot;&gt;&apos;myPattern&apos;&lt;/span&gt; });    
            
        testObj(&lt;span class=&quot;str&quot;&gt;&apos;something&apos;&lt;/span&gt;);
        
        equal(
            testObj.error, 
            &lt;span class=&quot;str&quot;&gt;&apos;I can\&apos;t believe the pattern doesn\&apos;t match \&apos;myPattern\&apos;.&apos;&lt;/span&gt;, 
            &lt;span class=&quot;str&quot;&gt;&apos;The formatted error message is correct.&apos;&lt;/span&gt;);    
    }
);
Expected: &lt;span class=&quot;str&quot;&gt;&quot;I can&apos;t believe the pattern doesn&apos;t match &apos;myPattern&apos;.&quot;&lt;/span&gt;
Result:    &lt;span class=&quot;str&quot;&gt;&quot;Invalid.&quot;&lt;/span&gt;
Diff: &lt;span class=&quot;str&quot;&gt;&quot;I can&apos;t believe the pattern doesn&apos;t match &apos;myPattern&apos;.&quot;&lt;/span&gt; &lt;span class=&quot;str&quot;&gt;&quot;Invalid.&quot;&lt;/span&gt; &lt;/pre&gt;
&lt;/div&gt;
Digging a bit into the source, I found the function that formats the error messages; it simply replaces {0} in the message with the params value.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;formatMessage: function (message, &lt;span class=&quot;kwrd&quot;&gt;params&lt;/span&gt;) {
    &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt; (message) === &lt;span class=&quot;str&quot;&gt;&apos;function&apos;&lt;/span&gt;)
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; message(&lt;span class=&quot;kwrd&quot;&gt;params&lt;/span&gt;);
    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; message.replace(/\{0\}/gi, &lt;span class=&quot;kwrd&quot;&gt;params&lt;/span&gt;);
};&lt;/pre&gt;
So to change the error message to have it include the pattern, we can pass a pattern object which contains our message with the params placeholder and the params value.&amp;nbsp;&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;test(&lt;span class=&quot;str&quot;&gt;&apos;2. When the object is invalid, the error message contains our formatted message.&apos;&lt;/span&gt;, 
    function () {   
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; testObj = ko
            .observable(&lt;span class=&quot;str&quot;&gt;&apos;&apos;&lt;/span&gt;)
            .extend({ pattern: {
                message: &lt;span class=&quot;str&quot;&gt;&apos;I can\&apos;t believe the pattern doesn\&apos;t match \&apos;{0}\&apos;.&apos;&lt;/span&gt;,
                &lt;span class=&quot;kwrd&quot;&gt;params&lt;/span&gt;: &lt;span class=&quot;str&quot;&gt;&apos;myPattern&apos;&lt;/span&gt;
        }});                            
                
        testObj(&lt;span class=&quot;str&quot;&gt;&apos;something&apos;&lt;/span&gt;);
        
        equal(
            testObj.error, 
            &lt;span class=&quot;str&quot;&gt;&apos;I can\&apos;t believe the pattern doesn\&apos;t match \&apos;myPattern\&apos;.&apos;&lt;/span&gt;, 
            &lt;span class=&quot;str&quot;&gt;&apos;The formatted error message is correct.&apos;&lt;/span&gt;);    
    }
);
The formatted error message &lt;span class=&quot;kwrd&quot;&gt;is&lt;/span&gt; correct.
Expected: &lt;span class=&quot;str&quot;&gt;&quot;I can&apos;t believe the pattern doesn&apos;t match &apos;myPattern&apos;.&quot;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
This will make our test pass. It&apos;s not a great idea to repeat this in each location though. Since the plugin exposes its rules, you can just go in, modify the default message for the pattern rule, and see it applied everywhere.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;test(&lt;span class=&quot;str&quot;&gt;&apos;3. When the objects are invalid, the error message contains our formatted message.&apos;&lt;/span&gt;, 
    function () {
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; testObj1 = ko.observable(&lt;span class=&quot;str&quot;&gt;&apos;&apos;&lt;/span&gt;).extend({ pattern: &lt;span class=&quot;str&quot;&gt;&apos;myPattern&apos;&lt;/span&gt; });
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; testObj2 = ko.observable(&lt;span class=&quot;str&quot;&gt;&apos;&apos;&lt;/span&gt;).extend({ pattern: &lt;span class=&quot;str&quot;&gt;&apos;myPattern&apos;&lt;/span&gt; });
                                            
        ko.validation.rules[&lt;span class=&quot;str&quot;&gt;&apos;pattern&apos;&lt;/span&gt;].message = 
            &lt;span class=&quot;str&quot;&gt;&apos;I can\&apos;t believe the pattern doesn\&apos;t match \&apos;{0}\&apos;.&apos;&lt;/span&gt;,    
        
        testObj1(&lt;span class=&quot;str&quot;&gt;&apos;something&apos;&lt;/span&gt;);
        testObj2(&lt;span class=&quot;str&quot;&gt;&apos;something&apos;&lt;/span&gt;);
        
        equal(
            testObj1.error, 
            &lt;span class=&quot;str&quot;&gt;&apos;I can\&apos;t believe the pattern doesn\&apos;t match \&apos;myPattern\&apos;.&apos;&lt;/span&gt;, 
            &lt;span class=&quot;str&quot;&gt;&apos;The formatted error message is correct for testObj1.&apos;&lt;/span&gt;);      
        equal(
            testObj2.error, 
            &lt;span class=&quot;str&quot;&gt;&apos;I can\&apos;t believe the pattern doesn\&apos;t match \&apos;myPattern\&apos;.&apos;&lt;/span&gt;, 
            &lt;span class=&quot;str&quot;&gt;&apos;The formatted error message is correct for testObj2.&apos;&lt;/span&gt;);      
    }
);
The formatted error message &lt;span class=&quot;kwrd&quot;&gt;is&lt;/span&gt; correct.
Expected: &lt;span class=&quot;str&quot;&gt;&quot;I can&apos;t believe the pattern doesn&apos;t match &apos;myPattern&apos;.&quot;&lt;/span&gt;
The formatted error message &lt;span class=&quot;kwrd&quot;&gt;is&lt;/span&gt; correct.
Expected: &lt;span class=&quot;str&quot;&gt;&quot;I can&apos;t believe the pattern doesn&apos;t match &apos;myPattern&apos;.&quot;&lt;/span&gt;
&lt;/pre&gt;
I hope that even if you weren&apos;t interested in this exact scenario, this post gave you an idea on how to go at customizing knockout validation messages.&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/40570741/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/40570741/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/40570741/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/40570741/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/40570741/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/40570741/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/40570741/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/40570741/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/1121726328435571986/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/40570741/0/jefclaes~Customizing-a-knockout-validation-message.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/1121726328435571986?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/1121726328435571986?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/40570741/0/jefclaes~Customizing-a-knockout-validation-message.html' title='Customizing a knockout validation message'/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry>
<entry gd:etag='W/&quot;DEIERX45cSp7ImA9WhBVFUs.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2013/04/modeling-four-eye-principle.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-7251261762480969475</id><published>2013-04-21T19:48:00.000+02:00</published><updated>2013-04-21T19:48:24.029+02:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2013-04-21T19:48:24.029+02:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='CodeSnippets'/><category scheme='http://www.blogger.com/atom/ns#' term='Ramblings'/><title>Modeling the four-eye principle</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Working in a financial domain over the last year, it was only a matter of time before I would be confronted with one of the variations of &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~en.wikipedia.org/wiki/Two-man_rule&quot;&gt;the two-man rule&lt;/a&gt;: the four-eye principle. Satisfying the principle is simple enough; an extra pair of eyes needs to approve of requested changes before they&apos;re applied to the system. This measure should prevent mistakes such as a user nuking North Korea by accident, or transferring all corporate funds to a personal off-shore bank account. In practice all you need is an accomplice.
&lt;br&gt;

&lt;br&gt;
Although I have seen artifacts of this concept, this is the first time I actively had to model it myself. Since I looked online for inspiration, but returned empty handed, I&apos;m documenting my findings here.
&lt;br&gt;

&lt;br&gt;
I started out modeling the concept directly on the relevant entities, but it was obvious really soon that this was going nowhere. The solution headed in the wrong direction from the get go: copying records, dirty tracking, a bunch of possible states, resulting in complex transitions, and the need for an audit log. I couldn&apos;t even address these concerns without them bleeding into other layers such as queries and repositories. This design also failed to cover one edge scenario where we don&apos;t need an entity at all.
&lt;br&gt;

&lt;br&gt;
Returning home, I gave it another shot, but this time I modeled the principle as a separate concept, not touching any existing entities. A user hands in a request, which will be persisted, and will just sit there until a supervisor approves or declines it. If it&apos;s accepted, the request state gets updated, and all request handlers are invoked. It&apos;s the request handlers that are responsible for applying the requested change(s) to the system. Before the request handlers are invoked, no existing entities are touched.
&lt;br&gt;

&lt;br&gt;
Modeling the concept this way also leans closer to reality. You want to keep your core system as clean and simple as possible, to avoid confusion and mistakes where you can. If we would go back in time twenty years, the requests would also have lived in a separate drawer.
&lt;br&gt;

&lt;br&gt;
Here&apos;s some of my tinkering trying to support this concept.
&lt;br&gt;

&lt;br&gt;
A request is actually a template. It will always contain the current state, and some meta data concerning previous state transitions, but the actual content is generic. When a supervisor accepts or declines a request, a guard makes sure the user that made the original request, is not the one doing the supervision. Other guards make sure the status transition makes sense; you need to make a new request once it has been supervised. When the request is accepted, a domain event gets raised.
&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Request
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Request(Requested requested, IRequestContent content)
    {
        Guard.ForEmpty(requested, &lt;span class=&quot;str&quot;&gt;&quot;requested&quot;&lt;/span&gt;);
        Guard.ForEmpty(content, &lt;span class=&quot;str&quot;&gt;&quot;content&quot;&lt;/span&gt;);
        Id = Guid.NewGuid();
        Requested = requested;
        Content = content;
        Status = Status.Waiting;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Guid Id { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Requested Requested { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Supervised Supervised { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; IRequestContent Content { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Status Status { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Accept(Supervised supervised)
    {         
        ChangeStatus(Status.Accepted, supervised);
        DomainEvents.Raise(&lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; RequestAcceptedEvent() { RequestId = Id });
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Decline(Supervised supervised)
    {           
        ChangeStatus(Status.Declined, supervised);            
    }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; ChangeStatus(Status status, Supervised supervised)
    {
        Guard.ForEmpty(supervised, &lt;span class=&quot;str&quot;&gt;&quot;supervised&quot;&lt;/span&gt;);
        Guard.SupervisingUserBeingTheRequestingUser(Requested.By, supervised.By);
        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (Status != Status.Waiting)
            &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; InvalidOperationException(
                &lt;span class=&quot;str&quot;&gt;&quot;This request is already accepted or declined.&quot;&lt;/span&gt;);
        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (status == Status.Waiting)
            &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; InvalidOperationException(
                &lt;span class=&quot;str&quot;&gt;&quot;The status shouldn&apos;t be changed to Waiting after creation.&quot;&lt;/span&gt;);            
        Status = status;
        Supervised = supervised;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; Equals(&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; obj)
    {
        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (obj == &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt; || GetType() != obj.GetType())
            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;;
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; other = obj &lt;span class=&quot;kwrd&quot;&gt;as&lt;/span&gt; Request;
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; Id == other.Id;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; GetHashCode()
    {
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.Id.GetHashCode();
    }
}  &lt;/pre&gt;
&lt;/div&gt;
An event handler listens for the request accepted event, and uses the content&apos;s type to make a generic type, which is then used to search the container for relevant request handlers. Since our type system isn&apos;t aware of our specific types - request handlers and request content are both objects at this point, I sprinkle some dynamic on top, and rely on the DLR to invoke the correct method. I think drawing outside the static lines here helps keeping things simple; it&apos;s definitely nicer to read than its counterpart, which needs to rely on reflection.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;interface&lt;/span&gt; IRequestHandler&amp;lt;TRequestContent&amp;gt;
{
    &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; OnAccepted(TRequestContent requestContent);
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; RequestAcceptedEventHandler : IEventHandler&amp;lt;RequestAcceptedEvent&amp;gt;
{
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; IKernel _kernel;
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; IRequestRepository _requestRepository;
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; RequestAcceptedEventHandler(IKernel kernel, IRequestRepository requestRepository)
    {
        _kernel = kernel;
        _requestRepository = requestRepository;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Handle(RequestAcceptedEvent @&lt;span class=&quot;kwrd&quot;&gt;event&lt;/span&gt;)
    {
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; request = _requestRepository.GetById(@&lt;span class=&quot;kwrd&quot;&gt;event&lt;/span&gt;.RequestId);
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; requestHandlerType = 
            &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(IRequestHandler&amp;lt;&amp;gt;)
                .MakeGenericType(request.Content.GetType());
        &lt;span class=&quot;kwrd&quot;&gt;foreach&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; requestHandler &lt;span class=&quot;kwrd&quot;&gt;in&lt;/span&gt; _kernel.GetAll(requestHandlerType))
            ((dynamic)requestHandler).OnAccepted((dynamic)request.Content);
    }
}&lt;/pre&gt;
Now that we have this in place, a scenario where a user requests to have a missile launched, and a supervisor approves of this request, could look like this.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Main(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;[] args)
{
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; repository = kernel.Get&amp;lt;IRequestRepository&amp;gt;();
    
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; launchMissileRequest = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Request(
        &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Requested(&lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; User(&lt;span class=&quot;str&quot;&gt;&quot;MiniMe&quot;&lt;/span&gt;)),
        &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; LaunchMissileRequestContent(&lt;span class=&quot;str&quot;&gt;&quot;V-2&quot;&lt;/span&gt;, &lt;span class=&quot;str&quot;&gt;&quot;The Ozone Layer&quot;&lt;/span&gt;));
    
    repository.Add(launchMissileRequest);
    ListRepositoryContent(repository);
    
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; request = repository.GetById(launchMissileRequest.Id);
    
    request.Accept(&lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Supervised(&lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; User(&lt;span class=&quot;str&quot;&gt;&quot;DrEvil&quot;&lt;/span&gt;)));
    ListRepositoryContent(repository);
    Console.ReadLine();
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; LaunchMissileRequestHandler : IRequestHandler&amp;lt;LaunchMissileRequestContent&amp;gt;
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; OnAccepted(LaunchMissileRequestContent requestContent)
    {    
        Console.WriteLine(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;.Format(&lt;span class=&quot;str&quot;&gt;&quot;Launching {0} to {1}!!&quot;&lt;/span&gt;,
            requestContent.MissileName, requestContent.Destination));
    }
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; LaunchMissileRequestContent : IRequestContent
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; LaunchMissileRequestContent(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; missileName, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; destination)
    {
        Guard.ForEmpty(missileName, &lt;span class=&quot;str&quot;&gt;&quot;missile name&quot;&lt;/span&gt;);
        Guard.ForEmpty(destination, &lt;span class=&quot;str&quot;&gt;&quot;destination&quot;&lt;/span&gt;);
        MissileName = missileName;
        Destination = destination;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; MissileName { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; Destination { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; Summary
    {
        &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt; { &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;.Format(&lt;span class=&quot;str&quot;&gt;&quot;Launch {0} to {1}.&quot;&lt;/span&gt;, MissileName, Destination); }
    }
}&lt;span style=&quot;font-family: Times New Roman;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
This will result in the following being outputted to the console.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;-----------------------------------------
Id: dcd6eaba-1a3e-4d81-82f4-4b2938911e7e
Status: Waiting
Summary: Launch V-2 to The Ozone Layer.
-----------------------------------------
Launching V-2 to The Ozone Layer!!
-----------------------------------------
Id: dcd6eaba-1a3e-4d81-82f4-4b2938911e7e
Status: Accepted
Summary: Launch V-2 to The Ozone Layer.
-----------------------------------------&lt;/pre&gt;
&lt;b&gt;Fully exposed&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
It&apos;s rare to see people share how they go at modeling real-life problems - money and withdrawing funds from an account don&apos;t count. And I get it; you&apos;re fully exposed; there is more than one way to skin a cat; history and context is lost in translation; and the devil is in the details. It&apos;s a shame though; there is no technology or methodology that will save you when you get these things catastrophically wrong.
&lt;br&gt;

&lt;br&gt;
&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://github.com/JefClaes/FourEyesPrinciple&quot;&gt;The source of this article is up on GitHub&lt;/a&gt;. If you feel like toying with this concept, be my guest. Be gentle about it though.&amp;nbsp;&lt;/div&gt;
&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/40344413/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/40344413/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/40344413/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/40344413/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/40344413/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/40344413/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/40344413/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/40344413/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/7251261762480969475/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/40344413/0/jefclaes~Modeling-the-foureye-principle.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/7251261762480969475?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/7251261762480969475?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/40344413/0/jefclaes~Modeling-the-foureye-principle.html' title='Modeling the four-eye principle'/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry>
<entry gd:etag='W/&quot;Dk8EQ3s6eip7ImA9WhBWGUg.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2013/04/internationalization-in-nancyfx.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-5109807192744683269</id><published>2013-04-14T17:53:00.000+02:00</published><updated>2013-04-14T17:53:22.512+02:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2013-04-14T17:53:22.512+02:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='CodeSnippets'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='NancyFx'/><title>Internationalization in NancyFx</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
When I&apos;m building web applications for non-work projects, I still find myself using &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~nancyfx.org/&quot;&gt;Nancy&lt;/a&gt; most of the time. Something I looked at this week was how I could get the user&apos;s culture in Nancy. I looked a bit at &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://github.com/NancyFx&quot;&gt;the latest source&lt;/a&gt;, and discovered that recently some work has been done in this area.
&lt;br&gt;

&lt;br&gt;
When you look at the Nancy context, available in modules, you will find a Culture property.
&lt;br&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; SomeModule()
{
    Get[&lt;span class=&quot;str&quot;&gt;&quot;/&quot;&lt;/span&gt;] = _  =&amp;gt; {
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; cultureInfo = Context.Culture;
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; View[&lt;span class=&quot;str&quot;&gt;&quot;Home.cshtml&quot;&lt;/span&gt;];
    };
}&lt;/pre&gt;
Tracing through the source, you can see that this value is set in the default contextfactory, which in its turn queries a culture service. The service itself iterates over all culture conventions until it finds one that returns a value.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; CultureInfo DetermineCurrentCulture(NancyContext context)
{
    CultureInfo culture = &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;;
    &lt;span class=&quot;kwrd&quot;&gt;foreach&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; convention &lt;span class=&quot;kwrd&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.cultureConventions)
    {
        culture = convention(context);
        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (culture != &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;)
        {
            &lt;span class=&quot;kwrd&quot;&gt;break&lt;/span&gt;;
        }
    }
    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; culture;
}&lt;/pre&gt;
The default culture conventions make use of some built-in culture detection mechanisms. Six mechanisms are in place, and will be tried in a specific order.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;conventions.CultureConventions = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; List&amp;lt;Func&amp;lt;NancyContext, CultureInfo&amp;gt;&amp;gt;(6)
{
    BuiltInCultureConventions.FormCulture,
    BuiltInCultureConventions.PathCulture,
    BuiltInCultureConventions.HeaderCulture,
    BuiltInCultureConventions.SessionCulture,
    BuiltInCultureConventions.CookieCulture,
    BuiltInCultureConventions.ThreadCulture
};&lt;/pre&gt;
&lt;/div&gt;
&lt;ol style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Form: does the form data contain a CurrentCulture entry?&lt;/li&gt;
&lt;li&gt;Path: is the first part of the url a culture?&lt;/li&gt;
&lt;li&gt;Header: is the Accept-Language header present?&lt;/li&gt;
&lt;li&gt;Session: is there a CurrentCulture key in the session?&lt;/li&gt;
&lt;li&gt;Cookie: is there a CurrentCulture key in the cookie?&lt;/li&gt;
&lt;li&gt;Thread: what&apos;s the current thread culture?&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
So out-of-the-box Nancy is very smart about how she will try to determine a user&apos;s culture. You can either pass the culture to the relevant formatting functions, or you can set the culture for the execution of the whole request.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;

&lt;br&gt;&lt;/div&gt;
&lt;div&gt;
The latter can be achieved with a before hook. You can add this to an individual module, or to each module in your application by adding it to the bootstapper.&lt;/div&gt;
&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; RequestStartup(
    IKernel container, 
    IPipelines pipelines, 
    NancyContext context)
{
    &lt;span class=&quot;kwrd&quot;&gt;base&lt;/span&gt;.RequestStartup(container, pipelines, context);
    pipelines.BeforeRequest += ctx =&amp;gt;
    {
        Thread.CurrentThread.CurrentCulture = context.Culture;
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;;
    };
}&lt;/pre&gt;
I posted this on the mailing list and &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://twitter.com/grumpydev&quot;&gt;GrumpyDev&lt;/a&gt; raised one concern; depending on in which host you&apos;re running Nancy, it might not be guaranteed that the whole request is executed on the same thread, so that could produce some undesired results. ASP.NET runs each request on its own thread though.&amp;nbsp;&lt;/div&gt;
&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/40082716/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/40082716/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/40082716/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/40082716/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/40082716/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/40082716/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/40082716/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/40082716/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/5109807192744683269/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/40082716/0/jefclaes~Internationalization-in-NancyFx.html#comment-form' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/5109807192744683269?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/5109807192744683269?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/40082716/0/jefclaes~Internationalization-in-NancyFx.html' title='Internationalization in NancyFx'/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><thr:total>7</thr:total></entry>
<entry gd:etag='W/&quot;A04GQng7fyp7ImA9WhBWFEU.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2013/04/designing-entities-immutability-first.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-2600073273283664120</id><published>2013-04-07T17:35:00.000+02:00</published><updated>2013-04-09T08:45:23.607+02:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2013-04-09T08:45:23.607+02:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='Refactoring'/><category scheme='http://www.blogger.com/atom/ns#' term='DDD'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Ramblings'/><title>Designing entities: immutability first</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
The first year I wrote software for a living I spent my days mostly writing forms over data applications; most of my efforts were wasted just trying to make things work using ASP.NET and the Webforms engine. It was only after a year and graduating from the School of Hard Knocks that I learned there is a lot more to building clean and maintainable software than knowing the ins&apos; and outs&apos; of a proprietary UI technology.
&lt;br&gt;

&lt;br&gt;
One of the habits I have adapted over time, is designing new entities as immutable objects first, and to go from there. I believe this helps me to make more deliberate design decisions, leading to better designs.
&lt;br&gt;

&lt;br&gt;
Allow me to demonstrate this using a customer entity - I know this is clich&#xE9;, but I have a hard time coming up with original examples.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;A constructor&lt;/b&gt;
&lt;br&gt;

&lt;br&gt;
This one might sound rather obvious, but you would be surprised how many classes don&apos;t have the decency of a simple constructor, especially since C# introduced &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~msdn.microsoft.com/en-us/library/vstudio/bb384062.aspx&quot;&gt;object initializers&lt;/a&gt;. While object initializers definitely look good, they make your code harder to maintain; classes don&apos;t communicate what they need to get by, nor do they get the opportunity to protect their invariants as early as possible.
&lt;br&gt;

&lt;br&gt;
Like I said, I design my classes to be immutable from the start; after initialization they can&apos;t be modified. I&apos;m not even exposing any state for now.
&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Customer
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Customer(
        Guid id,
        &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; firstName,
        &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; lastName,
        &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; street,
        &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; city,
        &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; country,
        DateTime birthdate,
        &lt;span class=&quot;kwrd&quot;&gt;decimal&lt;/span&gt; balance)
    {
        FirstName = firstName;
        LastName = lastName;
        Street = street;
        City = city;
        Country = country;
        BirthDate = birthdate;
        Balance = balance;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Guid Id { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; FirstName { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; LastName { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; Street { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; City { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; Country { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; DateTime BirthDate { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;decimal&lt;/span&gt; Balance { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
}&lt;/pre&gt;
&lt;b&gt;Comparing identities&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
An entity is always unique within a system; it has an identity. To encapsulate comparing two entities, and to avoid repeating myself, I always override the Equals and GetHashCode methods. We&apos;re not guided into doing this by our object&apos;s immutability though, but by common sense.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; Equals(&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; obj)
{
    &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (obj == &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt; || GetType() != obj.GetType())
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;;            
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; other = obj &lt;span class=&quot;kwrd&quot;&gt;as&lt;/span&gt; Customer;
       
    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; Id == other.Id;
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; GetHashCode()
{
    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.Id.GetHashCode();
}&lt;/pre&gt;
&lt;b&gt;Defaults&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
When a new customer is created, its balance is still empty. The constructor is the perfect place to initialize this default.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Customer(
    Guid id,
    &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; firstName,
    &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; lastName,
    &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; street,
    &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; city,
    &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; country,
    DateTime birthdate)
{
    FirstName = firstName;
    LastName = lastName;
    Street = street;
    City = city;
    Country = country;
    BirthDate = birthdate;
    Balance = 0;
}&lt;/pre&gt;
&lt;b&gt;Protecting invariants&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
The next thing I&apos;ll do is use the constructor to guard for arguments that don&apos;t satisfy my objects invariants. This way we guarantee that the object can never be initialized with an invalid state; avoiding a bunch of trouble along the way.
&lt;br&gt;

&lt;br&gt;
We expect a customer to have a first name, last name, street, city and country which isn&apos;t empty. We also expect its&amp;nbsp;birth date&amp;nbsp;not to be in the future.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Customer(
    Guid id,
    &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; firstName,
    &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; lastName,
    &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; street,
    &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; city,
    &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; country,
    DateTime birthdate)
{
    Guard.ForNullOrEmpty(firstName, &lt;span class=&quot;str&quot;&gt;&quot;first name&quot;&lt;/span&gt;);
    Guard.ForNullOrEmpty(lastName, &lt;span class=&quot;str&quot;&gt;&quot;last name&quot;&lt;/span&gt;);
    Guard.ForNullOrEmpty(street, &lt;span class=&quot;str&quot;&gt;&quot;street&quot;&lt;/span&gt;);
    Guard.ForNullOrEmpty(city, &lt;span class=&quot;str&quot;&gt;&quot;city&quot;&lt;/span&gt;);
    Guard.ForNullOrEmpty(country, &lt;span class=&quot;str&quot;&gt;&quot;country&quot;&lt;/span&gt;);
    Guard.ForDatesInTheFuture(birthdate, &lt;span class=&quot;str&quot;&gt;&quot;birthdate&quot;&lt;/span&gt;);
    Id = id;
    FirstName = firstName;
    LastName = lastName;
    Street = street;
    City = city;
    Country = country;
    BirthDate = birthdate;            
    Balance = 0;
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Guard
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; ForNullOrEmpty(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; value, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; desc)
    {
        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;.IsNullOrEmpty(value))
            &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; NullReferenceException(desc);
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; ForDateInTheFuture(DateTime value, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; desc)
    {
        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (value &amp;gt; DateTimeProvider.Now())
            &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ArgumentException(
                &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;.Format(&lt;span class=&quot;str&quot;&gt;&quot;{0} can&apos;t be a date in the future.&quot;&lt;/span&gt;, desc))
    }
}&lt;/pre&gt;
&lt;b&gt;Composition and extracting value objects&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
I&apos;m fairly confident that every self-respecting programmer is annoyed by the fact that the obvious concepts name and address haven&apos;t been extracted yet. Especially since that bloated constructor is all up in your face. Let&apos;s go ahead and extract two value objects: name and address.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Customer
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Customer(
        Guid id,
        Name name,
        Address address,
        DateTime birthdate)
    {
        Guard.ForNull(name, &lt;span class=&quot;str&quot;&gt;&quot;name&quot;&lt;/span&gt;);
        Guard.ForNull(address, &lt;span class=&quot;str&quot;&gt;&quot;address&quot;&lt;/span&gt;);
        Guard.ForDateInTheFuture(birthdate, &lt;span class=&quot;str&quot;&gt;&quot;birthdate&quot;&lt;/span&gt;);
        Id = id;
        Name = name;
        Address = address;
        Balance = 0;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Guid Id { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; Name Name { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; Address Address { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; DateTime BirthDate { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;decimal&lt;/span&gt; Balance { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Name
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Name(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; first, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; last)
    {
        Guard.ForNullOrEmpty(first, &lt;span class=&quot;str&quot;&gt;&quot;first name&quot;&lt;/span&gt;);
        Guard.ForNullOrEmpty(last, &lt;span class=&quot;str&quot;&gt;&quot;last name&quot;&lt;/span&gt;);
        First = first;
        Last = last;
    }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; First { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; Last { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; Full 
    {
        &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;
        {
            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;.Format(&lt;span class=&quot;str&quot;&gt;&quot;{0} {1}&quot;&lt;/span&gt;, First, Last);
        }
    }
    
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; Equals(Object obj)
    {
        ...
    }
    
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; GetHashCode()
    {
        ...
    }
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Address
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Address(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; street, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; city, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; country)
    {
        Guard.ForNullOrEmpty(street, &lt;span class=&quot;str&quot;&gt;&quot;street&quot;&lt;/span&gt;);
        Guard.ForNullOrEmpty(city, &lt;span class=&quot;str&quot;&gt;&quot;city&quot;&lt;/span&gt;);
        Guard.ForNullOrEmpty(country, &lt;span class=&quot;str&quot;&gt;&quot;country&quot;&lt;/span&gt;);
        Street = street;
        City = city;
        Country = country;
    }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; Street { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; City { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; Country { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; Equals(Object obj)
    {
        ...
    }
    
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; GetHashCode()
    {
        ...
    }
}&lt;/pre&gt;
There, that looks better.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;Tell, don&apos;t ask&amp;nbsp;&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
In good OOP we tell objects what to do, we don&apos;t want to query an object for its state and do something based on that; that would lead to broken encapsulation and thereby more brittle code.
&lt;br&gt;

&lt;br&gt;
Since our immutable object isn&apos;t exposing any state yet, we are forced to ask ourselves why we want to expose something. This way, disregarding &quot;tell don&apos;t ask&quot; becomes a deliberate choice.
&lt;br&gt;

&lt;br&gt;
Let&apos;s say we want to decrease the balance, and throw an exception when funds are insufficient. Instead of asking the customer instance and acting on that..&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (!customer.HasSufficientFunds())
    &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; InsufficientFundsException();&lt;/pre&gt;
&lt;/div&gt;
It&apos;s better to encapsulate data and behaviour, and tell it what to do instead.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Customer
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Customer(
        Guid id,
        Name name,
        Address address,
        DateTime birthdate)
    {
        Guard.ForNull(name, &lt;span class=&quot;str&quot;&gt;&quot;name&quot;&lt;/span&gt;);
        Guard.ForNull(address, &lt;span class=&quot;str&quot;&gt;&quot;address&quot;&lt;/span&gt;);
        Guard.ForDateInTheFuture(birthdate, &lt;span class=&quot;str&quot;&gt;&quot;birthdate&quot;&lt;/span&gt;);
        Id = id;
        Name = name;
        Address = address;
        Balance = 0;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Guid Id { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; Name Name { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; Address Address { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; DateTime BirthDate { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;decimal&lt;/span&gt; Balance { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; HasSufficientFunds(&lt;span class=&quot;kwrd&quot;&gt;decimal&lt;/span&gt; value) 
    {
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; Balance - value &amp;gt;= 0;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; DecreaseBalance(&lt;span class=&quot;kwrd&quot;&gt;decimal&lt;/span&gt; value)
    {
        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (HasSufficientFunds(value))
            &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; InsufficientFundsException();
        Balance -= value;
    }
}&lt;/pre&gt;
&lt;/div&gt;
&lt;b&gt;Making operations explicit&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
Next thing we want to do is change the address of a customer. Since we&apos;re not exposing the address property directly, we&apos;re also forced to think about a useful name for the operation; I decided to name it MoveTo. With this we make things more explicit, and thus more evident for people who are new to the domain.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Customer
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Customer(
        Guid id,
        Name name,
        Address address,
        DateTime birthdate)
    {
        Guard.ForNull(name, &lt;span class=&quot;str&quot;&gt;&quot;name&quot;&lt;/span&gt;);
        Guard.ForNull(address, &lt;span class=&quot;str&quot;&gt;&quot;address&quot;&lt;/span&gt;);
        Guard.ForDateInTheFuture(birthdate, &lt;span class=&quot;str&quot;&gt;&quot;birthdate&quot;&lt;/span&gt;);
        Id = id;
        Name = name;
        Address = address;
        Balance = 0;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Guid Id { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; Name Name { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; Address Address { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; DateTime BirthDate { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;decimal&lt;/span&gt; Balance { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    ...
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; MoveTo(Address newAddress)
    {
        Guard.ForNull(newAddress, &lt;span class=&quot;str&quot;&gt;&quot;new address&quot;&lt;/span&gt;);
        Address = newAddress;
    }
}
&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; customer = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Customer(
    Guid.NewGuid(),
    &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Name(&lt;span class=&quot;str&quot;&gt;&quot;Jef&quot;&lt;/span&gt;, &lt;span class=&quot;str&quot;&gt;&quot;Claes&quot;&lt;/span&gt;),
    &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Address(&lt;span class=&quot;str&quot;&gt;&quot;Ergens&quot;&lt;/span&gt;, &lt;span class=&quot;str&quot;&gt;&quot;Antwerp&quot;&lt;/span&gt;, &lt;span class=&quot;str&quot;&gt;&quot;Belgium&quot;&lt;/span&gt;),
    &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; DateTime(1987, 10, 18));
customer.MoveTo(&lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Address(&lt;span class=&quot;str&quot;&gt;&quot;Quelque part&quot;&lt;/span&gt;, &lt;span class=&quot;str&quot;&gt;&quot;Brussels&quot;&lt;/span&gt;, &lt;span class=&quot;str&quot;&gt;&quot;Belgium&quot;&lt;/span&gt;));&lt;/pre&gt;
&lt;/div&gt;
&lt;b&gt;Opening up bit by bit&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
In the meanwhile our entity is no longer immutable, but we&apos;re doing a good job of not exposing any state. If you&apos;re using the same model for reads as you do for writes, you&apos;re going to need to expose some properties eventually; for querying, but also for assertions. Make sure to only expose the getters though, and to avoid violating &quot;Tell, don&apos;t ask&quot; since that became a lot easier now.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Customer
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Customer(
        Guid id,
        Name name,
        Address address,
        DateTime birthdate)
    {
        Guard.ForNull(name, &lt;span class=&quot;str&quot;&gt;&quot;name&quot;&lt;/span&gt;);
        Guard.ForNull(address, &lt;span class=&quot;str&quot;&gt;&quot;address&quot;&lt;/span&gt;);
        Guard.ForDateInTheFuture(birthdate, &lt;span class=&quot;str&quot;&gt;&quot;birthdate&quot;&lt;/span&gt;);
        Id = id;
        Name = name;
        Address = address;
        Balance = 0;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Guid Id { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Name Name { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Address Address { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; DateTime BirthDate { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;decimal&lt;/span&gt; Balance { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; HasSufficientFunds(&lt;span class=&quot;kwrd&quot;&gt;decimal&lt;/span&gt; value) 
    {
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; Balance - value &amp;gt;= 0;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; DecreaseBalance(&lt;span class=&quot;kwrd&quot;&gt;decimal&lt;/span&gt; value)
    {
        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (HasSufficientFunds(value))
            &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; InsufficientFundsException();
        Balance -= value;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; MoveTo(Address newAddress)
    {
        Guard.ForNull(newAddress, &lt;span class=&quot;str&quot;&gt;&quot;new address&quot;&lt;/span&gt;);
        Address = newAddress;
    }
}&lt;/pre&gt;
&lt;b&gt;Summarized&lt;/b&gt;
&lt;br&gt;

&lt;br&gt;
By making my entities immutable from the start I am guided into adhering to a bunch of good practices:
&lt;br&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;A constructor&lt;/li&gt;
&lt;li&gt;Comparing identities&lt;/li&gt;
&lt;li&gt;Defaults&lt;/li&gt;
&lt;li&gt;Protecting invariants&lt;/li&gt;
&lt;li&gt;Composition and extracting value objects&lt;/li&gt;
&lt;li&gt;Tell, don&apos;t ask&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Making operations explicit&lt;/li&gt;
&lt;li&gt;Opening up bit by bit&lt;/li&gt;
&lt;/ul&gt;

&lt;br&gt;
I hope this post made some sense. I&apos;d love to hear from you how I could improve this process, and which process you have accustomed yourself with over the years.&lt;/div&gt;&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/39832372/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/39832372/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/39832372/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/39832372/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/39832372/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/39832372/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/39832372/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/39832372/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/2600073273283664120/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/39832372/0/jefclaes~Designing-entities-immutability-first.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/2600073273283664120?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/2600073273283664120?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/39832372/0/jefclaes~Designing-entities-immutability-first.html' title='Designing entities: immutability first'/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><thr:total>6</thr:total></entry>
<entry gd:etag='W/&quot;D0MESXo-cCp7ImA9WhBXEUk.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2013/03/reading-large-files-in-chunks-with.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-8860299804918347168</id><published>2013-03-24T18:16:00.000+01:00</published><updated>2013-03-24T18:16:48.458+01:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2013-03-24T18:16:48.458+01:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='CodeSnippets'/><title>Reading large files in chunks with proper encapsulation</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
I&apos;ve been doing some work lately which involves sequentially reading large files (&amp;gt; 2 to 5GB). This entails that it&apos;s not an option to read the whole structure in memory; it&apos;s more reliable to process the file in chunks. I occasionally come across legacy that solves exactly this problem, but in a procedural way, resulting in tangled spaghetti. To be honest, the first piece of software I ever wrote in a professional setting also went at it in the wrong way.
&lt;br&gt;

&lt;br&gt;
There is no reason to let it come to this though; you can use the often overlooked &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~msdn.microsoft.com/en-us/library/vstudio/9k7k7cf0.aspx&quot;&gt;yield return keyword&lt;/a&gt; to improve encapsulation.
&lt;br&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
When you use the yield keyword in a statement, you indicate that the method, operator, or get accessor in which it appears is an iterator. You consume an iterator method by using a foreach statement or LINQ query. Each iteration of the foreach loop calls the iterator method. When a yield return statement is reached in the iterator method, expression is returned, and the current location in code is retained. Execution is restarted from that location the next time that the iterator function is called.&lt;/blockquote&gt;
Have a look at the following Reader class which takes advantage of yield returning. This class reads from file, line by line, building a chunk, to return it when the desired chunk size is attained. In the next iteration, the call will continue by clearing the lines - thereby releasing memory, and rebuilding the next chunk.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Reader
{
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; _chunkSize;
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Reader(&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; chunkSize) 
    {
        _chunkSize = chunkSize;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; IEnumerable&amp;lt;Chunk&amp;gt; Read(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; path)
    {
        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;.IsNullOrEmpty(path))
            &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; NullReferenceException(&lt;span class=&quot;str&quot;&gt;&quot;path&quot;&lt;/span&gt;);
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; lines = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; List&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;&amp;gt;();
        &lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; reader = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; StreamReader(path))
        {
            &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; line;
            while ((line = reader.ReadLine()) != &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;)
            {
                lines.Add(line);
                &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (lines.Count == _chunkSize)
                {
                    yield &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Chunk(lines);
                    lines.Clear();
                }
            }                
        }
        yield &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Chunk(lines);
    }
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Chunk
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Chunk(List&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;&amp;gt; lines) 
    {
        Lines = lines;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; List&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;&amp;gt; Lines { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
}&lt;span style=&quot;font-family: Times New Roman;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
And that&apos;s one way to achieve clean encapsulation without starving your machine&apos;s memory.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; reader = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Reader(chunkSize: 1000);
&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; chunks = reader.Read(&lt;span class=&quot;str&quot;&gt;@&quot;C:\big_file.txt&quot;&lt;/span&gt;);
&lt;span class=&quot;kwrd&quot;&gt;foreach&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; chunk &lt;span class=&quot;kwrd&quot;&gt;in&lt;/span&gt; chunks)            
    Console.WriteLine(chunk.Lines.Count);&lt;/pre&gt;
&lt;/div&gt;
&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/39365386/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/39365386/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/39365386/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/39365386/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/39365386/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/39365386/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/39365386/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/39365386/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/8860299804918347168/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/39365386/0/jefclaes~Reading-large-files-in-chunks-with-proper-encapsulation.html#comment-form' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/8860299804918347168?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/8860299804918347168?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/39365386/0/jefclaes~Reading-large-files-in-chunks-with-proper-encapsulation.html' title='Reading large files in chunks with proper encapsulation'/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><thr:total>8</thr:total></entry>
<entry gd:etag='W/&quot;CUcERn06eCp7ImA9WhBQFU4.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2013/03/putting-my-ironmq-experiment-under.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-7313014389965265690</id><published>2013-03-17T16:10:00.000+01:00</published><updated>2013-03-17T16:10:07.310+01:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2013-03-17T16:10:07.310+01:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='Refactoring'/><category scheme='http://www.blogger.com/atom/ns#' term='Messaging'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='HTTP'/><category scheme='http://www.blogger.com/atom/ns#' term='CodeSnippets'/><title>Putting my IronMQ experiment under stress</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Two weeks ago, &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2013/03/first-ironmq-impressions.html&quot;&gt;I shared my first impressions of IronMQ&lt;/a&gt;. Last week, &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2013/03/some-experimental-infrastructure-for.html&quot;&gt;I looked at some infrastructure to facilitate pulling from IronMQ&lt;/a&gt;. This implementation worked, but I hadn&apos;t put it under stress yet; &quot;First make it work, then make it fast&quot;, and all of that.
&lt;br&gt;

&lt;br&gt;
I arranged a simple scenario for testing: one message type - thus one queue, where there are eight queue consumers that simultaneously pull messages from that queue, and dispatch them to a handler which sleeps for one second.

&lt;br&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; MessageSleepForOneSecond { }
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; MessageSleepForOneSecondHandler : IMessageHandler&amp;lt;MessageSleepForOneSecond&amp;gt;
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Handle(MessageSleepForOneSecond message)
    {
        Thread.Sleep(1000);
    }
} &lt;/pre&gt;
To establish a baseline, I foolishly set the polling interval to only 100ms, and pulled 2000 messages from the queue one at a time. With this configuration I processed all 2000 messages in 2 minutes and 20 seconds, with an average throughput of 14.3 messages per second. In theory you would expect the throughput to be higher though.
&lt;br&gt;
The constraint in this story is the &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~msdn.microsoft.com/en-us/library/system.threading.threadpool.aspx&quot;&gt;CLR&apos;s thread pool&lt;/a&gt;. Every time a queue consumer&apos;s internal timer ticks, the callback which pulls from the queue and invokes the messagehandler, takes up a new thread on the thread pool. The thread pool makes a few threads available when you start your application, but once they&apos;re all in use, it will have to start new ones, which is rather expensive. More importantly though, when you&apos;re queuing too many tasks on the thread pool, and the number of active threads is higher than the number of processors, it will slow down, and wait 500ms to see if it can reuse the existing threads, before creating a new one. When the maximum number of threads is reached, the thread pool will still enlist your tasks in its queue, but only start processing them once threads become available again. In short, the thread pool has a few tricks up its sleeve to protect you from saturating your resources. Remember that too much parallelization and its corresponding context switches won&apos;t do you any good.
&lt;br&gt;

&lt;br&gt;
Having established a baseline, and having learned a bit more on how the thread pool behaves, I tried one of the first optimizations I already had in mind last week; pulling batches instead of single messages. This reduces the number of necessary HTTP requests, and the number of threads needed to do work on. To support this, I extended the queue consumer configuration with a new property, and changed the queue consumer to take the batch size into account.
&lt;br&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;interface&lt;/span&gt; IQueueConsumerConfiguration&amp;lt;T&amp;gt;
{
    &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; PollingInterval { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; BatchSize { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; }
}
&lt;span class=&quot;kwrd&quot;&gt;try&lt;/span&gt;
{
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; messages = (IEnumerable&amp;lt;Message&amp;gt;)&lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;;
    &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (!_queue.TryGet(&lt;span class=&quot;kwrd&quot;&gt;out&lt;/span&gt; messages, _queueConsumerConfiguration.BatchSize))
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;
    &lt;span class=&quot;kwrd&quot;&gt;foreach&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; message &lt;span class=&quot;kwrd&quot;&gt;in&lt;/span&gt; messages)
    {
        &lt;span class=&quot;kwrd&quot;&gt;try&lt;/span&gt;
        {
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; messageBody = (T)JsonConvert.DeserializeObject(message.Body, &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(T));
            _messageDispatcher.Dispatch&amp;lt;T&amp;gt;(messageBody);
            _queue.Delete(message.Id);
        }
        &lt;span class=&quot;kwrd&quot;&gt;catch&lt;/span&gt; (Exception ex)
        {
            _errorHandler.Handle(ex, message);
        }
    }
}
&lt;span class=&quot;kwrd&quot;&gt;catch&lt;/span&gt; (Exception ex)
{
    _errorHandler.Handle(ex, &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;);
}                &lt;span style=&quot;font-family: Times New Roman;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
On repeating the test with 2000 messages, the same polling interval of 100ms, but with a batch size of 30, the messages were now all processed in one minute and fifteen seconds, resulting in a throughput of 26 messages per second. That&apos;s almost an improvement of 100%.
&lt;br&gt;

&lt;br&gt;
This throughput isn&apos;t sustainable though if we had a lot more messages to process. We&apos;re starting a new thread every 100ms or 500ms, while the work we are doing on it only finishes after a rough 30 seconds (it&apos;s not only invoking the handlers, but the HTTP requests also take time). We&apos;re burning through threads quicker than we&apos;re releasing them. If we would run out of threads on the thread pool, it would just stop starting new ones, and queue the tasks until other threads are done doing work.
&lt;br&gt;

&lt;br&gt;
In my previous post I also considered a smart polling algorithm, but I haven&apos;t looked at that yet, what&apos;s in place is more than good enough for me at the moment.
&lt;br&gt;

&lt;br&gt;
Be sure to take these numbers with a grain of salt. I would have to test my infrastructure with millions of messages on the queue instead of just 2000 to get trustworthy results. I feel I can predict fairly well how the system will behave when put under load for a longer amount of time though; it would grind to a halt. As mentioned before, we would run out of threads to do work on. I simulated this by lowering the thread pool&apos;s maximum number of threads. Other parameters that influence the numbers in this test are: size of the messages, version of the runtime, the operating system, the amount of processors, latency of the network... I ran these tests with empty messages, .NET 4 installed on my own Windows 7 box with an Intel i7 on board.
&lt;br&gt;

&lt;br&gt;
It comes down to cherry picking a configuration per queue consumer that will be sustainable based on the amount of messages you expect, the desired throughput, and the time it takes to process a single message.
&lt;br&gt;

&lt;br&gt;
&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://github.com/JefClaes/ironMq-infrastructure&quot;&gt;Find the source on Github&lt;/a&gt;.&lt;/div&gt;
&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/39128902/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/39128902/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/39128902/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/39128902/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/39128902/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/39128902/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/39128902/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/39128902/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/7313014389965265690/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/39128902/0/jefclaes~Putting-my-IronMQ-experiment-under-stress.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/7313014389965265690?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/7313014389965265690?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/39128902/0/jefclaes~Putting-my-IronMQ-experiment-under-stress.html' title='Putting my IronMQ experiment under stress'/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry>
<entry gd:etag='W/&quot;DEIMRnYzfip7ImA9WhBRGUU.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2013/03/some-experimental-infrastructure-for.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-7347706355355214233</id><published>2013-03-10T17:29:00.000+01:00</published><updated>2013-03-11T08:23:07.886+01:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2013-03-11T08:23:07.886+01:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='Messaging'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='HTTP'/><category scheme='http://www.blogger.com/atom/ns#' term='Architecture'/><title>Some experimental infrastructure for IronMQ pull </title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
I wrote about using &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2013/03/first-ironmq-impressions.html&quot;&gt;IronMQ as a cloud-based message queue&lt;/a&gt; last week. In that post I explained that you can go at using IronMQ in two ways; either you pull from the queue yourself, or you let IronMQ push messages from the queue to your HTTP endpoints. At first sight, the latter allows you to outsource more infrastructure to their side, but upon closer inspection it &amp;nbsp;also introduces other concerns: security, local debugging and scalability.
&lt;br&gt;

&lt;br&gt;
Out-of-the-box there is no infrastructure in the client libraries to facilitate periodic pull - polling, that&apos;s why I took a stab at doing it myself. It&apos;s still rough, not production tested, and hasn&apos;t considered a bunch of niche scenarios, but it should give you an idea of the direction it&apos;s going.
&lt;br&gt;

&lt;br&gt;
A high-level overview of the components looks like this.
&lt;br&gt;

&lt;br&gt;
&lt;div style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~3.bp.blogspot.com/-Rj_3N0ekaZY/UTuZaTHgzaI/AAAAAAAABkI/QspoQJM1H-0/s1600/IronMQPoll.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;452&quot; src=&quot;http://3.bp.blogspot.com/-Rj_3N0ekaZY/UTuZaTHgzaI/AAAAAAAABkI/QspoQJM1H-0/s640/IronMQPoll.PNG&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;br&gt;
A queue host hosts multiple queue consumers. Each queue consumer will poll a queue for one type of message on a configurable interval, and dispatch dequeued messages to relevant message handlers. After handling the message, the message will be deleted from the queue. If something happened to go wrong, the error handler for this type of message will be invoked, and the message will automatically return to the queue.
&lt;br&gt;

&lt;br&gt;
I&apos;m going to look at each component, starting with the smallest, and slowly assemble them into bigger components.
&lt;br&gt;

&lt;br&gt;
Each queue consumer can be configured independently. For now, only the polling interval can be changed. By default it&apos;s one second, or 1000 milliseconds.
&lt;br&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;interface&lt;/span&gt; IQueueConsumerConfiguration&amp;lt;T&amp;gt;
{
    &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; PollingInterval { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; }
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; QueueConsumerConfiguration&amp;lt;T&amp;gt; : IQueueConsumerConfiguration&amp;lt;T&amp;gt;
{     
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; PollingInterval
    {
        &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt; { &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; 1000; }
    }       
}&lt;/pre&gt;
A queue can push messages, get raw messages, and delete them. The implementation makes use of the&amp;nbsp;&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://github.com/odeits/IronTools&quot;&gt;OSS IronIO client libraries&lt;/a&gt;.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;interface&lt;/span&gt; IQueue&amp;lt;T&amp;gt;
{
    &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; TryGet(&lt;span class=&quot;kwrd&quot;&gt;out&lt;/span&gt; Message message);
    &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Delete(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; messageId);
    &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Push(T message);
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Queue&amp;lt;T&amp;gt; : IQueue&amp;lt;T&amp;gt;
{
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; IronIO.IronMQ _queue;
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Queue(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; projectId, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; token)
    {
        Guard.ForEmptyString(projectId, &lt;span class=&quot;str&quot;&gt;&quot;projectId&quot;&lt;/span&gt;);
        Guard.ForEmptyString(token, &lt;span class=&quot;str&quot;&gt;&quot;token&quot;&lt;/span&gt;);
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; queueName = &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(T).Name; 
        _queue = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; IronMQ(queueName, projectId, token);
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; TryGet(&lt;span class=&quot;kwrd&quot;&gt;out&lt;/span&gt; Message message) 
    {
        message = _queue.Get();            
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; message != &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Delete(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; messageId)
    {
        Guard.ForNull(messageId, &lt;span class=&quot;str&quot;&gt;&quot;messageId&quot;&lt;/span&gt;);
        _queue.Delete(messageId);
    }
    
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Push(T message)
    {
        Guard.ForNull(message, &lt;span class=&quot;str&quot;&gt;&quot;message&quot;&lt;/span&gt;);
        _queue.Push(JsonConvert.SerializeObject(message));
    }
}&lt;/pre&gt;
A message dispatcher dispatches messages to the relevant handlers.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;interface&lt;/span&gt; IMessageDispatcher
{
    &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Dispatch&amp;lt;T&amp;gt;(T message);
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; MessageDispatcher : IMessageDispatcher
{
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; IKernel _kernel;
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; MessageDispatcher(IKernel kernel)
    {
        _kernel = kernel;            
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Dispatch&amp;lt;T&amp;gt;(T message)
    {
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; handlers = _kernel.GetAll&amp;lt;IMessageHandler&amp;lt;T&amp;gt;&amp;gt;();
      
        &lt;span class=&quot;kwrd&quot;&gt;foreach&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; handler &lt;span class=&quot;kwrd&quot;&gt;in&lt;/span&gt; handlers)
            handler.Handle(message);                        
    }
}&lt;/pre&gt;
If something goes wrong pulling the message from the queue or handling it, the error handler will be invoked passing in the exception and the raw message. Since it&apos;s possible that something is wrong with the message in itself, I pass in the raw message with the serialized message and all its meta data like id, delay and expiration date.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;interface&lt;/span&gt; IErrorHandler&amp;lt;T&amp;gt;
{
    &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Handle(Exception exception, Message message);
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; ErrorHandler&amp;lt;T&amp;gt; : IErrorHandler&amp;lt;T&amp;gt;
{       
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Handle(Exception exception, Message message)
    {
        &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; exception;
    }     
}&lt;/pre&gt;
Putting all these components to work together, we end up with a queue consumer. When a queue consumer is started, it instantiates a timer which will try to get a raw message from the queue on each tick. If there&apos;s a raw message, it will extract the body, deserialize it into the message, dispatch it, and finally delete the raw message from the queue. If something goes wrong here, the error handler will be invoked, and the message will automatically return back to the queue.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;interface&lt;/span&gt; IQueueConsumer&amp;lt;T&amp;gt; : IQueueConsumer where T : &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt;
{
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;interface&lt;/span&gt; IQueueConsumer : IDisposable
{
    &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Start();
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; QueueConsumer&amp;lt;T&amp;gt; : IQueueConsumer&amp;lt;T&amp;gt; where T : &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt;
{
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; IQueue&amp;lt;T&amp;gt; _queue;
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; IErrorHandler&amp;lt;T&amp;gt; _errorHandler;
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; IQueueConsumerConfiguration&amp;lt;T&amp;gt; _queueConsumerConfiguration;
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; IMessageDispatcher _messageDispatcher;
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; Timer _timer;        
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; QueueConsumer(
        IQueue&amp;lt;T&amp;gt; queue, 
        IErrorHandler&amp;lt;T&amp;gt; errorHandler,
        IQueueConsumerConfiguration&amp;lt;T&amp;gt; queueConsumerConfiguration,
        IMessageDispatcher messageDispatcher)
    {
        _queue = queue;
        _errorHandler = errorHandler;
        _queueConsumerConfiguration = queueConsumerConfiguration;
        _messageDispatcher = messageDispatcher;
    }    
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Start()
    {
        _timer = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Timer((x) =&amp;gt;
        {
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; message = (Message)&lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;;
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; messageBody = (T)&lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;;
            &lt;span class=&quot;kwrd&quot;&gt;try&lt;/span&gt;
            {
                &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (!_queue.TryGet(&lt;span class=&quot;kwrd&quot;&gt;out&lt;/span&gt; message))
                    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;
                messageBody = (T)JsonConvert.DeserializeObject(
                    message.Body, &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(T));
                _messageDispatcher.Dispatch&amp;lt;T&amp;gt;(messageBody);
                _queue.Delete(message.Id);
            }
            &lt;span class=&quot;kwrd&quot;&gt;catch&lt;/span&gt; (Exception ex)
            {
                _errorHandler.Handle(ex, message);
            }                
        }, &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;, 0, _queueConsumerConfiguration.PollingInterval);            
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Dispose()
    {
        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (_timer == &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;)
            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;
        _timer.Dispose();
    }
}&lt;/pre&gt;
&lt;/div&gt;
Since we have multiple queues to pull from, we can use a queue host to control multiple queue consumers at once. The queue host configuration decides which queue consumer to instantiate and start.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; QueueHostConfiguration
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; QueueHostConfiguration(IEnumerable&amp;lt;Type&amp;gt; messageTypes)
    {
        Guard.ForNull(messageTypes, &lt;span class=&quot;str&quot;&gt;&quot;messageTypes&quot;&lt;/span&gt;);
        MessageTypes = messageTypes;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; IEnumerable&amp;lt;Type&amp;gt; MessageTypes { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; QueueHost : IDisposable
{
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; IKernel _kernel;
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; QueueHostConfiguration _configuration;
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; List&amp;lt;IQueueConsumer&amp;gt; _consumers;
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; QueueHost(IKernel kernel, QueueHostConfiguration configuration)
    {
        _kernel = kernel;
        _configuration = configuration;
        _consumers = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; List&amp;lt;IQueueConsumer&amp;gt;();
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Start()
    {
        &lt;span class=&quot;kwrd&quot;&gt;foreach&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; messageType &lt;span class=&quot;kwrd&quot;&gt;in&lt;/span&gt; _configuration.MessageTypes)
        {
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; queueConsumerType = &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(IQueueConsumer&amp;lt;&amp;gt;).MakeGenericType(messageType);
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; queueConsumer = (IQueueConsumer)_kernel.Get(queueConsumerType);
            _consumers.Add(queueConsumer);
            queueConsumer.Start();
        }
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Dispose()
    {
        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (_consumers == &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;)
            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;
        &lt;span class=&quot;kwrd&quot;&gt;foreach&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; consumer &lt;span class=&quot;kwrd&quot;&gt;in&lt;/span&gt; _consumers)
            consumer.Dispose();
    }
}&lt;/pre&gt;
&lt;/div&gt;
In your application, you&apos;ll end up doing something like this to start the queue host.&amp;nbsp;&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; host = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; QueueHost(kernel, &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; QueueHostConfiguration(
    &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt;[] { &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(MyMessage) })))
{
    host.Start();
    Console.ReadLine();
}&lt;/pre&gt;
&lt;/div&gt;
All the components are glued together using Ninject and some conventions.&amp;nbsp;&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Bootstrapper
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Run(IKernel kernel)
    {
        kernel.Bind(x =&amp;gt; x
          .FromThisAssembly()
          .SelectAllClasses()
          .InheritedFrom(&lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(IMessageHandler&amp;lt;&amp;gt;))
          .BindAllInterfaces());
        kernel.Bind&amp;lt;Infrastructure.IMessageDispatcher&amp;gt;()
            .To&amp;lt;Infrastructure.MessageDispatcher&amp;gt;()
            .InTransientScope();
        kernel.Bind(x =&amp;gt; x
            .FromAssemblyContaining(&lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(IQueue&amp;lt;&amp;gt;))
            .SelectAllClasses()
            .InheritedFrom(&lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(IQueue&amp;lt;&amp;gt;))
            .BindAllInterfaces()
            .Configure(y =&amp;gt;
            {
                y.WithConstructorArgument(&lt;span class=&quot;str&quot;&gt;&quot;projectId&quot;&lt;/span&gt;, z =&amp;gt; { &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;str&quot;&gt;&quot;your_project_id&quot;&lt;/span&gt;; });
                y.WithConstructorArgument(&lt;span class=&quot;str&quot;&gt;&quot;token&quot;&lt;/span&gt;, z =&amp;gt; { &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;str&quot;&gt;&quot;your_token&quot;&lt;/span&gt;; });
            }));
        kernel
            .Bind(&lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(Infrastructure.IQueueConsumer&amp;lt;&amp;gt;))
            .To(&lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(Infrastructure.QueueConsumer&amp;lt;&amp;gt;));
        kernel
            .Bind(&lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(Infrastructure.IQueueConsumerConfiguration&amp;lt;&amp;gt;))
            .To(&lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(Infrastructure.QueueConsumerConfiguration&amp;lt;&amp;gt;));
        kernel
            .Bind(&lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(Infrastructure.IErrorHandler&amp;lt;&amp;gt;))
            .To(&lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(MyErrorHandler&amp;lt;&amp;gt;));    
    }
}&lt;/pre&gt;

&lt;br&gt;
This is what I got for now. Next step is to do some more serious integration testing, and see what gives. There are two things I already kind of expect to run into; the maximum number of concurrent connections, and thread starvation (each timer tick starts a new thread). Anything else I&apos;m going to run into?
&lt;br&gt;

&lt;br&gt;
The biggest disadvantage of opting for pull that is already obvious now, is the possible number of wasted HTTP requests. You could increase the polling interval, and thereby lower the number of requests, but this would harm the throughput of message bursts. Something I&apos;m considering right now, is introducing a smart polling algorithm. Another option that will lower the number of requests, is to pull batches instead of single messages from the queue. Implementing this one will be rather straightforward, yet improve things considerably.&lt;/div&gt;
&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/38875043/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/38875043/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/38875043/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/38875043/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/38875043/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/38875043/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/38875043/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/38875043/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/7347706355355214233/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/38875043/0/jefclaes~Some-experimental-infrastructure-for-IronMQ-pull.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/7347706355355214233?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/7347706355355214233?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/38875043/0/jefclaes~Some-experimental-infrastructure-for-IronMQ-pull.html' title='Some experimental infrastructure for IronMQ pull '/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-Rj_3N0ekaZY/UTuZaTHgzaI/AAAAAAAABkI/QspoQJM1H-0/s72-c/IronMQPoll.PNG' height='72' width='72'/><thr:total>0</thr:total></entry>
<entry gd:etag='W/&quot;DEcGRX4-eip7ImA9WhBRE08.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2013/03/first-ironmq-impressions.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-9036346875713449289</id><published>2013-03-03T16:45:00.000+01:00</published><updated>2013-03-03T16:53:44.052+01:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2013-03-03T16:53:44.052+01:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='Messaging'/><category scheme='http://www.blogger.com/atom/ns#' term='HTTP'/><category scheme='http://www.blogger.com/atom/ns#' term='REST'/><category scheme='http://www.blogger.com/atom/ns#' term='Architecture'/><title>First IronMQ impressions</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
First time I touched messaging was in the first few years of my professional life working on software that supported fire departments in their day-to-day activities. The dispatching software would send messages to a &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.intergraph.com/&quot;&gt;proprietary&lt;/a&gt; broker, which in its turn would forward them to interested subscribers; other dispatching clients, or services. To ensure availability, the broker component could failover to a different machine, but that was about it. It didn&apos;t allow you to queue or retry messages; if you weren&apos;t up when the messages were forwarded, you would never receive them. When the brokers were both down, all messages would be lost; the clients didn&apos;t have infrastructure out-of-the-box that could queue the messages locally until it came back up again. When things went haywire, and they occasionally did, these missing features would often leave us with an inconsistent state. More modern messaging software has solved these concerns though.
&lt;br&gt;

&lt;br&gt;
Although quite a few systems would benefit from asynchronous and loosely coupled messaging - especially to improve reliability and (perceived) performance, but also scalability, I still too seldom see or hear about projects that get to go that extra mile. Solutions often end up compromising in quality to avoid introducing that extra component and those unconventional questions. And this decision might be perfectly sound, because lots of factors are at play, not just technical ones. It&apos;s still a pity when you see solutions struggle to solve a problem in a decent way because they&apos;re stuck with synchronous communication.
&lt;br&gt;

&lt;br&gt;
Imagine a public website that&apos;s in the business of booking hotels. The offers they show to their customers are all based on data provided by third parties. Because it&apos;s so expensive to fetch this data, it&apos;s being cached, and as a result, it&apos;s stale seconds after fetching it. The moment a user confirms, they could fetch fresh data from the relevant third party to make sure the room is still available, but this process is error prone: the third party might be down, fetching the data is really slow, one of our their own components might be down, on conflicts they might want to compile a list of some decent alternatives, which in its turn might also be too slow if done on demand. One alternative could be to queue the booking, and process it in the back-end. Once they&apos;re done processing it, they can mail the user a confirmation or an apology with a list of alternatives attached. By making this process asynchronous, they avoid the risk of a slow user experience and clumsy failures they can&apos;t recover from, making them lose business in the long run. But then again, they also take the burden of extra infrastructure, new operational concerns and different questions. Trade-offs.
&lt;br&gt;

&lt;br&gt;
Anyways, in this blog post, I wanted to share some first impressions on &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.iron.io/mq&quot;&gt;IronMQ&lt;/a&gt;. I admittedly kind of accidentally discovered this service browsing through &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://appharbor.com/&quot;&gt;AppHarbor&lt;/a&gt;&apos;s add-ons. Here it is described as &quot;a scalable cloud-based message queue&quot;.
&lt;br&gt;

&lt;br&gt;
Basically IronMQ gives you a REST enabled queue in the cloud. After authenticating, you can POST a new message to the queue. If you are unable to POST the message, you&apos;ll lose it, since there is no support out-of-the-box for retrying or persisting the message on the client. Once the message is posted, another process can GET the message, and DELETE it after successfully processing it. If something happened to go wrong while processing the message, the message will return to the queue, and be retried one minute later. If the message processing keeps failing on subsequent retries, the retries won&apos;t repeat infinitely though; messages expire (the default is 7 days, and the maximum is 30 days). This is exactly the kind of infrastructure we need to support the asynchronous booking scenario: have the customer put its booking on the queue, and one of our background processes will try to process it; if something goes wrong, we&apos;ll just keep retrying for a while.
&lt;br&gt;

&lt;br&gt;
The &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~dev.iron.io/mq/reference/api/&quot;&gt;REST API&lt;/a&gt; is simple, yet there are &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~dev.iron.io/mq/libraries/&quot;&gt;client libraries available for most popular languages&lt;/a&gt;. They don&apos;t provide that much extra functionality though. Here&apos;s the gist.

&lt;br&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; queue = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; IronMQ(queueName, projectId, token);
queue.Push(&lt;span class=&quot;str&quot;&gt;&quot;{ hello: world }&quot;&lt;/span&gt;);
&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; message = queue.Get();
queue.Delete(message.Id);&lt;/pre&gt;
In this scenario you&apos;re responsible for pulling data from the queue. This is just one way to go at things though; another option is to let IronMQ push messages to your HTTP endpoints. While this allows you to outsource some infrastructure to their side, it raises other concerns:
&lt;br&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Security: you might need to enable HTTPS, and provide an authentication mechanism.&lt;/li&gt;
&lt;li&gt;Debugging: if you want to do some end-to-end integration testing on your local machine, you&apos;ll need to give your machine a public IP and set up something like &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~dyn.com/dns/&quot;&gt;dyndns&lt;/a&gt;.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Scalability: depending on the expected message volume, and the web stack you&apos;re rolling with, it might be more expensive to have to set up all these web servers, instead of a few background workers.&lt;/li&gt;
&lt;/ul&gt;
Errors are handled quite elegantly; once you processed the message successfully, make your endpoint return HTTP status code 200 or 202, and the message will be removed from the queue. HTTP status code 202 is used for long running processes. If the response code is in the 400 or 500 range, the message will return to the queue to be retried later.
&lt;br&gt;

&lt;br&gt;
When the expected volume of messages is rather small, it makes more sense to opt for push; you don&apos;t waste that many HTTP requests.
&lt;br&gt;

&lt;br&gt;
IronMQ makes it extremely simple to get started; &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.iron.io/&quot;&gt;go to their site&lt;/a&gt;, get a project id and a token, and start making HTTP calls. Do them yourself, or use one of the client API&apos;s. But it also seems to be all you&apos;re going to get; there is no infrastructure that addresses operational concerns, error queues, retry strategies, local queues,... IronMQ provides you with raw queueing infrastructure, not a framework.
&lt;br&gt;

&lt;br&gt;
Their site does give you a look into your queues though; you can&apos;t look at the messages, but you do get a nice overview.
&lt;br&gt;

&lt;br&gt;
&lt;div style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~4.bp.blogspot.com/-qdDG0M2rgg4/UTNvkBpnnnI/AAAAAAAABj4/ow3EmhxXik0/s1600/IronMq.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;338&quot; src=&quot;http://4.bp.blogspot.com/-qdDG0M2rgg4/UTNvkBpnnnI/AAAAAAAABj4/ow3EmhxXik0/s640/IronMq.PNG&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;br&gt;
I don&apos;t mind that it&apos;s not a turnkey solution though; I learn a lot from tinkering with this stuff. Solving problems and considering trade-offs for yourself is priceless.
&lt;br&gt;

&lt;br&gt;
Using HTTP for messaging still feels a bit quirky to me. As long as I can remember people have been making me believe HTTP is not the best fit for high-throughput messaging scenarios, and I do understand their motivations somewhat. But when even databases start to embrace HTTP, it&apos;s probably time to shake off the doctrine. It&apos;s so comfy to not have to understand a new protocol, and HTTP just seems such a sensible thing to do when you&apos;re off-premise.
&lt;br&gt;

&lt;br&gt;
I&apos;m going to conduct some more experiments this week, I&apos;ll see what gives.&lt;/div&gt;
&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/38639088/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/38639088/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/38639088/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/38639088/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/38639088/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/38639088/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/38639088/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/38639088/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/9036346875713449289/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/38639088/0/jefclaes~First-IronMQ-impressions.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/9036346875713449289?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/9036346875713449289?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/38639088/0/jefclaes~First-IronMQ-impressions.html' title='First IronMQ impressions'/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-qdDG0M2rgg4/UTNvkBpnnnI/AAAAAAAABj4/ow3EmhxXik0/s72-c/IronMq.PNG' height='72' width='72'/><thr:total>3</thr:total></entry>
<entry gd:etag='W/&quot;DEYCR3Y5fSp7ImA9WhBSGE0.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2013/02/my-christmas-holiday-project-postmortem.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-7566175163410769941</id><published>2013-02-24T16:42:00.001+01:00</published><updated>2013-02-25T16:29:26.825+01:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2013-02-25T16:29:26.825+01:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='Ramblings'/><title>My Christmas holiday project postmortem</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
Somewhere over a year and a half ago I discovered the music of Dire Straits, which has sparked a fanatical love and fascination for the guitar in me, and basically for every piece of music &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.markknopfler.com/&quot;&gt;Mark Knopfler&lt;/a&gt; has ever touched (*). A year ago, I finally had the courage to pick up the guitar myself. Not sure if I&apos;d stick with it, I made an uninformed purchase of a rather inexpensive Squier Jazzmaster, just because it somewhat resembled the real object of desire, a &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~en.wikipedia.org/wiki/Fender_Stratocaster&quot;&gt;Fender Stratocaster&lt;/a&gt;. Three months ago, I got rid of the Jazzmaster, and bought myself a tango red Mexican Stratocaster, and I&apos;m in love with it. Yet, I have also become very fond of the sound of a &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~en.wikipedia.org/wiki/Gibson_Les_Paul&quot;&gt;Les Paul&lt;/a&gt; these days. Having just bought the Strat, I thought I could maybe find a cheap used Les Paul online.
&lt;br&gt;

&lt;br&gt;
I set out to find one on&amp;nbsp;&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.2dehands.be/&quot;&gt;the most popular Belgian online secondhand marketplace&lt;span id=&quot;goog_2007999932&quot;&gt;&lt;/span&gt;&lt;/a&gt; (600k visitors daily), so I started browsing their listings daily. This turned out to be rather cumbersome and inefficient: constantly repeating the same process, items were already sold before I could make a bid, there were no new items since the last time I visited... It didn&apos;t take me long before I started thinking of a way to automate this dull process. Looking at other marketplaces, I found that some unburden their users by providing notifications; push instead of pull. Maybe I could build something similar?
&lt;br&gt;

&lt;br&gt;
Doing a bit of research over the weekend, I found out that they expose, what I call, an &lt;i&gt;accidental&lt;/i&gt; API; written in first place to provide a snappy mobile user experience, not to expose all their data to third parties. Having an uncomplicated way of searching their data, I built a bit of code on top of it. Nothing all too fancy though; a &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~quartznet.sourceforge.net/&quot;&gt;Quartz job&lt;/a&gt; which periodically queries their service, parses the results and stores them in a &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~ravendb.net/&quot;&gt;RavenDB&lt;/a&gt; database. A few times a day, these search results are then compiled, and sent to my inbox using &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.mailgun.com/&quot;&gt;MailGun&lt;/a&gt;. All of this running for free on &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://appharbor.com/&quot;&gt;AppHarbor&lt;/a&gt;.
&lt;br&gt;

&lt;br&gt;
Showing all of this to the girlfriend, she asked if I could set up the same thing for her, but then for a specific type of camera. This is when I decided it could be useful enough to make it publicly available. I thought of a few ways to support the costs of hosting (which are extremely low): embed ridiculously relevant ads in the mails, make people pay for more frequent polling, or sell it (although very unlikely).
&lt;br&gt;

&lt;br&gt;
Two weeks later, I had &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~tweedehandsmeldingen.com/&quot;&gt;&lt;b&gt;something working online&lt;/b&gt;&lt;/a&gt;.
&lt;br&gt;

&lt;br&gt;
&lt;div style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~3.bp.blogspot.com/-HocTICOulG8/USo0xrou5vI/AAAAAAAABjg/ARjwwZS0CLU/s1600/tweedehandsmeldingen.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;528&quot; src=&quot;http://3.bp.blogspot.com/-HocTICOulG8/USo0xrou5vI/AAAAAAAABjg/ARjwwZS0CLU/s640/tweedehandsmeldingen.PNG&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;br&gt;
But how do I inform people of its existence? I first thought of using Twitter to monitor for relevant tweets where people ask for something secondhand. I started out by using a new dedicated generic account, but this got suspended rather quickly. In the second iteration, I used my personal account. This yielded better results; people saw I was human, and regularly thanked me for the tip. They didn&apos;t sign up too often though..
&lt;br&gt;

&lt;br&gt;
Not willing to give up on the idea already, I used Google Adwords to advertise on the online marketplace directly. The results of this campaign were sobering, but extremely valuable; people just didn&apos;t care. As a side note; secondhand seems to be quite an expensive keyword!
&lt;br&gt;

&lt;br&gt;
&lt;div style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~1.bp.blogspot.com/--zqJVaJBR-Q/USfkg2RBnTI/AAAAAAAABjE/Pn45Xrjx7Jg/s1600/meldingenblog.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;347&quot; src=&quot;http://1.bp.blogspot.com/--zqJVaJBR-Q/USfkg2RBnTI/AAAAAAAABjE/Pn45Xrjx7Jg/s640/meldingenblog.PNG&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;br&gt;
&lt;div style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~4.bp.blogspot.com/-YPn3sEHhaww/USfkpDrIqeI/AAAAAAAABjM/31zUsbbA2Vo/s1600/adwords_results.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;196&quot; src=&quot;http://4.bp.blogspot.com/-YPn3sEHhaww/USfkpDrIqeI/AAAAAAAABjM/31zUsbbA2Vo/s640/adwords_results.PNG&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;br&gt;
In hindsight, I can think of plenty of reasons why this somewhat useful project has no success:
&lt;br&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;The problem it is trying to solve obviously isn&apos;t enough of a pain!&lt;/li&gt;
&lt;li&gt;People don&apos;t Google for it, and even if they did, this site had hardly any chance in making it to the first page.&lt;/li&gt;
&lt;li&gt;In general the secondhand offering is enormous, and people often quickly settle for less.&lt;/li&gt;
&lt;li&gt;Specialized markets aren&apos;t situated on these sites.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;People don&apos;t like giving away their email address, definitely not to strangers they don&apos;t trust.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Everyone struggles to keep their inboxes clean, receiving mail puts off people.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;

&lt;br&gt;
Damn, it&apos;s always evident in hindsight.&lt;/div&gt;
&lt;div&gt;

&lt;br&gt;&lt;/div&gt;
&lt;div&gt;
Here are a few things I learned/got confirmed:&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
&lt;li&gt;Being your own customer is priceless; you know exactly where the value is at.&lt;/li&gt;
&lt;li&gt;Chances are you will never see a user; don&apos;t spend too much time optimizing for scalability and reliability.&lt;/li&gt;
&lt;li&gt;Some Google ads plus a website with a simple form can be enough to let you cheaply validate the worthiness of pursuing an idea.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;

&lt;br&gt;
(*) Take some time to explore his work: &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.youtube.com/watch?v=5vUDmFjWgVo&quot;&gt;brothers in arms&lt;/a&gt;, &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.youtube.com/watch?v=aXXemzIo1ao&quot;&gt;postcards from Paraguay&lt;/a&gt;, &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.youtube.com/watch?v=VyOW8lQOG8Q&quot;&gt;song for Sonny Liston&lt;/a&gt;, &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.youtube.com/watch?v=-0T-JVeYXxs&quot;&gt;you and your friend&lt;/a&gt;, and so many more are worth a listen.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/38451601/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/38451601/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/38451601/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/38451601/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/38451601/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/38451601/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/38451601/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/38451601/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/7566175163410769941/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/38451601/0/jefclaes~My-Christmas-holiday-project-postmortem.html#comment-form' title='15 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/7566175163410769941?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/7566175163410769941?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/38451601/0/jefclaes~My-Christmas-holiday-project-postmortem.html' title='My Christmas holiday project postmortem'/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-HocTICOulG8/USo0xrou5vI/AAAAAAAABjg/ARjwwZS0CLU/s72-c/tweedehandsmeldingen.PNG' height='72' width='72'/><thr:total>15</thr:total></entry>
<entry gd:etag='W/&quot;CUQNQXg_cSp7ImA9WhBSEU8.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2013/02/adding-r-to-cqs-some-storage-options.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-240349995816733512</id><published>2013-02-17T17:57:00.000+01:00</published><updated>2013-02-17T18:49:50.649+01:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2013-02-17T18:49:50.649+01:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='DDD'/><category scheme='http://www.blogger.com/atom/ns#' term='Architecture'/><category scheme='http://www.blogger.com/atom/ns#' term='NoSql'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><title>Adding the R to CQS: some storage options</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
I&apos;ve been writing &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2013/01/separating-command-data-from-logic-and.html&quot;&gt;quite a bit&lt;/a&gt; about &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~en.wikipedia.org/wiki/Command%E2%80%93query_separation&quot;&gt;CQS&lt;/a&gt; (or command and query separation) lately. In &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2013/02/raising-events-in-commandhandlers.html&quot;&gt;my last post on using events&lt;/a&gt;, I already hinted towards bringing in the R; command and query &lt;b&gt;r&lt;/b&gt;esponsibility separation.
&lt;br&gt;

&lt;br&gt;
With CQS, commands can mutate data, while queries can only read that data. CQRS takes this one step further, and assigns commands and queries each a dedicated model; we now talk of a write side, and a read side.
&lt;br&gt;

&lt;br&gt;
I like &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://twitter.com/clemensv&quot;&gt;Clemens Vasters&lt;/a&gt; definition best.
&lt;br&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
CQRS is a simple pattern that strictly segregates the responsibility of handling command input into an autonomous system from the responsibility of handling side-effect-free query/read access on the same system. Consequently, the decoupling allows for any number of homogeneous or heterogeneous query/read modules to be paired with a command processor. This principle presents a very suitable foundation for event sourcing, eventual-consistency state replication/fan-out and, &amp;nbsp;thus, high-scale read access. In simple terms, you don&#x2019;t service queries via the same module of a service that you process commands through. In REST terminology, GET requests wire up to a different thing from what PUT, POST, and DELETE requests wire up to.&amp;nbsp;&lt;/blockquote&gt;
A nice drawing also helps in understanding CQRS (from &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~msdn.microsoft.com/en-us/library/jj591573&quot;&gt;the CQRS journey material&lt;/a&gt;).
&lt;br&gt;

&lt;br&gt;
&lt;div style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~2.bp.blogspot.com/-iDpToHUCqqM/UR9zdyzk44I/AAAAAAAABiw/d9KDU6rRLSE/s1600/CQRS_drawing.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;449&quot; src=&quot;http://2.bp.blogspot.com/-iDpToHUCqqM/UR9zdyzk44I/AAAAAAAABiw/d9KDU6rRLSE/s640/CQRS_drawing.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;br&gt;
Although scalability seems to be one of the big selling points of CQRS, there are still some valid arguments applicable to my world; the strongest one being able to avoid the discrepancy which exists while you use the same model for reading and writing. I think everyone suffers from this one regularly. A popular and realistic example is this one; an ORM is used to map our domain model to a relational database, the tables are mapped very closely to the structure of the domain model. Not long after, it becomes evident that it&apos;s impossible to write simple and performant queries targeting this datastructure. We could optimize for reads, but this would impact the complexity and performance of writing. With CQRS, reads and writes are segregated; we can now optimize both parts independently. And this doesn&apos;t only result in being able to show a list faster on a user&apos;s screen, but interesting things can also be done to empower reporting and data mining; think of how often using the same database for these tasks makes it hard and expensive to change things.
&lt;br&gt;

&lt;br&gt;
While I still have done very little with CQRS, I have been looking at more and more real world examples, trying to fill in the blanks. What always has been kind of vague to me, is how you go at storing your domain model, and your read models &lt;i&gt;in practice&lt;/i&gt;. Here are a few possible techniques - these are some proven techniques, and partially my own presumptions (you hardly find any OSS brown field examples).
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;The compromise&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
CQRS doesn&apos;t have to be an application-wide architecture necessarily; nothing stops you from introducing it gently, and just applying it to parts of your application where the added value is over-obvious. This could mean that you use a conventional architecture; a relational database with an ORM, or a document store, not distinguishing the write side from the read side. Yet for certain scenarios, you could introduce a specialized read or write side. For example; update the statistics read model on every relevant write, update a denormalized optimized read model for searches, etc..
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;NORM&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
While the relational paradigm definitely has its place, mapping your domain to the database can get complex, and require much maintenance. If you don&apos;t expect of your write side to be queryable, you can take advantage of less cumbersome techniques such as a key value store to store your domain model. This does force you to completely separate reads from writes though.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;Event Sourcing&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
When you look at most OSS CQRS implementations, &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~martinfowler.com/eaaDev/EventSourcing.html&quot;&gt;Event Sourcing&lt;/a&gt; and CQRS go hand in hand. With Event Sourcing, you capture all application state changes as a sequence of events. I&apos;m really fond of the theory behind this pattern, and I can imagine the added operational value of having a log of each change. Yet, I also think you could largely achieve the same result by enabling journaling and adding some interception. Storage wise, you store all the event streams in an event store, which is optimized for such a task. Your read side can again be whatever you fancy.
&lt;br&gt;

&lt;br&gt;
These three techniques aren&apos;t mutually exclusive. There are a bunch of arguments to consider, and everything is highly dependent on your technical and operational requirements.
&lt;br&gt;

&lt;br&gt;
What is your experience with CQRS? Which techniques have you applied &lt;i&gt;in practice&lt;/i&gt;?&lt;/div&gt;
&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/38241769/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/38241769/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/38241769/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/38241769/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/38241769/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/38241769/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/38241769/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/38241769/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/240349995816733512/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/38241769/0/jefclaes~Adding-the-R-to-CQS-some-storage-options.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/240349995816733512?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/240349995816733512?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/38241769/0/jefclaes~Adding-the-R-to-CQS-some-storage-options.html' title='Adding the R to CQS: some storage options'/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-iDpToHUCqqM/UR9zdyzk44I/AAAAAAAABiw/d9KDU6rRLSE/s72-c/CQRS_drawing.png' height='72' width='72'/><thr:total>0</thr:total></entry>
<entry gd:etag='W/&quot;DkQEQng-fip7ImA9WhBTFU8.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2013/02/premature-judgment.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-9054007029636572914</id><published>2013-02-10T16:46:00.001+01:00</published><updated>2013-02-10T20:25:03.656+01:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2013-02-10T20:25:03.656+01:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='Ramblings'/><title>Premature judgment</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
When I started my first job, I hardly ever judged my peers. After all, how could I? Everything was unknown for me; I couldn&apos;t differentiate good from bad. Over the years that has changed a bit, but with that, I&apos;ve also slowly become more judgmental towards peers, often prematurely, and not always deservedly.
&lt;br&gt;

&lt;br&gt;
The first few months of last year, I found myself doing maintenance on a legacy code base between projects. While I worked my way through layer after layer, I pointed my frustration towards those that had come before me; they were responsible for putting me in this mess. With half the office having touched the code base, that didn&apos;t really add up though. When I looked at the commit history of some of the offending modules, I found names that I didn&apos;t expect; those people were still around, and I actually thought of them pretty highly.
&lt;br&gt;

&lt;br&gt;
Judging someone&apos;s competence solely by code he has written in the past is a flaw. There are very little pieces of code I have written over the years where I still feel comfortable about today. When I reflect on what made it go wrong, I don&apos;t have to look far to find a bunch of reasons to blame it on; consistency was favored over common sense, major breakthroughs occurred only after the project was already in maintenance mode, people inexperienced with the domain and infrastructure were dumped on the project last minute to make up for bad planning, knowledge of the technology stack hadn&apos;t matured, some patterns and practices weren&apos;t commonplace yet, etc... I always find plenty of reasons to shift blame, but when I look at code written by someone else, it has to be their own fault; they must not be very good at building software. And this is unfair; I have no way of knowing the constraints they had to deal with, nor the context they had to work in. None of these justify neglecting basic hygiene though!
&lt;br&gt;

&lt;br&gt;
I tried to come up with other things that influence my opinion on someone before having actually worked with them; I found two.
&lt;br&gt;
The biggest influencer is word of mouth. I try to surround myself with people that share a similar thinking, and if that trusted circle has a strong opinion on someone else, I take note.
&lt;br&gt;
The last influencer is someone&apos;s online presence. When I learn of someone new joining ranks, I can&apos;t resist to look up what he&apos;s doing online. Twitter, Facebook or a blog can give away quite a bit.
&lt;br&gt;

&lt;br&gt;
All in all, I think some preconception is human, and might be the result of subconsciously protecting your work. You only want to involve those with whom you will enjoy working towards your shared goal.
&lt;br&gt;
&lt;i&gt;
&lt;br&gt;&lt;/i&gt;
&lt;i&gt;Have you experienced similar behavior? When do you judge prematurely?&lt;/i&gt;&lt;/div&gt;
&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/38033963/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/38033963/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/38033963/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/38033963/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/38033963/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/38033963/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/38033963/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/38033963/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/9054007029636572914/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/38033963/0/jefclaes~Premature-judgment.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/9054007029636572914?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/9054007029636572914?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/38033963/0/jefclaes~Premature-judgment.html' title='Premature judgment'/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><thr:total>5</thr:total></entry>
<entry gd:etag='W/&quot;CkYMQHo6cSp7ImA9WhNaGUw.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2013/02/raising-events-in-commandhandlers.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-8682371270438729017</id><published>2013-02-03T17:49:00.000+01:00</published><updated>2013-02-03T17:49:41.419+01:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2013-02-03T17:49:41.419+01:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='DDD'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='CodeSnippets'/><title>Raising events in commandhandlers</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
I&apos;ve explored quite a few options on how to handle commands and queries in the last few posts. I finally settled on &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2013/01/separating-command-data-from-logic-and.html&quot;&gt;this approach&lt;/a&gt;. The example used in that post looked like this.
&lt;br&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; CreateSubscriptionCommandHandler : ICommandHandler&amp;lt;CreateSubscriptionCommand&amp;gt;
{    
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; IDocumentSession _session;
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; CreateSubscriptionCommandHandler(IDocumentSession session)
    {
        _session = session;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Handle(CreateSubscriptionCommand command)
    {
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; subscription = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Documents.Subscription(
            command.Value, command.Category, command.EmailAddress);
        _session.Store(subscription);    
    }
}&lt;/pre&gt;
Now imagine I would want to do some extra stuff &lt;i&gt;after&lt;/i&gt; creating the subscription; update the sales statistics, append the email address to a mailing list, send out a confirmation email, etc..
&lt;br&gt;

&lt;br&gt;
You could go at this by simply extending the commandhandler, but the problem here is that you quickly end up with a bulky and dependency-heavy commandhandler, which will quickly fail to communicate its intent.
&lt;br&gt;

&lt;br&gt;
One solution could be to introduce events to decouple things in smaller pieces, and to help communicate intent more clearly.
&lt;br&gt;

&lt;br&gt;
The infrastructure to handle events is rather straightforward, and can be based on &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.udidahan.com/2009/06/14/domain-events-salvation/&quot;&gt;Udi Dahan&apos;s Domain Events Salvation&lt;/a&gt;.
&lt;br&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Events : IEvents
{
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; IKernel _kernel;
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Events(IKernel kernel)
    {
        _kernel = kernel;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Raise&amp;lt;T&amp;gt;(T @&lt;span class=&quot;kwrd&quot;&gt;event&lt;/span&gt;) where T : IEvent
    {
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; handlers = _kernel.GetAll&amp;lt;IEventHandler&amp;lt;T&amp;gt;&amp;gt;();
        &lt;span class=&quot;kwrd&quot;&gt;foreach&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; handler &lt;span class=&quot;kwrd&quot;&gt;in&lt;/span&gt; handlers)        
            handler.Handle(@&lt;span class=&quot;kwrd&quot;&gt;event&lt;/span&gt;);        
    }     
}&lt;/pre&gt;
When an event is raised, the eventing infrastructure will look in the container for implementations that can handle the event, and invoke them in a random order.
&lt;br&gt;

&lt;br&gt;
Raising an event from the commandhandler can be done by injecting this extra piece of infrastructure.
&lt;br&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; CreateSubscriptionCommandHandler : ICommandHandler&amp;lt;CreateSubscriptionCommand&amp;gt;
{    
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; IDocumentSession _session;
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; IEvents _events;
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; CreateSubscriptionCommandHandler(IDocumentSession session, IEvent events)
    {
        _session = session;
        _events = events;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Handle(CreateSubscriptionCommand command)
    {
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; subscription = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Documents.Subscription(
            command.Value, command.Category, command.EmailAddress);
        _session.Store(subscription);    
        
        _events.Raise(&lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; SubscriptionCreatedEvent(query.Id));
    }
}&lt;/pre&gt;
The SubscriptionCreatedEvent class is a simple value object, which exposes the subscription identifier.
&lt;br&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; SubscriptionCreatedEvent : IEvent
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; SubscriptionCreatedEvent(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; subscriptionId)
    {
        SubscriptionId = subscriptionId;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; SubscriptionId { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; Equals(Object other)
    {
        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (other == &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;)
            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;;
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; otherEvent = other &lt;span class=&quot;kwrd&quot;&gt;as&lt;/span&gt; SubscriptionCreatedEvent;
        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (otherEvent == &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;)
            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;;
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; otherEvent.SubscriptionId == SubscriptionId;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; GetHashCode()
    {
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; SubscriptionId.GetHashCode();
    }
}   &lt;/pre&gt;
To subscribe to this event, implement the IEventHandler interface, and register the implemenation in the container.
&lt;br&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;interface&lt;/span&gt; IEventHandler&amp;lt;T&amp;gt; where T : IEvent
{
    &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Handle(T @&lt;span class=&quot;kwrd&quot;&gt;event&lt;/span&gt;);
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; SendConfirmationMailOnSubscriptionCreated : IEventHandler&amp;lt;SubscriptionCreatedEvent&amp;gt;
{    
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt;  Handle(SubscriptionCreatedEvent @&lt;span class=&quot;kwrd&quot;&gt;event&lt;/span&gt;)
    {
        ...
    }
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; UpdateSalesStatisticsOnSubscriptionCreated : IEventHandler&amp;lt;SubscriptionCreatedEvent&amp;gt;
{    
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt;  Handle(SubscriptionCreatedEvent @&lt;span class=&quot;kwrd&quot;&gt;event&lt;/span&gt;)
    {
        ...
    }
}&lt;/pre&gt;
Eventhandlers are invoked synchronously, and participate in the commandhandler&apos;s unit of work, so if something goes haywire in one of the eventhandlers, nothing gets committed, not even what happened in the original commandhandler. Depending on your requirements, you might want to handle this differently though.
&lt;br&gt;

&lt;br&gt;
With this approach, tests also become more compact. Commandhandler tests now only need to assert that the event gets raised, and all the other logic gets offloaded to separate tests per eventhandler.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;Summary&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
By introducing events, you can decouple commandhandlers into more focused, and intent-revealing bits. Your tests are the perfect proof of how much cleaner things get. One of the cues to listen for is &lt;i&gt;when&lt;/i&gt;&amp;nbsp;you do x or &lt;i&gt;on&lt;/i&gt;&amp;nbsp;doing y, also do z.
&lt;br&gt;

&lt;br&gt;
&lt;i&gt;Are you using events? If so, domain events, or its big brother Event Sourcing?&lt;/i&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/37809803/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/37809803/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/37809803/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/37809803/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/37809803/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/37809803/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/37809803/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/37809803/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/8682371270438729017/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/37809803/0/jefclaes~Raising-events-in-commandhandlers.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/8682371270438729017?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/8682371270438729017?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/37809803/0/jefclaes~Raising-events-in-commandhandlers.html' title='Raising events in commandhandlers'/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry>
<entry gd:etag='W/&quot;CUcARnkyfip7ImA9WhNaE0w.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2013/01/organizing-commands-and-queries.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-2459998586633636896</id><published>2013-01-27T18:23:00.000+01:00</published><updated>2013-01-27T19:57:27.796+01:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2013-01-27T19:57:27.796+01:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='Refactoring'/><category scheme='http://www.blogger.com/atom/ns#' term='DDD'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><title>Organizing commands and queries</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
In the last few posts I settled on an architecture for handling commands and queries. A byproduct of &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2013/01/separating-command-data-from-logic-and.html&quot;&gt;the described approach&lt;/a&gt;, is that your codebase quickly racks up plentiful little classes; a class to hold data, and a handler to act on that data, for each use case.
&lt;br&gt;

&lt;br&gt;
There are a few ways you can go at organizing things.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;Everything in one location&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
When there is very little going on in your application, you can just dump everything in one location without getting hurt too much.
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;

&lt;br&gt;
&lt;div style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~2.bp.blogspot.com/-YIVFJ7F8PGU/UQL3bdY1OcI/AAAAAAAABiU/3ZNZhlkwMV4/s1600/DumpedEverything.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;254&quot; src=&quot;http://2.bp.blogspot.com/-YIVFJ7F8PGU/UQL3bdY1OcI/AAAAAAAABiU/3ZNZhlkwMV4/s400/DumpedEverything.PNG&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
&lt;b&gt;Folder per functionality&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
When your application grows, and the coherency between different use cases are obvious, you can just use folders - and corresponding namespaces, to organize your commands and queries, and to draw their functional boundaries. Uncle Bob and Mark Needham have &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.markhneedham.com/blog/2012/02/20/coding-packaging-by-vertical-slice/&quot;&gt;sold me on structuring my code based on functionality instead of technical concepts&lt;/a&gt;.
&lt;br&gt;

&lt;br&gt;
&lt;div style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~1.bp.blogspot.com/-wR9LLwJWFlU/UQL3hWo78YI/AAAAAAAABic/Sgze4gq5RGI/s1600/PerFolder.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;284&quot; src=&quot;http://1.bp.blogspot.com/-wR9LLwJWFlU/UQL3hWo78YI/AAAAAAAABic/Sgze4gq5RGI/s400/PerFolder.PNG&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;clear: both; text-align: center;&quot;&gt;

&lt;br&gt;&lt;/div&gt;
&lt;div style=&quot;clear: both; text-align: left;&quot;&gt;
Keeping each commandhandler in a separate class is especially interesting when they are rather bulky and contain a good amount of logic. You can think of each class as a little piece of functionality in itself. &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://github.com/ravendb/ravendb/tree/master/Raven.Studio/Commands&quot;&gt;Take a look at the RavenDB codebase&lt;/a&gt; to get an idea of what that could look like.&lt;/div&gt;
&lt;div style=&quot;clear: both; text-align: left;&quot;&gt;

&lt;br&gt;&lt;/div&gt;
&lt;div style=&quot;clear: both; text-align: left;&quot;&gt;
It also feels like this way tends to bring your code closer to the Solution Explorer; just one double-click and you are looking at your implementation; no scrolling or searching between method definitions necessary. Maybe the problem is now just shifted a level higher in the hierarchy though.&lt;/div&gt;

&lt;br&gt;
&lt;b&gt;Composing a service class&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
You can also opt to group commandhandler implementations in one service class. This variation might make more sense when your implementations are rather skinny, and don&apos;t do a whole lot but translating and forwarding your invocation.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; SubscriptionService : 
        ICommandHandler&amp;lt;SubscribeCommand&amp;gt;,
        ICommandHandler&amp;lt;UnsubscribeCommand&amp;gt;
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Handle(SubscibeCommand command)
    {
        &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; NotImplementedException();
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Handle(UnsubscribeCommand command)
    {
        &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; NotImplementedException();
    }
}&lt;/pre&gt;
&lt;/div&gt;
Use the hints your dependency graph gives you to find a composition that makes sense.
&lt;br&gt;

&lt;br&gt;
&lt;i&gt;How do you go at organizing commands and queries?&lt;/i&gt;&lt;/div&gt;
&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/37593208/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/37593208/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/37593208/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/37593208/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/37593208/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/37593208/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/37593208/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/37593208/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/2459998586633636896/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/37593208/0/jefclaes~Organizing-commands-and-queries.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/2459998586633636896?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/2459998586633636896?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/37593208/0/jefclaes~Organizing-commands-and-queries.html' title='Organizing commands and queries'/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-YIVFJ7F8PGU/UQL3bdY1OcI/AAAAAAAABiU/3ZNZhlkwMV4/s72-c/DumpedEverything.PNG' height='72' width='72'/><thr:total>4</thr:total></entry>
<entry gd:etag='W/&quot;DUANRn0yeyp7ImA9WhNaEEg.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2013/01/ravendb-drop-all-collections.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-3812553836325018348</id><published>2013-01-24T20:08:00.000+01:00</published><updated>2013-01-24T21:03:17.393+01:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2013-01-24T21:03:17.393+01:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='CodeSnippets'/><category scheme='http://www.blogger.com/atom/ns#' term='NoSql'/><title>RavenDB: Drop all collections</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
I never stub or mock the database when I&apos;m using&amp;nbsp;&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~ravendb.net/&quot;&gt;RavenDB&lt;/a&gt;. Generally, I use an embeddable documentstore running in memory, and initialize a new instance on every test. However, I like to run some stress tests against a real instance, and here I found myself wanting to wipe clean the state of previous tests, without having to create a new database (which is rather slow).
&lt;br&gt;

&lt;br&gt;
First I create the default DocumentsByEntityName index to make sure it&apos;s there - it normally gets created when you open the studio for the first time. Then I use one of the&amp;nbsp;&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~ravendb.net/docs/client-api/advanced/databasecommands&quot;&gt;advanced database commands:&lt;/a&gt;&amp;nbsp;DeleteByIndex, and query all the tags.
&lt;br&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; session = _documentStore.OpenSession())
{
    &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; RavenDocumentsByEntityName().Execute(_documentStore);
    session.Advanced.DatabaseCommands.DeleteByIndex(
            &lt;span class=&quot;str&quot;&gt;&quot;Raven/DocumentsByEntityName&quot;&lt;/span&gt;,
            &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; IndexQuery { Query = &lt;span class=&quot;str&quot;&gt;&quot;Tag: *&quot;&lt;/span&gt; });                
}&lt;/pre&gt;
This technique doesn&apos;t seem to be widely used judging by the first page of Google search results. If there is a reason for that though, let me know!&lt;/div&gt;
&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/37516356/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/37516356/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/37516356/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/37516356/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/37516356/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/37516356/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/37516356/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/37516356/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/3812553836325018348/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/37516356/0/jefclaes~RavenDB-Drop-all-collections.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/3812553836325018348?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/3812553836325018348?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/37516356/0/jefclaes~RavenDB-Drop-all-collections.html' title='RavenDB: Drop all collections'/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry>
<entry gd:etag='W/&quot;A0cEQ309fip7ImA9WhNaFUs.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2013/01/separating-command-data-from-logic-and.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-8361630651349030506</id><published>2013-01-20T22:03:00.002+01:00</published><updated>2013-01-30T19:03:22.366+01:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2013-01-30T19:03:22.366+01:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='Refactoring'/><category scheme='http://www.blogger.com/atom/ns#' term='DDD'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='CodeSnippets'/><category scheme='http://www.blogger.com/atom/ns#' term='NancyFx'/><title>Separating command data from logic and sending it on a bus</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
In &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2012/10/commands-queries-and-testing.html&quot;&gt;my first post on this topic&lt;/a&gt;, I started out with an attempt to limit abstractions to solely commands and queries. Commands and queries were self-contained and could be invoked by passing them to a context-providing generic handler. The drawback of this approach was that it made constructor dependency injection impossible. In a &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2012/10/commands-with-dependencies.html&quot;&gt;next post&lt;/a&gt;, I separated data from logic, but never got around to writing a dispatcher that associates command data with their handlers. Last week, &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2013/01/self-contained-commands-with.html&quot;&gt;I revisited the first approach&lt;/a&gt;, and added an unconventional implementation of injecting dependencies by an Inject method convention.
&lt;br&gt;

&lt;br&gt;
I still believe that last approach is very simple and works fine if extra dependencies are exceptional. I do admit that it will make architectural shoots harder to handle; everything is rather tightly coupled. So let&apos;s look at an alternative architecture which pulls all the bits apart, and should be better equipped to handle change.
&lt;br&gt;

&lt;br&gt;
Let&apos;s first separate command data from logic.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; CreateSubscriptionCommand 
{     
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; CreateSubscriptionCommand(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; value, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; category, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; emailAddress)
    {
        Guard.StringIsNullOrEmpty(value, &lt;span class=&quot;str&quot;&gt;&quot;value&quot;&lt;/span&gt;);
        Guard.StringIsNullOrEmpty(category, &lt;span class=&quot;str&quot;&gt;&quot;category&quot;&lt;/span&gt;);
        Guard.StringIsNullOrEmpty(emailAddress, &lt;span class=&quot;str&quot;&gt;&quot;emailAddress&quot;&lt;/span&gt;);
        Value = value;
        Category = category;
        EmailAddress = emailAddress;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; Value { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; Category { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; EmailAddress { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; Equals(Object other)
    {
        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (other == &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;)
            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;;
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; otherCommand = other &lt;span class=&quot;kwrd&quot;&gt;as&lt;/span&gt; CreateSubscriptionCommand;
        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (otherCommand == &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;)
            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;;
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; otherCommand.Value == Value &amp;amp;&amp;amp; 
            otherCommand.Category == Category &amp;amp;&amp;amp; 
            otherCommand.EmailAddress == EmailAddress;
    }    
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; GetHashCode()
    {
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; Value.GetHashCode() ^ 
            Category.GetHashCode() ^ 
            EmailAddress.GetHashCode();
    }
}&lt;/pre&gt;
&lt;/div&gt;
The data is just a POCO. Notice the equality overrides; this comes in handy when you&apos;re testing.
&lt;br&gt;

&lt;br&gt;
The class that handles on the data needs to implement the ICommandHandler interface.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; CreateSubscriptionCommandHandler 
    : ICommandHandler&amp;lt;CreateSubscriptionCommand&amp;gt;
{    
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; IDocumentSession _session;
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; CreateSubscriptionCommandHandler(IDocumentSession session)
    {
        _session = session;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Handle(CreateSubscriptionCommand command)
    {
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; subscription = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Documents.Subscription(
            command.Value, command.Category, command.EmailAddress);
        _session.Store(subscription);    
    }
}&lt;/pre&gt;
&lt;/div&gt;
Compared to the previous approach, we&apos;re now injecting the session instead of having it handy as a property; that coupling is now completely gone.
&lt;br&gt;

&lt;br&gt;
Last thing left to do is create an interface that consumers can use to send commands on: a bus.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Bus : IBus
{
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; IKernel _kernel;
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; Bus(IKernel kernel)
    {
        _kernel = kernel;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; ExecuteCommand&amp;lt;T&amp;gt;(T command) where T : &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt;
    {
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; handler = _kernel.Get&amp;lt;ICommandHandler&amp;lt;T&amp;gt;&amp;gt;();
        handler.Handle(command);
        _kernel.Get&amp;lt;IDocumentSession&amp;gt;().SaveChanges();
    }
}&lt;/pre&gt;
The ExecuteCommand method dispatches data to the correct handler by resolving it from the container, and also commits the unit of work. 
&lt;br&gt;

&lt;br&gt;
The consumer can execute commands like this.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;bus.ExecuteCommand(
    &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; CreateQueryCommand(queryValue, category, emailAddress));&lt;/pre&gt;
With this approach having all the bits spread, we have a bit more work gluing all the pieces together. The session is now known in the container, and is request scoped. The commandhandlers are also all registered in the container.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; ConfigureRequestContainer(IKernel container, NancyContext context)
{        
        &lt;span class=&quot;rem&quot;&gt;// you don&apos;t want to register them all individually&lt;/span&gt;
        container
            .Bind&amp;lt;ICommandHandler&amp;lt;CreateSubscriptionCommand&amp;gt;&amp;gt;()
            .To&amp;lt;CreateSubscriptionCommandHandler&amp;gt;();        
        &lt;span class=&quot;rem&quot;&gt;// snip..&lt;/span&gt;
        container.Bind&amp;lt;IDocumentSession&amp;gt;()
            .ToMethod((ctx) =&amp;gt; { 
                &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; ctx.Kernel.Get&amp;lt;IDocumentStore&amp;gt;().OpenSession();    
            })
            .InSingletonScope();                          
}&lt;/pre&gt;
&lt;/div&gt;

&lt;br&gt;
I think this approach might suit a lot of projects better if your commands are dependency heavy.
&lt;br&gt;
What I like most is that handling architectural shoots will be easier. For example: right now, all behaviour is in my entities and in my commands; the segregation of application services and domain services is non-existent. And this works fine so far; I yet have to find a use case where I would benefit from more separation. If that would change in the future though, I can introduce abstractions, and concepts, without breaking consumer code, and without having to do awkward stuff managing the newly introduced dependencies.
&lt;br&gt;

&lt;br&gt;
&lt;i&gt;As always, your thoughts are appreciated.&lt;/i&gt;&lt;/div&gt;
&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/37399626/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/37399626/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/37399626/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/37399626/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/37399626/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/37399626/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/37399626/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/37399626/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/8361630651349030506/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/37399626/0/jefclaes~Separating-command-data-from-logic-and-sending-it-on-a-bus.html#comment-form' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/8361630651349030506?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/8361630651349030506?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/37399626/0/jefclaes~Separating-command-data-from-logic-and-sending-it-on-a-bus.html' title='Separating command data from logic and sending it on a bus'/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><thr:total>10</thr:total></entry>
<entry gd:etag='W/&quot;DkYARXc7cSp7ImA9WhNbF0g.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2013/01/self-contained-commands-with.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-3969669136244403173</id><published>2013-01-13T18:17:00.000+01:00</published><updated>2013-01-21T08:42:24.909+01:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2013-01-21T08:42:24.909+01:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='CodeSnippets'/><title>Self-contained commands with dependencies </title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;i&gt;Also read: &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2013/01/separating-command-data-from-logic-and.html&quot;&gt;separating command data from logic and sending it on a bus&lt;/a&gt;&lt;/i&gt;
&lt;br&gt;

&lt;br&gt;
In October I looked at &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2012/10/commands-queries-and-testing.html&quot;&gt;an architecture that limits abstractions to solely commands and queries&lt;/a&gt;.&amp;nbsp;In that post, I had some infrastructure that looked like this.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Command
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Execute();
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Query&amp;lt;T&amp;gt;
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;abstract&lt;/span&gt; T Execute();
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;interface&lt;/span&gt; ICommandHandler
{
    &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Execute(Command command);
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; CommandHandler : ICommandHandler
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Execute(Command command)
    {
        command.Execute();
    }
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;interface&lt;/span&gt; IQueryHandler 
{
    T Execute&amp;lt;T&amp;gt;(Query&amp;lt;T&amp;gt; query);
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; QueryHandler : IQueryHandler
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; T Execute&amp;lt;T&amp;gt;(Query&amp;lt;T&amp;gt; query)
    {
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; query.Execute();
    }
}&lt;/pre&gt;
&lt;/div&gt;
Commands and queries are both accompanied by their specific handler. In this example, the handler does nothing but invoking the command or query. In reality, you want your handlers to do a little more. For example: provide the commands and queries with a context to work with, add logging, handle your unit of work and all of that good stuff.
&lt;br&gt;

&lt;br&gt;
Let&apos;s look at the infrastructure, and particularly the handlers of a project that uses RavenDB to store its data.
&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Command
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; IDocumentSession Session { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Execute();           
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Query&amp;lt;T&amp;gt;
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; IDocumentSession Session { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; &lt;span class=&quot;kwrd&quot;&gt;set&lt;/span&gt;; }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;abstract&lt;/span&gt; T Execute();
}
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; CommandHandler : ICommandHandler
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Execute(Command command)
    {            
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; store = DocumentStore.Get();
        &lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; session = store.OpenSession())
        {
            command.Session = session;
            command.Execute();
            session.SaveChanges();
        }
    }
}
    
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; QueryHandler : IQueryHandler
{    
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; T Execute&amp;lt;T&amp;gt;(Query&amp;lt;T&amp;gt; query)
    {
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; store = DocumentStore.Get();
        &lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; session = store.OpenSession())
        {
            query.Session = session;
            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; query.Execute();
        }
    }
}&lt;span style=&quot;font-family: Times New Roman;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
The handlers take care of creating and managing the session, but also provide the commands and queries with a reference to the session.
&lt;br&gt;

&lt;br&gt;
An actual command could look like this.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; ConfirmOrderCommand : Command
{
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; Guid _token;
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; ConfirmOrderCommand(Guid token)
    {
        _token = token;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Execute()
    {
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; order = Session.Query&amp;lt;Documents.Order&amp;gt;().Where(x =&amp;gt; x.Token == _token).First();
        order.ChangeStatus(Documents.Status.Confirmed);
    }
}&lt;/pre&gt;
I really like this style of command and queries; very little ceremony. The downside though, is that you can&apos;t use constructor dependency injection. &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2012/10/commands-with-dependencies.html&quot;&gt;Like discussed in this post&lt;/a&gt;, you could split your classes in two parts: the handler and the data, and you would solve that problem.
&lt;br&gt;

&lt;br&gt;
I wasn&apos;t that keen on that approach. Also, now that I&apos;m so accustomed to having fast in-memory integration tests with RavenDB, it&apos;s exceptional that I have the need to inject dependencies. I worked out an alternative which allows me to inject dependencies without having to put my data somewhere else.
&lt;br&gt;

&lt;br&gt;
Instead of injecting the dependencies through the constructor, we&apos;re going to use an Inject method. This is a convention; there is no interface that enforces this. Returning to our ConfirmOrderCommand, we&apos;ll add support for creating a new folder on the file system.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; ConfirmOrderCommand : Command
{
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; IFileSystem _fileSystem;
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; Guid _token;
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; ConfirmOrderCommand(Guid token)
    {
        _token = token;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Execute()
    {    
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; order = Session.Query&amp;lt;Documents.Order&amp;gt;().Where(x =&amp;gt; x.Token == _token).First();
        
        _fileSystem.CreateDirectory(Path.Combine(&quot;D:\&quot;, order.Customer.Id));
        order.ChangeStatus(Documents.Status.Confirmed);
    }
    
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Inject(IFileSystem fileSystem) 
    {
        _fileSystem = fileSystem;
    }
}&lt;/pre&gt;
We can now amplify the commandhandler to automatically resolve and inject the dependencies into our commands. The handler uses reflection to look for a method named Inject on the type. If this method exists, it will inspect the method for its expected arguments and try to resolve those, to finally invoke the Inject method with its resolved arguments.&amp;nbsp;&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; CommandHandler : ICommandHandler
{
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; IKernel _kernel;
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; CommandHandler() { }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; CommandHandler(IKernel kernel)
    {
        _kernel = kernel;
    }
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Execute(Command command)
    {
        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (_kernel != &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;)
            ResolveDependenciesIfNeeded(command);
            
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; store = DocumentStore.Get();
        &lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; session = store.OpenSession())
        {
            command.Session = session;
            command.Execute();
            session.SaveChanges();
        }
    }
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; ResolveDependenciesIfNeeded(Command command)
    {
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; method = command.GetType().GetMethod(&lt;span class=&quot;str&quot;&gt;&quot;Inject&quot;&lt;/span&gt;);
        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (method != &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;)
        {
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; parameters = method.GetParameters();
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; parameterInstances = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; List&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;&amp;gt;();
            &lt;span class=&quot;kwrd&quot;&gt;foreach&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; parameter &lt;span class=&quot;kwrd&quot;&gt;in&lt;/span&gt; parameters)
            {
                &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; type = parameter.ParameterType;
                &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; instance = _kernel.Get(type);
                parameterInstances.Add(instance);
            }
            method.Invoke(command, parameterInstances.ToArray());
        }
    }
}&lt;span style=&quot;font-family: Times New Roman;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
Consumers now don&apos;t have to care about the dependencies; they just have to be registered in the container. In the tests however, we can now explicitly inject mocks or stubs, and&amp;nbsp;take advantage of having discoverable dependencies though the Inject convention.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;[TestClass]
&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; When_confirming_an_order
{
    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; Mock&amp;lt;IFileSystem&amp;gt; _fileSystem;
    [TestInitialize]
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; When()
    {
        DocumentStore.InitializeEmbedded();
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; cmd = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ConfirmOrderCommand(&lt;span class=&quot;str&quot;&gt;&quot;_token_&quot;&lt;/span&gt;);
        
        &lt;span class=&quot;rem&quot;&gt;// Inject mock&lt;/span&gt;
        _fileSystem = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Mock&amp;lt;IFileSystem&amp;gt;();    
        cmd.Inject(_fileSystem.Object);
        &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; CommandHandler().Execute(cmd);
    }
    [TestMethod]
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; the_status_is_changed_to_confirmed()
    {
        ...
    }
    
    [TestMethod]
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; a_new_folder_is_created()
    {
        _fileSystem.Verify(...);
    }
}&lt;/pre&gt;
Although I haven&apos;t really gone the distance with this implementation - I only have one command that has extra dependencies, I find this technique showing lots of promise. You get the leanness of self-contained commands and queries, while you still allow discoverable dependency injection by convention, supported by a tiny bit of infrastructure in the handlers.
&lt;br&gt;

&lt;br&gt;
&lt;i&gt;I&apos;d like to hear your opinion.&lt;/i&gt;&lt;/div&gt;
&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/37206355/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/37206355/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/37206355/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/37206355/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/37206355/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/37206355/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/37206355/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/37206355/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/3969669136244403173/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/37206355/0/jefclaes~Selfcontained-commands-with-dependencies.html#comment-form' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/3969669136244403173?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/3969669136244403173?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/37206355/0/jefclaes~Selfcontained-commands-with-dependencies.html' title='Self-contained commands with dependencies '/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><thr:total>13</thr:total></entry>
<entry gd:etag='W/&quot;CUMNSX08fyp7ImA9WhNUFU0.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2013/01/keeping-your-appharbor-application-pool.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-2883388167595426776</id><published>2013-01-06T21:18:00.000+01:00</published><updated>2013-01-06T21:18:18.377+01:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2013-01-06T21:18:18.377+01:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Hacking'/><category scheme='http://www.blogger.com/atom/ns#' term='NancyFx'/><title>Keeping your AppHarbor application pool alive</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
By default, IIS will shut down your application pool when it has been idle for more than 20 minutes. This is annoying when your website is only visited sporadically; visitors might not have the patience to wait for your application pool to spin up again. When you&apos;re running your own machine, you can higher or disable the idle-timeout, but when you&apos;re running on a cloud service like &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://appharbor.com/&quot;&gt;AppHarbor&lt;/a&gt; you can&apos;t.
&lt;br&gt;

&lt;br&gt;
One solution is to frequently make a request yourself to keep the application pool alive. You can use a third party service (like &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://www.pingdom.com/&quot;&gt;Pingdom&lt;/a&gt; or &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://stillalive.com/&quot;&gt;StillAlive&lt;/a&gt;), but chances are you don&apos;t want to take an extra dependency for something that trivial.
&lt;br&gt;

&lt;br&gt;
AppHarbor contains the required infrastructure to do this yourself: &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~support.appharbor.com/kb/getting-started/background-workers&quot;&gt;background workers&lt;/a&gt; and &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~blog.appharbor.com/2012/4/18/scheduled-tasks-using-quartz-and-appharbor-background-workers&quot;&gt;scheduling&lt;/a&gt;.
&lt;br&gt;

&lt;br&gt;
First create a new &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~quartznet.sourceforge.net/&quot;&gt;Quartz&lt;/a&gt; job which makes a request to your web application when it&apos;s invoked.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; KeepAliveJob : IJob
{
    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Execute(IJobExecutionContext context)
    {
        &lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; (WebClient client = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; WebClient())
        {
            client.DownloadString(&lt;span class=&quot;str&quot;&gt;&quot;http://your_webapp.com&quot;&lt;/span&gt;);
        }
    }
}&lt;/pre&gt;
&lt;/div&gt;
Then schedule your job to be triggered every 19 minutes or so.
&lt;br&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; keepAliveJob = JobBuilder.Create&amp;lt;KeepAliveJob&amp;gt;().Build();
&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; keepAliveTrigger = TriggerBuilder.Create()
                .WithSimpleSchedule(x =&amp;gt; x.WithIntervalInMinutes(19).RepeatForever())
                .Build();
scheduler.ScheduleJob(keepAliveJob, keepAliveTrigger);    
scheduler.Start();   &lt;span style=&quot;font-family: Times New Roman;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
And that should be it; you&apos;re now running your own ping service.&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt;   &lt;/span&gt;&lt;/div&gt;
&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/37041866/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/37041866/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/37041866/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/37041866/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/37041866/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/37041866/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/37041866/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/37041866/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/2883388167595426776/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/37041866/0/jefclaes~Keeping-your-AppHarbor-application-pool-alive.html#comment-form' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/2883388167595426776?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/2883388167595426776?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/37041866/0/jefclaes~Keeping-your-AppHarbor-application-pool-alive.html' title='Keeping your AppHarbor application pool alive'/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><thr:total>9</thr:total></entry>
<entry gd:etag='W/&quot;D04FQ3w-fip7ImA9WhNVGUs.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2012/12/2012-annual-review.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-6885093676042747049</id><published>2012-12-31T15:58:00.001+01:00</published><updated>2012-12-31T15:58:32.256+01:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2012-12-31T15:58:32.256+01:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='General'/><category scheme='http://www.blogger.com/atom/ns#' term='Ramblings'/><title>2012 Annual Review</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
It&apos;s that time of the year again where I take some time to look back on the year passed and peek at the year ahead. This is mostly a post I like to write up for myself, forcing reflection.
&lt;br&gt;

&lt;br&gt;
The biggest personal changes this year were moving out of my parents&apos; place, and my girlfriend&apos;s decision to study medicine after graduating as a Master of Arts earlier this year. I had no idea how things would turn out once we lived together, but so far we have been doing great.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;My career&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
September marked one year working for &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.linkedin.com/company/euricom?trk=hb_tab_compy_id_30393/&quot;&gt;Euricom&lt;/a&gt;. I&apos;m still at my first client, and while I definitely regularly have my share of the enterprise blues, I also learned a lot working on several projects: from maintaining legacy to leading green fields. Fairly, I often doubt if traditional enterprise life is &lt;i&gt;it&lt;/i&gt; for me though. 
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;Blog&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
I published 66 posts this year, which seems to be consistent with previous years.
&lt;br&gt;

&lt;br&gt;
While writing has turned into a habit over the years, I often struggle with deciding what I should write about. Any reason is probably a good one though; documenting, sharing opinions and experiences, or just writing for the sake of writing... But I still feel like I should add value and contribute something worthwhile when I spend time on this blog.
&lt;br&gt;

&lt;br&gt;
The topics haven&apos;t changed that much this year. I still write often on Web technologies (ASP.NET, NancyFx and REST) - something I didn&apos;t get to spend much time on at work this year, but I also wrote about architecture, testing and NoSQL. Next to those topics, I also penned some of my experiences gained doing experimental side projects.
&lt;br&gt;
In 2013, I intent to get more out of my comfort zone, and to also write down thoughts which are not that strongly held. 
&lt;br&gt;

&lt;br&gt;
Page views have more than doubled (173k) compared to 2011, which I&apos;m humbled by, but I seem to care less about that than a little while ago. It had even been over a month since I logged into Google Analytics.
&lt;br&gt;

&lt;br&gt;
&lt;div style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~4.bp.blogspot.com/-ox6z1Klcxvo/UN7dV8L1AzI/AAAAAAAABhI/X-eirB-xd6o/s1600/traffic.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;92&quot; src=&quot;http://4.bp.blogspot.com/-ox6z1Klcxvo/UN7dV8L1AzI/AAAAAAAABhI/X-eirB-xd6o/s640/traffic.PNG&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;br&gt;
&lt;b&gt;Community&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
It very much depends on what I&apos;m doing that day, but I still spend quite some time on &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~twitter.com/JefClaes&quot;&gt;Twitter&lt;/a&gt;. I often blurt out thoughts on software, and regularly, someone who knows better than me replies, and challenges my looks on software. That&apos;s how I get value out of Twitter. That, and animated GIFs of course.
&lt;br&gt;

&lt;br&gt;
In real life, I went to see a few interesting speakers at local user groups, and &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2012/10/slides-and-code-from-my-webnet-europe.html&quot;&gt;gave a talk myself at Web.NET Europe Milan&lt;/a&gt; - international speaker, wooh. I want to applaud the organization of Web.NET Europe once more; &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2012/10/post-webnet-europe.html&quot;&gt;they did a great job&lt;/a&gt;.
&lt;br&gt;

&lt;br&gt;
In general, I started to value artificial sponsored user groups less. They have their place, and they do add value, but it&apos;s not something that I feel I need to be a part of. Having some beers with a few likeminded developers suits me better.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;Travelling&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
Buying an apartment and all of that, we didn&apos;t get to make any epic travels this year. I got to visit three different countries though: &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2012/07/finito.html&quot;&gt;Italy&lt;/a&gt;, &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2012/09/slides-and-code-from-my-tunisia-rest.html&quot;&gt;Tunisia&lt;/a&gt;, &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2012/10/slides-and-code-from-my-webnet-europe.html&quot;&gt;Italy again&lt;/a&gt;, and &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2012/10/cote-dopale.html&quot;&gt;France&lt;/a&gt;. Two out of four were sponsored by my job; not bad.
&lt;br&gt;

&lt;br&gt;
We&apos;re setting out for a big trip again in 2013. &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2011/09/once-upon-time-in-west.html&quot;&gt;We fell in love with America two years ago&lt;/a&gt;, so we&apos;ve been researching the South-West again - but closer to the Mexican border this time. Other destinations are still open for discussion though.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;Projects&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
I spent a considerate part of 2012 &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2011/09/building-small-things.html&quot;&gt;building small things on the side&lt;/a&gt;. This didn&apos;t result in anything useful, but most importantly, it got me in the habit of working on my own things, and I put together a toolset which enables me to ship things fast (NancyFx, Twitter Bootstrap, MongoDB, AppHarbor, ...).
&lt;br&gt;

&lt;br&gt;
The first project I did in 2012 was Docary. This was supposed to be something between a timesheet and a diary. This idea quickly died after I couldn&apos;t commit to using it myself. Technically I played with &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2011/11/programming-for-future-of-mobile.html&quot;&gt;early versions of jQuery mobile&lt;/a&gt; and EF, and learned why you shouldn&apos;t overlayer your MVC application - or any web application for the matter.
&lt;br&gt;

&lt;br&gt;
For the second project, I and &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://twitter.com/davybrion&quot;&gt;Davy Brion&lt;/a&gt; worked on &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://github.com/JefClaes/topdevlinks&quot;&gt;TopDevLinks&lt;/a&gt;. This was supposed to be a linkblog implementation on top of ASP.NET MVC, &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2012/10/commands-queries-and-testing.html&quot;&gt;CQS&lt;/a&gt; and MongoDB. We both lost interest in the concept eventually.
&lt;br&gt;

&lt;br&gt;
I made my girlfriend a &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://github.com/JefClaes/kristienbehets-portfolio&quot;&gt;petite portfolio site&lt;/a&gt; built on top of NancyFx, the FlickR API, and some jQuery plug-ins. Right now, it&apos;s actually &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~kristienbehets.be/&quot;&gt;running as a static site on GitHub pages&lt;/a&gt; though.
&lt;br&gt;

&lt;br&gt;
&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2012/11/released-kill-long-meetings.html&quot;&gt;I already blogged about the next project&lt;/a&gt;: &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~killlongmeetings.com/&quot;&gt;Kill Long Meetings&lt;/a&gt;. This one is still around, but quickly floundered into forgetfulness after its five minutes of Twitter fame.
&lt;br&gt;

&lt;br&gt;
The last two things I worked on this year were my Antwerp Open Data submissions. I jotted down some technical details &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2012/12/released-my-antwerp-open-data.html&quot;&gt;here&lt;/a&gt;. &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2012/11/released-nancyaspnetspritesrazor.html&quot;&gt;The Nancy.AspNetSprites.Razor package&lt;/a&gt; also sprouted out of that effort (almost 100 downloads!).
&lt;br&gt;

&lt;br&gt;
Now that I look back at it, I did write quite some code after my hours this year... Next to being in the moment of building and shipping stuff, I genuinely believe it makes me better at my job.
&lt;br&gt;

&lt;br&gt;
I hope to be able to do as much in 2013, but to also let it be something worthwhile. I&apos;ll be actually already shipping something new in a few weeks if all goes well.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;Sport/Health&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
The biggest gift I gave myself health wise this year, was giving up on smoking; I lit my last one over six months ago!
&lt;br&gt;

&lt;br&gt;
Moving to Antwerp, and not having any area to put my weights, I&apos;ve joined a gym again, where I&apos;m doing a two times a week compound routine. That should make me stronger again; I&apos;ve lost a lot of beef since picking up running three years ago.
&lt;br&gt;

&lt;br&gt;
I haven&apos;t given up on running - living close to the city park helps. I just missed the 1000km (or 621 miles) milestone this year, which is kind of lame, but I&apos;m far from complaining.
&lt;br&gt;

&lt;br&gt;
&lt;div style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~4.bp.blogspot.com/-IHbaqYFm_iI/UOGn-oaaEtI/AAAAAAAABhc/uu6vApjGPz4/s1600/nikerunning.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;358&quot; src=&quot;http://4.bp.blogspot.com/-IHbaqYFm_iI/UOGn-oaaEtI/AAAAAAAABhc/uu6vApjGPz4/s640/nikerunning.PNG&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;br&gt;
I don&apos;t know what I hope for in this area in 2013. It&apos;s starting to dawn on me that, even though those goals I set for myself have pushed me further than I thought I was capable of - I couldn&apos;t jog 1km without a break three years ago, they are not that important. It eventually comes down to nourishing your body, and making use of it in every way possible while you still can.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;Conclusion&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
Earlier this week, I strolled down the main street of Brussels and crossed a beggar with one leg and no arms. Next to feeling extremely sorry for that man, I felt truly blessed; I&apos;m healthy, loved, have more than I need, and I get to do what I like for a living. I need to remind myself more of that in 2013 - I can be a whiny bitch.
&lt;br&gt;

&lt;br&gt;
I plan to keep course in 2013, but as a better man.
&lt;br&gt;

&lt;br&gt;
How was your year? What do you plan for in 2013?
&lt;br&gt;

&lt;br&gt;
Now, if you&apos;ll excuse me, I&apos;m going to help a hand in preparing the festivities before the girlfriend really gets in a faul mood.
&lt;br&gt;

&lt;br&gt;
&lt;i&gt;Holy crap, when I sat down to write this, I didn&apos;t expect to write a whole book. I&apos;m wondering how many people actually made it down here.&amp;nbsp;&lt;/i&gt;&lt;/div&gt;
&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/36882593/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/36882593/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/36882593/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/36882593/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/36882593/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/36882593/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/36882593/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/36882593/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/6885093676042747049/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/36882593/0/jefclaes~Annual-Review.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/6885093676042747049?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/6885093676042747049?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/36882593/0/jefclaes~Annual-Review.html' title='2012 Annual Review'/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-ox6z1Klcxvo/UN7dV8L1AzI/AAAAAAAABhI/X-eirB-xd6o/s72-c/traffic.PNG' height='72' width='72'/><thr:total>1</thr:total></entry>
<entry gd:etag='W/&quot;DkMGQHw7eyp7ImA9WhNVEko.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2012/12/2012s-most-read-posts.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-7056265304908908274</id><published>2012-12-23T15:53:00.000+01:00</published><updated>2012-12-23T15:53:41.203+01:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2012-12-23T15:53:41.203+01:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='Blogging'/><category scheme='http://www.blogger.com/atom/ns#' term='General'/><title>2012's most read posts</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
I look forward to writing this post each year; it&apos;s by far the easiest one to write, and it provides me with an occasion to look back on previous years (&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2009/12/high-5-five-most-popular-blog-posts-of.html&quot;&gt;2009&lt;/a&gt;, &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2010/12/top-5-popular-posts-of-2010.html&quot;&gt;2010&lt;/a&gt;, &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2011/12/2011s-most-read-posts.html&quot;&gt;2011&lt;/a&gt;). It&apos;s entertaining - and shameful too - to see what kept me busy back then, which opinions I held, and which technologies and techniques are still relevant in the meanwhile. Anyways, here it goes.
&lt;br&gt;

&lt;br&gt;
The most read post this year, with 37.797 page views, is &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2012/03/how-web-application-can-download-and.html&quot;&gt;How a web application can download and store over 2GB without you even knowing it&lt;/a&gt;. I just ran this experiment again with the latest Chrome build, and apparently the Chrome team hasn&apos;t addressed these concerns in the meanwhile; the browser still behaves exactly the same. I&apos;m guessing usage stats might prove that it&apos;s not worth the effort.
&lt;br&gt;

&lt;br&gt;
The second most read post, with 14.371 page views, is &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2012/03/learning-hacker-way.html&quot;&gt;Learning: the Hacker Way&lt;/a&gt;. I still firmly stand by this one today. Passive learning can only take you so far; it&apos;s crucial to supplement passive learning with a high volume of getting your hands dirty.
&lt;br&gt;

&lt;br&gt;
With 14.085 page views, &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2012/11/commuting-have-you-done-math.html&quot;&gt;Commuting: have you done the math?&lt;/a&gt; comes in third. Commuting wastes a good part of your life; optimizing your commute can significantly improve the quality of your average day. Readers shared some interesting experiences in the comments on this one.
&lt;br&gt;

&lt;br&gt;
Having 5.215 page views, the post &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2012/05/why-i-will-always-love-rss.html&quot;&gt;Why I will always love RSS&lt;/a&gt; is the penultimate item in this list. This writing is basically a rant on how, although I somewhat understand the motivation behind public companies fencing their gardens, it is sad to see that even peers seem to advertise the death of RSS, while it&apos;s RSS that has enabled me to follow my favorite sources of information without having to rely on others to tell me what to read, and without having to be connected the whole damn time.
&lt;br&gt;

&lt;br&gt;
With 1000 views less, making it the last item in the list, is the post&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2012/03/html5-offline-web-applications-as.html&quot;&gt; HTML5 Offline Web applications as an afterthought in ASP.NET MVC&lt;/a&gt;. It was this post that landed me a &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2012/03/html5-offline-web-applications-as.html&quot;&gt;paid article on InfoQ&lt;/a&gt;. I should revisit this topic again, I&apos;m curious to see how many websites are already making use of this HTML5 super cache to improve performance, or to truly provide offline access.
&lt;br&gt;

&lt;br&gt;
Thank &lt;i&gt;you&lt;/i&gt; for reading in 2012!&lt;/div&gt;
&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/36672819/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/36672819/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/36672819/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/36672819/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/36672819/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/36672819/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/36672819/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/36672819/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/7056265304908908274/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/36672819/0/jefclaes~s-most-read-posts.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/7056265304908908274?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/7056265304908908274?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/36672819/0/jefclaes~s-most-read-posts.html' title='2012&apos;s most read posts'/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry>
<entry gd:etag='W/&quot;CE4GRXczeSp7ImA9WhNWFko.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2012/12/released-my-antwerp-open-data.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-4081102401222578054</id><published>2012-12-16T16:44:00.000+01:00</published><updated>2012-12-16T16:48:44.981+01:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2012-12-16T16:48:44.981+01:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='Opensource'/><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='CodeSnippets'/><category scheme='http://www.blogger.com/atom/ns#' term='Tips'/><category scheme='http://www.blogger.com/atom/ns#' term='Hacking'/><category scheme='http://www.blogger.com/atom/ns#' term='Browser'/><category scheme='http://www.blogger.com/atom/ns#' term='NancyFx'/><title>Released: My Antwerp Open Data submissions</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
A little while ago the city of Antwerp released their &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~opendata.antwerpen.be/&quot;&gt;Open Data&lt;/a&gt; initiative, and it included a meetup where you could show something you built, build something on the spot, or pitch your ideas. When I first heard of the initiative I had nothing going on the side, and was looking for something tangible I could build to try out a few technologies. I couldn&apos;t come up with an original idea, and ended up building two web applications using the Open Data datasets: Culture Mosaic, and Where to pee in Antwerp?
&lt;br&gt;
Since I was bedridden due to the flu, and my ideas were not that great, I eventually ended up not going to the meetup, but I figured I would share some stuff I picked up along the way here.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;Culture Mosaic&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
The first web application uses the &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~api.antwerpen.be/v1/infrastructuur/cultuur.json&quot;&gt;culture dataset&lt;/a&gt; to display a masonry of cultural attraction images.
&lt;br&gt;

&lt;br&gt;
&lt;div style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~1.bp.blogspot.com/-TVB6EGqecTA/UM3rlOloOEI/AAAAAAAABgk/DkgWRV8TiP8/s1600/antwerp+culre.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;446&quot; src=&quot;http://1.bp.blogspot.com/-TVB6EGqecTA/UM3rlOloOEI/AAAAAAAABgk/DkgWRV8TiP8/s640/antwerp+culre.PNG&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;br&gt;
The images available vary in size, and some turned out to be quite large. If I wanted to display all the images at once, I had to make them smaller; resize them. For this task, I found the &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~imageresizing.net/&quot;&gt;ImageResizer&lt;/a&gt; library &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~nuget.org/packages/ImageResizer&quot;&gt;on Nuget&lt;/a&gt;. Although you can reference remote images using an ImageResizer extension, I chose to download the images locally, to then resize them and to finally cache them on disk.
&lt;br&gt;

&lt;br&gt;
I run these tasks in parallel and wait for all of them to finish, using the &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~msdn.microsoft.com/en-us/library/dd537609.aspx&quot;&gt;TPL&lt;/a&gt;.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; TryToDownloadAllImages(Culture culture)
{
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; tasks = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; List&amp;lt;Task&amp;gt;();
    &lt;span class=&quot;kwrd&quot;&gt;foreach&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; item &lt;span class=&quot;kwrd&quot;&gt;in&lt;/span&gt; culture.Items)
    {
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; localPath = Path.Combine(_pathConfiguration.ImagesFolderPath, item.ImageName);
        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (!File.Exists(localPath))
            tasks.Add(CreateImageDownloadTask(item.Image, localPath));
    }
    Task.WaitAll(tasks.ToArray());     
}&lt;/pre&gt;
&lt;/div&gt;
Downloading a remote file is straightforward using the &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~msdn.microsoft.com/en-us/library/ez801hhe.aspx&quot;&gt;WebClient&lt;/a&gt; class. Right after downloading the image, I use the ImageBuilder singleton to resize the image to a width of 340px.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; Task CreateImageDownloadTask(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; imageUrl, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; localPath)
{
    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; Task.Factory.StartNew(() =&amp;gt;
    {
        &lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; client = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; WebClient())
        {
            &lt;span class=&quot;kwrd&quot;&gt;try&lt;/span&gt;
            {                        
                client.DownloadFile(imageUrl, localPath);
                ImageBuilder.Current.Build(
                    localPath, 
                    localPath, 
                    &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ResizeSettings(&lt;span class=&quot;str&quot;&gt;&quot;maxwidth=340&quot;&lt;/span&gt;));
            }            
            &lt;span class=&quot;kwrd&quot;&gt;catch&lt;/span&gt; (ArgumentException) 
            {
                &lt;span class=&quot;rem&quot;&gt;// filename malformatted; swallow&lt;/span&gt;
            }
        }
    });                    
}                
&lt;/pre&gt;
Now that I have my resized images, I can render them in my view. This is &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~nancyfx.org/&quot;&gt;NancyFx&lt;/a&gt; with the Razor view engine by the way.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;loading&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
    Loading..
&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;      
&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;container&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;display:none;&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
    @foreach (var item in Model.Items)
    {               
       &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;@item.Url&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;/Content/images/@item.ImageName&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;@item.Name&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;@item.Name&quot;&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;/&amp;gt;&lt;/span&gt;
       &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;             
    }
&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
To achieve the masonry effect, I used this &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~masonry.desandro.com/&quot;&gt;jQuery plug-in&lt;/a&gt;. The one tricky part here is to only initialize the effect after all the images have really loaded. For this, I used the &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://github.com/desandro/imagesloaded&quot;&gt;imagesLoaded&lt;/a&gt; plug-in.&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;$container.imagesLoaded(function () {
    $loading.hide();
    $container.show();
    $container.masonry({
        itemSelector: &lt;span class=&quot;str&quot;&gt;&apos;img&apos;&lt;/span&gt;
    });
});&lt;/pre&gt;
One last thing I wanted, was to center the masonry on screen, but since I didn&apos;t want to use a fixed width, I had to dynamically recalculate the optimal width each time the window is resized.&amp;nbsp;&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; setContainerWidth = function (container) {
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; imageWidth = 340;
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; bodyWidth = $(&lt;span class=&quot;str&quot;&gt;&quot;body&quot;&lt;/span&gt;).width();
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; numberOfImagesNextToEachother = Math.floor(bodyWidth / imageWidth);
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; optimalWidth = (imageWidth * numberOfImagesNextToEachother) + (numberOfImagesNextToEachother * 4);
    container.css(&lt;span class=&quot;str&quot;&gt;&quot;width&quot;&lt;/span&gt;, optimalWidth + &lt;span class=&quot;str&quot;&gt;&quot;px&quot;&lt;/span&gt;);
};
$(window).resize(function () {
    setContainerWidth($container);
});&lt;/pre&gt;
&lt;/div&gt;
Since we have the width of the images (340px), we can use trivial math to calculate the optimal amount of width we can consume.
&lt;br&gt;

&lt;br&gt;
&lt;i&gt;You can find the &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~antwerp-culture.apphb.com/&quot;&gt;working bits on AppHarbor&lt;/a&gt;. Source is &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://github.com/JefClaes/Antwerp.Apps.CultureMosaic&quot;&gt;on GitHub&lt;/a&gt;.&lt;/i&gt;
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;Where to pee in Antwerp?&lt;/b&gt;
&lt;br&gt;
&lt;b&gt;
&lt;br&gt;&lt;/b&gt;
The next application is a mobile web application that uses &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~api.antwerpen.be/v1/infrastructuur/openbaartoilet.json&quot;&gt;the public toilets dataset&lt;/a&gt; to show the nearest toilets based on your location.
&lt;br&gt;

&lt;br&gt;
&lt;div style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~3.bp.blogspot.com/-ZiI5COwno8Y/UM3r7T70l3I/AAAAAAAABg0/Jf_b_1A_ZBc/s1600/wheretopee.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;640&quot; src=&quot;http://3.bp.blogspot.com/-ZiI5COwno8Y/UM3r7T70l3I/AAAAAAAABg0/Jf_b_1A_ZBc/s640/wheretopee.PNG&quot; width=&quot;448&quot; /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;br&gt;
I wanted to introduce a constraint client-side of having to work with a somewhat crooked dataset, that&apos;s why I just return the dataset using Nancy as is.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; ToiletsModule()
{
    Get[&lt;span class=&quot;str&quot;&gt;&quot;/Toilets&quot;&lt;/span&gt;] = p =&amp;gt;
    {
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; response = Response.AsFile(&lt;span class=&quot;str&quot;&gt;@&quot;Content\json\toilets.json&quot;&lt;/span&gt;);
        response.ContentType = &lt;span class=&quot;str&quot;&gt;&quot;application/json&quot;&lt;/span&gt;;
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; response;
    };
}&lt;span style=&quot;font-family: Times New Roman;&quot;&gt;&lt;span style=&quot;white-space: normal;&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
At the client, I&apos;m using &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~jquerymobile.com/&quot;&gt;jQuery Mobile&lt;/a&gt; and &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~angularjs.org/&quot;&gt;angular.js&lt;/a&gt;. It had been a while since I had done something with jQuery Mobile, but this version felt very solid (compared to the beta versions I played with before). Turns out though, that to make jQuery Mobile and angular.js play nice, you have to include the &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://github.com/tigbro/jquery-mobile-angular-adapter&quot;&gt;jQuery Mobile Angular adapter&lt;/a&gt;. The size of all these libraries unminified was a performance hog; &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2012/11/nancyfx-and-bundling-with-cassette.html&quot;&gt;Cassette&lt;/a&gt; to the rescue.
&lt;br&gt;

&lt;br&gt;
The first thing you do with angular, is defining a module. &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~docs.angularjs.org/guide/module&quot;&gt;A module&lt;/a&gt; instantiates, wires and bootstraps the application.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; toiletApp = { };        
toiletApp.module = angular.module(&lt;span class=&quot;str&quot;&gt;&apos;toiletModule&apos;&lt;/span&gt;, []);&lt;/pre&gt;
To separate concerns, and make things testable, angular &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~docs.angularjs.org/guide/dev_guide.services.creating_services&quot;&gt;lets you define services&lt;/a&gt; for your application using a factory. By using a factory you also make your service an &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~docs.angularjs.org/guide/di&quot;&gt;injectable dependency&lt;/a&gt; for other parts of your application.
&lt;br&gt;
I added a toilet service to this module which makes the ajax call, sorts the results based on nearest by, to eventually make them available to the caller by invoking a callback.&amp;nbsp;The &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~docs.angularjs.org/api/ng.$http&quot;&gt;$http&lt;/a&gt; dependency is one of angular&apos;s core services that lets you do ajax requests.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;toiletApp.module.factory(&lt;span class=&quot;str&quot;&gt;&apos;toiletService&apos;&lt;/span&gt;, function ($http, Toilet) {
&lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; {
    getToilets: function (onSucess, onError, coordinates) {
        $http
            .&lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;(&lt;span class=&quot;str&quot;&gt;&apos;toilets&apos;&lt;/span&gt;)
            .success(function (data) {
                &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; toilets = [];
                &lt;span class=&quot;kwrd&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; i = 0; i &amp;lt; data.openbaartoilet.length; i++) {
                    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; toilet = data.openbaartoilet[i];
                    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; ourToilet = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Toilet(
                        toilet.omschrijving,
                        toilet.point_lat,
                        toilet.point_lng,
                        toilet.betalend === &lt;span class=&quot;str&quot;&gt;&quot;niet betalend&quot;&lt;/span&gt; ? &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt; : &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;,
                        toilet.straat,
                        toilet.huisnummer);
                    toilets.push(ourToilet);
                }
                &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (coordinates) {
                    toilets.sort(function (a, b) {
                        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; aDistance = a.calculateDistance(coordinates);
                        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; bDistance = b.calculateDistance(coordinates);
                        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (aDistance &amp;lt; bDistance)
                            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; -1;
                        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (aDistance &amp;gt; bDistance)
                            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; 1;
                        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; 0;
                    });
                }
                onSucess(toilets);
            })
            .error(function() { onError() });
    }
};&lt;/pre&gt;
You might have noticed the Toilet dependency; into this class I project the items returned from the ajax call.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;toiletApp.module.factory(&lt;span class=&quot;str&quot;&gt;&apos;Toilet&apos;&lt;/span&gt;, function () {               
&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; Toilet = function (name, lat, lng, isPaying, street, houseNumber) {
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; lastCalculatedCoord;
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; lastCalculatedDistance;
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.name = name;
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.latitude = lat;
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.longitude = lng;
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.isPaying = isPaying;
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.street = street;
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.houseNumber = houseNumber;
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.lastCalculatedDistance = function () {
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; lastCalculatedDistance;
    };
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.calculateDistance = function (coordinates) {
        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (coordinates) {
            &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (lastCalculatedCoord == coordinates) {
                &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; lastCalculatedDistance;
            }
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; currentPosLatLon = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; LatLon(coordinates.latitude, coordinates.longitude);
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; destinationPosLatLon = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; LatLon(&lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.latitude, &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.longitude);
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; dist = Math.ceil(currentPosLatLon.distanceTo(destinationPosLatLon) * 1000);
            lastCalculatedCoord = coordinates;
            lastCalculatedDistance = dist;
            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; lastCalculatedDistance;
        }
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;;
    };
    &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.getMapUrl = function () {
        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; coord = &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.latitude + &lt;span class=&quot;str&quot;&gt;&quot;,&quot;&lt;/span&gt; + &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;.longitude;
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;str&quot;&gt;&quot;...&quot;&lt;/span&gt;;
    };
};&lt;/pre&gt;
The Toilet class also has a method to calculate the distance from the item to any given coordinate. I first wanted to make use of the &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://developers.google.com/maps/documentation/distancematrix/&quot;&gt;Google Distance Matrix API&lt;/a&gt; to calculate the actual travel distance, but that didn&apos;t really work out to well for more than 100 items; you can&apos;t batch your requests, and the free version of the API has a threshold on the amount of queries. I turned to calculating the great-circle distance instead, using &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.movable-type.co.uk/scripts/latlong.html&quot;&gt;this library&lt;/a&gt;.
&lt;br&gt;

&lt;br&gt;
Since we want to make use of the client&apos;s coordinates, I also defined a geo service, which makes use of the &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.jefclaes.be/2010/12/html5-geolocation-api-is-scary-good.html&quot;&gt;HTML5 GeoLocation API&lt;/a&gt; to query for the user&apos;s coordinates.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;toiletApp.module.factory(&lt;span class=&quot;str&quot;&gt;&apos;geoService&apos;&lt;/span&gt;, function() {
    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; {
        getLocation: function (onSucess, onError, onNotAllowed) {
            &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (navigator.geolocation) {
                navigator.geolocation.getCurrentPosition(
                    function (position) {
                        onSucess(position);
                    },
                    function (err) {
                        onError(err);
                    }
                );
            } &lt;span class=&quot;kwrd&quot;&gt;else&lt;/span&gt; {
                onNotAllowed(message);
            }
        }
    };
});&lt;/pre&gt;
After defining these pieces, I injected them into the ContentController. The &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~docs.angularjs.org/guide/dev_guide.mvc.understanding_controller&quot;&gt;controller&lt;/a&gt; is responsible for augmenting angular&apos;s scope, which is the connection to our view, our model. Properties and methods are made available to the view by augmenting the $scope variable. There is quite some not that interesting tinkering going on in the controller, so I left it out for brevity.&lt;/div&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;toiletApp.ContentController = function ($scope, geoService, toiletService) {
    $scope.toilets = [];
    ...
}&lt;/pre&gt;
After setting ng-app and ng-controller, we can make use of angular&apos;s &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~docs.angularjs.org/guide/directive&quot;&gt;directives&lt;/a&gt; and &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~docs.angularjs.org/guide/dev_guide.templates.filters.using_filters&quot;&gt;filters&lt;/a&gt; to render our page. Directives are - as the documentation puts it - a way to teach HTML new tricks. Think of it as HTML helpers. Filters are used to format data.
&lt;br&gt;

&lt;br&gt;
The view binds each toilet to a new collapsible div. The content of the div shows some basic information, and a button which shows the toilet on a map.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;html&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;ng-app&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;toiletModule&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
        ....
    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;data-role&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;page&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;home&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;ng-controller&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;toiletApp.ContentController&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt; 
            
            &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;data-role&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;header&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;Where to pee in Antwerp?&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;#&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;data-icon&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;refresh&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;ng-click&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;reload()&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;Reload&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;                
            &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt; 
            
            &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;data-role&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;content&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
                
                &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;content-primary&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;    
                    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;{{ message }}&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
                   
                    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;data-role&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;collapsible&quot;&lt;/span&gt; 
                         &lt;span class=&quot;attr&quot;&gt;ng-repeat&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;toilet in toilets | limitTo: itemsLimit()&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;h3&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
                            {{ toilet.name }} 
                            ({{ toilet.lastCalculatedDistance() | distance }}) 
                            {{ toilet.isPaying | isPayingDollarSign }} 
                        &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;h3&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;                        
                        &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;strong&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;Name: &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;strong&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;{{ toilet.name }}&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;strong&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;Distance: &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;strong&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;{{ toilet.last..() | distance }}&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;strong&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;Paying: &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;strong&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;{{ toilet.isPaying | isPayingYesNo }}&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;strong&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;Street: &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;strong&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;{{ toilet.street }} &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;strong&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;Housenumber: &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;strong&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;{{ toilet.houseNumber }} &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;{{ toilet.getMapUrl() }}&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;data-role&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;button&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
                            Show location on a map
                        &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;                     
                             
                    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;ng-show&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;hasMoreItemsToShow()&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;ng-click&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;showMoreItems()&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;Show more toilets&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;    
                    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;        
                &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;        
            &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt; 
            
            &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;data-role&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;footer&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;h4&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;Made possible by Antwerp Open Data&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;h4&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt; 
        &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;    
&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
You might notice how I used filters to format the isPaying and distance property. These are also defined in the module.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;toiletApp.module.filter(&lt;span class=&quot;str&quot;&gt;&apos;isPayingDollarSign&apos;&lt;/span&gt;, function () {
    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; function (value) {
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; value ? &lt;span class=&quot;str&quot;&gt;&quot;$&quot;&lt;/span&gt; : &lt;span class=&quot;str&quot;&gt;&quot;&quot;&lt;/span&gt;;
    }
});
toiletApp.module.filter(&lt;span class=&quot;str&quot;&gt;&apos;isPayingYesNo&apos;&lt;/span&gt;, function () {
    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; function (value) {
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; value ? &lt;span class=&quot;str&quot;&gt;&quot;Yes&quot;&lt;/span&gt; : &lt;span class=&quot;str&quot;&gt;&quot;No&quot;&lt;/span&gt;;
    }
});
toiletApp.module.filter(&lt;span class=&quot;str&quot;&gt;&apos;distance&apos;&lt;/span&gt;, function () {
    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; function (value) {
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; value ? value + &lt;span class=&quot;str&quot;&gt;&quot;m&quot;&lt;/span&gt; : &lt;span class=&quot;str&quot;&gt;&quot;&quot;&lt;/span&gt;;
    }
});&lt;/pre&gt;
&lt;i&gt;You can find the&amp;nbsp;&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~antwerp-wheretopee.apphb.com/&quot;&gt;working bits on AppHarbor&lt;/a&gt;. Source is&amp;nbsp;&lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://github.com/JefClaes/Antwerp.Apps.WhereToPee&quot;&gt;on GitHub&lt;/a&gt;.&lt;/i&gt;
&lt;br&gt;
&lt;i&gt;
&lt;br&gt;&lt;/i&gt;
&lt;b&gt;Summary&lt;/b&gt;
&lt;br&gt;

&lt;br&gt;
I can only applaud the Open Data initiative; my hope is that the datasets get more interesting though. Which also makes me wonder if the government is even measuring the more interesting stuff?
&lt;br&gt;

&lt;br&gt;
All in all, these two applications aren&apos;t very innovative. Yet, they did give me the opportunity to experiment with some stuff I can&apos;t play with on the day job (yet). I&apos;m always amazed how quickly you can slap together a small application using the available building blocks out there. I&apos;m most content with picking up angular.js; I will be advertising this framework in a professional context from now on.&lt;/div&gt;
&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/36480986/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/36480986/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/36480986/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/36480986/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/36480986/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/36480986/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/36480986/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/36480986/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/4081102401222578054/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/36480986/0/jefclaes~Released-My-Antwerp-Open-Data-submissions.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/4081102401222578054?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/4081102401222578054?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/36480986/0/jefclaes~Released-My-Antwerp-Open-Data-submissions.html' title='Released: My Antwerp Open Data submissions'/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-TVB6EGqecTA/UM3rlOloOEI/AAAAAAAABgk/DkgWRV8TiP8/s72-c/antwerp+culre.PNG' height='72' width='72'/><thr:total>1</thr:total></entry>
<entry gd:etag='W/&quot;A0YMRHs4fyp7ImA9WhNWE04.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2012/12/show-more-pagination-with-angularjs.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-4385302750473860617</id><published>2012-12-12T19:57:00.000+01:00</published><updated>2012-12-12T20:06:25.537+01:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2012-12-12T20:06:25.537+01:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='CodeSnippets'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='Browser'/><title>Show More pagination with angular.js</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
I built my first application with &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~angularjs.org/&quot;&gt;angular.js&lt;/a&gt; over these last few weeks (not during business hours), and although I still have lots and lots to discover and learn, I think I somewhat grasp the basics.
&lt;br&gt;

&lt;br&gt;
In the application I built, I had to implement paging because rendering all the items at once was too slow on mobile devices (on my Windows Phone 7 anyways). The paging variant I decided on was the &apos;Show More&apos; technique.
&lt;br&gt;

&lt;br&gt;
Let me walk you - as an introduction to Angular - through a simple application that uses paging for a list of 24 items.
&lt;br&gt;

&lt;br&gt;
We start by defining a &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~docs.angularjs.org/guide/module&quot;&gt;module&lt;/a&gt;. In an Angular module, you should instantiate, wire and bootstrap parts of your application.
&lt;br&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; module = angular.module(&lt;span class=&quot;str&quot;&gt;&apos;module&apos;&lt;/span&gt;, []);&lt;/pre&gt;
We can already bind the module to our empty view.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;ng-app&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;module&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
In our module we want to define an itemService which will return an array of 24 items. By using a factory method we make our service an &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~docs.angularjs.org/guide/di&quot;&gt;injectable dependency&lt;/a&gt; for other parts of our application.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;module.factory(&lt;span class=&quot;str&quot;&gt;&apos;itemService&apos;&lt;/span&gt;, function() {
    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; {
        getAll : function() {
            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; items = [];
            &lt;span class=&quot;kwrd&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; i = 1; i &amp;lt; 25; i++) {
                items.push(&lt;span class=&quot;str&quot;&gt;&apos;Item &apos;&lt;/span&gt; + i);                       
            }
            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; items;
        }
    };              
});&lt;/pre&gt;
Now that we have a service that can give us items, we want to work towards actually rendering these items. To do that, we&apos;ll have to define a &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~docs.angularjs.org/guide/dev_guide.mvc.understanding_controller&quot;&gt;controller&lt;/a&gt;. An Angular controller lets you augment an instance of Angular&apos;s scope, which in its turn serves as your connection to the view.&amp;nbsp;&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;ListController = function($scope, itemService) {
    $scope.items = itemService.getAll();    
};&lt;/pre&gt;
Notice how we use dependency injection to inject an instance of the itemService.
&lt;br&gt;

&lt;br&gt;
All our items are available on the scope now, but we still have an empty view. Let&apos;s fix that.
&lt;br&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;ng-app&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;module&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;ng-controller&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;ListController&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;ul&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
       &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;li&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;ng-repeat&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;item in items&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
          {{ item }}        
       &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;li&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;               
    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;ul&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;Show more&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;    
&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
Items are being rendered making use of Angular&apos;s built-in ng-repeat directive. &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~docs.angularjs.org/guide/directive&quot;&gt;Directives&lt;/a&gt; are - as the documentation puts it nicely - a way to teach HTML new tricks. MVC folks may think of it as HTML helpers.
&lt;br&gt;

&lt;br&gt;
What&apos;s left to do in this example, is what we initially set out to do; implement paging. For that, we&apos;ll first add some extra variables to the controller, and some new methods on to the scope. These should be self-descriptive.&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;
ListController = function($scope, itemService) {
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; pagesShown = 1;
    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; pageSize = 5;
    $scope.items = itemService.getAll();
    $scope.itemsLimit = function() {
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; pageSize * pagesShown;
    };
    $scope.hasMoreItemsToShow = function() {
        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; pagesShown &amp;lt; ($scope.items.length / pageSize);
    };
    $scope.showMoreItems = function() {
        pagesShown = pagesShown + 1;         
    };
};&#x200B;&lt;/pre&gt;
We can now make use of those new methods on the scope in our view.&amp;nbsp;&lt;/div&gt;
&lt;pre class=&quot;csharpcode&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;ng-app&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;module&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;ng-controller&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;ListController&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;ul&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
       &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;li&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;ng-repeat&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;item in items | limitTo: itemsLimit()&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
          {{ item }}        
       &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;li&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;               
    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;ul&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;ng-show&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;hasMoreItemsToShow()&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;ng-click&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;showMoreItems()&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;Show more&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;    
&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
We made use of directives to add behaviour to the &apos;Show more&apos; button and used the limitTo filter to limit the number of items rendered. Filters are used to format display data.
&lt;br&gt;

&lt;br&gt;
&lt;b&gt;Here is the full &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~jsfiddle.net/JefClaes/HPu9n/9/&quot;&gt;jsFiddle&lt;/a&gt;.&lt;/b&gt;
&lt;br&gt;

&lt;br&gt;
I&apos;m pretty sure you can abstract paging into a reusable component, but I thought this scenario shows a good bunch of basic Angular concepts.
&lt;br&gt;

&lt;br&gt;
&lt;i&gt;So what are your thoughts on Angular? Pretty slick, right? Or are you already using Angular?&lt;/i&gt;&lt;/div&gt;&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/36381141/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/36381141/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/36381141/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/36381141/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/36381141/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/36381141/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/36381141/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/36381141/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/4385302750473860617/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/36381141/0/jefclaes~Show-More-pagination-with-angularjs.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/4385302750473860617?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/4385302750473860617?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/36381141/0/jefclaes~Show-More-pagination-with-angularjs.html' title='Show More pagination with angular.js'/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><thr:total>3</thr:total></entry>
<entry gd:etag='W/&quot;D0ENQ3w9fyp7ImA9WhNWEEs.&quot;'>
<feedburner:origLink>http://www.jefclaes.be/2012/12/its-not-cake-we-are-baking.html</feedburner:origLink><id>tag:blogger.com,1999:blog-1165127106246535168.post-1453800137926801691</id><published>2012-12-09T16:08:00.000+01:00</published><updated>2012-12-09T16:08:12.267+01:00</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2012-12-09T16:08:12.267+01:00</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Nhibnerate'/><category scheme='http://www.blogger.com/atom/ns#' term='Ramblings'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><title>It's not cake we are baking</title><content type='html'>&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;
I recently watched a talk on Vimeo where &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://twitter.com/ChristinGorman&quot;&gt;Christin Gorman&lt;/a&gt; talks about how cookie dough relates to Hibernate; why use the generic, bloated and one-fits-all solution when you can mix together your own yummy cookie dough? We should aspire to be the Gordon Ramsey of software, not the college student who can only cook Ramen noodles. If you haven&apos;t watched or listened to her talk, you should; it&apos;s only a few minutes long, and she brings it really well. &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~vimeo.com/28885655&quot;&gt;Go ahead&lt;/a&gt;, I&apos;ll wait.
&lt;br&gt;

&lt;br&gt;
When I first watched her talk, it rubbed me the wrong way, but I couldn&apos;t yet figure out the flaw in her plea. It recently dawned upon me that we are not in the business of baking cakes, but we are in the business of serving hungry people. And those people really don&apos;t care which ingredients were used to bake your cake; they only care about how it tastes, how fast it&apos;s served, and how much they&apos;re paying for it. And although the romantic in me really sympathizes with her view, the realist just can&apos;t. Over these few years only, each and every attempt of a hand-rolled ORM I&apos;ve seen, ended with a horrible aftertaste. There is no way that you spend as much time building a good API from scratch as you do setting up an existing one. Writing and maintaining your own ORM is &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~ayende.com/blog/1340/25-reasons-not-to-write-your-own-object-relational-mapper&quot;&gt;not a trivial thing to do&lt;/a&gt;, and there are already so many flavors* - from grandma&apos;s recipe to decadent supreme deluxe - to pick from, that it&apos;s hardly ever a justified decision. Read the package and choose the option that satisfies your daily caloric needs, and go from there. You can still sweeten, or swap some ingredients, before serving. And if you really can&apos;t resist - which is perfectly healthy, bake all the cake you want, at home. Maybe, one day, you can bring a successful one to work.
&lt;br&gt;

&lt;br&gt;
* &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~nhforge.org/&quot;&gt;NHibernate&lt;/a&gt;, &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~msdn.microsoft.com/en-us/data/ef.aspx&quot;&gt;Entity Framework&lt;/a&gt;, &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~code.google.com/p/dapper-dot-net/&quot;&gt;Dapper&lt;/a&gt;, &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~https://github.com/robconery/massive&quot;&gt;Massive&lt;/a&gt;, &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~simple.data/&quot;&gt;Simple.Data&lt;/a&gt;, &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.llblgen.com/&quot;&gt;LLBLGen Pro&lt;/a&gt;, &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~www.telerik.com/products/orm.aspx&quot;&gt;OpenAccess&lt;/a&gt;, &lt;a href=&quot;http://feed.jefclaes.be/~/t/0/0/jefclaes/~subsonicproject.com/&quot;&gt;SubSonic&lt;/a&gt; ...&lt;/div&gt;
&lt;Img align=&quot;left&quot; border=&quot;0&quot; height=&quot;1&quot; width=&quot;1&quot; style=&quot;border:0;float:left;margin:0;padding:0&quot; hspace=&quot;0&quot; src=&quot;http://feed.jefclaes.be/~/i/36292084/0/jefclaes&quot;&gt;

&lt;div style=&quot;clear:both;padding-top:0.2em;&quot;&gt;&lt;a title=&quot;Add to Any&quot; href=&quot;http://feed.jefclaes.be/_/26/36292084/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/addtoany20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Bit.ly&quot; href=&quot;http://feed.jefclaes.be/_/25/36292084/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/bitly20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to FaceBook&quot; href=&quot;http://feed.jefclaes.be/_/2/36292084/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/fbshare20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Share on Google+&quot; href=&quot;http://feed.jefclaes.be/_/30/36292084/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/googleplus20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Add to Reddit&quot; href=&quot;http://feed.jefclaes.be/_/1/36292084/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/reddit20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Tweet This&quot; href=&quot;http://feed.jefclaes.be/_/24/36292084/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/twitter20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;a title=&quot;Subscribe by RSS&quot; href=&quot;http://feed.jefclaes.be/_/20/36292084/JefClaes&quot;&gt;&lt;img height=&quot;20&quot; src=&quot;http://assets.feedblitz.com/i/rss20.png&quot; style=&quot;border:0;margin:0;padding:0;&quot;&gt;&lt;/a&gt;&amp;#160;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.jefclaes.be/feeds/1453800137926801691/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://feed.jefclaes.be/~/36292084/0/jefclaes~Its-not-cake-we-are-baking.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/1453800137926801691?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1165127106246535168/posts/default/1453800137926801691?v=2'/><link rel='alternate' type='text/html' href='http://feed.jefclaes.be/~/36292084/0/jefclaes~Its-not-cake-we-are-baking.html' title='It&apos;s not cake we are baking'/><author><name>Jef Claes</name><uri>https://plus.google.com/112241785627837335137</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-ZzXnkFyDsxU/AAAAAAAAAAI/AAAAAAAABhw/avxM8eCzMes/s512-c/photo.jpg'/></author><thr:total>6</thr:total></entry>
</feed>

