<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Jef Claes</title>
    <link>https://jefclaes.be/feeds/posts/default</link>
    <description>Recent content on Jef Claes</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    
    <lastBuildDate>Sun, 12 Aug 2018 14:58:00 +0200</lastBuildDate>
    <atom:link href="https://jefclaes.be/feeds/posts/default" rel="self" type="application/rss" />
    
    <item>
      <title>GES scavenging and the hidden cost of link events</title>
      <link>https://jefclaes.be/2018/08/ges-scavenging-and-hidden-cost-of-link.html</link>
      <pubDate>Sun, 12 Aug 2018 14:58:00 +0200</pubDate>
      <guid>https://jefclaes.be/2018/08/ges-scavenging-and-hidden-cost-of-link.html</guid>
      <description>&lt;p&gt;Somewhere around a year ago, we started using
&lt;a href=&#34;https://eventstore.org/&#34;&gt;GES&lt;/a&gt; in production as the primary data store
of our new loyalty system. The system stores two types of data.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;External services push batches of dumb downed events to the loyalty
system. For example: a user logged on, played a game or participated
in a competition. These events are &lt;strong&gt;transient&lt;/strong&gt; by nature. Once the
loyalty system has processed them, they only need to be kept around
for a few days.&lt;/li&gt;
&lt;li&gt;When these ingress events are processed, they go through a mini
pipeline in which each event is assigned a specific weight, for then
to be aggregated and translated to a command. This command awards a
user with virtual currency to spend in the loyalty shop and a number
of points contributing to a higher rank - unlocking more priviliges.
The state machine that stores a user&amp;rsquo;s balance and points is backed
by a stream which is &lt;strong&gt;stored indefinitely&lt;/strong&gt;. Unless the user asks
to be forgotten that is.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As a rough estimate, for every 1000 ingress transient events, only 1
needs to be stored indefinitely as part of a state machine.&lt;/p&gt;
&lt;p&gt;When implementing this more than a year ago, I thought I had done my
homework and knew how to make sure the ingress events would get cleaned
up. First you make sure the &lt;em&gt;$maxAge&lt;/em&gt; metadata is set on the streams you
want to clean up, for then to schedule the scavenging process (other
databases use the term vacuum). This worked without any surprises. Once
scavenging had been run, I could see disk space being released. However,
after a few months I started to become a bit suspicious of my
understanding of the scavening process. GES was releasing less disk
space than I expected.&lt;/p&gt;
&lt;p&gt;Even though, we had been quite generous while provisioning the nodes
with disk space, we would run out very soon. Much to my frustration, the
&amp;ldquo;Storage is cheap&amp;rdquo; mantra gets thrown around too lightly. While the
statement in essence is not wrong, for a database like GES that&amp;rsquo;s built
on top of a log, more data also means slower node restarts (index
verification), slower scavenges and slower &lt;em&gt;$all&lt;/em&gt; subscriptions.&lt;/p&gt;
&lt;p&gt;GES has no built-in system catalog that allows you to discover which
streams are taking up all this space. However, you can implement an $all
subscription and count events per stream or even count the bytes in the
event payload.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Main(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;[] args) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; conn = EventStoreConnection.Create(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ConnectionSettings.Create().Build(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; IPEndPoint(IPAddress.Parse(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;), &lt;span style=&#34;color:#ae81ff&#34;&gt;1113&lt;/span&gt;))) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        conn.ConnectAsync().Wait(&lt;span style=&#34;color:#ae81ff&#34;&gt;5000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        conn.SubscribeToAllFrom(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Position.Start,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            CatchUpSubscriptionSettings.Default,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            eventAppeared: Count, liveProcessingStarted: Print, subscriptionDropped: Warn,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            userCredentials: &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; UserCredentials(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;admin&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;changeit&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Console.ReadLine();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Print(EventStoreCatchUpSubscription sub) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; count &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;  counts.ToList().OrderByDescending(x =&amp;gt; x.Value)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Console.WriteLine(&lt;span style=&#34;color:#e6db74&#34;&gt;$&amp;#34;{count.Key}: {count.Value}&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; Task Count(EventStoreCatchUpSubscription sub, ResolvedEvent e) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; ev = e.Link ?? e.Event;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (!counts.ContainsKey(ev.EventStreamId)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        counts.Add(ev.EventStreamId, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        counts[ev.EventStreamId] += &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Task.CompletedTask;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Output&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// $et-LoggedIn : ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// $et-GamePlayed : ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Inspecting the results, we found that the streams emitted by the
built-in system projections contained a disproportionate amount of
events. Most of them were ingress events and should have been long
scavenged! As it turns out, this was a wrong assumption on my part.
Built-in projections build new streams by linking to the original event
(instead of a emitting a new one). But when an event is scavenged,
events linking to the original event still linger around on disk.
Although link events are much smaller than the original event usually -
it&amp;rsquo;s just a pointer, the bytes used to store the pointer &lt;em&gt;and&lt;/em&gt; the event
envelope still take up quite some space when there&amp;rsquo;s billions of them!&lt;/p&gt;
&lt;p&gt;Luckily, I was only using a small portion of the built-in projections. I
created a custom projection that only created streams I was actually
interested in, pointed my code in the right direction, stopped the
built-in projections and deleted the now irrelevant streams.&lt;/p&gt;
&lt;p&gt;Running the scavenging process after being able to delete all these
streams was very satisfying. The scavenging process loops through all
the transaction file chunks one by one. It reads a chunk and writes a
temporary new one, only containing the events that haven&amp;rsquo;t been deleted.
Once it reaches the end of the file, it swaps out the newly written file
with the old one. Since writes are slower than reads, this makes that
scavenging is actually way faster when there&amp;rsquo;s more to scavenge - or
less data to be written to a new file. After all the chunks have been
scavenged, the process merges the now smaller files into new chunks when
possible. This process is quite transparant by design; all you have to
do is list the files in the data directory when scavenging.&lt;/p&gt;
&lt;p&gt;When this whole process was complete, used disk space went down from
410GB to 47GB! Having trimmed all this excessive data, scavenging is
faster (hours not days), node restarts are faster and resetting an $all
subscription makes me less anxious.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Amazon Redshift - Fundamentals</title>
      <link>https://jefclaes.be/2018/05/amazon-redshift-fundamentals.html</link>
      <pubDate>Tue, 01 May 2018 14:17:00 +0200</pubDate>
      <guid>https://jefclaes.be/2018/05/amazon-redshift-fundamentals.html</guid>
      <description>&lt;p&gt;Late 2017, we set out to replace and upgrade our existing reporting and
analytics infrastructure with something that would be a better fit for
our workloads. Keeping costs and required maintenance at a minimum would
be a nice plus, making for an easy sell. After a bit of research, it was
obvious &lt;a href=&#34;https://aws.amazon.com/redshift/&#34;&gt;Amazon Redshift&lt;/a&gt; had the
potential to tick all the right boxes. While steadily porting the most
problematic workloads away from our existing infrastructure, I started
writing an investigative article on the fundamental concepts of Amazon
Redshift. I learned a lot studying each individual building block,
allowing me to make some small, but impactful changes to our own setup
along the way.&lt;/p&gt;
&lt;p&gt;The outcome is a 10.000 word document (1 hour reading time), covering 7
topics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Storage&lt;/li&gt;
&lt;li&gt;Distribution&lt;/li&gt;
&lt;li&gt;Importing data&lt;/li&gt;
&lt;li&gt;Table maintenance&lt;/li&gt;
&lt;li&gt;Exporting data&lt;/li&gt;
&lt;li&gt;Query processing&lt;/li&gt;
&lt;li&gt;Workload management&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The text is available in three formats:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://s3-eu-west-1.amazonaws.com/cdn.jefclaes.be/amazon-redshift-fundamentals/aws-redshift-fundamentals.html&#34;&gt;HTML&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://s3-eu-west-1.amazonaws.com/cdn.jefclaes.be/amazon-redshift-fundamentals/aws-redshift-fundamentals.epub&#34;&gt;EPUB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://s3-eu-west-1.amazonaws.com/cdn.jefclaes.be/amazon-redshift-fundamentals/aws-redshift-fundamentals.mobi&#34;&gt;MOBI&lt;/a&gt; (Kindle)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The project is open source and available &lt;a href=&#34;https://github.com/JefClaes/amazon-redshift-fundamentals&#34;&gt;on
Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks to everyone who proof-read earlier iterations and provided me
with indispensable feedback.&lt;/p&gt;
&lt;p&gt;I hope this work can teach you as much as it thought me. I&amp;rsquo;m looking
forward to your feedback.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Consumed in 2017</title>
      <link>https://jefclaes.be/2018/01/consumed-in-2017.html</link>
      <pubDate>Wed, 03 Jan 2018 21:28:00 +0100</pubDate>
      <guid>https://jefclaes.be/2018/01/consumed-in-2017.html</guid>
      <description>&lt;p&gt;Another year, another 17 books, 6 shows and 3 movies consumed. Here&amp;rsquo;s
this year&amp;rsquo;s highlights.&lt;/p&gt;
&lt;h2 id=&#34;books&#34;&gt;Books&lt;/h2&gt;
&lt;h3 id=&#34;the-zen-and-art-of-motor-cycle-maintenance&#34;&gt;The Zen and Art of Motor Cycle Maintenance&lt;/h3&gt;
&lt;p&gt;The author is a tormented soul on a quest to define quality. You&amp;rsquo;re his
passenger, driving shot gun on a CB77 Super Hawk, in for an exhausting
intellectual journey through the high mountains of reasoning. You will
often fear getting lost and feel slightly anxious that the driver might
drive of a cliff any moment, but he won&amp;rsquo;t. Once you see the top of the
mountain for the first time, you&amp;rsquo;ll be happy he doesn&amp;rsquo;t make it too easy
on you, and you&amp;rsquo;ll be more appreciative of the road that took you there.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Throughout the process of fixing the machine things always come up,
low-quality things, from a dusted knuckle to an accidentally ruined
“irreplaceable” assembly. These drain off gumption, destroy enthusiasm
and leave you so discouraged you want to forget the whole business. I
call these things “gumption traps.” &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Peace of mind isn’t at all superficial to technical work. It’s the
whole thing. That which produces it is good work and that which
destroys it is bad work. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;It’s the style that gets you; technological ugliness syruped over with
romantic phoniness in an effort to produce beauty and profit by people
who, though stylish, don’t know where to start because no one has ever
told them there’s such a thing as Quality in this world and it’s real,
not style.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://www.amazon.com/gp/product/0060589469/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;linkCode=as2&amp;amp;creativeASIN=0060589469&amp;amp;linkId=38a657fd4701b9259f0dd3e486d51045&#34;&gt;Amazon&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;the-soul-of-a-new-machine&#34;&gt;The Soul of a New Machine&lt;/h3&gt;
&lt;p&gt;The type of writing I wish there was more of. It&amp;rsquo;s the closest I&amp;rsquo;ll ever
get to experience building a mini-computer. It makes one appreciate how
much we&amp;rsquo;re standing on the shoulders of giants. So much has changed in
40 years and even more hasn&amp;rsquo;t changed at all. People will be people.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Adopting a remote, managerial point of view, you could say that the
Eagle project was a case where a local system of management worked as
it should: competition for resources creating within a team inside a
company an entrepreneurial spirit, which was channeled in the right
direction by constraints sent down from the top. But it seems more
accurate to say that a group of engineers got excited about building a
computer. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;In the sixties there was proposed a “National Data Bank,” which would,
theoretically, improve the government’s efficiency by allowing
agencies to share information. The fact that such a system could be
abused did not mean it would be, proponents said; it could be
constructed in such a way as to guarantee benign use. Nonsense, said
opponents, who managed to block the proposal; no matter what the
intent or the safeguards, the existence of such a system would
inevitably lead toward the creation of a police state.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://www.amazon.com/gp/product/0316491977/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;linkCode=as2&amp;amp;creativeASIN=0316491977&amp;amp;linkId=a467823d00576c3c9683dcf515188781&#34;&gt;Amazon&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;winter-is-coming-why-vladimir-putin-and-the-enemies-of-the-free-world-must-be-stopped&#34;&gt;Winter is Coming: Why Vladimir Putin and the Enemies of the Free World Must Be Stopped&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;ve been trying to get better educated on the history of world
politics and long-lasting international conflicts. Growing up in Western
Europe with very little direct conflict, you&amp;rsquo;re never really taught why
other parts of the world seem to be so messed up and why they&amp;rsquo;re so
angry at us.&lt;/p&gt;
&lt;p&gt;Although you might find Kasparov to be a bit &lt;em&gt;too&lt;/em&gt; convincing, he has
good reasons to hold strong opinions and is in a unique position to shed
light on what&amp;rsquo;s been happening under the Putin regime. It&amp;rsquo;s like
listening to someone who just escaped an abusive relationship. I was
remembered of Hintjens&amp;rsquo; &lt;a href=&#34;https://www.amazon.com/gp/product/1514342022/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;linkCode=as2&amp;amp;creativeASIN=1514342022&amp;amp;linkId=d4389546b4a3f69246ef5b49d3beed13&#34;&gt;The Psychopath
Code&lt;/a&gt;
more than once.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Like a weed, evil can be cut back but never entirely uprooted. It
waits for its chance to spread through the cracks in our vigilance. It
can take root in the fertile soil of our complacency, or even the
rocky rubble of the fallen Berlin Wall. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;If the road to hell is paved with good intentions, compromises on
principles are the streetlights. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;He and his junta have turned the country into a petro-state, and
exporting natural resources to an insatiable global market doesn’t
require entrepreneurs or programmers, let alone writers and
professors. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Putin and his defenders abroad bragged about Russia’s rising GDP, but
it was like taking the average temperature of all the patients in a
hospital. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The hypocrisy of condemning weak dictatorships while embracing strong
ones destroys American and European credibility and undermines any
attempt at global leadership; in fact, it seems to encourage smaller
autocracies to aspire to greater ambitions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://www.amazon.com/gp/product/1610397193/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;linkCode=as2&amp;amp;creativeASIN=1610397193&amp;amp;linkId=8cfe9da4e80d07c4aa706a1934842b7e&#34;&gt;Amazon&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;shows&#34;&gt;Shows&lt;/h2&gt;
&lt;h3 id=&#34;westworld&#34;&gt;Westworld&lt;/h3&gt;
&lt;p&gt;In a not so distant future, the rich will be spending their free time
visiting amusement parks inhabited by lifelike robots. Once you pay your
entry ticket, you can be the protagonist of any story you want. Maybe
you want good value for money and go on an epic quest chasing a bad guy
to the edge of the park, or maybe you just want to drink, gamble and
maybe kill a few randoms for fun in the saloon just feet away from the
drop-off point? Like playing Red Dead Redemption post-virtual reality.&lt;/p&gt;
&lt;p&gt;The setting, cast and especially the story line are out of this world.
Reading up on fan theories after the show is half the fun. It&amp;rsquo;s amazing
how many plausible theories were put out and how a small community is
able to dissect every little scene looking for hints to figure out the
park&amp;rsquo;s mysterious past.&lt;/p&gt;
&lt;p&gt;This show made me question if I understood what it is that makes us
human. Aren&amp;rsquo;t we all just the result of our pre-programmed genetics and
the events we experience throughout our lives?&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2018-01-03-consumed-in-2017-ww.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2018-01-03-consumed-in-2017-ww.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.imdb.com/title/tt0475784/?ref_=nv_sr_1&#34;&gt;IMDB&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;stranger-things-2&#34;&gt;Stranger Things 2&lt;/h3&gt;
&lt;p&gt;I just finished watching this one last night. It&amp;rsquo;s like reading a
really good Stephen King novel, but in color. I noticed yesterday&amp;rsquo;s
season finale was 61 minutes long; good things do happen when you&amp;rsquo;re not
constrained to TV time.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2018-01-03-consumed-in-2017-st.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2018-01-03-consumed-in-2017-st.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.netflix.com/be/title/80057281&#34;&gt;Netflix&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;podcasts&#34;&gt;Podcasts&lt;/h2&gt;
&lt;p&gt;Commutes have gotten earlier and longer this year. I&amp;rsquo;ve cut back on the
technology podcasts in favor of a more broad range of topics.&lt;/p&gt;
&lt;h3 id=&#34;the-joe-rogan-experience&#34;&gt;The Joe Rogan Experience&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s a bit like sitting in on a conversation between two people at a
bar. One person is a talkative and enjoyable guy, not afraid to ask
questions and the other is happy to drop knowledge on a specific (and
often fringe) topic. Topics range from diet and fitness, to economy and
politics. Some episodes that stood out for me recently are the ones with
&lt;a href=&#34;http://podcasts.joerogan.net/podcasts/colin-moriarty-3&#34;&gt;Colin Moriarty&lt;/a&gt;
and &lt;a href=&#34;http://podcasts.joerogan.net/podcasts/nina-teicholz&#34;&gt;Nina
Teicholz&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;conversations-with-tyler&#34;&gt;Conversations with Tyler&lt;/h3&gt;
&lt;p&gt;The same concept, being a one-on-one conversation covering a wide
range of topics. However, this one is more formal and often a bit (too?)
academic. This podcast on &lt;a href=&#34;https://medium.com/conversations-with-tyler/tyler-cowen-larry-summers-blog-secular-stagnation-twitter-421a69ed84c8&#34;&gt;Marcroeconomics, Mentorship and Avoiding
Complacency&lt;/a&gt;
might give you a good idea on what to expect.&lt;/p&gt;
&lt;h3 id=&#34;dan-carlins-history-x&#34;&gt;Dan Carlin&amp;rsquo;s History X&lt;/h3&gt;
&lt;p&gt;Extremely thoroughly researched lectures on important periods of our
history. &lt;a href=&#34;http://www.dancarlin.com/hardcore-history-59-the-destroyer-of-worlds/&#34;&gt;The Destroyer of
Worlds&lt;/a&gt;
is a 6 hour long, but captivating piece on the history of nuclear
warfare and filled in a lot of gaps for me.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Passing the AWS Certified Solutions Architect exam</title>
      <link>https://jefclaes.be/2017/12/passing-aws-certified-solutions.html</link>
      <pubDate>Fri, 15 Dec 2017 20:34:00 +0100</pubDate>
      <guid>https://jefclaes.be/2017/12/passing-aws-certified-solutions.html</guid>
      <description>&lt;p&gt;Before last week, the only certification exam I ever passed was the
Microsoft .NET Framework Application Development Foundation
certification. This was almost eight years ago. My manager back then
thought getting certified was the best way for me to get a raise. It
would be a win-win. I for one would learn something along the way, and
the company would have less trouble keeping its Microsoft Gold
partnership. As far as I remember, I spent a good six months reading,
studying and memorizing &lt;a href=&#34;https://www.amazon.com/MCTS-Self-Paced-Training-Exam-70-536/dp/0735626197&#34;&gt;this 794 pages thick
book&lt;/a&gt;.
Although the book did teach me a fair amount of solid .NET framework
internals, most time was spent force feeding myself the ins and outs of
framework API&amp;rsquo;s you only need once in a blue moon and should just Google
for when needed.&lt;/p&gt;
&lt;p&gt;This time around though, it was my own decision to get certified. Mid
2016, our components were getting more and more structured in a way that
allowed us to deploy them away from our on-premise data center.
Components that didn&amp;rsquo;t own data bound to a specific territory by
regulatory requirements and that would allow for some down-time were the
obvious candidates.&lt;/p&gt;
&lt;p&gt;Moving some of our infrastructure to the cloud, we had a few goals in
mind:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Take advantage of managed cloud services to reduce operation cost significantly.&lt;/li&gt;
&lt;li&gt;More freedom to scale up or down. The structure of the contracts with our data center (and regulations that require us to own our own racks) generally forces us to over provision our infrastructure. Making changes halfway the contract takes time and is costly.&lt;/li&gt;
&lt;li&gt;Ease into learning how to run software on the cloud for when we move to other markets or when we build services that have less strict territoriality constraints.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Getting started with AWS is easy enough. Starting an EC2 instance,
attaching a disk, using a managed database, configuring a load balancer
is child&amp;rsquo;s play. But when it came to networking, security,
fault-tolerance and properties guaranteed by AWS, I had a lot of
questions. I hoped to find answers going over the AWS Certified
Solutions Architect material. Why not set myself an artificial goal and
get certified while I was at it?&lt;/p&gt;
&lt;p&gt;After three months of studying, I passed the exam with a score of 95%.
Here&amp;rsquo;s a list of the resources I used, including how much money and time
were spent.&lt;/p&gt;
&lt;h3 id=&#34;exam-blueprint&#34;&gt;Exam Blueprint&lt;/h3&gt;
&lt;p&gt;You should go over the exam blueprint to understand what they expect
you to know to pass the exam. It&amp;rsquo;s a good idea to go over the document
while studying and to tick off domains you feel comfortable with.&lt;/p&gt;
&lt;p&gt;Money spent: €0, time spent: 30 minutes&lt;/p&gt;
&lt;h3 id=&#34;a-cloud-guru&#34;&gt;A Cloud Guru&lt;/h3&gt;
&lt;p&gt;A good collection of short videos and mini-exams covering all the
topics needed to pass the exam. Details that require extra attention to
pass the exam are highlighted throughout the course.&lt;/p&gt;
&lt;p&gt;You can get the videos on &lt;a href=&#34;https://acloud.guru/&#34;&gt;acloud.guru&lt;/a&gt; for €99. I
got it through &lt;a href=&#34;https://www.udemy.com/&#34;&gt;Udemy&lt;/a&gt; for only €10. Worth every
cent.&lt;/p&gt;
&lt;p&gt;Money spent: €10, time spent: 26 hours&lt;/p&gt;
&lt;h3 id=&#34;faqs-and-whitepapers&#34;&gt;FAQs and Whitepapers&lt;/h3&gt;
&lt;p&gt;AWS advises you to read a &lt;a href=&#34;https://aws.amazon.com/certification/certification-prep/&#34;&gt;specific set of whitepapers and
FAQs&lt;/a&gt;. The
material can be a bit dry, but it&amp;rsquo;s extremely useful. Not just to pass
the exam, but to avoid nasty surprises in production.&lt;/p&gt;
&lt;p&gt;Money spent: €0, time spent: 6 hours&lt;/p&gt;
&lt;h3 id=&#34;aws-open-guide&#34;&gt;AWS Open Guide&lt;/h3&gt;
&lt;p&gt;An &lt;a href=&#34;https://github.com/open-guides/og-aws&#34;&gt;open-source effort&lt;/a&gt; to
document real world experiences running environments on AWS.&lt;/p&gt;
&lt;p&gt;Money spent: €0, time spent: 1 hour&lt;/p&gt;
&lt;h3 id=&#34;whizzlabs&#34;&gt;Whizzlabs&lt;/h3&gt;
&lt;p&gt;Somewhere around &lt;a href=&#34;https://www.whizlabs.com/&#34;&gt;500 practice questions&lt;/a&gt;
that tease out the topics you don&amp;rsquo;t completely master. When I got a
question wrong, I would read up on the topic and play around in the AWS
console until I felt like I got it.&lt;/p&gt;
&lt;p&gt;Although there were some questions that were very similar, you can&amp;rsquo;t
pass the exam by just studying these questions.&lt;/p&gt;
&lt;p&gt;Money spent: €20, time spent: 12 hours&lt;/p&gt;
&lt;h3 id=&#34;exam-guru&#34;&gt;Exam Guru&lt;/h3&gt;
&lt;p&gt;Mobile app affiliated with A Cloud Guru containing more practice
questions. These are less scenario based and less in-depth. The
Whizzlabs questions are much more in the direction of what to expect on
the actual exam. Disappointing to be fair.&lt;/p&gt;
&lt;p&gt;Money spent: €20, time spent: 2 hours&lt;/p&gt;
&lt;h3 id=&#34;test-exam&#34;&gt;Test exam&lt;/h3&gt;
&lt;p&gt;A small set of questions provided by AWS in the style of the actual
exam. This was very much a waste of time and money. Whizzlabs had copied
all of these questions word for word.&lt;/p&gt;
&lt;p&gt;Money spent: €20, time spent: 20 minutes&lt;/p&gt;
&lt;h3 id=&#34;test-day&#34;&gt;Test day&lt;/h3&gt;
&lt;p&gt;The least enjoyable part of the experience. 55 multiple choice
questions need to be answered in 80 minutes. Half of the questions are
quite straight forward. The other half are more involved. For the longer
questions, I first read the answers and wrote down the options. For then
to read the question and strike through the options that definitely were
not a part of the answer. This helped me to focus on the important bits
of the question and to gain momentum plowing through the questions at a
steady pace. I finished with 25 minutes left.&lt;/p&gt;
&lt;p&gt;Money spent: €135, time spent: 90 minutes. Extra money spent on parking
in the city center of Brussels: €10, searching for a spot: 60 minutes&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;In short&amp;hellip; Go over the material, practice, take notes, practice some
more, review your notes until you get sick of them.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Fast projections</title>
      <link>https://jefclaes.be/2017/07/fast-projections.html</link>
      <pubDate>Sun, 30 Jul 2017 14:34:00 +0200</pubDate>
      <guid>https://jefclaes.be/2017/07/fast-projections.html</guid>
      <description>&lt;p&gt;Most EventStore client libraries allow you to subscribe to a stream by
passing in a callback which is invoked when an event occurs (either a
live or historic event).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Envelope&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Id &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Int64
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Event &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Event
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Historic &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;EventOccurred&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Envelope &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;unit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s say we subscribe to a stream of a popular video service, and we
want to project a read model that shows how many videos a viewer has
watched. We don&amp;rsquo;t care about the bookmarked videos for now.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Event&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; WatchedVideo &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; WatchedVideo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; BookmarkedVideo &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; BookmarkedVideo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; WatchedVideo &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; ViewerId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; VideoId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; At &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; DateTime &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; BookmarkedVideo &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; ViewerId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; VideoId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; At &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; DateTime &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We&amp;rsquo;re sitting on top of storage that can execute a single statement and
a batch of statements.&lt;/p&gt;
&lt;p&gt;The statements supported are limited:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set a checkpoint&lt;/li&gt;
&lt;li&gt;Increment the view count for a viewer&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Statement&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Checkpoint &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; Int64
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; IncrementViewCount &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; int
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Batch&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Statement seq
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Storage&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ExecuteStatement &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Statement &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;unit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ExecuteBatch &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Batch &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;unit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  CalculateCost &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;unit&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;decimal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The storage engine exposes a method which calculates the cost of
executed statements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Executing a single statement costs 1 execution unit&lt;/li&gt;
&lt;li&gt;Executing a batch also costs 1 execution unit plus 0.1 execution unit per statement in the batch&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;the-stream&#34;&gt;The stream&lt;/h3&gt;
&lt;p&gt;For this exercise the stream contains 3500 historic views, 50 historic
bookmarks and 100 live views.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; stream &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; seq &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; i &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; 1L &lt;span style=&#34;color:#f92672&#34;&gt;..&lt;/span&gt; 3500L &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;yield&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; i&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Event &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; WatchedVideo &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; ViewerId &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; VideoId &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; At &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; DateTime.UtcNow &lt;span style=&#34;color:#f92672&#34;&gt;};&lt;/span&gt; Historic &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; i &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; 3551L &lt;span style=&#34;color:#f92672&#34;&gt;..&lt;/span&gt; 3650L &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;yield&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; i&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Event &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; WatchedVideo &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; ViewerId &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; VideoId &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; At &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; DateTime.UtcNow &lt;span style=&#34;color:#f92672&#34;&gt;};&lt;/span&gt; Historic &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; i &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; 3501L &lt;span style=&#34;color:#f92672&#34;&gt;..&lt;/span&gt; 3550L &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;yield&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; i&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Event &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; BookmarkedVideo &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; ViewerId &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; VideoId &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; At &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; DateTime.UtcNow &lt;span style=&#34;color:#f92672&#34;&gt;};&lt;/span&gt; Historic &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;first-attempt&#34;&gt;First attempt&lt;/h3&gt;
&lt;p&gt;The first attempt at projecting the stream to state, executes a
statement for each event we&amp;rsquo;re interested in and checkpoints after each
event (even the ones we&amp;rsquo;re not interested in).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; ``First try`` &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;storage &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Storage&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; EventOccurred &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; envelope &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; envelope&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Event &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; WatchedVideo x &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; IncrementViewCount &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ViewerId&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; storage&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ExecuteStatement
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Checkpoint envelope&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Id &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; storage&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ExecuteStatement
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// ## First try ##
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// -----------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// - Viewcount: seq [[1, 3500]; [2, 100]]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// - Checkpoint: 3650L
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// -----------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// = Cost: 7250.0M
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The cost of this projection is high: 7250 execution units - even though
there are only 3600 events we&amp;rsquo;re interested in. We execute a statement
for each event we handled and checkpoint immediately after, even for the
events we didn&amp;rsquo;t handle.&lt;/p&gt;
&lt;h3 id=&#34;less-checkpointing&#34;&gt;Less checkpointing&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s not hard to get rid of some of the checkpointing though.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; ``Less checkpointing`` &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;storage &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Storage&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; EventOccurred &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; envelope &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; envelope&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Event &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; WatchedVideo x &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      IncrementViewCount &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ViewerId&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; storage&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ExecuteStatement
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Checkpoint envelope&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Id &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; storage&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ExecuteStatement
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// ## Less checkpointing ##
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// -----------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// - Viewcount: seq [[1, 3500]; [2, 100]]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// - Checkpoint: 3650L
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// -----------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// = Cost: 7200.0M
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The cost has improved, but only marginally. We saved 50 execution units
by avoiding checkpointing after events we do not handle. Time for a
bigger improvement..&lt;/p&gt;
&lt;h3 id=&#34;batching&#34;&gt;Batching&lt;/h3&gt;
&lt;p&gt;Instead of handling each event individually, we will buffer them as
soon as they come in. When we&amp;rsquo;re catching up and seeing historic events,
we only flush the buffer every 100 events. When we&amp;rsquo;re caught up, we
flush on each event. We want to always make a best attempt at showing
fresh data.&lt;/p&gt;
&lt;p&gt;When the buffer gets flushed, events are mapped into a sequence of
statements, which are sent in batch to the storage engine. The
checkpoint is appended to the tail of the batch.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; ``Batching`` &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;storage &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Storage&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; EventOccurred &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; envelope &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; flushOn &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; envelope&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Historic &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt; 100 &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; flush () &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; batch &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        buffer
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.map &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; env &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; env&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Event &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; WatchedVideo x &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; IncrementViewCount &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ViewerId&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Some
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; None
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.choose id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;batch &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.isEmpty&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; Checkpoint envelope&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Id &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.append batch
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; storage&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ExecuteBatch
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      buffer&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Clear()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; envelope&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Event &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; WatchedVideo &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; buffer&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Add envelope
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; buffer&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Count &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; flushOn &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      flush()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// ## Batching ##
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// -----------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// - Viewcount: seq [[1, 3500]; [2, 100]]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// - Checkpoint: 3650L
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// -----------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// = Cost: 508.5M
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This approach makes a significant difference. Execution cost has reduced
by 93%! Batching of historic events makes replays much faster, but with
some extra effort we can take this optimization even further.&lt;/p&gt;
&lt;h3 id=&#34;batching-with-transformation&#34;&gt;Batching with transformation&lt;/h3&gt;
&lt;p&gt;It always pays off to understand the guarantees and intricacies of the
storage you&amp;rsquo;re using. Looking closely at the storage interface, we find
that we can increment the view count by any number. If we use a local
data structure to aggregate the view count up front, we can reduce the
number of statements even further.&lt;/p&gt;
&lt;p&gt;In practice, we filter the for events we&amp;rsquo;re interested in, group by the
viewer id, count the values and map that into a single statement per
viewer.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; ``Batching with transformation`` &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;storage &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Storage&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; EventOccurred &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; envelope &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; flushOn &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; envelope&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Historic &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt; 100 &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; flush () &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; batch &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        buffer
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.map &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; env &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; env&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Event &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; WatchedVideo x &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; Some x 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; None
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.choose id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.groupBy &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; e &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; e&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ViewerId&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.map &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;viewerId&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; e&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;viewerId&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; e &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.length&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.map &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;viewerId&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; length&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; IncrementViewCount &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;viewerId&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; length&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;batch &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.isEmpty&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; Checkpoint envelope&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Id &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.append batch
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; storage&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ExecuteBatch
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      buffer&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Clear()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; envelope&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Event &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; WatchedVideo &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; buffer&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Add envelope
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; buffer&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Count &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; flushOn &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      flush()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// ## Batching with transformation ##
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// -----------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// - Viewcount: seq [[1, 3500]; [2, 100]]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// - Checkpoint: 3650L
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// -----------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// = Cost: 162.0M
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This further reduces costs by more than 2/3th. The optimization makes
the code a bit more elaborate, but not necessarily that more complex -
it&amp;rsquo;s still a local optimization.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In three steps, we brought cost down from 7250 execution units to only
162 units. That makes me a 44x engineer, right?&lt;/p&gt;
&lt;p&gt;In general, storage is one of the slowest components of your system.
Making your system faster often involves making it do less work.
Avoiding waste by batching and some more work up front, can make a big
impact when you want to make your projection faster.&lt;/p&gt;
&lt;p&gt;You can find the complete F# script
&lt;a href=&#34;https://gist.github.com/JefClaes/215d202fcdf9aa58968b92a129241292&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>From human decisions, to suggestions to automated decisions</title>
      <link>https://jefclaes.be/2017/07/from-human-decisions-to-suggestions-to.html</link>
      <pubDate>Sun, 23 Jul 2017 08:48:00 +0200</pubDate>
      <guid>https://jefclaes.be/2017/07/from-human-decisions-to-suggestions-to.html</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been wanting to share this experience for a while, but it took me a
while to come up with a story and example I could use in a blog post.&lt;/p&gt;
&lt;p&gt;I help out during the weekends in a small family run magic shop. I&amp;rsquo;m the
third generation working in the shop. My great-grandfather always hoped
that his only son would follow in his footsteps as a carpenter. But at
only eighteen years old, my grandfather said goodbye to the chisels and
sawdust, and set out for the big city to chase his dream of becoming a
world class magician. The first few years were tough, he was no Houdini.
He would (hardly) get by performing at kid birthday parties, weddings
and store openings. That&amp;rsquo;s how he met my late grandmother. She worked as
a shop girl in one of the first malls that were built in the city, and
happened to show up each time my grandfather performed in one of the
stores. After getting married, having a baby (my dad) and saving every
dime they earned, my grandfather was able to rent a hole in the wall and
open up his own tiny magic shop - in that same mall. Once my dad
finished school, he worked as a middle school teacher for a few years,
giving up on that job to join his father in the family business. He
loves to tell you how he can now still teach children, without the chore
of grading their homework. I&amp;rsquo;ve been running around and helping out in
the store since I could barely walk. I guess you can say that magic runs
in our blood.&lt;/p&gt;
&lt;p&gt;Since the beginning of time, our trade has relied on secrecy. However,
due to the rise of the internet, magic is dying a slow death. Even the
greatest of tricks and illusions are challenged and destroyed in the
open by non-believers. Our craft is now reduced by many to a cheap
fairground attraction.&lt;/p&gt;
&lt;p&gt;My grandfather, even after suddenly losing grandma last year, isn&amp;rsquo;t
willing to give up on the business though. &amp;ldquo;There will be a time when
the people need magic once more, and we will be waiting right here.&amp;rdquo; He
decided not to see modern technology as the nemesis of magic, but rather
as a potential assistant.&lt;/p&gt;
&lt;p&gt;Instead of fiddling in his study all night with a book of cards, a hat,
a scarf and the lonely rabbit, I&amp;rsquo;ve been working with him trying to show
him what happened in technology over the last 30 years. Being a
programmer, I started by showing off some of my unfinished hobby
projects experimenting with micro controllers. I hadn&amp;rsquo;t gotten much
further than making some LEDs blink controlled by my voice, but that was
enough to spark my grandfather&amp;rsquo;s creativity. &amp;ldquo;Can that chip make the
lights go out? Can it blow smoke? Can it sense if I flip it around real
fast?&amp;rdquo; One evening, tired after brainstorming and testing ideas all
night, he told me &amp;ldquo;being able to tell these little computers what to do
might not be magic, but a miracle&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;I would like to tell you the details of what we came up with, but I&amp;rsquo;d
have to make you disappear after I did. To make a long story short, it
was an overwhelming success. Neighbourhood magicians picked it up, and
even mere mortals thought it was a great gimmick they could show off
with. A friend of mine even told me he used our invention to pick up
girls. It wasn&amp;rsquo;t for long before I got daily emails and tweets from all
over the world, begging me to ship our gadget their way.&lt;/p&gt;
&lt;p&gt;Thanks to some lovely open source software, I was able to set up a full
blown web shop in a matter of days. While orders started rolling in, we
got a grip on how to actually produce our new product at a sufficient
pace. Shipping overseas turned out to be surprisingly easy. What we
didn&amp;rsquo;t anticipate for was how to handle returns and refunds.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This is where the actual story starts&amp;hellip;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;When our usual customers visit the store, we take our sweet time to show
them how to perform the trick. This results in us knowing our customers
pretty well and hardly ever having anyone return an item or ask for a
refund. Admittedly, growing the same connection with our customers
online hasn&amp;rsquo;t been a success. A lot of them lack the magician mindset.
You can&amp;rsquo;t just buy magic, you have to put the practice in to make the
magic happen. These maladjusted expectations make for quite a few phoney
complaints.&lt;/p&gt;
&lt;p&gt;Me, my dad and my grandfather in turn have been performing the chore of
handling returns and refunds. This domain of the open source shop is
very much underdeveloped. Even something as simple as looking up a
customer&amp;rsquo;s details and order history, requires scanning multiple pages
of information or even querying the database by hand. Making a
well-informed decision takes up way more time than it should.&lt;/p&gt;
&lt;h3 id=&#34;a-use-case-specific-view&#34;&gt;A use case specific view&lt;/h3&gt;
&lt;p&gt;The first thing I did in an attempt to speed up this process was
building a use case specific view. I asked my dad and grandfather which
heuristics they use and which data is needed to feed those heuristics.
To get the full picture as soon as possible, I imposed the rule that
only this specific view can be used to make a decision. If a piece of
data was lacking, I would add it the same day.&lt;/p&gt;
&lt;p&gt;This process was more useful than I expected. What we learned is that we
all used different heuristics, but were also victim to different biases.
For example, I learned that my grandfather used to have a Dutch
neighbour who would leave for work very early, and slam the door so
loud, it woke my grandfather up each morning. He has grown a disliking
for the Dutch ever since. When customers were Belgian, he would much
more lean towards issuing a refund, since he believes Belgians are less
likely to lie about the cause of a broken item. We also discovered that
we used different words for specific numbers. I would use &amp;ldquo;Items
purchased sum&amp;rdquo;, but my dad would use &amp;ldquo;Items purchased lifetime&amp;rdquo; to
define the total amount of money spent purchasing items. We decided on
being more explicit and making a composition of all those words.&lt;/p&gt;
&lt;p&gt;I ended up with a simple screen that rendered a read model that looked
something like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ReadModel&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    DaysSinceItemPurchased &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; int
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ItemPrice &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;decimal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ItemPurchasedSumLifetime &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;decimal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    RefundedToPurchasedItemsRatio &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;decimal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    CustomerId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    CustomerName &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    CustomerCity &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    CustomerCountryCode &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2017-07-23-from-human-decisions-to-suggestions-to-automated-decisions-readmodel.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2017-07-23-from-human-decisions-to-suggestions-to-automated-decisions-readmodel.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Based on heuristics in the head and a snapshot of information available in the
world, we would make a decision and click a button to execute a specific
command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Command&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; IssueRefund
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; IssuePartialRefund
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; AwardCoupon
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; ShipReplacement
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; DenyRefund
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; DeferDecision
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Snapshot&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    SnapshotId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Value &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; ReadModel
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Decision&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    BasedOnSnapshotId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Command &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Command
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    MadeBy &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MakeDecision&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Snapshot &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; Decision
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; makeHumanDecision by &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; MakeDecision &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Heuristics in the head, fed by knowledge in the world
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; snapshot &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            BasedOnSnapshotId &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; snapshot&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;SnapshotId
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Command &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; IssueRefund
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            MadeBy &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; by
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;making-suggestions&#34;&gt;Making suggestions&lt;/h3&gt;
&lt;p&gt;By now, I had gotten quite interested in this domain. Each day I would
go over all of the decisions and see whether I understood why a decision
was made. I would call the shop each time I didn&amp;rsquo;t understand and
scribble down notes whenever I discovered a new implicit rule. In the
meanwhile, I started experimenting with codifying these rules to make
automated decisions, but when I ran the older snapshots through my
routine the results were not 100% there yet. Instead of making automated
decisions, I switched to making suggestions instead.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Suggestion&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Command &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Command
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Confidence &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; int
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Suggestions&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    BasedOnSnapshotId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Options &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Suggestion seq
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MakeSuggestion&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Snapshot &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; Suggestions
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; machineMakesSuggestions snapshot &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; returnWindowInDays &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 14
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; itemInReturnWindow &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; snapshot&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Value&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;DaysSinceItemPurchased &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; returnWindowInDays
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; options &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; itemInReturnWindow &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Command &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ShipReplacement&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Confidence &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 51 &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Command &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; IssueRefund&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Confidence &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 49 &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Command &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; DenyRefund&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Confidence &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0 &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Command &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; AwardCoupon&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Confidence &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0 &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Command &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; IssuePartialRefund&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Confidence &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0 &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Command &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; DenyRefund&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Confidence &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 50 &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Command &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; AwardCoupon&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Confidence &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 30 &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Command &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; IssuePartialRefund&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Confidence &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 10 &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Command &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ShipReplacement&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Confidence &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 10 &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Command &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; IssueRefund&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Confidence &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0 &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; BasedOnSnapshotId &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; snapshot&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;SnapshotId&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Options &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; options &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I rendered these suggestions on top of the existing view and observed
the decisions that were made.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2017-07-23-from-human-decisions-to-suggestions-to-automated-decisions-suggestions.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2017-07-23-from-human-decisions-to-suggestions-to-automated-decisions-suggestions.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;PickSuggestion&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Suggestions &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; Decision
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; humanPicksSuggestion by &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; PickSuggestion &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; suggestions &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            BasedOnSnapshotId &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; suggestions&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;BasedOnSnapshotId
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Command &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; IssueRefund
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            MadeBy &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; by
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;My partners in crime were quite ecstatic with this new feature. They had
a bit more room to breathe and could spend more time doing things they
liked.&lt;/p&gt;
&lt;p&gt;After observing and comparing the suggestions with the decisions made, I
kept tweaking the routine a bit more. I got close but I felt as if I
wasn&amp;rsquo;t quite there yet.&lt;/p&gt;
&lt;h3 id=&#34;automating-decisions&#34;&gt;Automating decisions&lt;/h3&gt;
&lt;p&gt;It was my grandfather who eventually pushed me to fully automate
making these decisions. He said &amp;ldquo;I almost always find myself picking the
first option. It&amp;rsquo;s fine if the machine is a bit off now and then. Just
defer decisions and call in a human when the machine is not confident
enough.&amp;rdquo; How can I question my grandfather&amp;rsquo;s wisdom? And so this
happened&amp;hellip;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; machinePicksSuggestion &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; PickSuggestion &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; suggestions &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; confidenceTreshold &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 50
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; command &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            suggestions&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Options
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.filter &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Confidence &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; confidenceTreshold&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.sortByDescending &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Confidence&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.map &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Command&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; withFallbackTo DeferDecision
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.head
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            BasedOnSnapshotId &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;  suggestions&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;BasedOnSnapshotId
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Command &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; command
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            MadeBy &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Machine&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;from-human-decisions-to-suggestions-to-automated-decisions&#34;&gt;From human decisions, to suggestions, to automated decisions&lt;/h3&gt;
&lt;p&gt;With that, we&amp;rsquo;ve come full circle. I&amp;rsquo;m happy to report that my dad,
grandfather and I are back to spending more time in my grandfather&amp;rsquo;s
study coming up with new tricks.&lt;/p&gt;
&lt;p&gt;I regularly have a look at the data to check for anomalies and to tweak
the routine a bit further. But even that is taking up less and less
time. To be fair, I didn&amp;rsquo;t invest in a full blown test suite even though
this small routine has grown into 200 lines of code. I find much relief
in the fact that when I replay past decisions, I hardly ever find a
regression.&lt;/p&gt;
&lt;p&gt;Maybe if we invent another popular trick like this one, we will acquire
enough data to let the machine do the learning for me. For now, it&amp;rsquo;s
automagical enough.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>How to organize a meetup</title>
      <link>https://jefclaes.be/2017/02/how-to-organize-meetup.html</link>
      <pubDate>Mon, 13 Feb 2017 21:21:00 +0100</pubDate>
      <guid>https://jefclaes.be/2017/02/how-to-organize-meetup.html</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve organized a few &lt;a href=&#34;https://www.meetup.com/dddbelgium/&#34;&gt;DDDBE&lt;/a&gt; meetups
in the past, and always succeed in forgetting something. Either someone
points it out well in advance, or I end up stressing last minute. This
post partly serves as a checklist for myself, but it would be a welcome
side effect to also see it encourage others to help out organizing
future meetups. Organizing a meetup is not rocket science, having a list
of what to take care of is a good start.&lt;/p&gt;
&lt;h3 id=&#34;finding-a-speaker&#34;&gt;Finding a speaker&lt;/h3&gt;
&lt;p&gt;One of the crucial ingredients of an interesting evening is the
speaker and the content they bring. My strategy is to use Twitter
to keep a tab on people that produce content that&amp;rsquo;s of interest to me. A
meetup is a great excuse to meet in person and to hear them out. When
it&amp;rsquo;s someone who isn&amp;rsquo;t local, I keep an eye on whether they will be
attending any conferences nearby in the future.&lt;/p&gt;
&lt;h3 id=&#34;contacting-a-speaker&#34;&gt;Contacting a speaker&lt;/h3&gt;
&lt;p&gt;The medium you use doesn&amp;rsquo;t matter that much, whether it&amp;rsquo;s through
Twitter, email, Slack or in person, as long as you give them enough
context to work with.&lt;/p&gt;
&lt;p&gt;Things to mention when contacting someone:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Introduce yourself and the user group.&lt;/li&gt;
&lt;li&gt;Tell them why you think he or she would make a great guest. Which was the talk, tweet or blog that piqued your interest? What is it that makes the content so relevant to your audience?&lt;/li&gt;
&lt;li&gt;Tell them about the expected composition of the audience. Will there be 20 people or 100? Should most of them be quite familiar with the topic, or do you think an introductory talk would work better?&lt;/li&gt;
&lt;li&gt;Propose a date or a small set of dates from the get-go. Even if none of those dates work, you might settle on an alternative date instead which allows you to move forward and start planning.&lt;/li&gt;
&lt;li&gt;To avoid awkward situations, mention up front whether expenses can be covered or not. Not having a budget normally isn&amp;rsquo;t an issue when speakers are local or when they&amp;rsquo;re around for a conference or customer. When they have to get on a plane, it&amp;rsquo;s another matter.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;gathering-speaker-requirements&#34;&gt;Gathering speaker requirements&lt;/h3&gt;
&lt;p&gt;Ask the speaker what he needs, to be able to do his session:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A projector&lt;/li&gt;
&lt;li&gt;A whiteboard&lt;/li&gt;
&lt;li&gt;Modelling space&lt;/li&gt;
&lt;li&gt;Markers and sticky notes&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;selecting-a-location-sponsor&#34;&gt;Selecting a location sponsor&lt;/h3&gt;
&lt;p&gt;With those requirements in mind, you can start looking for a location
sponsor to host the meetup.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a luxury to have a pool of location sponsors. Depending on the
speaker and format of the session, you can make a selection on what
would be the best fit. When the speaker is a big name in the community,
try to find a location that fits a lot of people. A large auditorium
perhaps. When it&amp;rsquo;s a workshop, make sure there&amp;rsquo;s plenty of modelling
space. An open space with lots of walls or windows you can use to your
advantage. If you think the interest in a certain topic will be rather
limited, aim for something a bit smaller and more cozy, which could
benefit the quality of interactions between the speaker and the
audience.&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;ve come up with a short list of ideal locations, you should be
aware of the type of relationship your community has with the sponsor.
Even if they don&amp;rsquo;t get much out of it, they might not mind doing you a
favor once in a while, but hosting a weekly meetup might be a bit much.
I like to order them in a way that makes a best attempt at a round-robin
distribution. This also benefits attendees and avoids over concentrated
geographical communities. Not everyone&amp;rsquo;s up to drive half way across the
country on a weekday for a one hour talk.&lt;/p&gt;
&lt;h3 id=&#34;contacting-a-location-sponsor&#34;&gt;Contacting a location sponsor&lt;/h3&gt;
&lt;p&gt;Keep a list of location sponsors and the people you need to contact, and
who inside your community knows them best. You have a higher chance of
getting a positive response if you have someone that knows them well
contact them. You can send an email, but there&amp;rsquo;s a high risk that it
ends up in a low priority queue somewhere - nobody likes sending out
those reminder emails. It&amp;rsquo;s more efficient to just call them, to ping
them on Slack or to send them a direct message on Twitter - in that
particular order.&lt;/p&gt;
&lt;p&gt;Prepare a list of things the location sponsor needs to know:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The date&lt;/li&gt;
&lt;li&gt;The name of the speaker and the subject&lt;/li&gt;
&lt;li&gt;The speaker requirements&lt;/li&gt;
&lt;li&gt;The amount of people you&amp;rsquo;re expecting&lt;/li&gt;
&lt;li&gt;Expectations towards food: sandwiches, pizzas, soda, beers?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I try to contact location sponsors one after the other. This avoids
broadcasting the request, to have to turn it down later on. This has
never been a problem, as long as response times are low. If you have to
wait weeks to get a reply, you&amp;rsquo;re going to end up stressing out once the
deadline approaches.&lt;/p&gt;
&lt;h3 id=&#34;meetupcom&#34;&gt;Meetup.com&lt;/h3&gt;
&lt;p&gt;You can schedule a meetup as soon as the speaker and the date are
confirmed.&lt;/p&gt;
&lt;p&gt;Opening the RSVP&amp;rsquo;s is best done after the location is also confirmed and
not more than one month in advance. You want to avoid people reserving
their seat to eventually not show up.&lt;/p&gt;
&lt;p&gt;Details you want to include when making the announcement:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The date&lt;/li&gt;
&lt;li&gt;The location and the maximum number of attendees&lt;/li&gt;
&lt;li&gt;The speaker and the abstract of the session&lt;/li&gt;
&lt;li&gt;Where to park your car&lt;/li&gt;
&lt;li&gt;Whether food is provided or not. Include what to expect if possible, so that people with a specific diet can make the necessary arrangements.&lt;/li&gt;
&lt;li&gt;The agenda of the evening: doors open, start of the session, debriefing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Not all these details need to be present when you schedule the meetup,
you can still enrich later on. My own experience tells me I mostly care
about the speaker, date and location. I only look at the specifics one
week up front.&lt;/p&gt;
&lt;p&gt;When you have people on the waiting list, it&amp;rsquo;s a good idea to send a
personal reminder one week in advance, asking people to update their
RSPV&amp;rsquo;s in case they can&amp;rsquo;t make it. These seem to be more effective than
the auto generated ones.&lt;/p&gt;
&lt;p&gt;Even with those reminders, you will often find a percentage of people
not showing up. Many factors influence the no-show rate. Count the empty
chairs, and allow for some overbooking once you get a feel for it. The
worst thing that can happen is that the organizers have to watch the
session standing up.&lt;/p&gt;
&lt;h3 id=&#34;speaker-gift&#34;&gt;Speaker gift&lt;/h3&gt;
&lt;p&gt;Like Christmas gifts, you also want to think of a speaker gift up front.
This doesn&amp;rsquo;t have to be something super expensive, a small token of
appreciation will do. I&amp;rsquo;m going to guess this is a culture thing. In
Belgium people often end up gifting each other beers or wine. This isn&amp;rsquo;t
always appropriate or practical. Not everyone likes to drink and when
you&amp;rsquo;re travelling it&amp;rsquo;s quite literally a burden on your shoulders. I&amp;rsquo;m
actually thinking that something small, like a book with a personal note
might be a better idea.&lt;/p&gt;
&lt;h3 id=&#34;recording&#34;&gt;Recording&lt;/h3&gt;
&lt;p&gt;Before recording a session, there are a few things you need to consider.&lt;/p&gt;
&lt;p&gt;Does the speaker mind being recorded? Some bring experimental content
that&amp;rsquo;s rough around the edges which isn&amp;rsquo;t necessarily something they&amp;rsquo;re
ready to show to a large audience. Others see it as a perfect
opportunity to be able to pitch a conference talk for later on, or to
spread their content.&lt;/p&gt;
&lt;p&gt;When you announce that the talk will be recorded up front, more people
tend to stay at home. They can catch the video later on, but eventually
often end up never doing so. Even when they do, they&amp;rsquo;ve missed out on
the best bits: the interactions before and after the talk.&lt;/p&gt;
&lt;h3 id=&#34;day-of-the-meetup&#34;&gt;Day of the meetup&lt;/h3&gt;
&lt;p&gt;Make sure you set aside enough time in your agenda. You don&amp;rsquo;t want to be
stressing out last minute, or God forbid, be late.&lt;/p&gt;
&lt;p&gt;Your job is to make the speaker as comfortable as can be, and to think
fast when something falls apart last minute.&lt;/p&gt;
&lt;p&gt;If the speaker has been travelling, go get him at the station or at the
airport. Travel is tiring. Reassure him he can just relax from now on,
you will take care of anything he needs. The basics first: is he
thirsty, hungry, does he need to use the toilet, an internet connection?
You will also help him set up his laptop and put a bottle of water
nearby before the session starts.&lt;/p&gt;
&lt;p&gt;Arrive at the venue in time, at least 20 minutes up front. Say hi to the
host and quick check whether all requirements are met.&lt;/p&gt;
&lt;p&gt;Once the first people start pouring in, say hi, point them in the right
direction and make some small talk. Once a small crowd has found its way
to sandwiches and the social area, you can focus on ensuring the room
and speaker are ready to go. The next batch of people to come in will be
able to find their way on their own.&lt;/p&gt;
&lt;p&gt;Once people are well fed and settled, take the stage and do a short
introduction:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Community announcements: scheduled meetups, oncoming befriended conferences&amp;hellip;&lt;/li&gt;
&lt;li&gt;Sponsor raffles: software licenses, conference tickets&amp;hellip;&lt;/li&gt;
&lt;li&gt;Mention the types of sponsoring the community is still looking for: locations, markers, budget&amp;hellip;&lt;/li&gt;
&lt;li&gt;Thank the sponsor(s) and allow them to say a few words if they like to&lt;/li&gt;
&lt;li&gt;The agenda for the night&lt;/li&gt;
&lt;li&gt;The speaker(s)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now the session is well on its way, you can mostly just sit back and
relax. Pay attention though. In case nobody wants to go first during QA,
you should lead by example and have a question ready.&lt;/p&gt;
&lt;p&gt;Once questions dry up, or people are thirsty, thank the speaker and
don&amp;rsquo;t forget to hand off your speaker gift.&lt;/p&gt;
&lt;p&gt;After the session, the location sponsor usually has a fridge with
beverages you&amp;rsquo;re free to plunder. Out of courtesy, you don&amp;rsquo;t want to
make it too late and see yourself out in time. Ask the host what time
that should be. Usually 30% of the people leave right after the talk,
the rest sticks around for one or two drinks. When the time comes to
leave, not everyone wants to head home right away. As part of your prep,
find a bar that&amp;rsquo;s nearby and easily accessible, where you can gather
afterwards in case not everyone has had enough.&lt;/p&gt;
&lt;h3 id=&#34;give-thanks&#34;&gt;Give thanks&lt;/h3&gt;
&lt;p&gt;Whew, congratulations, you made it! The only thing left to do is to
thank the speaker and the location sponsor once more. Give them a shout
out in public, and send them a personal thank you note through a more
personal medium.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thanks to the whole DDDBE community for the inspiration and the
platform. Thanks to &lt;a href=&#34;https://twitter.com/mathiasverraes&#34;&gt;Mathias&lt;/a&gt;,
&lt;a href=&#34;https://twitter.com/ylorph&#34;&gt;Yves&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/one75&#34;&gt;Stijn&lt;/a&gt;,
&lt;a href=&#34;https://twitter.com/selketjah&#34;&gt;Gien&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/antoniosklimis&#34;&gt;Antonios&lt;/a&gt; in particular for reviewing.&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Printing money - hacking loyalty points</title>
      <link>https://jefclaes.be/2017/02/printing-money-hacking-loyalty-points/</link>
      <pubDate>Sun, 12 Feb 2017 00:20:00 +0100</pubDate>
      <guid>https://jefclaes.be/2017/02/printing-money-hacking-loyalty-points/</guid>
      <description>&lt;p&gt;At work, we&amp;rsquo;ve all grown quite vigilant when it comes to customers
trying to cheat the system. A necessary trait when working in a domain
where money flows back and forth and customers are always trying to find
an edge that will turn the tables.&lt;/p&gt;
&lt;p&gt;While most tend to leave this mindset at work, one colleague in
particular, is always probing, trying to find cracks in the surface of
everyday models. Years of practice have made him exceptionally good at
it too. When you want more than a shallow review of your design, you go
see him.&lt;/p&gt;
&lt;p&gt;I happened to be a part of his last quest, in which we reverse
engineered a case of security by obscurity involving a large supermarket
chain.&lt;/p&gt;
&lt;p&gt;A bit of backstory first. This supermarket - as many others - offers a
loyalty program. In return for your data, you earn one point per two
euros spent. As soon as you&amp;rsquo;ve saved up 500 points, you get a 5 euro
coupon which you can use to get a discount or to buy an item in their
loyalty shop. To identify yourself, you receive a card which you show to
the cashier on checkout or which you scan yourself when using the
self-checkout. When you forgot your card in the car or at home, they
print a code on the receipt. This allows you to claim your points
afterwards by handing it to the cashier, or again by scanning it
yourself at the self-checkout.&lt;/p&gt;
&lt;p&gt;In this example, we purchased something small without using our loyalty
card. The item cost less than four euros, earning us one meager loyalty
point. If you take a closer look at the ticket, you can see the amount
of points being repeated at the tail of the barcode.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2017-02-12-printing-money-hacking-loyalty-points-ticket.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2017-02-12-printing-money-hacking-loyalty-points-ticket.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re familiar with the anatomy of some of the established barcode
standards, you might notice they&amp;rsquo;re using the UPC symbology to encode
loyalty points.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2017-02-12-printing-money-hacking-loyalty-points-upc.gif&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2017-02-12-printing-money-hacking-loyalty-points-upc.gif&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;After proving the manufacturer code was connected to the store the
ticket was printed at - by purchasing multiple products from different
branches, we figured we could just go ahead and forge our own loyalty
points. A quick Google search and a printer were all the tools we
needed.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2017-02-12-printing-money-hacking-loyalty-points-forge.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2017-02-12-printing-money-hacking-loyalty-points-forge.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So we first purchased two products on two different days. This gave us a
ticket worth one point and another one worth two points. We printed our
own barcode worth three points, and claimed it at the self-checkout. We
weren&amp;rsquo;t stopped by security on our way out, and the points were credited
to our points wallet, so I guess it was a successful experiment.&lt;/p&gt;
&lt;p&gt;To be fair, if it wasn&amp;rsquo;t for the self-checkout option, it would be much
harder to get away with this. If we had to hand over our ticket to a
human, we would have needed to counterfeit a lot more than just the
barcode. There are reasons it&amp;rsquo;s so incredibly hard to print fake money. &lt;/p&gt;
&lt;p&gt;The system used is quite simple; both from a customer perspective as a
technical perspective. It&amp;rsquo;s a lightweight stateless model which should
hardly require any maintenance.&lt;/p&gt;
&lt;p&gt;If you wanted to make this system more secure - not necessarily bullet
proof, I can think of two obvious options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Leave the validation of points to humans. I&amp;rsquo;m not sure how hard it would be to make a high quality copy of a ticket with lots of points on it. &lt;/li&gt;
&lt;li&gt;Spawn a new state machine identified by a random token each time you hand out points. This state machine allows points to be claimed and to expire. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Please chime in if you know of battle-tested models for this type of
functionality. &lt;/p&gt;
&lt;p&gt;Closing off, we didn&amp;rsquo;t do any harm during our research: we didn&amp;rsquo;t take
more than we paid for.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Everyone has to serve somebody, but software has to serve more than one</title>
      <link>https://jefclaes.be/2017/01/gotta-serve-somebody-or-somebodies.html</link>
      <pubDate>Fri, 13 Jan 2017 15:08:00 +0100</pubDate>
      <guid>https://jefclaes.be/2017/01/gotta-serve-somebody-or-somebodies.html</guid>
      <description>&lt;p&gt;When people get paid to write software, we very often find some form of
friction between the people that build the software and those that pay
to have it built.&lt;/p&gt;
&lt;p&gt;The company I joined three years ago was no exception. When I joined,
they had just launched three months ago, weren&amp;rsquo;t seeing any return on
investment and prospects weren&amp;rsquo;t too bright either.&lt;/p&gt;
&lt;p&gt;I won&amp;rsquo;t lie, that first year was quite stressful. The business model
sucked, the code was even worse. That first year, I wouldn&amp;rsquo;t have been
too surprised if the whole team had been let go. In that situation, I
could have played it safe, but to be fair, there was something quite
exciting about actually having skin in the game and trying to make
something out of nothing.&lt;/p&gt;
&lt;p&gt;The best thing to come out of this situation, is that each and every
engineer acquired a high sense of ownership. When you&amp;rsquo;re a team of only
a few people, you have to carry your weight and make an impact. And the
only impact that mattered was coming up with changes that would make
customers return to us instead of to our competitors. A product without
customers, isn&amp;rsquo;t a product at all.&lt;/p&gt;
&lt;p&gt;Being extremely customer-focussed, we did set aside many of our own
concerns. Both from a personal and technical perspective. We spent too
much time at the office, putting in more hours than ideal. We were lucky
to have a young team, that didn&amp;rsquo;t have a large day-to-day personal
workload though. Since we were also the ones running the operational
side of things in the early days, the tooling that was built covered the
bare minimum, in a very crude way. On the technical side of things, we
played the hand we were dealt. We tried not to make things worse - like
treating a slowly healing wound. Improving things when constraints
allowed it, still taking the rare short cut when our hand was forced. I
still believe today that had we invested in the large technical overhaul
the code base deserved - putting ourselves in a position where we would
have shipped less features and changes - we would have found ourselves
completely pushed out of the market and without a job six months
later.&lt;/p&gt;
&lt;p&gt;Once things started to turn around for the better, we acquired more and
more return customers, but we also acquired a set of customers we didn&amp;rsquo;t
anticipate.&lt;/p&gt;
&lt;p&gt;When we were still small, we would handle customer tickets ourselves.
The owners didn&amp;rsquo;t think the workload warranted another hire. After we
threw away the homegrown, not very inviting to use, ticket system, we
switched to an off-the-shelf live chat system. This gave us a lot more
customer feedback - more than we could manage. Where tickets can be
processed in batch, chats are expected to be replied to in real time.
Nothing you can juggle in-between programming work, giving us a good
reason to hire extra people. For these people to be productive, and
actually able to help customers, they also needed access to those crude
tools we built earlier. Turns out, those tools didn&amp;rsquo;t really cut it. We
needed to listen to their feedback and work towards building tooling
that&amp;rsquo;s obvious and easy to use. And there you have it, an extra type of
&amp;ldquo;customer&amp;rdquo; we needed to satisfy.&lt;/p&gt;
&lt;p&gt;But it didn&amp;rsquo;t stop right there. Like a scurry of squirrels after a bird
feeder, there was more and more pressure from within the organization to
provide more sophisticated tools for the expanding operational needs,
like invoicing, content management, customer segmentation, localization
and so much more.&lt;/p&gt;
&lt;p&gt;So far, we had always put the end customer above all. We had always been
very conservative with our technical budgets. We did refactor
aggressively, but only changing the inside doesn&amp;rsquo;t always cut it. Larger
structural, organizational changes require you to move mountains. Well,
more like small hills. We knew the domain and its characteristics well
enough to have a pretty good idea where we wanted to go, but the clock
had always kept us from making big technical leaps forward.&lt;/p&gt;
&lt;p&gt;One could ask: if we have been able to postpone these changes for so
long, are they necessary at all? If you would ask non-technical
stakeholders, they would probably prioritize the next &amp;ldquo;one more
feature&amp;rdquo;. Hell, they would probably only start caring when the system
comes down crashing every few days. Who we should really be asking
however is those maintaining the system. If they feel as if they&amp;rsquo;re
operating a system that&amp;rsquo;s headed toward needing life support, we should
probably pay attention. Eventually something has to give. Eventually you
might see your software become a serious liability, or you might see
people jump ship even before the tipping point. &lt;strong&gt;Engineers are just as
much of a customer as your end customer - code is a product too&lt;/strong&gt;.
Engineers also have certain needs you want to satisfy to turn them into
happy return customers, who like spending their time, energy and
creativity on your product.&lt;/p&gt;
&lt;p&gt;It might sound backwards, but even the people you&amp;rsquo;re paying at the end
of the month, are very much customers of your product. A monthly pay
check might buy you a higher pain barrier, but it&amp;rsquo;s not unbounded
either. You might even see some of the most passionate people succumb
early on. People on the payroll are as much a vital part of the
ecosystem as the end customer. If they don&amp;rsquo;t like being a customer,
chances are, your end customer won&amp;rsquo;t either. Highly contagious. &lt;strong&gt;While
the end customer is still &lt;em&gt;King&lt;/em&gt; in this story, to build something truly
sustainable for the future, you need to reckon with each and every
entity that interacts with the software.&lt;/strong&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Consumed in 2016</title>
      <link>https://jefclaes.be/2016/12/consumed-in-2016.html</link>
      <pubDate>Tue, 27 Dec 2016 22:10:00 +0100</pubDate>
      <guid>https://jefclaes.be/2016/12/consumed-in-2016.html</guid>
      <description>&lt;p&gt;I&amp;rsquo;m keeping the tradition alive, sharing how much I&amp;rsquo;ve consumed over the
last year highlighting the things that stood out. 18 books, 8 movies and
9 shows. Looks like I consumed more than other years, which probably
also explains why I produced less after-hours.&lt;/p&gt;
&lt;h3 id=&#34;books&#34;&gt;Books&lt;/h3&gt;
&lt;p&gt;I finished &lt;a href=&#34;https://www.amazon.com/gp/product/B01N49DY6V/ref=as_li_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=B01N49DY6V&amp;amp;linkCode=as2&amp;amp;tag=diofanedebyje-20&amp;amp;linkId=1adc667326be5a331e60a6dd5887c04d&#34;&gt;the Dark Tower
series&lt;/a&gt;
after 3 years. Following Roland Deschain and his ka-tet throughout the 8
books has been an epic adventure. Finishing Harry Potter by the time I
was 18, I had little hopes to be ever dragged into such a long and
captivating tale ever again. &lt;a href=&#34;https://www.amazon.com/gp/product/0307947300/ref=as_li_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0307947300&amp;amp;linkCode=as2&amp;amp;tag=diofanedebyje-20&amp;amp;linkId=6a6574320422180688105e09b861f0f2&#34;&gt;The
Stand&lt;/a&gt;,
another epic by Stephen King is also high up on my list. I&amp;rsquo;ve seem to
have taken a liking to stories that are set in a post-apocalyptic world,
in which the antagonist is not necessarily a horde of zombies.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Control the things you can control, maggot. Let everything else take a
flying fuck at you, and if you must go down, go down with your guns
blazing. - Stephen King, The Dark Tower&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Show me a man or a woman alone and I&amp;rsquo;ll show you a saint. Give me two
and they&amp;rsquo;ll fall in love. Give me three and they&amp;rsquo;ll invent the
charming thing we call &amp;lsquo;society&amp;rsquo;. Give me four and they&amp;rsquo;ll build a
pyramid. Give me five and they&amp;rsquo;ll make one an outcast. Give me six and
they&amp;rsquo;ll reinvent prejudice. Give me seven and in seven years they&amp;rsquo;ll
reinvent warfare. Man may have been made in the image of God, but
human society was made in the image of His opposite number, and is
always trying to get back home. - Stephen King, The Stand&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://www.amazon.com/gp/product/1492999776/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;linkCode=as2&amp;amp;creativeASIN=1492999776&amp;amp;linkId=03afcb88b939d45a6ebfedc09ebdbbf4&#34;&gt;Culture and
Empire&lt;/a&gt;
and &lt;a href=&#34;https://www.amazon.com/gp/product/1514342022/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;linkCode=as2&amp;amp;creativeASIN=1514342022&amp;amp;linkId=612a4ff9d8bbab71929db9b734caae8d&#34;&gt;The Psychopath
Code&lt;/a&gt;
by the late Pieter Hintjens were thought provoking, yet easy reads. I
wish more authors could break apart complex problems in such an
understandable fashion. Pieter&amp;rsquo;s ability to research any given topic and
to build a convincing case is a skill I&amp;rsquo;d like to acquire one day.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For the sake of argument, let&amp;rsquo;s divide society into four roughly equal
chunks. We have the bandits, who specialize in taking from others.
Then, we have the beggars, who specialize in getting something for
nothing. Middle management, perhaps. Then, we have the bureaucrats,
who specialize in making rules and keeping things organized. Finally,
we have the bakers, who specialize in making things that other people
need. - Pieter Hintjens, Culture and Empire&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;When the cost of secrets held by one person or group outweighs the
benefits to society, then it&amp;rsquo;s right that those secrets be leaked.
Security does not just trump Liberty, he takes her into a dark back
alley, violates her repeatedly, and then beats her senseless with a
heavy stick. - Pieter Hintjens, Culture and Empire&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As far as technical books go, I&amp;rsquo;ve been mostly reading about things that
are relevant to my current job. I learned most from &lt;a href=&#34;https://www.amazon.com/gp/product/149192912X/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;linkCode=as2&amp;amp;creativeASIN=149192912X&amp;amp;linkId=a194cfa2ea5cdc2427fd1452d83c15a5&#34;&gt;Site Reliability
Engineering&lt;/a&gt;
and &lt;a href=&#34;https://www.amazon.com/gp/product/0735658560/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;linkCode=as2&amp;amp;creativeASIN=0735658560&amp;amp;linkId=8aa3434b97209c75c728659b2fb92a5e&#34;&gt;SQL Server 2012
Internals&lt;/a&gt;.
They are long, very slow reads, but the information has a depth to it
which is hard to get by in other formats. In retrospect, I often wonder
if I might have been better of reading them more selectively though.&lt;br&gt;
Covering the same domain, I finally got around to reading the classic
&lt;a href=&#34;https://www.amazon.com/gp/product/0978739213/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;linkCode=as2&amp;amp;creativeASIN=0978739213&amp;amp;linkId=88f383c6d381d16ab2482c69a5364c89&#34;&gt;Release
it!&lt;/a&gt;
This book was published in 2007, and it shows. However, that doesn&amp;rsquo;t
mean it&amp;rsquo;s not worth your time. It&amp;rsquo;s fascinating to see how much the
infrastructure landscape has changed over the years. Knowing where we&amp;rsquo;re
coming from deploying and running large systems helps me understand why
we&amp;rsquo;re doing things in a certain way today.&lt;/p&gt;
&lt;h3 id=&#34;movies&#34;&gt;Movies&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;http://www.imdb.com/title/tt1663202/?ref_=fn_al_tt_1&#34;&gt;The Revenant&lt;/a&gt;.
If you&amp;rsquo;re looking for a rich storyline, you might end up disappointed.
However, it&amp;rsquo;s the high quality cinematography and breathtaking scenery
that make this film. I&amp;rsquo;m a sucker for the romance of the American
frontier though.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.imdb.com/title/tt3774114/?ref_=fn_al_tt_1&#34;&gt;Snowden&lt;/a&gt;. Not a
documentary, but a Hollywood picture telling the story of the most
disputed whistleblower of the century. To be fair, having worked with
government tech over the years, I used to be ignorant of the fact that a
government agency would be able to acquire the talent needed to build
and run a mass surveillance system successfully. Being Belgian, I
totally ignored the fact that in other countries there are some really
smart people patriotic enough to serve their country no matter what.
Although I read up on the subject when it was early days, the massive
scale of it all hit me like a ton of bricks halfway through the movie.
Generally I&amp;rsquo;m pretty excited to work in a field that has changed how we
communicate, distribute and do work in such a small period of time.
However, it has become more and more apparent to me that the centralized
nature of the things we build and use, is also a huge threat to our
freedom. It&amp;rsquo;s crucial that we learn from this incident, and grow towards
a world where pardoning Snowden is the obvious thing to do, and in which
the people in power toying with our privacy are the outcasts.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I think the greatest freedom that I have gained, the fact that I don&amp;rsquo;t
have to worry about what happens tomorrow, because I&amp;rsquo;m happy with what
I&amp;rsquo;ve done today. - Edward Snowden&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;shows&#34;&gt;Shows&lt;/h3&gt;
&lt;p&gt;I got around to watching the first episode of Westworld yesterday, and
my expectations are sky-high. Friends have been hyping me up over this
show since the first episode.&lt;/p&gt;
&lt;p&gt;Earlier in the year, I watched &lt;a href=&#34;http://www.imdb.com/title/tt2707408/?ref_=fn_al_tt_1&#34;&gt;Narcos&lt;/a&gt; and &lt;a href=&#34;http://www.imdb.com/title/tt4574334/?ref_=nv_sr_1&#34;&gt;Stranger Things&lt;/a&gt;. Netflix focussing more on content creation instead of rapidly expanding their portfolio with third party content might pay off big time. Both
shows bring high quality, bingeable content.&lt;/p&gt;
&lt;h3 id=&#34;podcasts&#34;&gt;Podcasts&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://www.thisamericanlife.org/&#34;&gt;This American Life&lt;/a&gt; has been a
favorite of mine for a long time. The Monday morning commute almost
becomes enjoyable. Almost.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://softwareengineeringdaily.com/&#34;&gt;Software Engineering Daily&lt;/a&gt; is
the podcast that I use to break out of my technological echo chamber.
The pace at which these have been published is unheard-of. Five days a
week there&amp;rsquo;s a fresh one hour interview with a high-profile guest
involved in building incredibly interesting systems at scale.&lt;/p&gt;
&lt;p&gt;Being the accidental DBA at work, the SQL Server Pain Relief podcast has
been compensating for the lack of people I know that have first hand
experience running large, high available and performance intensive SQL
Server production systems.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If there&amp;rsquo;s anything I really missed out on that I should watch or read,
let me know!&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Commands and events with JustSaying and AWS</title>
      <link>https://jefclaes.be/2016/09/commands-and-events-with-justsaying-and.html</link>
      <pubDate>Sun, 18 Sep 2016 20:52:00 +0200</pubDate>
      <guid>https://jefclaes.be/2016/09/commands-and-events-with-justsaying-and.html</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been looking into handing a bit of our messaging infrastructure
over to a managed alternative. Managing your own messaging
infrastructure that should be highly available is not always an
investment you want to make in this day and age. Going through the
documentation and relying on experiences from some people I trust, I
ended up looking at AWS and
&lt;a href=&#34;https://aws.amazon.com/sns/&#34;&gt;SNS&lt;/a&gt;/&lt;a href=&#34;https://aws.amazon.com/sqs/&#34;&gt;SQS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Making the Github repository rounds, looking for inspiration, I stumbled
on &lt;a href=&#34;https://github.com/justeat/JustSaying&#34;&gt;JustSaying&lt;/a&gt;: a library by the
people from JustEat implementing a message bus on top of AWS.&lt;/p&gt;
&lt;p&gt;I wanted to find two messaging patterns in this library:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Command queuing. A common pattern in our components is to react to an event by making an HTTP request to an external partner. To improve reliability and throughput, we generally don&amp;rsquo;t make that HTTP request in the projection itself, but rather drop a command onto a queue which will then be processed in parallel using a bounded amount of retries. When things do go wrong, we either retry  the messages by moving them from the error queue back to the input queue or we change the reaction and reset the projection checkpoint, sending the commands again.&lt;/li&gt;
&lt;li&gt;Pub-sub. Another pattern used when there is a certain level of
familiarity between components, is to have a component publish
events. Other components can subscribe to these messages and have
them delivered to their own queues.`&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Both these styles are supported by JustSaying.&lt;/p&gt;
&lt;p&gt;In this example, I have two commands: BookFlight and CancelBooking, with
two related events: FlightWasBooked and BookingWasCancelled.&lt;/p&gt;
&lt;p&gt;Since JustSaying requires messages to inherit from a base class, these
message definitions live on the outside, far from the domain. This
allows to decouple the domain from the outside contracts and to make
sure the events go out to the world in the format I want them to be.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BookFlight&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;inherit&lt;/span&gt; Message()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CancelBooking&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;inherit&lt;/span&gt; Message()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;FlightWasBooked&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;inherit&lt;/span&gt; Message()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BookingWasCancelled&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;inherit&lt;/span&gt; Message()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To handle these messages, JustSaying requires you to implement the
IHandler interface.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;HandleBookFlight&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; IHandler&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;BookFlight&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;member&lt;/span&gt; this.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handle&lt;/span&gt; msg &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; printfn &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Book flight&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;HandleCancelBooking&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; IHandler&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;CancelBooking&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;member&lt;/span&gt; this.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handle&lt;/span&gt; msg &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; printfn &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Cancel booking&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;HandleFlightWasBooked&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; IHandler&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;FlightWasBooked&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;member&lt;/span&gt; this.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handle&lt;/span&gt; msg &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; printfn &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Flight was booked&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;HandleBookingWasCancelled&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; IHandler&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;BookingWasCancelled&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;member&lt;/span&gt; this.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handle&lt;/span&gt; msg &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; printfn &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Booking was cancelled&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Having this out of the way, we need to configure the bus (publishers and
subscribers).&lt;/p&gt;
&lt;p&gt;First of all, Amazon needs to know who we are and what we&amp;rsquo;re allowed to
do.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; bus &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  CreateMeABus.DefaultClientFactory &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Func&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;IAwsClientFactory&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; () &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; DefaultAwsClientFactory&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;credentials&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&amp;gt;&lt;/span&gt; IAwsClientFactory&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We should define which region our infrastructure lives in.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CreateMeABus.InRegion&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;eu-west-1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can configure our command queue. Commands should be published
using an SQS publisher, directly dropping messages into the &amp;ldquo;Commands&amp;rdquo;
queue. A point-to-point subscriber will directly pull messages from the
&amp;ldquo;Commands&amp;rdquo; queue and hand them over to the command handlers.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;WithSqsMessagePublisher&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;BookFlight&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Action&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;SqsWriteConfiguration&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;QueueName &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Commands&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;WithSqsMessagePublisher&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;CancelBooking&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Action&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;SqsWriteConfiguration&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;QueueName &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Commands&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;WithSqsPointToPointSubscriber()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;IntoQueue&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Commands&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;WithMessageHandler&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; HandleBookFlight()&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;WithMessageHandler&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; HandleCancelBooking()&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Events are not directly dropped to an SQS queue, but will be created as
an SNS topic. We can use SQS to subscribe to these topics and have them
delivered to an &amp;ldquo;Events&amp;rdquo; queue.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;WithSnsMessagePublisher&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;FlightWasBooked&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;WithSnsMessagePublisher&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;BookingWasCancelled&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;WithSqsTopicSubscriber()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;IntoQueue&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Events&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;WithMessageHandler&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; HandleFlightWasBooked()&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;WithMessageHandler&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; HandleBookingWasCancelled()&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once the bus has been created, we can start listening and publishing
messages.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bus&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;StartListening()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bus&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Publish&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; BookFlight()&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bus&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Publish&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; FlightWasBooked()&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;JustSaying will create two SNS topics and four SQS queues: two input
queues and two error queues.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2016-09-18-commands-and-events-with-justsaying-and-aws-sns.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2016-09-18-commands-and-events-with-justsaying-and-aws-sns.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2016-09-18-commands-and-events-with-justsaying-and-aws-sqs.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2016-09-18-commands-and-events-with-justsaying-and-aws-sqs.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Those topic and queue names are not that descriptive once you introduce
multiple components and might cause names to collide. JustSaying allows
you to define a custom naming strategy. I&amp;rsquo;ve settled on a strategy that
is based on the message type and prefixed with the component name. This
has the added advantage that each message type now goes into its own
queue.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ComponentNamingStrategy&lt;/span&gt; () &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; INamingStrategy &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;member&lt;/span&gt; this.&lt;span style=&#34;color:#a6e22e&#34;&gt;GetQueueName&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;sqsConfig&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; messageType&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;component_&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; messageType&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ToLower()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;member&lt;/span&gt; this.&lt;span style=&#34;color:#a6e22e&#34;&gt;GetTopicName&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;topicName&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; messageType&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;component_&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; messageType&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ToLower()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;WithNamingStrategy&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Func&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;INamingStrategy&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ComponentNamingStrategy() &lt;span style=&#34;color:#f92672&#34;&gt;:&amp;gt;&lt;/span&gt; INamingStrategy&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2016-09-18-commands-and-events-with-justsaying-and-aws-sqsnamingstrategy.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2016-09-18-commands-and-events-with-justsaying-and-aws-sqsnamingstrategy.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This whole experiment has had a scary low learning curve (maybe a bit
too low). While I&amp;rsquo;m still in the assess-phase, I&amp;rsquo;m fairly optimistic
that running on top of SNS/SQS might take away some of our operational
burden. Going over the JustSaying API and code base, it&amp;rsquo;s quite
opinionated and there are things I might have approached differently.
Some features I&amp;rsquo;d like to see, like the library providing a message
envelope as a first-class citizen (a base message class is something
I&amp;rsquo;ve regretted in the past) is being worked on, so I&amp;rsquo;m keeping my eye on
those. Since I&amp;rsquo;m only using command queuing at the moment, I should be
pretty safe from future breaking changes to the message format and such.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>My InfoQ interview on DDD, events and legacy</title>
      <link>https://jefclaes.be/2016/08/my-infoq-article-on-ddd-events-and.html</link>
      <pubDate>Sun, 21 Aug 2016 15:07:00 +0200</pubDate>
      <guid>https://jefclaes.be/2016/08/my-infoq-article-on-ddd-events-and.html</guid>
      <description>&lt;p&gt;Seems that it&amp;rsquo;s impossible to beat the Gaussian curve of blogging
frequency. On the other hand, I spent quite some of my mental blogging
budget on an interview with InfoQ.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m a bit bummed out that it&amp;rsquo;s such a large wall of text. When submitting the answers, I highlighted some snippets which should make for easier scanning. Too bad the formatting was lost when publishing it. I included some highlights below.&lt;/p&gt;
&lt;p&gt;The interview itself can be found &lt;a href=&#34;https://www.infoq.com/news/2016/08/software-devs-ddd-drive-business&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Extracting components:&lt;/strong&gt; Starting out, this can be as trivial as
trying to model boundaries as namespaces or modules. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Invariants:&lt;/strong&gt; Having core properties enforced deep within the model,
allows for a better night&amp;rsquo;s sleep.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Sizing aggregates:&lt;/strong&gt; Make your aggregates as small as they can be,
but not any smaller. There&amp;rsquo;s a big difference between an invariant
that needs to be strongly held and data that helps the aggregate to
make a decision, but which doesn&amp;rsquo;t require strong consistency. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;ORM pitfalls:&lt;/strong&gt; Being able to navigate through a graph, which
basically walks through your whole database, is a great way to lose
any sense of transactional boundaries. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The value of bounded contexts:&lt;/strong&gt; Now when I switch between bounded
contexts, it feels like walking through a door, entering a separate
room where you can tackle a problem with an unbiased mindset, allowing
you to use the right tool for the job. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Introducing domain events:&lt;/strong&gt; When you don&amp;rsquo;t want to or can&amp;rsquo;t afford
to invest in the full paradigm shift there&amp;rsquo;s a middle ground. You can
try a hybrid approach in which you, next to persisting state, also
persist the events that led up to a specific state. This does entail
the risk of introducing a bug which causes split-brain in which your
events do not add up to your state.  &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Designing contracts:&lt;/strong&gt; If you get the semantics wrong, you will end
up with a system that&amp;rsquo;s held together by brittle contracts that break
constantly.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    
    <item>
      <title>Pieter Hintjens</title>
      <link>https://jefclaes.be/2016/04/pieter-hintjens.html</link>
      <pubDate>Wed, 27 Apr 2016 22:47:00 +0200</pubDate>
      <guid>https://jefclaes.be/2016/04/pieter-hintjens.html</guid>
      <description>&lt;p&gt;Writing doesn&amp;rsquo;t necessarily always come naturally to me. It often takes
me days, weeks or even months of toying with an idea, before I think
it&amp;rsquo;s mature enough to put it down into writing. I can&amp;rsquo;t afford that
luxury this time though, I wouldn&amp;rsquo;t think of myself as much of a friend
if Pieter didn&amp;rsquo;t get to read this in time.&lt;/p&gt;
&lt;p&gt;I met Pieter the first time in a bar in Vilnius, December 2013, I
accidentally ended up sitting next to him during the traditional
pre-conf drinks. The first thing that stood out, was what a comfortable
warm sweater he was wearing - I still cherish the memory of that grey
woolen sweater on cold winter nights. I&amp;rsquo;m still unsure whether it was
the sweater or his undeniable radiant charisma that made its way into my
memories. When Pieter talks, people tend to listen, or at least pay
attention. That&amp;rsquo;s what I ended up doing that night - listening, sipping
in the knowledge, afraid to make a fool out of myself joining the
conversation.&lt;/p&gt;
&lt;p&gt;That next day Pieter opened the conference with probably the most
motivational keynote I ever attended, aptly titled &amp;ldquo;Building stuff
changes everything&amp;rdquo;. Him being a fellow countryman and me having a few
Lithuanian beers in me, helped me gather enough courage to properly
introduce myself and talk for a bit.&lt;/p&gt;
&lt;p&gt;From that moment on, we would only meet a few times a year, traveling to
Vilnius with the Belgian delegation or as a guest at the Domain Driven
Design Belgium meetup. During that time, we had a few - far from enough - lengthy conversations. Me mostly asking questions, him sharing his
point of view, and me trying hard to keep up, taking it all in. Although
he was always more than happy to entertain each question you would throw
at him, I would always feel a bit selfish keeping him to myself for too
long.&lt;/p&gt;
&lt;p&gt;The most memorable talk I had with Pieter was during a tête-à-tête in
the Vilnius sky bar. We would mingle Dutch and English, whichever
language made the next sentence sound best. We shared some personal
experiences, he laid out most of the groundwork for what a good year
later materialized into &amp;ldquo;The Psychopath Code&amp;rdquo;, but most importantly he
allowed me a peek through his eyes, looking at his playground we like to
call life.&lt;/p&gt;
&lt;p&gt;You don&amp;rsquo;t need his Mensa membership card, to realize he is a highly
gifted individual. He could have pursued anything he wanted and been
good at it, but &lt;strong&gt;he chose all-out for people, freedom and love&lt;/strong&gt; -
making it his mission to evangelize his core beliefs.&lt;/p&gt;
&lt;p&gt;His words - both spoken and written - have inspired me more than he can
imagine. And they will likely continue to inspire others for many more
years to come. &lt;strong&gt;His work has given me a framework to build on for the
rest of my life. There&amp;rsquo;s so much to learn from how he is capable of
dissecting the world, to document things that are broken and his
tireless effort to make it whole again - one protocol, one word, one hug
at a time.&lt;/strong&gt; Where I would often feel overwhelmed by dark hopeless
sentiments, he has given me enough tools to overcome those. From his
mouth to my heart: &amp;ldquo;We&amp;rsquo;re not much more than a pile of ants, but
together we can achieve tremendous things&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Pieter, I&amp;rsquo;m not half the writer you are, but I hope these words can
serve as a testimony to your children what a great dad they had. If your
time comes, know that I&amp;rsquo;m grateful that I&amp;rsquo;ve been able to call you my
friend.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Using a batch layer for fast(er) aggregations </title>
      <link>https://jefclaes.be/2016/04/using-batch-layer-for-faster.html</link>
      <pubDate>Sun, 24 Apr 2016 22:43:00 +0200</pubDate>
      <guid>https://jefclaes.be/2016/04/using-batch-layer-for-faster.html</guid>
      <description>&lt;p&gt;In the oldest system I&amp;rsquo;m maintaining right now, we have an account
aggregate that, next to mutating various balances, produces immutable
financial transactions. These transactions are persisted together with
the aggregate itself to a relational database. The transactions can be
queried by the owner of the account in an immediate consistent
fashion.&lt;/p&gt;
&lt;p&gt;The table with these transactions looks similar to this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;CREATE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;TABLE&lt;/span&gt; [dbo].[&lt;span style=&#34;color:#66d9ef&#34;&gt;Transaction&lt;/span&gt;] (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	[Id] [int] &lt;span style=&#34;color:#66d9ef&#34;&gt;IDENTITY&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	[&lt;span style=&#34;color:#66d9ef&#34;&gt;Timestamp&lt;/span&gt;] [datetime] &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	[AccountId] [int] &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	[TransactionType] [varchar](&lt;span style=&#34;color:#ae81ff&#34;&gt;25&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	[CashAmount] [decimal](&lt;span style=&#34;color:#ae81ff&#34;&gt;19&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	[BonusAmount] [decimal](&lt;span style=&#34;color:#ae81ff&#34;&gt;19&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;NOT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	[...] [...] () &lt;span style=&#34;color:#66d9ef&#34;&gt;NULL&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;/* Too much metadata I&amp;#39;m not very happy about */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;CONSTRAINT&lt;/span&gt; [Tx_PK] &lt;span style=&#34;color:#66d9ef&#34;&gt;PRIMARY&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;KEY&lt;/span&gt; CLUSTERED ( [Id] &lt;span style=&#34;color:#66d9ef&#34;&gt;ASC&lt;/span&gt;) 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;WITH&lt;/span&gt; (PAD_INDEX &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;OFF&lt;/span&gt;, STATISTICS_NORECOMPUTE &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;OFF&lt;/span&gt;, IGNORE_DUP_KEY &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;OFF&lt;/span&gt;, ALLOW_ROW_LOCKS &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;ON&lt;/span&gt;, ALLOW_PAGE_LOCKS &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;ON&lt;/span&gt;, FILLFACTOR &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;ON&lt;/span&gt; [&lt;span style=&#34;color:#66d9ef&#34;&gt;PRIMARY&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;ON&lt;/span&gt; [&lt;span style=&#34;color:#66d9ef&#34;&gt;PRIMARY&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There&amp;rsquo;s an index on the timestamp, the account identifier and the
transaction type, which allows for &lt;em&gt;fast enough&lt;/em&gt; reads for the most
common access patterns which only return a small subset.&lt;/p&gt;
&lt;p&gt;In a use case we recently worked on, we wanted real-time statistics of
an account&amp;rsquo;s transactions over its life time.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;SELECT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  TransactionType,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;SUM&lt;/span&gt;(CashAmount) &lt;span style=&#34;color:#66d9ef&#34;&gt;AS&lt;/span&gt; CashAmount,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;SUM&lt;/span&gt;(BonusAmount) &lt;span style=&#34;color:#66d9ef&#34;&gt;AS&lt;/span&gt; BonusAmount,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;COUNT&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;AS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Count&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;/* ... */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Transaction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;WHERE&lt;/span&gt; AccountId &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;@&lt;/span&gt;AccountId
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;GROUP&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;BY&lt;/span&gt; TransactionType, &lt;span style=&#34;color:#75715e&#34;&gt;/* ... */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Running this query would seek the account id index, to look up all rows
that match given predicate. In case one account has tens of thousands of
transactions, this results in a high amount of reads. In case your
database fits into memory, SQL Server can probably satisfy your query
looking in its buffer cache. Although this still has overhead, it&amp;rsquo;s
supposed to be a lot faster than when SQL Server is forced to do
physical reads - reading pages straight from disk. In this case, where
transactions are often years old, and the database does not fit into
memory, odds are high that SQL Server will be reading from disk - which
is dog-slow.&lt;/p&gt;
&lt;p&gt;One option would be to create a new covering index (including columns
like CashAmount etc) for this specific workload. The problem is that
indexes don&amp;rsquo;t come for free. You pay for them on every write, and
depending on your performance goals, that might be a cost you want to
avoid. It might even be impossible, or too expensive to create such an
index on environments that have no maintenance window and no license
that allows for online index builds. Assuming that when you don&amp;rsquo;t own
said license, you don&amp;rsquo;t have read replicas available either.&lt;/p&gt;
&lt;p&gt;Considering the workload, the never-changing nature of financial
transactions and constraints in place, we applied &lt;a href=&#34;https://en.wikipedia.org/wiki/Lambda_architecture&#34;&gt;Lambda
Architecture&lt;/a&gt; theory
on a small scale, starting by building daily aggregations of
transactions per account.&lt;/p&gt;
&lt;p&gt;This translates into scheduling a job which catches up all days, by
performing a query per day and appending the results to a specific
table.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/** Aggregate transactions by day **/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;INSERT&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;INTO&lt;/span&gt; [dbo].[DailyTransactionAggregation]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;SELECT&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#66d9ef&#34;&gt;CONVERT&lt;/span&gt;(DATE, &lt;span style=&#34;color:#66d9ef&#34;&gt;Timestamp&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;AS&lt;/span&gt; Datestamp,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     AccountId
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     TransactionType
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#66d9ef&#34;&gt;COUNT&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;AS&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Count&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#66d9ef&#34;&gt;SUM&lt;/span&gt;(CashAmount) &lt;span style=&#34;color:#66d9ef&#34;&gt;AS&lt;/span&gt; CashAmount,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#66d9ef&#34;&gt;SUM&lt;/span&gt;(BonusAmount) &lt;span style=&#34;color:#66d9ef&#34;&gt;AS&lt;/span&gt; BonusAmount,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#75715e&#34;&gt;/* ... */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt; [dbo].[&lt;span style=&#34;color:#66d9ef&#34;&gt;Transaction&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;WHERE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Timestamp&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; :&lt;span style=&#34;color:#66d9ef&#34;&gt;start&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;AND&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Timestamp&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; :&lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;GROUP&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;BY&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;CONVERT&lt;/span&gt;(DATE, &lt;span style=&#34;color:#66d9ef&#34;&gt;Timestamp&lt;/span&gt;), TransactionType, AccountId,   &lt;span style=&#34;color:#75715e&#34;&gt;/* ... */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On our dataset, this compresses the transaction table by a factor of
more than 300. Not just that, by separating reads from writes, we give
ourselves so much more breathing room and options, which makes me sleep
so much better at night.&lt;/p&gt;
&lt;p&gt;As you probably noticed, for real-time statistics on this data, we&amp;rsquo;re
still missing today&amp;rsquo;s transactions in this table. Since today&amp;rsquo;s
transactions are a much smaller subset and likely to live in SQL
Server&amp;rsquo;s cache, we can query both the batch table and the transaction
table, to eventually merge the results of both queries. For our use
case, resource usage and query response times have dropped
significantly, especially for the &lt;em&gt;largest&lt;/em&gt; accounts.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t see it happening in the near future, but in case the usage of
these queries grows, we can still borrow more Lambda Architecture
practices and push further.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Notifications from an event log</title>
      <link>https://jefclaes.be/2016/04/notifications-from-event-log.html</link>
      <pubDate>Sun, 17 Apr 2016 17:37:00 +0200</pubDate>
      <guid>https://jefclaes.be/2016/04/notifications-from-event-log.html</guid>
      <description>&lt;p&gt;User notifications are a feature that came as an afterthought, but
turned out to be rather easy to implement - without touching (read:
breaking) existing functionality - thanks to having an immutable event
log.&lt;/p&gt;
&lt;p&gt;In the domain I&amp;rsquo;m working in at the moment, we will often give users
incentives to return to the website, or to extend their stay on the
website. These incentives were only communicated by email at first, and
this is a decent medium when you want users to return to the website.
However, when you want to extend their stay on the website, you want to
avoid users switching contexts between your website and their mail
client. But also, as soon as they return to your website, you want to
show them a crisp overview of all relevant calls to action. Having most
calls to action map to a specific page, the list of notifications can
serve as a one-click starting point, lowering the hurdle to browse to a
relevant page.&lt;/p&gt;
&lt;p&gt;Notifying a user is one thing. Another use case we wanted to solve, is
to dismiss notifications as soon as they are no longer relevant.&lt;/p&gt;
&lt;p&gt;Two examples of when a notification might no longer be considered
relevant:&lt;br&gt;
1.When a bonus is awarded to a user, he might ignore the notification and activate the bonus by directly browsing to the specific page.
2.When a bonus is awarded to a user, he might not visit the website before the bonus expires.&lt;/p&gt;
&lt;p&gt;In these cases, to avoid confusion and unsatisfied customers, we want to
dismiss the notification automatically.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s say that we&amp;rsquo;re going to implement notifications for bonuses. We
have these type of events to work with.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Events&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; BonusAwarded &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; payload &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; BonusAwarded
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; BonusActivated &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; payload &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; BonusActivated
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; BonusExpired &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; payload &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; BonusExpired
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; BonusAwarded &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; BonusId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Guid&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; UserId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Guid&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; ExpiryDate &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; DateTime &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; BonusActivated &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; BonusId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Guid&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; UserId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Guid&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; BonusExpired &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; BonusId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Guid&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; UserId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Guid&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On the other hand, we have a set of commands that interact with
notifications.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Commands&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; NotifyUser &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; payload &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; NotifyUser
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; ReadNotification &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; payload &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; ReadNotification
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; DismissNotification &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; payload &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; DismissNotification
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; NotifyUser &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; NotificationId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Guid&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; UserId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Guid&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; TemplateId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Guid&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Data &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Map&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; LinkId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; ReadNotification &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; NotificationId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Guid&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; UserId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Guid &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; DismissNotification &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; UserId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Guid&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; LinkId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A notification has an identifier, references a user, contains some data,
and most importantly can be linked to &lt;em&gt;something&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Working from an immutable event log, we can project the events to
commands (to dispatch them eventually).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; react log &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  log
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.map &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; e &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; e &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; BonusAwarded payload &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; NotifyUser &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         NotificationId &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Guid.NewGuid()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         UserId &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; userId
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         TemplateId &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BonusAwarded&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         Data &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ExpiryDate&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; payload&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ExpiryDate&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ToString&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;CultureInfo.InvariantCulture&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Map.ofList
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         LinkId &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;bonus/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; payload&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;BonusId&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ToString&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;N&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; BonusActivated payload &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; DismissNotification &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         UserId &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; payload&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;UserId
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         LinkId &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;bonus/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; payload&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;BonusId&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ToString&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;N&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; BonusExpired payload &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; DismissNotification &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         UserId &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; payload&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;UserId
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         LinkId &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;bonus/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; payload&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;BonusId&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ToString&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;N&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;log &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; react &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; dispatch &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; ignore
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When a bonus is awarded to a user, we will notify the user, providing
the template id and data that can be used inside of the template. In
this example, the notification can be linked to a specific bonus,
leveraging the bonus identifier.&lt;/p&gt;
&lt;p&gt;The user might now see something like this.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2016-04-17-notifications-from-an-event-log-Notification1.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2016-04-17-notifications-from-an-event-log-Notification1.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Being aware of the events which a bonus produces over its lifetime, and
their significance, we choose to dismiss the notification as soon as the
bonus is activated or expired (leveraging the bonus identifier as the
link again).&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2016-04-17-notifications-from-an-event-log-Notification2.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2016-04-17-notifications-from-an-event-log-Notification2.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now it&amp;rsquo;s up to the UX team (if you&amp;rsquo;re lucky enough to have one) to
decide on how to visualize the difference between a read and a dismissed
notification (if at all).&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Functional one-liner for running totals in C#</title>
      <link>https://jefclaes.be/2016/03/functional-one-liner-for-running-totals.html</link>
      <pubDate>Mon, 28 Mar 2016 16:22:00 +0200</pubDate>
      <guid>https://jefclaes.be/2016/03/functional-one-liner-for-running-totals.html</guid>
      <description>&lt;p&gt;Visualizing some data earlier this week I had to compute the &lt;a href=&#34;https://en.wikipedia.org/wiki/Running_total&#34;&gt;running
total&lt;/a&gt; of a sequence of
numbers.&lt;/p&gt;
&lt;p&gt;For example, if the input sequence was [ 100; 50; 25 ] the result of
the computation would be a new sequence of [ 100; 150; 175 ].&lt;/p&gt;
&lt;p&gt;Muscle memory made me take a procedural approach, which works, but made
me wonder if I could get away with less lines of code and without
mutable state.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; IEnumerable&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&amp;gt; ToRunningTotalProcedural(IEnumerable&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&amp;gt; sequence)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; runningTotal = &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; item &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; sequence)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        runningTotal += item;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;yield&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; runningTotal;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Although C# doesn&amp;rsquo;t try very hard to push a functional approach, the
BCL does give you some useful tools.&lt;/p&gt;
&lt;p&gt;The first thing that comes to mind is using &lt;a href=&#34;https://msdn.microsoft.com/en-us/library/bb548651(v=vs.100).aspx&#34;&gt;IEnumerable&amp;rsquo;s Aggregate
function&lt;/a&gt;,
which will apply a function over each item in the sequence and will pass
the aggregated partial result the next time the function is applied.
Each time the function is applied, we can take the last item (if it
exists) of the aggregated partial result and add the current item&amp;rsquo;s
value to it, and append that sum to the aggregated partial result.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; IEnumerable&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&amp;gt; ToRunningTotalFunctionalAggregate(IList&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&amp;gt; sequence)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; sequence.Aggregate(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ImmutableList&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&amp;gt;.Empty, 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        (acc, item) =&amp;gt; rt.Add(acc.Any() ? acc.Last() + item : item));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Another more compact - but less efficient approach - I could think of,
is using the index of each element in the sequence, to take subsets and
to sum their values.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; IEnumerable&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&amp;gt; ToRunningTotalLinqTake(IList&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&amp;gt; sequence)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; sequence.Select((item, i) =&amp;gt; sequence.Take(i + &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;).Sum());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Running out of ideas, I ported &lt;a href=&#34;https://msdn.microsoft.com/en-us/library/ee340364.aspx&#34;&gt;F#&amp;rsquo;s Scan&lt;/a&gt; function which allows more compact code, without giving up efficiency. This function, similar to the Aggregate function, applies a function over each item in the sequence. However, instead of passing the aggregated partial result each time the function is applied, the value of the last computation is passed in, to finally return the list of all computations.&lt;/p&gt;
&lt;p&gt;With a bit of good will, C# allows you to be more functional too.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Consumed in 2015</title>
      <link>https://jefclaes.be/2016/01/consumed-in-2015.html</link>
      <pubDate>Fri, 01 Jan 2016 14:49:00 +0100</pubDate>
      <guid>https://jefclaes.be/2016/01/consumed-in-2015.html</guid>
      <description>&lt;p&gt;I started in &lt;a href=&#34;http://www.jefclaes.be/2015/01/consumed-in-2014.html&#34;&gt;2014&lt;/a&gt; to keep lists of everything I consume. I&amp;rsquo;ve continued this effort throughout
2015 and can now share the items I particularly enjoyed.&lt;/p&gt;
&lt;p&gt;In 2015, I read 16 books and 3 papers, watched 3 movies and 4 shows,
listened to 1 audio book and no podcasts. A lot less TV compared to
2014, but most of that time went to playing video games with some of my
friends. Also a lot less time spent in the car listening to audiobooks
or podcasts, since I&amp;rsquo;m now dropping off my girlfriend every day.&lt;/p&gt;
&lt;p&gt;Going over the books I&amp;rsquo;ve read this year here are my recommendations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.amazon.com/gp/product/1593275528/ref=as_li_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=1593275528&amp;amp;linkCode=as2&amp;amp;tag=diofanedebyje-20&amp;amp;linkId=L4KDLJVACFMLJIAR&#34;&gt;The book of F#&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.amazon.com/gp/product/039334777X/ref=as_li_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=039334777X&amp;amp;linkCode=as2&amp;amp;tag=diofanedebyje-20&amp;amp;linkId=4TOQ52ZSBRV3RQ2G&#34;&gt;Naked Statistics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.amazon.com/gp/product/0812972155/ref=as_li_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0812972155&amp;amp;linkCode=as2&amp;amp;tag=diofanedebyje-20&amp;amp;linkId=RYTAWFCK3BXA4Q6H&#34;&gt;Masters Of Doom&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.amazon.com/gp/product/0374533555/ref=as_li_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0374533555&amp;amp;linkCode=as2&amp;amp;tag=diofanedebyje-20&amp;amp;linkId=LCTOPQ73ULL5WIJ2&#34;&gt;Thinking Fast and Slow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.amazon.com/gp/product/0451211243/ref=as_li_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0451211243&amp;amp;linkCode=as2&amp;amp;tag=diofanedebyje-20&amp;amp;linkId=5O4G7FPHYXTJFUL5&#34;&gt;The Dark Tower series&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.amazon.com/gp/product/0441172717/ref=as_li_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0441172717&amp;amp;linkCode=as2&amp;amp;tag=diofanedebyje-20&amp;amp;linkId=M6PXTIKY55OZOEXZ&#34;&gt;Dune&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most of the TV shows I&amp;rsquo;ve watched this year were more than great:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.imdb.com/title/tt2802850/?ref_=nv_sr_1&#34;&gt;Fargo Season 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.imdb.com/title/tt3032476/?ref_=nv_sr_1&#34;&gt;Better Call Saul Season 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.imdb.com/title/tt2707408/?ref_=fn_al_tt_1&#34;&gt;Narcos Season 1&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Visualizing event streams</title>
      <link>https://jefclaes.be/2015/12/visualizing-event-streams.html</link>
      <pubDate>Sun, 20 Dec 2015 17:59:00 +0100</pubDate>
      <guid>https://jefclaes.be/2015/12/visualizing-event-streams.html</guid>
      <description>&lt;p&gt;In my recent talk on &lt;a href=&#34;http://www.jefclaes.be/2015/11/slides-from-my-talk-evil-by-design-at.html&#34;&gt;Evil by
Design&lt;/a&gt;,
I showed how I&amp;rsquo;ve been visualizing event streams as a means to get a
better grip on how aggregates behave in production. The talk&amp;rsquo;s scope
kept me from showing the code that goes together with the examples
shown. Consider this post as an addendum to that talk.&lt;/p&gt;
&lt;p&gt;First off, we need a few types: a string that identifies a stream, an
event containing a timestamp and its name. A stream which is a
composition of an identifier and a sequence of events. We also need a
function that&amp;rsquo;s able to read a stream based on its identifier.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;StreamId&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Event&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Timestamp &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; DateTime&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Name &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Payload &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Stream&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; StreamId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; StreamId&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Events &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; seq&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Event&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ReadStream&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; StreamId &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; Stream
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; readStream &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; streamId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; StreamId &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    StreamId &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; streamId
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Events &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; seq &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;// implementation goes here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once we&amp;rsquo;ve implemented that, we want to go ahead and visualize a single
stream. Having some experience with Google Charts, I used the
&lt;a href=&#34;https://tahahachana.github.io/XPlot/&#34;&gt;XPlot.GoogleCharts&lt;/a&gt; package.&lt;/p&gt;
&lt;p&gt;I want to visualize my event stream as a timeline. For that, it makes
only sense to use the Timeline graph. This means that I&amp;rsquo;ll have to make
sure I transform my data into a format the Timeline chart can work with,
which is a sequence of tuples.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Timeline data
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;data &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; seq&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;#&lt;/span&gt;value &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;#&lt;/span&gt;value&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;data &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; seq&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;#&lt;/span&gt;value &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;#&lt;/span&gt;value&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;let asTimelineEventStream stream =
    stream.Events
    |&amp;gt; Seq.map (fun e -&amp;gt;
    (
        stream.StreamId,
        e.Name,
        e.Timestamp,
        e.Timestamp.AddMilliseconds(float 1)
    ))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So we write a function which accepts a stream, and returns a sequence of
tuples containing the stream identifier, the event name and the
timestamp of the event.&lt;/p&gt;
&lt;p&gt;With just a few lines of code, we can already compose our way to a
timeline.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;#34;withdrawrequest/...&amp;#34;
|&amp;gt; readStream
|&amp;gt; asTimelineEventStream
|&amp;gt; Chart.Timeline
|&amp;gt; Chart.Show
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2015-12-20-visualizing-event-streams-eventstream_viz_1.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2015-12-20-visualizing-event-streams-eventstream_viz_1.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The result tells a small story: a withdrawal to a casino was requested
at 9:44PM, approved at 12:15PM the next day, and eventually completed 7
hours later.&lt;/p&gt;
&lt;p&gt;From an operational perspective, this visualization can be used as
visual assistance for your support team when users have a question or a
complaint. From a more technical perspective, it can be used to get a
feel of the domain language and business processes without having to
look at code or tests. I could even see this being used in the
front-end, where you enable users to monitor a process; think package
tracking, document verification and so on.&lt;/p&gt;
&lt;p&gt;Once you start exploring aggregates, you will notice that some
aggregates look healthier than others; lean and short-lived. While other
aggregates are fat and long-lived which can introduce a set of
problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;rebuilding state from a large event stream might kill performance&lt;/li&gt;
&lt;li&gt;there&amp;rsquo;s often more contention on larger aggregates making optimistic (or pessimistic) concurrency very annoying&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2015-12-20-visualizing-event-streams-eventstream_vis_1_1.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2015-12-20-visualizing-event-streams-eventstream_vis_1_1.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Spotting one of these instances is an invitation to review your model,
to revise true invariants and to break things apart.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ve now looked at an aggregate&amp;rsquo;s event stream in isolation, but often
something happening in one place leads to a reaction somewhere else. A
simple example: when a new user registers, a promotion is awarded. We
can visualize this by rendering multiple streams on one timeline.&lt;/p&gt;
&lt;p&gt;Technically, we need to transform a sequence of streams to a single
sequence of tuples which we can feed the chart. It&amp;rsquo;s as simple as
mapping each stream for then to flatten the result into a single
sequence.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; asTimelineEventStreams streams &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    streams
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.map asTimelineEventStream
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.concat
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;correlatedStreams
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; asTimelineEventStreams
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Chart.Timeline
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Chart.Show
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This one extra step makes the result even more useful.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2015-12-20-visualizing-event-streams-eventstream_viz_2.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2015-12-20-visualizing-event-streams-eventstream_viz_2.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s more potential though; consider showing the payload when
hovering over an event, adding commands in the mix, zooming out, zooming
in, filtering&amp;hellip;&lt;/p&gt;
&lt;p&gt;If this is something you could see being useful to you or your
organization, let me know! Maybe I can port some bits and polish the
concept in the open.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Slides from my talk &#34;Evil by Design&#34; at Build Stuff</title>
      <link>https://jefclaes.be/2015/11/slides-from-my-talk-evil-by-design-at.html</link>
      <pubDate>Wed, 18 Nov 2015 15:47:00 +0100</pubDate>
      <guid>https://jefclaes.be/2015/11/slides-from-my-talk-evil-by-design-at.html</guid>
      <description>&lt;p&gt;Third time attending Build Stuff, first time doing a talk. I&amp;rsquo;m happy
that it&amp;rsquo;s out of the way and can now just enjoy the conference, but I&amp;rsquo;m
even more excited that it was well-received! The talk should have been
recorded, but you can already find the abstract and slides below.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Last year I ventured into the domain of (online) gambling. Given that
the industry has been around since forever, I expected most problems
to be of the technical kind. As it turned out, the struggle with
technology was only part of a bigger problem; to move forward we
needed to fully grasp the industry and its consumers. Events started out as a way to dismantle a legacy system, but quickly
proved to be an effective tool to gain a deeper understanding of our
domain. Visualising event streams, we discovered patterns that helped
us identify what drives different types of users. Having a better understanding of what customers are looking for, we
dove into existing literature to learn which techniques and models
casinos use to cater for each type of user. We learned how to program
chance while staying true to the Random Number God. Even when variance
is brutal, casinos have enough data and tools to steer clear from the
pain barrier. All of this entails interesting problems and software, but isn&amp;rsquo;t my
code damaging society? Or is gambling just another human trait?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://www.slideshare.net/jclaes/evil-by-design&#34;&gt;Slides&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Defining big wins</title>
      <link>https://jefclaes.be/2015/11/defining-big-wins.html</link>
      <pubDate>Mon, 16 Nov 2015 21:31:00 +0100</pubDate>
      <guid>https://jefclaes.be/2015/11/defining-big-wins.html</guid>
      <description>&lt;p&gt;Casinos invest a lot of energy selling the dream. One way to do this is
by showing off people winning big in your casino. Everyone has seen
those corny pictures of people holding human-sized cheques right? It&amp;rsquo;s a
solid tactic, since empirical evidence shows that after a store has sold
a large-prize winning lottery ticket, the ticket sales increase from 12
to 38% over the following weeks.&lt;/p&gt;
&lt;p&gt;If we look at slot machine play, what exactly defines a big win? The
first stab we took at this was quite sloppy. We took an arbitrary number
and said wins bigger than 500 euro are impressive. This was quick and
easy to implement, but when we observed the results we noticed that when
you have players playing at high stakes, a win of 500 euro really isn&amp;rsquo;t
that impressive, and we would see the exceptional high roller often
dominate the results.&lt;/p&gt;
&lt;p&gt;What defines a big win, is not the amount, but how many times the win
multiplies your stake. Betting 1 euro to win 200 euro sounds like quite
the return right? Coming to this conclusion, we had to define a
multiplier threshold that indicates a big win.&lt;/p&gt;
&lt;p&gt;Having each win correlate to a bet, we could project the multipliers,
and look at the distribution.&lt;/p&gt;
&lt;p&gt;In this example I&amp;rsquo;m using matlab, but we could do the same using Excel
or code.&lt;/p&gt;
&lt;p&gt;So first we load the multipliers data set.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;multipliers = csvread(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;C:\data\multipliers.csv&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For then to look at its histogram, visualizing how the multipliers are
distributed.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;histfit(multipliers)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2015-11-16-defining-big-wins-hist1.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2015-11-16-defining-big-wins-hist1.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here we notice that there is a skewness towards large values; a few
points are much larger than the bulk of data. Logarithmic scales can
help us here.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;histfit(log(multipliers), &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2015-11-16-defining-big-wins-hist2.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2015-11-16-defining-big-wins-hist2.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This shows us a pretty fitting bell curve, meaning the multipliers are
somewhat log normally distributed. We could now use the log standard
deviation to pick the outliers.&lt;/p&gt;
&lt;p&gt;But we can also tabulate the data set and hand pick the cut-off of
normal wins.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-matlab&#34; data-lang=&#34;matlab&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tabulate(log(round(multipliers)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Value    Count   Percent
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;54905&lt;/span&gt;     &lt;span style=&#34;color:#ae81ff&#34;&gt;21.54&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0.693147&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;68548&lt;/span&gt;     &lt;span style=&#34;color:#ae81ff&#34;&gt;26.89&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;1.09861&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;29680&lt;/span&gt;     &lt;span style=&#34;color:#ae81ff&#34;&gt;11.64&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;1.38629&lt;/span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;16421&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;6.44&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;1.60944&lt;/span&gt;     &lt;span style=&#34;color:#ae81ff&#34;&gt;8900&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;3.49&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;1.79176&lt;/span&gt;     &lt;span style=&#34;color:#ae81ff&#34;&gt;8102&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;3.18&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;1.94591&lt;/span&gt;     &lt;span style=&#34;color:#ae81ff&#34;&gt;2238&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0.88&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;2.07944&lt;/span&gt;     &lt;span style=&#34;color:#ae81ff&#34;&gt;5953&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;2.34&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;2.19722&lt;/span&gt;     &lt;span style=&#34;color:#ae81ff&#34;&gt;1044&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0.41&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;2.30259&lt;/span&gt;     &lt;span style=&#34;color:#ae81ff&#34;&gt;3297&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;1.29&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#ae81ff&#34;&gt;2.3979&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;625&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0.25&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;2.48491&lt;/span&gt;     &lt;span style=&#34;color:#ae81ff&#34;&gt;1128&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0.44&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;2.56495&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;687&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0.27&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;2.63906&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;544&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0.21&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;2.70805&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;820&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0.32&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;2.77259&lt;/span&gt;     &lt;span style=&#34;color:#ae81ff&#34;&gt;1402&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0.55&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;2.83321&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;364&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0.14&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;2.89037&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;344&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0.13&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;2.94444&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;185&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0.07&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;2.99573&lt;/span&gt;     &lt;span style=&#34;color:#ae81ff&#34;&gt;2406&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0.94&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;3.04452&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;162&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0.06&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;3.09104&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;139&lt;/span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;0.05&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We could now write a rule in our projection of big wins which states
that a log(multiplier) larger than 3 is considered to be a &lt;em&gt;big&lt;/em&gt; win.&lt;/p&gt;
&lt;p&gt;Matlab, Excel and the like are great domain specific tools for data
exploration which can help you reach a better feel and understanding.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Bulk SQL projections with F# and type providers</title>
      <link>https://jefclaes.be/2015/10/bulk-sql-projections-with-f-and-type.html</link>
      <pubDate>Sun, 18 Oct 2015 15:30:00 +0200</pubDate>
      <guid>https://jefclaes.be/2015/10/bulk-sql-projections-with-f-and-type.html</guid>
      <description>&lt;p&gt;Early Summer, I had to set up an integration with an external partner.
They required of us to daily provide them with a relational dataset
stored in SQL Server. Most, if not all of the data was temporal,
append-only by nature; think logins, financial transactions..&lt;/p&gt;
&lt;p&gt;Since the data required largely lived in an eventstore on our end, I
needed fast bulk projections. Having experimented with a few approaches,
I eventually settled on projections in F# taking advantage of type
providers.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s say we have an event for when users watched a video and one for
when users shared a video.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Events&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; WatchedVideo &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; payload &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; WatchedVideo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; SharedVideo &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; payload &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; SharedVideo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; WatchedVideo &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; UserId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Title &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Timestamp &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; DateTime &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; SharedVideo &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; UserId &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Title &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Timestamp &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; DateTime &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We want to take streams from our eventstore and project them to a
specific state; a stream goes in and state comes out.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;EventStream&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; seq&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Events&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Projection&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;#39;&lt;/span&gt;state&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; EventStream &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;#39;&lt;/span&gt;state
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then we want to take that state, and store it in our SQL Server
database.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;StoreState&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;#39;&lt;/span&gt;state&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; SqlConnection &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; SqlTransaction &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;#39;&lt;/span&gt;state &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;unit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Some infrastructure that reads a specific stream, runs the projection,
stores the state and checkpoints the projection, could look like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; runSqlProjection input &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; checkpoint &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; readCheckpoint input&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ProjectionName
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; events &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; readEvents input&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;SourceStreamName checkpoint
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; newCheckpoint &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; events &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.map&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;EventId&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.max
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; state &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; events &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; unwrap &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; input&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Projection
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;use&lt;/span&gt; conn &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; SqlConnection&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;destinationConnectionString&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   conn&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Open()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;use&lt;/span&gt; tx &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; conn&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;BeginTransaction&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;IsolationLevel.ReadCommitted&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   input&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;StoreState conn tx state
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   writeCheckpoint input&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ProjectionName newCheckpoint conn tx
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   tx&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Commit()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To avoid data corruption, storing the state and writing the checkpoint
happens in the same transaction.&lt;/p&gt;
&lt;p&gt;With this piece of infrastructure in place, we are close to implementing
an example. But before we do that, we first need to install the
&lt;a href=&#34;https://www.nuget.org/packages/FSharp.Data.SqlClient&#34;&gt;FSharp.Data.SqlClient
package&lt;/a&gt;. Using
this package, we can use the &lt;a href=&#34;http://fsprojects.github.io/FSharp.Data.SqlClient/&#34;&gt;SqlProgrammabilityProvider type
provider&lt;/a&gt; to provide
us with types for each table in our destination database. In the snippet
below, I&amp;rsquo;ll create a typed dataset for the WatchedVideos table and add a
row.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Destination&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; SqlProgrammabilityProvider&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Data Source=...&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// or type Destination = SqlProgrammabilityProvider&amp;lt;&amp;#34;Name=Destination&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// **magic**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; dt &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Destination.dbo&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Tables&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;WatchedVideos()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dt&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;AddRow&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Jef&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Tesla&amp;#39;s New Autopilot&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; DateTime.UtcNow&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I haven&amp;rsquo;t defined this type, nor was it generated by me. The
SqlProgrammabilityProvider type provider gives you these for free, based
on the meta data it can extract from the destination database. This also
means that when you change your table, without changing your code, the
compiler will have no mercy and immediately feed back where you broke
your code. In this usecase, where you rather rebuild your data than
migrate it, the feedback loop of changing your database model becomes so
short, that it allows you to break stuff with much confidence. The only
caveat here is that the compiler must always be able to access that
specific database, compiling without fails. In practice, this means you
need to ship your source with a build script that sets up your database
locally before you do any work.&lt;/p&gt;
&lt;p&gt;Going from a stream to a dataset is quite declarative and
straightforward with the help of pattern matching.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; toWatchedVideosDataset stream &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; dt &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Destination.dbo&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Tables&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;WatchedVideos()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  stream 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.iter&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; e &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; e &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Events.SharedVideo x &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; dt&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;AddRow&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;UserId&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Title&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Timestamp&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; ()&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  dt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Storing the result in an efficient fashion is also simple, since the
dataset directly exposes a BulkCopy method.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; storeState conn tx &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; state &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Destination.dbo&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Tables&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;WatchedVideos &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    state&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;BulkCopy&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;conn&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; SqlBulkCopyOptions.Default&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; tx&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When we put this all together, we end up with this composition.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;runSqlProjection &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ProjectionName &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;WatchedVideos&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   SourceStreamName &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;$all&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   Projection &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; toWatchedVideosDataset
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   StoreState &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; storeState
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Executing this program, we can see the data was persisted like
expected.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2015-10-18-bulk-sql-projections-with-f-and-type-providers-bulkprojection.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2015-10-18-bulk-sql-projections-with-f-and-type-providers-bulkprojection.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In the real world, you also want to take care of batching and logging,
but that isn&amp;rsquo;t too hard to implement.&lt;/p&gt;
&lt;p&gt;Having this approach in production for some time now, I&amp;rsquo;m still quite
happy with how it turned out. The implementation is fast, and the code
is compact and easy to maintain.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Aspect ratio calculation</title>
      <link>https://jefclaes.be/2015/09/aspect-ratio-calculation.html</link>
      <pubDate>Fri, 11 Sep 2015 23:40:00 +0200</pubDate>
      <guid>https://jefclaes.be/2015/09/aspect-ratio-calculation.html</guid>
      <description>&lt;p&gt;Earlier today I was writing a migration script in F# where I had to
calculate the aspect ratio based on the given screen dimensions. This is
one of those problems where I don&amp;rsquo;t even mind breaking my head over, but
directly head over to Stackoverflow to find an accepted answer which I
can just copy paste. Since I didn&amp;rsquo;t find an F# snippet I could use, I
ported some JavaScript, and embedded the result below for future snippet
hunters.&lt;/p&gt;
&lt;p&gt;The aspectRatio function does two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Recursively find the greatest common divisor between the width and height&lt;/li&gt;
&lt;li&gt;Divide the width and height by the greatest common divisor&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; aspectRatio width height &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; rec greatestCommonDivisor x y &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; y &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; 0 &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; x
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; greatestCommonDivisor y &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;x &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; y&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; gcd &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; greatestCommonDivisor width height
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  width &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; gcd&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; height &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; gcd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// &amp;gt; aspectRatio 1200 900;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// val it : int * int = (4, 3)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// &amp;gt; aspectRatio 100 100;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// val it : int * int = (1, 1)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// &amp;gt; aspectRatio 900 1200;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// val it : int * int = (3, 4)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>Basic casino math</title>
      <link>https://jefclaes.be/2015/06/basic-casino-math.html</link>
      <pubDate>Mon, 22 Jun 2015 22:52:00 +0200</pubDate>
      <guid>https://jefclaes.be/2015/06/basic-casino-math.html</guid>
      <description>&lt;p&gt;In a previous series of posts, I went over the models used by casinos to
spin a wheel
(&lt;a href=&#34;http://www.jefclaes.be/2014/12/spinning-wheel.html&#34;&gt;spinning&lt;/a&gt;,
&lt;a href=&#34;http://www.jefclaes.be/2014/12/spinning-wheel-manipulating-odds.html&#34;&gt;manipulating the
odds&lt;/a&gt;,
&lt;a href=&#34;http://www.jefclaes.be/2014/12/spinning-wheel-clustering-and-near.html&#34;&gt;clustering and near
misses&lt;/a&gt;).
I did not yet expand on the basic mathematical models that ensure a
casino makes money.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s pretend we are spinning the wheel again. The wheel has 5 pockets,
and just one of those is the winning one. Given we will be using an
unmodified wheel, you win 1 out of 5 spins. Each bet costs you 1 euro.
Looking at the true odds (1/5), the casino should pay out 4 euro for you
to break even.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt; - 1M (Loss)
 - 1M (Loss)
 - 1M (Loss)
 - 1M (Loss)
 + 4M (Win)
 = 0M (Total)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Respecting the true odds would not make the casino any money, they pay
out less to ensure that the house has an edge on you. So instead of
paying out 4 euro, it will be a tad less.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;-  1M (Loss)
-  1M (Loss)
-  1M (Loss)
-  1M (Loss)
+  3M (Win)
= -1M (Total)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;strong&gt;house edge&lt;/strong&gt; can be cast into a fairly simple formula.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; houseEdge oddsOfWinning winnings oddsOfLosing stake &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  oddsOfWinning &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; winnings &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; oddsOfLosing &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; stake
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;houseEdge &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; 1M &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; 5M &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; 3M &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; 4M &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; 5M &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; 1M &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; printfn &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%A&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 0.20M
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this example, the house edge is a whopping 20%, meaning statistically
20% of each bet will go to the casino. So the higher the house edge, the
better?&lt;/p&gt;
&lt;p&gt;Not really, if players constantly go through their bankroll in a matter
of minutes, it&amp;rsquo;s not very likely they will keep returning to your
casino. The inverse to the house edge, and maybe even a more important
number, is the &lt;strong&gt;payout percentage&lt;/strong&gt;. When the house edge is 20%, the
player&amp;rsquo;s payout percentage will be 80%. For each bet you make, you will
statistically see a return of 80%. As a player to get maximum value for
money - to play as long as possible - you should aim to play in a casino
that has the highest payout percentages.&lt;/p&gt;
&lt;p&gt;Often misunderstood is that this does not mean you will get to keep 80%
of your bankroll by the end of the night. The payout percentage relates
to a single bet. The casino&amp;rsquo;s &lt;strong&gt;hold&lt;/strong&gt;, or money eventually left on the
table, is several times the house edge, since players tend to circulate
through the same money more than once. So the longer you play, the more
the house edge will nibble at your bankroll.&lt;/p&gt;
&lt;p&gt;Knowing the house edge, it&amp;rsquo;s pretty simple for a casino to predict a
&lt;strong&gt;customer&amp;rsquo;s worth&lt;/strong&gt;; multiply the house edge, the average stake and the
number of games per hour.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; customerValue houseEdge stake handsPerHour &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       houseEdge &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; stake &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; handsPerHour
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;customerValue 0&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;2M 1M 60M &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; printfn &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%A&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 12M
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Given we spin the wheel 60 times an hour for a stake of 1 euro, we will
make the casino 12 euro an hour on average. The higher this number, the
bigger your potential, the harder a casino will try to make you a
regular.&lt;/p&gt;
&lt;p&gt;Understanding how casinos make a living, it&amp;rsquo;s safe to say &lt;em&gt;casinos
aren&amp;rsquo;t the place to play for money, but to play with money&lt;/em&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Consumed: Queries and projections (F#)</title>
      <link>https://jefclaes.be/2015/05/consumed-queries-and-projections-f.html</link>
      <pubDate>Sun, 24 May 2015 18:00:00 +0200</pubDate>
      <guid>https://jefclaes.be/2015/05/consumed-queries-and-projections-f.html</guid>
      <description>&lt;p&gt;This is the third post in my series on porting a node.js application to
an F# application.&lt;/p&gt;
&lt;p&gt;So far, I&amp;rsquo;ve looked at &lt;a href=&#34;http://www.jefclaes.be/2015/04/parsing-command-line-arguments-with-f.html&#34;&gt;parsing command line
arguments&lt;/a&gt;,
&lt;a href=&#34;http://www.jefclaes.be/2015/05/consumed-handling-commands-f.html&#34;&gt;handling commands and storing
events&lt;/a&gt;.
Today, I want to project those events into something useful that can be
formatted and printed to the console.&lt;/p&gt;
&lt;p&gt;In the original application, I only had a single query. The result of
this query lists all items consumed grouped by category, sorted
chronologically.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Query&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; List
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ListResult&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Categories &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; seq&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Category&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; Category &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Name &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Items &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; seq&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Item&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; Item &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Id &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Timestamp &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; DateTime&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Category &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Description&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Url&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Handling the query is done in a similar fashion to handling commands.
The handle function matches each query and has a dependency on the event
store.&lt;/p&gt;
&lt;p&gt;Where C# requires a bit of plumbing to get declarative projections
going, F#&amp;rsquo;s pattern matching and set of built-in functions give you
this for free.&lt;/p&gt;
&lt;p&gt;We can fold over the event stream, starting with an empty list, to
append each item that was consumed, excluding the ones that were removed
later. Those projected items can then be grouped by category, to be
mapped into a category type that contains a sorted list of items.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; handle read query &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; query &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Query.List &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; folder state e &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; e &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Event.Consumed data &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            Id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; data&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Id&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            Timestamp &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; data&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Timestamp&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            Category &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; data&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Category&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            Description &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; data&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Description&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            Url &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; data&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Url
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt; state
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Event.Removed data &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        List.filter &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Id &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt; data&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Id&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; state
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; read &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;$all&amp;#34;&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; EventStream.NotExists &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Categories &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Seq.empty &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; EventStream.Exists &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; events &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; items &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Seq.fold folder [] events
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; categories &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            items
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.groupBy &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Category&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.map &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; y &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Name &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; x&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Items &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; y &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.sortBy &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Timestamp&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Categories &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; categories &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The result can be printed to the console using a more imperative
style.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; parse argv &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Success&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;Query&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;query&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; QueryHandling.handle &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;read path&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; query
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; c &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; result&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Categories &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           printfn &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%s&amp;#34;&lt;/span&gt; c&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Name
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           printfn &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%s&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;String.replicate c&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Name&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Length &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; i &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; c&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Items &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; ts &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; i&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Timestamp&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ToString&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dd/MM/yyyy&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               printfn &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%s - %s | %s (%s)&amp;#34;&lt;/span&gt; ts i&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Id i&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Description i&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Url
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And that&amp;rsquo;s it, we&amp;rsquo;ve come full circle. We can now consume items, remove
items and query for a list of consumed items.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;λ Consumed.exe -help

Following commands are available:
-n consume -c category -d description -u url
-n remove -id id
-n list

λ Consumed.exe -n consume -c book -d &amp;#34;The Drawing of the Three&amp;#34; -u &amp;#34;...&amp;#34;

Yay! Something happened = Success ...

λ consumed.exe -n list

book
----
24/05/2015 - 24052015125831 | The Drawing of the Three (...)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Compared to the node.js implementation, the F# version required
substantially less code (two to three times less). More importantly,
although I wrote tests for both, I felt way more confident completing
the F# version. A strong type system, discriminated unions, pattern
matching, purity, composability and a smart compiler makes way for
sensible and predictable code.&lt;/p&gt;
&lt;p&gt;Source code is &lt;a href=&#34;https://github.com/JefClaes/consumed-f&#34;&gt;up on Github&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Consumed: Handling commands (F#)</title>
      <link>https://jefclaes.be/2015/05/consumed-handling-commands-f.html</link>
      <pubDate>Sun, 17 May 2015 17:51:00 +0200</pubDate>
      <guid>https://jefclaes.be/2015/05/consumed-handling-commands-f.html</guid>
      <description>&lt;p&gt;As &lt;a href=&#34;http://www.jefclaes.be/2015/04/parsing-command-line-arguments-with-f.html&#34;&gt;I wrote
earlier&lt;/a&gt;,
I&amp;rsquo;ve been working on porting a node.js web application to an F# console
application. It&amp;rsquo;s an application I wrote to learn node.js but still use
today to keep track of &lt;a href=&#34;http://www.jefclaes.be/2015/01/consumed-in-2014.html&#34;&gt;all the things I
consume&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The application is able to consume an item, to remove a consumed item
and to query all consumed items.&lt;/p&gt;
&lt;p&gt;In the previous post, I parsed command line arguments into typed
commands and queries. Today, I&amp;rsquo;ll look at handling the two commands.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Command&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Consume &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; data &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; ConsumeData
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Remove &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; data &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; RemoveData
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; ConsumeData &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Id &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Category &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Description &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Url &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; RemoveData &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Id &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ve refactored the command discriminated union to contain records with
data that go along with the command - I found that this makes for more
discoverable and refactor-friendly deconstruction later on.&lt;/p&gt;
&lt;h3 id=&#34;validation&#34;&gt;Validation&lt;/h3&gt;
&lt;p&gt;Before we do anything with the command, we need to make sure it passes
basic validation. The validate function takes a command, and returns a
success or failure result. Validation can fail because an argument is
empty, its structure is invalid or it&amp;rsquo;s out of range. Inside the
function we match the command discriminated union with each case,
validate the data and return a result.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Result&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;#39;&lt;/span&gt;TSuccess&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;#39;&lt;/span&gt;TFailure&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Success &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;#39;&lt;/span&gt;TSuccess
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Failure &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;#39;&lt;/span&gt;TFailure
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ValidationFailure&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; ArgumentEmpty &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; ArgumentStructure &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; ArgumentOutOfRange &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;HandlingFailure&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Validation &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; ValidationFailure
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; succeeds s &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Success s
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; validationFails f &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Failure&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;Validation&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;f&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; validate cmd &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; cmd &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Consume data &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	    &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; data&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt; validationFails&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;ArgumentEmpty&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	        &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; data&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Category &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt; validationFails&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;ArgumentEmpty&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;category&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	        &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; data&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Description &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt; validationFails&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;ArgumentEmpty&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	        &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; data&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Url &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt; validationFails&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;ArgumentEmpty&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;url&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	        &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[|&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;book&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;movie&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;|]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.exists &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Equals&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;data&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Category&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; StringComparison.OrdinalIgnoreCase&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt; validationFails&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;ArgumentOutOfRange&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;category&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;         
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	        &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; data&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Url&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Contains&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; data&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Url&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Contains&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt; validationFails&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;ArgumentStructure&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;url&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	        &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; succeeds cmd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	    &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Remove data &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	    &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; data&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt; validationFails&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;ArgumentEmpty&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	        &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; succeeds cmd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	    &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;producing-events&#34;&gt;Producing events&lt;/h3&gt;
&lt;p&gt;Having validated the command, we can start thinking about doing
something useful. I want the command handlers to be pure, to be able to
focus on computation, without having to worry about side effects.&lt;/p&gt;
&lt;p&gt;Since the node.js web application stores its data in the form of events,
this one will too. I can now migrate the existing event store to a
simple text file living in my Dropbox, for then to drop the existing
Postgres database.&lt;/p&gt;
&lt;p&gt;This means that command handlers will need to produce events.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Event&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Consumed &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; data &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; ConsumedData
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Removed &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; data &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; RemovedData
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; ConsumedData &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Timestamp &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; DateTime&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Id &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Category &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Description &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Url &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;and&lt;/span&gt; RemovedData &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Timestamp &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; DateTime&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Id &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CmdResult&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Event &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; stream &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;event&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Event
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;dependencies&#34;&gt;Dependencies&lt;/h3&gt;
&lt;p&gt;Looking at the tests the command handlers need to satisfy, we know
that a command handler depends on the system time and the eventstore.&lt;/p&gt;
&lt;p&gt;The dependency on time is just a function that takes no arguments and
returns a datetime.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;unit&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; DateTime
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;An implementation could look like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; thetime() &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; DateTime.UtcNow
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Reading an event stream is a function that takes a stream name and
returns an event stream.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;EventStream&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; NotExists &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; name &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Exists &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; name &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; events &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; seq&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Event&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; EventStream
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Implementing a naïve event store takes more than one line on code.&lt;/p&gt;
&lt;h3 id=&#34;an-eventstore&#34;&gt;An eventstore&lt;/h3&gt;
&lt;p&gt;This implementation stores events in a text file. When an event is
stored, it gets serialized to JSON for then to be appended to a text
file. When reading a stream it will read all events from disk,
deserialize them to then filter by stream name before returning it as an
event stream - it&amp;rsquo;s not exactly web scale.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;StoredEvent&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Stream &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Body &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Event  &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; store path stream e &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; serialize e &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; JsonConvert.SerializeObject e
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; writeToDisk &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; line &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;use&lt;/span&gt; wr &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; StreamWriter&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;path&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            wr&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;WriteLine&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;line&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; eventOnDisk &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Stream &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; stream&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Body &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; e &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        serialize eventOnDisk &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; writeToDisk 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Success eventOnDisk
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; read path stream &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; deserialize x &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; JsonConvert.DeserializeObject&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;StoredEvent&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;(&lt;/span&gt;x&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; readFromDisk &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; File.ReadAllLines path &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.map deserialize
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; eventsFromDisk &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; stream &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;$all&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; readFromDisk
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; readFromDisk &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.filter &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; e &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; e&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Stream &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; stream&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; eventsFromDisk &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.isEmpty &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; EventStream.NotExists stream
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; EventStream.Exists &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;stream&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; eventsFromDisk &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.map &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; e &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; e&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Body&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The signature for reading a stream doesn&amp;rsquo;t satisfy the signature we
defined earlier though. We can satisfy it by creating a &lt;a href=&#34;http://fsharpforfunandprofit.com/posts/partial-application/&#34;&gt;partially
applied function&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// path:string -&amp;gt; stream:string -&amp;gt; EventStream to string -&amp;gt; EventStream
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; read stream &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; read &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;eventstore.txt&amp;#34;&lt;/span&gt; stream
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;handlers&#34;&gt;Handlers&lt;/h3&gt;
&lt;p&gt;Handlers focus on pure computation, they just need to return an event
or a failure.&lt;/p&gt;
&lt;p&gt;We can only consume an item once, and we can only remove items that
exist. It shouldn&amp;rsquo;t be possible to consume items that have been removed.
There isn&amp;rsquo;t much needed on the inside to cover these use cases.&lt;/p&gt;
&lt;p&gt;We inject the event store and time dependencies by passing in the
relevant functions - since I&amp;rsquo;m already using this function further on in
program.fs, the compiler can infer the signatures, no need to explicitly
state the signatures I defined earlier.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CommandFailure&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; ItemAlreadyConsumed
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; ItemDoesNotExist
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;HandlingFailure&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Validation &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; ValidationFailure
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Command &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; CommandFailure
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; commandFails f &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Failure&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;Command&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;f&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; handle read thetime cmd &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; cmd &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Command.Consume data &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; stream &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; sprintf &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;consumeditem/%s&amp;#34;&lt;/span&gt; data&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	    &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; read stream &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; EventStream.Exists &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	        commandFails ItemAlreadyConsumed
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; EventStream.NotExists stream &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	        succeeds &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; Event &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; stream&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; Consumed &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Timestamp &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; thetime()&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; data&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Id&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Category &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; data&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Category&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Description &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; data&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Description&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Url &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; data&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Url &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Command.Remove data &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; stream &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; sprintf &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;consumeditem/%s&amp;#34;&lt;/span&gt; data&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Id
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	    &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; read stream &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; EventStream.NotExists &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	        commandFails ItemDoesNotExist
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; EventStream.Exists &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; stream &lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	        succeeds &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; Event &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; stream&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; Removed &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Timestamp &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; thetime()&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; data&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Id &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;side-effects&#34;&gt;Side effects&lt;/h3&gt;
&lt;p&gt;So far we have been able to avoid intentional side effects - we did
introduce functions that might have accidental side effects (reading
from disk and reading the system time ). It would be nice to be able to
restart the application without losing all state, so we need to take the
result the command produced and persist it. A small function takes care
of matching each result to invoke the relevant side effect. So far, we
only want to store events. With this, we successfully isolated side
effects to one small function.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; sideEffects store input &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; input &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Event &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; stream&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;event&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; store stream &lt;span style=&#34;color:#66d9ef&#34;&gt;event&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;putting-it-all-together&#34;&gt;Putting it all together&lt;/h3&gt;
&lt;p&gt;By now, we can validate commands, handle them and take care of their
side effects. We can now compose those pieces together using &lt;a href=&#34;http://fsharpforfunandprofit.com/posts/recipe-part2/&#34;&gt;Railway
Oriented
Programming&lt;/a&gt; and
invoke the pipeline. The output gets matched, so we can print something
relevant for the user to see.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; read stream &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; read path stream
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; handleCommand cmd &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	cmd 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; validate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; handle read thetime 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; switch &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; sideEffects &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;store path&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; handleCommand cmd &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Success e 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; printfn &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Yay! Something happened = %A&amp;#34;&lt;/span&gt; e
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Failure&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;Command&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;ItemAlreadyConsumed&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; printfn &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Item was already consumed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Failure&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;Command&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;ItemDoesNotExist&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; printfn &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Item does not exist&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Failure&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;Validation&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;ArgumentEmpty x&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; printfn &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Argument empty = %A&amp;#34;&lt;/span&gt; x
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Failure&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;Validation&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;ArgumentStructure x&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; printfn &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Argument structure invalid = %A&amp;#34;&lt;/span&gt; x
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Failure&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;Validation&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;ArgumentOutOfRange x&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; printfn &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Argument out of range = %A&amp;#34;&lt;/span&gt; x
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next time, we&amp;rsquo;ll look at implementing queries.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Finding unused code (F#)</title>
      <link>https://jefclaes.be/2015/04/finding-unused-code-f.html</link>
      <pubDate>Sun, 26 Apr 2015 18:06:00 +0200</pubDate>
      <guid>https://jefclaes.be/2015/04/finding-unused-code-f.html</guid>
      <description>&lt;p&gt;Coming from C#, I&amp;rsquo;m used to the compiler warning me about unused
variables. Relying on the compiler to help me with &lt;a href=&#34;http://www.jefclaes.be/2015/03/checked-errors-in-f.html&#34;&gt;checked exceptions
in F#&lt;/a&gt;, I
noticed that unused values (and functions) would go unnoticed. Having
accidentally read earlier that &lt;a href=&#34;https://downloads.haskell.org/~ghc/7.0-latest/docs/html/users_guide/options-sanity.html&#34;&gt;Haskell has a compiler flag to check for
unused
bindings&lt;/a&gt;,
I looked for the F# equivalent but failed to find it, until Scott
Wlaschin pointed me in &lt;a href=&#34;https://downloads.haskell.org/~ghc/7.0-latest/docs/html/users_guide/options-sanity.html&#34;&gt;the right
direction&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;By using the &amp;ndash;warnon:1182 flag, the compiler will warn you about unused
bindings.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2015-04-26-finding-unused-code-f-CompilerFlag.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2015-04-26-finding-unused-code-f-CompilerFlag.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For example, compiling Paket.Core with this flag enabled, outputs the
following warnings.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;1&amp;gt;C:\Paket\src\Paket.Core\Utils.fs(88,9): warning FS1182: The value &amp;#39;fi&amp;#39; is unused
1&amp;gt;C:\Paket\src\Paket.Core\Utils.fs(361,46): warning FS1182: The value &amp;#39;econt&amp;#39; is unused
1&amp;gt;C:\Paket\src\Paket.Core\Utils.fs(361,52): warning FS1182: The value &amp;#39;ccont&amp;#39; is unused
1&amp;gt;C:\Paket\src\Paket.Core\PackageSources.fs(97,25): warning FS1182: The value &amp;#39;uri&amp;#39; is unused
1&amp;gt;C:\Paket\src\Paket.Core\RemoteDownload.fs(147,18): warning FS1182: The value &amp;#39;downloaded&amp;#39; is unused
1&amp;gt;C:\Paket\src\Paket.Core\RemoteUpload.fs(71,16): warning FS1182: The value &amp;#39;whyIsThisNeeded&amp;#39; is unused
1&amp;gt;C:\Paket\src\Paket.Core\RemoteUpload.fs(85,17): warning FS1182: The value &amp;#39;progressSubscription&amp;#39; is unused
...
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Looking into these warnings revealed values and functions that can be
deleted, but no apparent bugs. There are also cases where unused
bindings make sense, for example when you pass in a function that does
not use all of its arguments or when pattern matching. In these cases
you can suppress the warning by prefixing the bindings with an
underscore.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;cont&lt;span style=&#34;color:#f92672&#34;&gt;,_&lt;/span&gt;econt&lt;span style=&#34;color:#f92672&#34;&gt;,_&lt;/span&gt;ccont&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A useful compiler feature which strangely enough is opt-in. I plan on
using it from now on.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Consumed: Parsing command line arguments (F#)</title>
      <link>https://jefclaes.be/2015/04/parsing-command-line-arguments-with-f.html</link>
      <pubDate>Sun, 19 Apr 2015 16:54:00 +0200</pubDate>
      <guid>https://jefclaes.be/2015/04/parsing-command-line-arguments-with-f.html</guid>
      <description>&lt;p&gt;Last year, I set out to write my first node.js application; a small web
application for keeping lists of &lt;a href=&#34;http://www.jefclaes.be/2015/01/consumed-in-2014.html&#34;&gt;everything I
consume&lt;/a&gt;. I had
something working pretty quickly, deployed it to Heroku and still find
myself using it today. Since there&amp;rsquo;s very little use for having it
running on a server, and because I wanted something to toy with getting
better at F#, I decided to port it to an F# console application.&lt;/p&gt;
&lt;p&gt;With the UI gone, I need to resort to passing in arguments from the
command line to have my program transform those into valid commands and
queries that can be executed.&lt;/p&gt;
&lt;p&gt;The set of commands and queries is limited; consume an item, remove an
item and query a list of everything consumed.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;module&lt;/span&gt; Contracts &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Command&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Consume &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; id &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; description &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; url &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Remove &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; id &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Query&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; List
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ideally I go from a sequence of strings to a typed command or query.
However, when the list of arguments can&amp;rsquo;t be parsed, I expect a result
telling me what failed just the same.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Result&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;#39;&lt;/span&gt;TSuccess&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;#39;&lt;/span&gt;TFailure&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Success &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;#39;&lt;/span&gt;TSuccess
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Failure &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;#39;&lt;/span&gt;TFailure
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ParserFailure&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; ArgumentsMissing 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; KeyMissing &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; KeyLooksLikeValue &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; NotFound
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&amp;lt;&lt;/span&gt;Test&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; ``Parsing consume command``() &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; expected &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Consume&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;The Dark Tower&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://thedarktower.com&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; actual &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; parse &lt;span style=&#34;color:#f92672&#34;&gt;[|&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;--n&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;consume&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;--id&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;--d&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;The Dark Tower&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;--u&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://thedarktower.com&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;|]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; actual &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Success&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;Command&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;x&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; should equal expected
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; Assert.Fail() 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since we need the name to identify the command or query, I expect the
input to have at least two arguments.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; ensureEnoughElements input &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; input &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.length &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; 1 &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; Success input 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; Failure ArgumentsMissing
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Arguments come in pairs; a key and a value. My first thought was to
build a map here, but that made key validation, key transformations and
pattern matching harder.  I can actually get away with transforming the
input to a sequence of tuples.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; pair input &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	input 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.pairwise   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.mapi &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; i x &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; 2 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0 &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt; Some&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;x&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; None&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.choose id      
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Hoping to avoid some mistakes in the input, basic validation makes sure
the keys actually look like keys, instead of a value. Keys start with a
single or double dash.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; ensureKeysDontLookLikeValue &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; arguments &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; seq&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; looksLikeValue &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		arguments 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.tryFind &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; k&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; v &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;k&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;StartsWith&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; k&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;StartsWith&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;--&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; looksLikeValue &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Some &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; key&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; value &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; Failure&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;KeyLooksLikeValue key&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; None &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; Success arguments 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once that validation is out of the way, I strip away those dashes. That
should make the two last steps easier.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; stripKeys &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; arguments &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; seq&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    arguments &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.map &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; k&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; v &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; k&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Replace&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;).&lt;/span&gt;ToLower()&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; v &lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The name is required, so I wrote a small function that makes sure a
specific key exists.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; ensureKeyExists key arguments &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;      
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; arguments &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.exists &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; k&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; v &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; k &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; key &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; Success arguments
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; Failure&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;KeyMissing key&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now that I have a list of arguments,  I can map them into a typed
command or query using pattern matching.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; toCommandOrQuery arguments &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; arguments &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.toList &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;n&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;consume&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; id &lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; description &lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;u&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; url &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	Success&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;Command&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;Consume&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;id&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; description&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; url&lt;span style=&#34;color:#f92672&#34;&gt;)))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;n&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;remove&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; id &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	Success&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;Command&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;Remove&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;id&lt;span style=&#34;color:#f92672&#34;&gt;)))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;n&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;list&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;)]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	Success&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;Query&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;List&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; Failure NotFound 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Having written all these small functions, I can simply compose them
using &lt;a href=&#34;https://twitter.com/scottwlaschin&#34;&gt;Scott Wlaschin&lt;/a&gt;&amp;rsquo;s &lt;a href=&#34;http://fsharpforfunandprofit.com/posts/recipe-part2/&#34;&gt;Railway
oriented
programmming&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	input 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; ensureEnoughElements
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; switch pair
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; ensureKeysDontLookLikeValue
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; switch stripKeys
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; ensureKeyExists &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;n&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; toCommandOrQuery
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is far from a generic command line parser, but it&amp;rsquo;s simple and
covers my needs.&lt;/p&gt;
&lt;p&gt;Next up, executing those commands and queries, and printing feedback.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Checked errors in F#</title>
      <link>https://jefclaes.be/2015/03/checked-errors-in-f.html</link>
      <pubDate>Sun, 29 Mar 2015 17:19:00 +0200</pubDate>
      <guid>https://jefclaes.be/2015/03/checked-errors-in-f.html</guid>
      <description>&lt;p&gt;In the land of C#, exceptions are king. &lt;a href=&#34;https://msdn.microsoft.com/en-us/library/ms173160(v=vs.80).aspx&#34;&gt;By
definition&lt;/a&gt;
exceptions help us deal with &amp;ldquo;unexpected or exceptional situations that
arise while a program is running&amp;rdquo;. In that regard, we&amp;rsquo;re often
optimistic, overoptimistic. Most code bases treat errors as exceptional
while they&amp;rsquo;re often commonplace. We are so confident about the
likelyhood of things going wrong, we don&amp;rsquo;t even feel the need to
communicate to consumers what might go wrong. If a consumer of a method
wants to know what exceptions might be thrown, he needs to resort to
reading the documentation (or source) and hope it&amp;rsquo;s up-to-date.&lt;/p&gt;
&lt;p&gt;Java on the other hand has a concept of unchecked and checked
exceptions. Unchecked exceptions are exceptions that are caused by a
programming mistake and should be left unhandled (null reference,
division by zero, argument out of range etc); while checked exceptions
are exceptions that your program might be able to recover from. They
become part of the method signature and the Java compiler forces
consumers to handle them explicitly.&lt;/p&gt;
&lt;p&gt;While checked exceptions might bloat the method&amp;rsquo;s contract and enlarge
the API surface area, they might have every right to. Dealing with
errors is an important part of programming. Having discoverable errors
which require thoughtful care, should improve overall quality. Having
said that, it also requires careful consideration from the designer to
decide what&amp;rsquo;s truly exceptional.&lt;/p&gt;
&lt;p&gt;Coming up with something that can compete with the mechanics of checked
exceptions in C# seems to be impossible. We could return a result with
an error from a method, but the compiler doesn&amp;rsquo;t force you to do
anything with that result.&lt;/p&gt;
&lt;p&gt;F# on the other hand doesn&amp;rsquo;t allow for the result of an expression to
be thrown away. That is, unless you explicitly ignore it, or bind it and
leave it unused.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at an example. We start by defining two discriminated unions.
The first type defines a generic result; it can either be success or
failure. The second type defines all the errors that can be returned
after deleting a file.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Result&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;#39;&lt;/span&gt;TSuccess&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;#39;&lt;/span&gt;TError&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Success &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;#39;&lt;/span&gt;TSuccess
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Error &lt;span style=&#34;color:#66d9ef&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;&amp;#39;&lt;/span&gt;TError
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DeleteFileError&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; FileInUse 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; OpenHandle 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; UnauthorizedAccess 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then we write a function that deletes a file, but instead of throwing
exceptions when an error occurs, it returns a specific error. When no
errors occur, success is returned.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; deleteFile name &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; name &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;inuse.txt&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; Error&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;FileInUse&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;openhandle.txt&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; Error&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;OpenHandle&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;unauthorizedaccess.txt&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; Error&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;UnauthorizedAccess&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; Success()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When I now use this function, the compiler will tell me that it has a
return value which needs to ignored or binded.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;deleteFile &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;inuse.txt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// This expression should have type &amp;#39;unit&amp;#39;, but has type &amp;#39;Result&amp;lt;unit,DeleteFileError&amp;gt;&amp;#39;. 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Use &amp;#39;ignore&amp;#39; to discard the result of the expression, or &amp;#39;let&amp;#39; to bind the result to a name.	
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;deleteFile &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;inuse.txt&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; ignore
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; res &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; deleteFile &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;inuse.txt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While ignoring a result stands out, an unused binding is easier to go
unnoticed. I wish the F# compiler had a flag to detect unused
bindings.&lt;/p&gt;
&lt;p&gt;Assuming I don&amp;rsquo;t ingore the result, I can use pattern matching to
address each error specifically.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; deleteFileAggressively name retries &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; rec deleteFileAggressivelyIn name retries retry &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; deleteFile name &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Success &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Error&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;FileInUse&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Error&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;OpenHandle&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; retry &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; retries &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				Thread.Sleep 1000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				printfn &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Trying to delete file: retry %A of %A&amp;#34;&lt;/span&gt; retry retries
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				deleteFileAggressivelyIn name retries &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;retry &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; printfn &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Failed to delete file agressively&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Error&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;UnauthorizedAccess&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; printfn &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Unauthorized access&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	deleteFileAggressivelyIn name retries 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;deleteFileAggressively &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;inuse.txt&amp;#34;&lt;/span&gt; 5
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By not including a wildcard pattern, extending the contract by adding
errors will introduce a breaking change. We&amp;rsquo;ll have to consider what to
do with newly added errors.&lt;/p&gt;
&lt;p&gt;For example, if I add the error PathTooLong, the compiler shows me this
warning.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;// Incomplete pattern matches on this expression. 
// For example, the value &amp;#39;Error (PathTooLong (_))&amp;#39; may indicate a case not covered by the pattern(s).
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In summary, it might be more safe to be a bit less optimistic when it
comes to errors. Instead of throwing exceptions, making errors part of
the public interface, communicating errors explicitly, and handing
responsibility on what to do with the error to the caller, might lead to
more robust systems. While this can be achieved with C#, the mechanics
are error-prone. Expressions and pattern matching make that F# allows
for stronger, yet still not ideal, mechanics.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Scaling promotion codes</title>
      <link>https://jefclaes.be/2015/03/scaling-promotion-codes/</link>
      <pubDate>Sun, 15 Mar 2015 18:01:00 +0100</pubDate>
      <guid>https://jefclaes.be/2015/03/scaling-promotion-codes/</guid>
      <description>&lt;p&gt;In our system a backoffice user can issue a promotion code for users to
redeem. Redeeming a promotion code, a user receives a discount on his
next purchase or a free gift. A promotion code is only active for a
limited amount of time, can only be redeemed a limited amount of times
and can only be redeemed once per user.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; TryRedeem(UserId userId)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (HasAlreadyBeenRedeemedByUser(userId)) &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (NoLongerActive()) &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (Depleted()) &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	Apply(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; PromotionCodeRedeemed(userId.Value));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In code these requirements translated into a promotion code aggregate
which would guard three invariants.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; promotionCode = _promotionCodeRepository.GetById(promotionCodeId);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (promotionCode.TryRedeem(userId)) 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	_promotionCodeRepository.Update(promotionCode);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; RedeemPromotionCodeResponse.Success();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; RedeemPromotionCodeResponse.Unavailable();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The command handler looked something like this.&lt;/p&gt;
&lt;p&gt;Depending on the promotion code, we would often have a bunch of users
doing this simultaneously, leading to a &lt;a href=&#34;http://www.jefclaes.be/2014/11/splitting-hot-aggregates.html&#34;&gt;hot
aggregate&lt;/a&gt;,
leading to concurrency exceptions.&lt;/p&gt;
&lt;p&gt;Studying the system, we discovered that the limit on the amount of times
a promotion code could be redeemed was not being used in practice.
Issued promotion codes all had the limit set to 999999. Just by looking
at production usage, we were able to remove an invariant, saving us some
trouble.&lt;/p&gt;
&lt;p&gt;The next invariant we looked at, is the one that avoids users redeeming
a promotion code multiple times. Instead of this being part of the big
promotion code aggregate, a promotion code redemption now is a separate
aggregate. The promotion code aggregate now picks up a new role; the
role of a factory, it decides on the creation of new life.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Maybe&amp;lt;PromotionCodeRedemption&amp;gt; Redeem(UserId userId)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (NoLongerActive()) &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Maybe&amp;lt;PromotionCodeRedemption&amp;gt;.Empty();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Maybe&amp;lt;PromotionCodeRedemption&amp;gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; PromotionCodeRedemption(Id, userId));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The promotion code redemption&amp;rsquo;s identifier is a composition of the
promotion code identifier and the user identifier. Thus even when the
aggregate is stored as a stream, we can check in a consistent fashion
whether the aggregate (or stream) already exists, avoiding users
redeeming a promotion code multiple times. On creation of the stream,
the repository can pass to the event store that it expects no stream to
be there yet, making absolutely sure we don&amp;rsquo;t redeem twice. The event
store would throw an exception when it would find a stream to already
exist (think unique key constraint).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; promotionCodeRedemptionId = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; PromotionCodeRedemptionId(promotionCodeId, userId);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (_promotionCodeRedemptionRepository.Exists(promotionCodeRedemptionId))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; RedeemPromotionCodeResponse.Unavailable();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; promotionCodeRedemption = promotionCode.Redeem(userId);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (promotionCodeRedemption.HasValue())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	_promotionCodeRedemptionRepository.Add(promotionCodeRedemption.Value);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; RedeemPromotionCodeStatus.Success();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; RedeemPromotionCodeResponse.Unavailable();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this example, we were able to remove an annoying and expensive
invariant by looking at the data. Even if we had to keep supporting
promotion code depletion, we might have removed this invariant and
replaced it with data fed into the aggregate/factory from the read
model. Ask yourself, how big is the cost of having a few more people
redeem a promotion code? Teasing apart the aggregate even further, we
discovered that the promotion code had a second role; a creational role.
It now helps us spawning promotion code redemptions while still making
sure this only happens when the promotion code is active. Each promotion
code redemption is now a new short-lived aggregate, while the promotion
code itself stays untouched. By checking the existence of the aggregate
up front and by using the stream name to enforce uniqueness, we avoid
users redeeming a promotion code more than once. This has allowed us to
completely avoid contention on the promotion code, making it perform
without hiccups.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Domain Language: The Playthrough Bonus</title>
      <link>https://jefclaes.be/2015/02/domain-language-playthrough-bonus.html</link>
      <pubDate>Mon, 23 Feb 2015 19:05:00 +0100</pubDate>
      <guid>https://jefclaes.be/2015/02/domain-language-playthrough-bonus.html</guid>
      <description>&lt;p&gt;Since online gambling has been regulated in Belgium, basically each
eligible license holder has complemented their land based operations
with an online counterpart. Being such a small country, everyone wants
to secure their market share as soon as possible. The big players have
been pouring tons of money in to marketing and advertising, it&amp;rsquo;s
everywhere: radio, television, (online) newspapers, bus stops,
billboards, sport events, airplane vouchers - you name it. While
regulations for land based casinos are very strict and almost
overprotective, regulations for online play are much more permissive.
This makes that online casinos can be rather aggressive acquiring new
customers.&lt;/p&gt;
&lt;p&gt;You will often see online casinos hand out free registration bonuses:
&amp;ldquo;You get 10 euro for free when you sign up, no strings attached!&amp;rdquo;. This
makes it look like casinos are just handing out free cash right? We
should all know better than that though.&lt;/p&gt;
&lt;p&gt;There are always conditions to cash out a bonus. Bonuses come in
different forms and flavors and preconditions to clear them vary wildly.
The Playthrough Bonus is the favorite among players by far; it&amp;rsquo;s
straightforward and requires zero investment.&lt;/p&gt;
&lt;p&gt;When you receive a Playthrough Bonus, you receive an amount of bonus
money, which can be converted to cash by wagering it a specific amount
of times. For example; you receive a Playthrough Bonus of 10 euro, which
needs to be wagered 30 times before the bonus is cleared. This means
that you need to bet 300 euro (10 euro multiplied by 30) in total to
clear the bonus and to receive what&amp;rsquo;s left off your balance.&lt;/p&gt;
&lt;p&gt;So is betting the bonus amount 30 times realistic, or will you always
close your browser empty handed with nothing to show for on your
balance? The answer depends heavily on the payout rate. This percentage
represents how much of the money that goes into the casino, is returned
to players. In a formula, this is the wins divided by the bets. This
percentage is generally a lot higher than most people expect. Casinos
aim for a payout rate between 95 and 99 percent. They want to cultivate
a long term relationship with happy and social customers, not clear your
bank account as soon as you open the door. Note that the payout
percentage is an average, not all games are a smooth ride. Some players
like big wins, and big losses, while others feel more comfortable losing
small, but don&amp;rsquo;t mind winning small either. Casinos also prefer a smooth
ride, especially when it comes to bonuses. They might even tweak games
to have less aggressive, more equally distributed wins when bonus money
is in play.&lt;/p&gt;
&lt;p&gt;Now let&amp;rsquo;s look at how much money would be left on our balance when we
try to clear a Playthrough Bonus of 10 euro with a playthrough of 30 and
a payout percentage of 98.&lt;/p&gt;
&lt;p&gt;I defined two records (excuse my primitive obsession). First a Bonus
record that contains an amount, a balance, the total amount of bets and
a playthrough. A few functions are associated with the Bonus record;
they allow the bonus to be created, to bet, to win, to check if it still
accepts bets and to check if the bonus has been cleared. The second
record, the GameSettings, define the payout percentage and the stake of
a bet.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Bonus&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Amount &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;decimal&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Balance &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;decimal&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Bets &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;decimal&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Playthrough&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;decimal&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;member&lt;/span&gt; Create amount playthrough &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Amount &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; amount&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Balance &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; amount&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Bets &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0M&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Playthrough &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; playthrough &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;       
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;member&lt;/span&gt; x.&lt;span style=&#34;color:#a6e22e&#34;&gt;Win&lt;/span&gt; amount &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; x &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt; Balance &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Balance &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; amount &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;member&lt;/span&gt; x.&lt;span style=&#34;color:#a6e22e&#34;&gt;AcceptsBet&lt;/span&gt; amount &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Balance &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; amount &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; 0M
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;member&lt;/span&gt; x.&lt;span style=&#34;color:#a6e22e&#34;&gt;Cleared&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Playthrough &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Amount &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Bets &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; 0M
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;member&lt;/span&gt; x.&lt;span style=&#34;color:#a6e22e&#34;&gt;Bet&lt;/span&gt; amount &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;AcceptsBet amount &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; x &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt; Bets &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Bets &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; amount&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Balance &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Balance &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; amount &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; invalidOp &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Bonus can&amp;#39;t accept bet&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GameSettings&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Payout &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;decimal&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Stake &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;decimal&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After defining these structures, I defined a function that recursively
keeps playing (bet and win) until either the bonus is cleared, or the
bonus no longer accepts bets (out of money).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; rec playUntilCleared &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; bonus &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Bonus &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; settings &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;          
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; bonus&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Cleared &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; bonus
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;         
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; bet &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; settings&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Stake
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; win &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; settings&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Stake &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; 100M &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; settings&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Payout
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; bonus&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;AcceptsBet bet &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; bonus
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; playUntilCleared &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; bonus&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Bet&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;bet&lt;span style=&#34;color:#f92672&#34;&gt;).&lt;/span&gt;Win&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;win&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; settings            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When we run this function we know the answer to our question. On
average, we will clear the bonus with four euro left on our balance.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;printfn &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%A&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; playUntilCleared &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; Bonus.Create 10M 30M &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Payout &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 98M&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Stake &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;2M &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// {Amount = 10M;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Balance = 4.000M;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Bets = 300.0M;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Playthrough = 30M;}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When we turn down the payout to be one percent lower, we only have 1
euro left on our balance. When we turn it down even more, there won&amp;rsquo;t be
anything left.&lt;/p&gt;
&lt;p&gt;Given a few parameters which should be available to you (bonus amount,
playthrough and even payout percentage), you can calculate how feasible
it is to clear a Playthrough Bonus. Unless variance is on your side, I
guess it will rarely turn out to be a lucrative grind.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Side by side</title>
      <link>https://jefclaes.be/2015/02/side-by-side.html</link>
      <pubDate>Sun, 15 Feb 2015 17:34:00 +0100</pubDate>
      <guid>https://jefclaes.be/2015/02/side-by-side.html</guid>
      <description>&lt;p&gt;This week marked my first year at my current employer. While that event
went by rather silently, one year in, a few of my observations are
finally shaping up to be cast into writing.&lt;/p&gt;
&lt;p&gt;Where I used to work in the typical battery cage, I&amp;rsquo;m now part of a team
of just four people, having the luxury of a big dedicated room to
ourselves - a whole floor actually. The room is set up almost
symmetrically; two desks on one side of the room and two more on the
other side, with quite some space in between. Having only four people in
the room makes it easy to casually throw something at the group - be it
a question, a critique or a random idea.&lt;/p&gt;
&lt;p&gt;I made good use of this perk early on, but noticed that I would too
often find myself amid a Mexican Standoff. We would often get ourselves
into discussions that quickly turned into a
my-opinion-versus-your-opinion and would lead nowhere.&lt;/p&gt;
&lt;p&gt;It didn&amp;rsquo;t make sense how I got myself into this situation time after
time, until I read somewhere how to approach petting an unfamiliar
dog.&lt;br&gt;
Our species have more in common than you would think. Our shared history
of pack hunting has made both our species highly social and
interdependent.&lt;br&gt;
For example, when you approach an unfamiliar dog, you shouldn&amp;rsquo;t pet him
on the head since this can be very threatening. It&amp;rsquo;s better to approach
him from the side to rub his ears, neck or back. This behaviour is an
evolutionary remnant of pack hunting; members of the pack would rub each
other&amp;rsquo;s shoulder constantly chasing their next meal.&lt;/p&gt;
&lt;p&gt;It occurred to me that the cause of our unproductive discussions might
be as simple as our desks being in an aggressive position, desk-to-desk
or face-to-face.&lt;br&gt;
Looking back at my previous jobs, I found no precedents of having
discussions in this position. The horrors of the open plan had always
forced me to either walk over or to find a meeting room.&lt;/p&gt;
&lt;p&gt;But when I look at my personal relationships and discussions, I find
more situations that confirm this theory. When going for drinks, most of
my friends prefer a noisy and crowded bar, which force you side-by-side
just to make yourself understood. Even when communicating with my
girlfriend, it&amp;rsquo;s not the cliché tete-a-tete dinner dates that yield the
best conversations, it&amp;rsquo;s taking a walk, long road trips or even cooking
together.&lt;/p&gt;
&lt;p&gt;When it came to avoiding these unproductive situations at work, I now
carefully consider which things I can just throw out there, or which
things require a side-by-side approach. Even when you got yourself in
trouble face-to-face, you can still guide things into a more
constructive direction by changing the situation.&lt;/p&gt;
&lt;p&gt;Getting side-by-side shouldn&amp;rsquo;t be too hard in a professional
environment. Both pair programming and whiteboard sessions (or one of
its more exotic evolutions - model storming, mob programming etc) are
ingrained in most places now.&lt;/p&gt;
&lt;p&gt;Evolution has wired our brain in a way that makes being side-by-side,
preferably chasing the same goal, extremely amicable. Although we&amp;rsquo;re no
longer hunting for food, we still find ourselves chasing different means
of prosperity and success. Just like before, it&amp;rsquo;s still the case that
we&amp;rsquo;re at our best as a team, side-by-side, in pack.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Averages are not good enough (F#)</title>
      <link>https://jefclaes.be/2015/01/averages-are-not-good-enough-f.html</link>
      <pubDate>Sun, 18 Jan 2015 18:40:00 +0100</pubDate>
      <guid>https://jefclaes.be/2015/01/averages-are-not-good-enough-f.html</guid>
      <description>&lt;p&gt;Let&amp;rsquo;s (no pun intended) look at a set of response times of a web
service.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; responseTimes &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; 18&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;0&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 21&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;0&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 41&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;0&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 42&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;0&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 48&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;0&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 50&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;0&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 55&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;0&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 90&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;0&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;People like having a single number to summarize a piece of data. The
average is the most popular candidate. The average is calculated by
dividing the sum of the input elements by the number of input elements.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; average input &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; length &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; input &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.length
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; length &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; 0 &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; raise &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;|&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ArgumentException&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Input sequence is empty&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;input &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.sum&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;float&lt;/span&gt; length 	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Average = 45.625
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// (18 + 21 + 41 + 42 + 48 + 50 + 55 + 90) / 8
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The average is a measure of centre which is fragile to outliers; one or
two odd irregular values might skew the outcome. The median on the other
hand is always representative of the centre, not just when the data
distribution is symmetric. The median is determined by sorting the input
elements and picking the one in the middle.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(|&lt;/span&gt;Even&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt;Odd&lt;span style=&#34;color:#f92672&#34;&gt;|)&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; 2 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0 &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt; Even
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; Odd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; median input &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; sortedInput &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; input &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.sort
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; length &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; input &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.length
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; length &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; 0 &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; raise &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;|&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ArgumentException&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Input sequence is empty&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; 1 &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; input &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.nth 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; length &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Even &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; first &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; sortedInput &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.nth &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;length &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; 2 &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; second &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; sortedInput &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.nth &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;length &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; 2&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;						&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;first &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; second&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;float&lt;/span&gt; 2&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;                             
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Odd &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; sortedInput &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.nth &lt;span style=&#34;color:#f92672&#34;&gt;((&lt;/span&gt;length &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; 2&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;				
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Median = 45.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 18 21 41 42 48 50 55 90
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//          __ __
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Both measures are terrible at showing how the data is distributed
though. The average and median response time might look fair, but maybe
there are a few outliers which are giving a few customers a bad time.&lt;/p&gt;
&lt;p&gt;Instead of reducing our input down to a single number, it might be
better to extract a table that displays the frequency of various
outcomes in the input.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; frequencyDistribution input &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	input &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	Seq.groupBy &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; x &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; x &lt;span style=&#34;color:#66d9ef&#34;&gt;when&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; 30&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;0 &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; 0&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; 30 &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; x &lt;span style=&#34;color:#66d9ef&#34;&gt;when&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; 70&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;0 &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; 30&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; 70 &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; x &lt;span style=&#34;color:#66d9ef&#34;&gt;when&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; 90&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;0 &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; 70&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; 90 &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; 90&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; System.Int32.MaxValue &lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	Seq.map &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;x&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; y&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; x&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; y &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.length&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Frequency Distribution = seq [
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// ([(0, 30)], 2); 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// ([(30, 70)], 5); 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// ([(90, 2147483647)], 1)]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now this is more useful; we can clearly see that the data is not
distributed equally and there are a few outliers in our response times
we need to investigate further.&lt;/p&gt;
&lt;p&gt;This table takes up quite a bit of ink though. What if we want to get
rid of the table, but maintain a feel for the distribution of the
data?&lt;/p&gt;
&lt;p&gt;The standard deviation measures the amount of variation from the
average. A low standard deviation means that the data points are very
close to the mean. A high standard deviation indicates that the data
points are spread out over a large range of values.&lt;br&gt;
It is calculated by taking the square root of the average of the squared
differences of the values from their average value.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; standardDeviation input  &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; avg &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; input &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.average
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; input &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.map&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; System.Math.Pow&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;float&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; avg&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;float&lt;/span&gt; 2&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.sum
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; y &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; input &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.length &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;float&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; variance &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	System.Math.Sqrt variance
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Average = 45.625; Standard Deviation = 20.87425148
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The standard deviation is even more useful when you put the average at
the centre of a graph, lay out the input elements according their
deviation of the average and see a bell graph drawn. This means that we
can use the &lt;em&gt;empirical&lt;/em&gt; 68-95-99.7 rule to get a feel of how the data is
distributed.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In statistics, the so-called 68–95–99.7 rule is a shorthand used to
remember the percentage of values that lie within in a band around the
mean in a normal distribution with a width of one, two and three
standard deviations, respectively; more accurately, 68.27%, 95.45% and
99.73% of the values lie within one, two and three standard deviations
of the mean, respectively. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2015-01-18-averages-are-not-good-enough-f-Standard-Deviation-Graph.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2015-01-18-averages-are-not-good-enough-f-Standard-Deviation-Graph.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For our set of response times, this means that 68.27% of the response
times lies within the 24.8 and 66.4 range, 95.45% lies within the 4 and
87.2 range, while 99.73% lies within the -16.8 and 108 range.&lt;/p&gt;
&lt;p&gt;When we calculate the standard deviation, we can put one extra number
next to the average and derive from just two numbers how the data is
distributed.&lt;/p&gt;
&lt;p&gt;In conclusion, the mean and the median hide outliers. Looking at the
frequency distribution gives you a more complete picture. If we insist
on having less data to look at, the standard deviation and the
68–95–99.7 rule can compress the same complete picture into just two
numbers.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Consumed in 2014</title>
      <link>https://jefclaes.be/2015/01/consumed-in-2014.html</link>
      <pubDate>Sun, 11 Jan 2015 17:45:00 +0100</pubDate>
      <guid>https://jefclaes.be/2015/01/consumed-in-2014.html</guid>
      <description>&lt;p&gt;Starting 2014, I wanted to look more closely at everything I consume. So
I started keeping a list of everything I read, watch and listen to.&lt;/p&gt;
&lt;p&gt;I started off with a markdown file on Github that quikcly evolved into a
good excuse to dabble with an alternative stack. I ended up writing an
event sourced node.js application on top of postgres, hosted on Heroku.
I could write a post on that particular experience, but it&amp;rsquo;s safe to say
&lt;a href=&#34;http://notes.ericjiang.com/posts/751&#34;&gt;this blog post&lt;/a&gt; captures it
better than I ever could.&lt;/p&gt;
&lt;p&gt;In 2014, I listened to 10 audiobooks and 18 podcasts, read 20 books and
watched 12 movies and 13 shows.&lt;/p&gt;
&lt;p&gt;I just went over the list and cherry picked three items per category
that stuck with me the most.&lt;/p&gt;
&lt;h3 id=&#34;books&#34;&gt;Books&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;http://www.amazon.com/gp/product/0691160880/ref=as_li_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0691160880&amp;amp;linkCode=as2&amp;amp;tag=diofanedebyje-20&amp;amp;linkId=VOHHIGAAZRBYS4CW&#34;&gt;Addiction by Design&lt;/a&gt;: An incredibly complete overview of the gambling industry, with insights into the human psyche which apply far outside the domain of gambling. &lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.amazon.com/gp/product/1451627297/ref=as_li_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=1451627297&amp;amp;linkCode=as2&amp;amp;tag=diofanedebyje-20&amp;amp;linkId=PWN25BXIZGUYENQL&#34;&gt;11/22/63&lt;/a&gt;: I try to read a fiction book for every non-fiction book I read. This was my first &amp;ldquo;real&amp;rdquo; King book, and I was hooked instantly. I devoured the 880 pages thick book in less than two weeks, and was left with a big gaping hole in my heart - the journey was more than worth it. &lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.amazon.com/gp/product/3950307826/ref=as_li_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=3950307826&amp;amp;linkCode=as2&amp;amp;tag=diofanedebyje-20&amp;amp;linkId=PLZSBRRPM2O3LYTA&#34;&gt;SQL Performance Explained&lt;/a&gt;: The author succeeds in capturing the essentials in only 204 pages. This is one of those books you want to have going around at the office. &lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;movies&#34;&gt;Movies&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;http://www.imdb.com/title/tt0423853/?ref_=fn_al_tt_1&#34;&gt;Be Here To Love Me&lt;/a&gt;: Not-your-average documentary about Townes van Zandt; my musical and philosophical discovery of 2014. A troubled soul, struggling with the futility of existence. Simple poetic songs beautifully crafted, capturing in a few words what would take others books. While darkness inspired his best work, it was also the search for relief of that same darkness that led him further down the path of self-destructive behaviour. Painful to watch. &lt;a href=&#34;https://www.youtube.com/watch?v=UPxz_4wIa4g&#34;&gt;Rake&lt;/a&gt;, &lt;a href=&#34;http://youtu.be/kFh4DebJAfs?t=1m30s&#34;&gt;Waiting around to die&lt;/a&gt;, &lt;a href=&#34;https://www.youtube.com/watch?v=V825I5waU3g&#34;&gt;Snake Mountain Blues&lt;/a&gt;, &lt;a href=&#34;https://www.youtube.com/watch?v=EaqKdl_T3ak&#34;&gt;Dollar Bill Blues&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.imdb.com/title/tt0381849/?ref_=fn_al_tt_1&#34;&gt;3-10 to Yuma&lt;/a&gt;: A true modern Western, capturing the American West beautifully, &lt;a href=&#34;http://www.jefclaes.be/2011/09/once-upon-time-in-west.html&#34;&gt;making me nostalgic&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.imdb.com/title/tt0790636/?ref_=fn_al_tt_1&#34;&gt;Dallas Buyers Club&lt;/a&gt;: Is there one role Matthew McConaughey can&amp;rsquo;t hack?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2015-01-11-consumed-in-2014-Townes.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2015-01-11-consumed-in-2014-Townes.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;audio-books&#34;&gt;Audio books&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;http://www.audible.com/pd/Bios-Memoirs/On-Writing-Audiobook/B002V1A0WE/ref=a_search_c4_1_1_srTtl?qid=1420974710&amp;amp;sr=1-1&#34;&gt;On Writing - A Memoir of the Craft&lt;/a&gt;: &amp;ldquo;What follows is an attempt to put down, briefly and simply, how I came to the craft (of telling stories on paper), what I know about it now, and how it&amp;rsquo;s done. It&amp;rsquo;s about the day job; it&amp;rsquo;s about the language.&amp;rdquo; If you&amp;rsquo;re not a King fan, you will be after finishing this one. &lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.audible.com/pd/Business/Getting-to-Yes-Audiobook/B004X1T8G4/ref=a_search_c4_1_1_srTtl?qid=1420974726&amp;amp;sr=1-1&#34;&gt;Getting to Yes&lt;/a&gt;: Separate people and issues, focus on interest, generate options and use objective criteria. But also, what to do when the other party is more powerful or when they use dirty tricks.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.audible.com/pd/Science-Technology/Blink-Audiobook/B002VAEK3K/ref=a_search_c4_1_1_srTtl?qid=1420974744&amp;amp;sr=1-1&#34;&gt;Blink&lt;/a&gt;: Making decisions in the blink of an eye; why you should go with instinct and why you shouldn&amp;rsquo;t.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;shows&#34;&gt;Shows&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;http://www.imdb.com/title/tt2356777/?ref_=fn_al_tt_1&#34;&gt;True Detective&lt;/a&gt;: &amp;ldquo;Life&amp;rsquo;s barely long enough to get good at one thing. So be careful what you get good at.&amp;rdquo; &amp;ldquo;If the only thing keeping a person decent is the expectation of divine reward then, brother, that person is a piece of shit.&amp;rdquo; &amp;ldquo;People incapable of guilt usually do have a good time.&amp;rdquo; Heavy stuff.&lt;/li&gt;
&lt;li&gt;[Rick and Morty](&lt;a href=&#34;http://www.imdb.com/title/tt2861424/?ref_=fn_al_tt_1&#34;&gt;http://www.imdb.com/title/tt2861424/?ref_=fn_al_tt_1&lt;/a&gt;: &amp;ldquo;Listen, Morty, I hate to break it to you but what people call love is just a chemical reaction that compels animals to breed.&amp;rdquo; &amp;ldquo;Nobody exists on purpose. Nobody belongs anywhere. Everybody&amp;rsquo;s gonna die. Come watch TV? &amp;ldquo;Snuffles was my slave name, you can call me snowball because my fur is white and pretty.&amp;rdquo; Must be the best animated series of the moment hands down, looking forward to next season. The first season is &lt;a href=&#34;https://www.youtube.com/channel/UCmPIe8rQUYlI7bQp2ONfxvg&#34;&gt;available for free&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.imdb.com/title/tt1520211/?ref_=fn_al_tt_1&#34;&gt;The Walking Dead&lt;/a&gt;: Addictive soap opera that features zombies.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2015-01-11-consumed-in-2014-TrueDetective.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2015-01-11-consumed-in-2014-TrueDetective.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;papers&#34;&gt;Papers&lt;/h3&gt;
&lt;p&gt;Mostly classics on Functional Programming.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;http://shaffner.us/cs/papers/tarpit.pdf&#34;&gt;Out of the tarpit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.erlang.se/doc/programming_rules.shtml&#34;&gt;Program Development using Erlang&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.smashcompany.com/technology/object-oriented-programming-is-an-expensive-disaster-which-must-end&#34;&gt;OOP is an expensive disaster which must end&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
    </item>
    
    <item>
      <title>TDD as the crack cocaine of software</title>
      <link>https://jefclaes.be/2014/12/tdd-as-crack-cocaine-of-software.html</link>
      <pubDate>Sun, 28 Dec 2014 17:29:00 +0100</pubDate>
      <guid>https://jefclaes.be/2014/12/tdd-as-crack-cocaine-of-software.html</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;The psychologist Mihaly Csikszentmihalyi popularized the term &amp;ldquo;flow&amp;rdquo;
to describe states of absorption in which attention is so narrowly
focused on an activity that a sense of time fades, along with the
troubles and concerns of day-to-day life. &amp;ldquo;Flow provides an escape
from the chaos of the quotidian,&amp;rdquo; he wrote. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a snippet from the highly recommended book &lt;a href=&#34;http://www.amazon.com/gp/product/0691160880/ref=as_li_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0691160880&amp;amp;linkCode=as2&amp;amp;tag=diofanedebyje-20&amp;amp;linkId=B2LQH4574PP6A5AL&#34;&gt;Addiction by
Design&lt;/a&gt;,
which not only gives you an incredibly complete overview of the gambling
industry, but also insights into the human psyche which apply far
outside the domain of gambling.&lt;/p&gt;
&lt;p&gt;For me, this book was an eye-opener, with the biggest realization being
that most gamblers don&amp;rsquo;t play to win. They play to lose. To lose
themselves. Slot machines and video poker are for many people the
quickest and surest way to reach flow. It&amp;rsquo;s this phenomenon that has
earned machine gambling the title of &amp;ldquo;the crack cocaine of gambling.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s not just gamblers that crave for flow though, we all do.&lt;/p&gt;
&lt;p&gt;Some of us get up early on the weekends, to drive halfway across the
country for a few hours of intensive mountain biking. Others come home
after work, throw their laptop in the corner, to engage in an online
shooter, zoning out for a good hour. Others will accidentally waste
their entire Sunday morning solving a crossword puzzle they bumped on
reading the newspaper.&lt;/p&gt;
&lt;p&gt;All these activities meet a specific set of preconditions.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Csikszentmihalyi identified four preconditions of flow: first, each
moment of the activity must have a little goal; second, the rules of
attaining that goal must be clear; third, the activity must give
immediate feedback so that one has certainty, from moment to moment,
on where one stands; fourth, the tasks of the activity must be matched
with operational skills, bestowing a sense of simultaneous control and
challenge.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Machine play has all these properties. Let&amp;rsquo;s look at video poker. The
goal is to make a winning combination. The set of winning combinations
should be easy enough to remember; they&amp;rsquo;re similar to live poker. After
pushing &amp;ldquo;deal&amp;rdquo; you get five cards. The player decides which cards to
&amp;ldquo;hold&amp;rdquo;. Pushing the &amp;ldquo;deal&amp;rdquo; button the second time will draw new cards
from the same virtual deck. After the draw, you immediately know whether
you&amp;rsquo;ve won or lost. Feedback is instantaneous. A game is over in a few
seconds. Although the outcome is determined by chance, there is some
degree of skill involved; it&amp;rsquo;s up to you to hold the right cards.&lt;br&gt;
&lt;span class=&#34;Apple-tab-span&#34; style=&#34;white-space: pre;&#34;&gt; &lt;/span&gt;&lt;br&gt;
As programmers we&amp;rsquo;re lucky enough to inadvertently end up in the zone
frequently. Without a doubt, it&amp;rsquo;s in this state most of us do our best
work. In the zone, it&amp;rsquo;s constant feedback and a sense of moving forward
that keep me going. One could argue that the zone is inherent to the
activity of programming. I&amp;rsquo;d say that the length of the feedback loop
and the size of the goals are critical and hard to maintain without
working at it.&lt;/p&gt;
&lt;p&gt;In this regard, there are a few techniques that help me reach a state of
flow. At first I could get by just trying to get the code to compile or
to just launch whatever it was I was working on. But once you&amp;rsquo;re
comfortable with a code base, getting it to compile isn&amp;rsquo;t much of a
challenge, and having to start your application to get feedback gets old
real quick. Most often it&amp;rsquo;s TDD that helps me get there these days. You
start of with a failing test, your mission: to make it pass. The rules
are simple; when your test goes from red to green, you&amp;rsquo;re allowed to
move on. It&amp;rsquo;s important that tests are fast to be able to give you that
immediate feedback. How fast? Fast enough for you not to lose focus. It
stands for itself that the fourth precondition is met too; you&amp;rsquo;re
writing the code, doing your best to bend it your way.&lt;/p&gt;
&lt;p&gt;When TDD is sold as a productivity booster, it are often strengths such
as automated continuous validation of correctness, partitioning of work
in smaller units and cleaner and better designed code that are used as
arguments. While these are valid arguments, it&amp;rsquo;s a shame that the power
of TDD as a consistent gateway to flow gets neglected or undersold.&lt;/p&gt;
&lt;p&gt;Getting in the zone by yourself is one thing, getting there surrounded
by a group of people is often out of the question. Here &lt;a href=&#34;http://www.jefclaes.be/2014/05/ncrafts-eventstorming-slides.html&#34;&gt;Event
Storming&lt;/a&gt;
has helped me out. Small goals; what happens before this event? Rules;
write the previous event down on a yellow post-it. Feedback; once the
post-it is up, we see that we&amp;rsquo;re reaching a better understanding of the
big picture. Control and challenge; you&amp;rsquo;re the one searching for deeper
insight, writing and putting up the post-its.&lt;/p&gt;
&lt;p&gt;The activities that get me in a state of flow are the ones that I enjoy
the most and which enable me to output my best results. If you reread
the four preconditions, and assess the things that get you going, you
might learn that the same goes for you.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Spinning the wheel: clustering and near misses</title>
      <link>https://jefclaes.be/2014/12/spinning-wheel-clustering-and-near.html</link>
      <pubDate>Sun, 14 Dec 2014 17:13:00 +0100</pubDate>
      <guid>https://jefclaes.be/2014/12/spinning-wheel-clustering-and-near.html</guid>
      <description>&lt;p&gt;The previous post showed a simple model casinos use to manipulate the
odds. Instead of relying on the physical wheel for randomness, they rely
on a virtual list of indexes that maps to the physical wheel.&lt;/p&gt;
&lt;p&gt;Using that same model, it&amp;rsquo;s easy to fiddle with the virtual indexes so
that they map to misses right next to the winning pocket, creating &amp;ldquo;near
misses&amp;rdquo;. &amp;ldquo;Near misses&amp;rdquo; make players feel less like losing, since you
&amp;ldquo;almost won&amp;rdquo;. Casinos use this technique to get the next spin out of
you.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s create more specific labels - a label for each individual
pocket.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;WheelSpaceLabel&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Miss1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Miss2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Miss3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Win
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The winning pocket is in the physical wheel at index two. We need the
virtual indexes to make clusters next to the winning label. Four indexes
map to Miss2, one maps to Win and three map to Miss3. We intentionally
ignore Miss1.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-12-14-spinning-the-wheel-clustering-and-near-misses-SpinningTheWheelClusteringAndNearMisses.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-12-14-spinning-the-wheel-clustering-and-near-misses-SpinningTheWheelClusteringAndNearMisses.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; physicalWheel &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;Miss1&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Miss2&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Win&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Miss3&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.ofList
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; virtualWheel &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;1&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 2&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 3&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 3&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 3&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.ofList
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Spinning the wheel one million times reveals the pattern; Miss1 gets
ignored, while we hardly ever win but very often &amp;ldquo;just&amp;rdquo; miss.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Results seq &lt;span style=&#34;color:#f92672&#34;&gt;[(&lt;/span&gt;Miss3&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; 37501&lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;Miss2&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; 49901&lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;Win&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; 12598&lt;span style=&#34;color:#f92672&#34;&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since the law states that randomness and visualization are two separate
concepts, casinos are free to operate in this gray zone, as long as
randomness stays untouched.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Spinning the wheel: manipulating the odds</title>
      <link>https://jefclaes.be/2014/12/spinning-wheel-manipulating-odds.html</link>
      <pubDate>Thu, 11 Dec 2014 19:24:00 +0100</pubDate>
      <guid>https://jefclaes.be/2014/12/spinning-wheel-manipulating-odds.html</guid>
      <description>&lt;p&gt;The previous post defined a basic set of data structures and functions
to spin a wheel of fortune in F#.&lt;/p&gt;
&lt;p&gt;There was very little mystery to that implementation though. The
physical wheel had four pockets and spinning the wheel would land you a
win one out of four spins. As a casino, it&amp;rsquo;s impossible to come up with
an interesting payout using this model.&lt;/p&gt;
&lt;p&gt;To juice up the pot, casinos started adding more pockets to the wheel of
fortune. This meant that the odds were lower, but the possible gain was
higher. More pockets also allowed casinos to play with alternative
payouts, such as multiple smaller pots instead of one big one.&lt;/p&gt;
&lt;p&gt;Adding pockets to the wheel didn&amp;rsquo;t turn out the way casinos hoped for
though. Although players were drawn to a bigger price pot, they were
more intimidated by the size of the wheel - it was obvious that the
chances of winning were very slim now.&lt;/p&gt;
&lt;p&gt;Today, instead of having the physical wheel determine randomness,
randomness is determined virtually.&lt;/p&gt;
&lt;p&gt;Casinos now define a second set of virtual indexes that map to the
indexes of the physical wheel.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-12-11-spinning-the-wheel-manipulating-the-odds-SpinningTheWheelManipulatingTheOdds.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-12-11-spinning-the-wheel-manipulating-the-odds-SpinningTheWheelManipulatingTheOdds.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; virtualIndexes &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;0&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 0&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 2&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 3&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 3&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.ofList
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There are seven virtual indexes; six map to a miss pocket and only one
maps to a win pocket - one out of seven is a win.&lt;/p&gt;
&lt;p&gt;Instead of picking a random index in the physical wheel, we now pick a
random index in the virtual indexes and map that back to an index in the
physical wheel.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; rng &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Random()       
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; random &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;rng &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Random&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; virtualIndexes &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	virtualIndexes &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.nth &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;rng&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Next&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;0&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; virtualIndexes &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.length&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; spin physicalWheel virtualIndexes rng &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	physicalWheel &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.nth &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;random rng virtualIndexes&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When we now spin the wheel a million times, the outcome is different.
Although the physical wheel has four pockets, we now only win one out of
seven times or 14% of the time.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;seq &lt;span style=&#34;color:#f92672&#34;&gt;[(&lt;/span&gt;Miss&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; 856903&lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;Win&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; 143097&lt;span style=&#34;color:#f92672&#34;&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Using this technique, the physical wheel only serves for interaction and
visualization. Randomness is determined virtually, not physically.&lt;/p&gt;
&lt;p&gt;In my next post, I&amp;rsquo;ll describe how casinos have tweaked this model to
create &amp;ldquo;near misses&amp;rdquo;, making players feel as if they just missed the big
pot.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Spinning the wheel</title>
      <link>https://jefclaes.be/2014/12/spinning-wheel.html</link>
      <pubDate>Tue, 09 Dec 2014 19:56:00 +0100</pubDate>
      <guid>https://jefclaes.be/2014/12/spinning-wheel.html</guid>
      <description>&lt;p&gt;In this post, I&amp;rsquo;ll define a basic set of data structures and functions
to spin a wheel of fortune. In the next post, I&amp;rsquo;ll show you the simple
model casinos use to build a bigger, more attractive pot, without
touching the physical wheel and without losing money. Finally, I&amp;rsquo;ll show
you how casinos tweak that model to bend the odds and create near
misses.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-12-09-spinning-the-wheel-SpinTheWheel.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-12-09-spinning-the-wheel-SpinTheWheel.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s say we have a physical wheel with four pockets, which are labeled
either miss or win.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;PocketLabel&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Miss &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; Win
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Pocket&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Label &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; PocketLabel &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;PhysicalWheel&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Pocket seq
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Three out of four pockets are labeled as a miss, one is labeled as a
win. This makes the odds to win one out of four, or 25%.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;physicalWheel &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; PhysicalWheel&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Label &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Miss &lt;span style=&#34;color:#f92672&#34;&gt;};&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Label &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Miss &lt;span style=&#34;color:#f92672&#34;&gt;};&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Label &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Win &lt;span style=&#34;color:#f92672&#34;&gt;};&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; Label &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Miss &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.ofList
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Spinning the wheel, we should end up in one of four pockets. We can do
this by picking a random index of the physical wheel.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; rng &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Random()       
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; randomIndex &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;rng &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Random&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; physicalWheel &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  rng&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Next&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;0&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; physicalWheel &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.length&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; spin physicalWheel rng &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  physicalWheel &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.nth &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;randomIndex rng physicalWheel&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To avoid a shoulder injury spinning the wheel multiple times, we&amp;rsquo;ll
define a function that does this for us instead.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; spin physicalWheel rng times &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;1 &lt;span style=&#34;color:#f92672&#34;&gt;..&lt;/span&gt; times&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; List.map &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; spin physicalWheel rng&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now I can spin the wheel one million times.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; results &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; spin physicalWheel rng 1000000 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the math adds up, we should win 25% of the time. To verify this,
we&amp;rsquo;ll group the results by label and print them.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; groupedResults &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	results
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.groupBy &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; x&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Label&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.map &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;x&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; y&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;x&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;y &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.length&lt;span style=&#34;color:#f92672&#34;&gt;)))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;printfn &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%A&amp;#34;&lt;/span&gt; groupedResults
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Give or take a few hundred spins, we&amp;rsquo;re pretty close to winning 25% of
the time.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;seq &lt;span style=&#34;color:#f92672&#34;&gt;[(&lt;/span&gt;Miss&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; 750505&lt;span style=&#34;color:#f92672&#34;&gt;);&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;Win&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; 249495&lt;span style=&#34;color:#f92672&#34;&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When the odds are this fair, it&amp;rsquo;s impossible to come up with an
attractive enough payout without the casino going broke. What if we
wanted to advertise a bigger pot, while keeping the same physical wheel,
without losing money? Tomorrow, I&amp;rsquo;ll write about the simple model
casinos have been using to achieve this.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Hot aggregate detection using F#</title>
      <link>https://jefclaes.be/2014/11/hot-aggregate-detection-using-f.html</link>
      <pubDate>Sun, 16 Nov 2014 17:20:00 +0100</pubDate>
      <guid>https://jefclaes.be/2014/11/hot-aggregate-detection-using-f.html</guid>
      <description>&lt;p&gt;Last week, I wrote about &lt;a href=&#34;http://www.jefclaes.be/2014/11/splitting-hot-aggregates.html&#34;&gt;splitting a hot
aggregate&lt;/a&gt;.
Discovering that specific hot aggregate was easy; it would cause
transactional failures from time to time.&lt;/p&gt;
&lt;p&gt;Long-lived hot aggregates often are an indication of a missing concept
and an opportunity for teasing things apart. Last week, I took one
long-lived hot aggregate and pulled smaller short-lived hot aggregates
out, identifying two missing concepts.&lt;/p&gt;
&lt;p&gt;Hunting for more hot aggregates, I could visualize event streams and use
my eyes to detect bursts of activity, or I could have a little function
analyze the event streams for me.&lt;/p&gt;
&lt;p&gt;Looking at an event stream, we can identify a hot aggregate by having a
lot of events in a short window of time.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-11-16-hot-aggregate-detection-using-f-HotAggregateDetection.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-11-16-hot-aggregate-detection-using-f-HotAggregateDetection.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s say that when six events occur within five seconds from each
other, we&amp;rsquo;re dealing with a hot aggregate.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&amp;lt;&lt;/span&gt;Test&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;member&lt;/span&gt; this&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;``Given a hot aggregate, a hot aggregate will be detected``() &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; treshold &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; secondsInWindow &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 5		   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; eventStream &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; createEventStream &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;0&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 2&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 10&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 11&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 12&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 13&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 14&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 60&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; 90&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	streamIsHot eventStream treshold secondsInWindow &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; should equal &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What I came up with is a function that folds over an event stream. It
will walk over each event, maintaining the time window, allowing us to
look back in time. When the window size exceeds the treshold, the event
stream will be identified as hot. Once identified, the remaining events
won&amp;rsquo;t be analyzed.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; streamIsHot &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;events &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; seq&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Event&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;)&lt;/span&gt; treshold secondsInWindow &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;      
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; folder acc e &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;         
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; detect acc e &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; windowFilter &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fun&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; e&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Timestamp&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;AddSeconds&lt;span style=&#34;color:#f92672&#34;&gt;(-&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;float&lt;/span&gt; secondsInWindow&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; window &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; e&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Timestamp &lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt; acc&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Window &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; List.filter windowFilter
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; hot &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;window &lt;span style=&#34;color:#f92672&#34;&gt;|&amp;gt;&lt;/span&gt; Seq.length&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; treshold
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt; acc &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt; Hot &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; hot&lt;span style=&#34;color:#f92672&#34;&gt;;&lt;/span&gt; Window &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; window &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;match&lt;/span&gt; acc&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Hot &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; acc
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; detect acc e   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;Seq.fold folder initialDetectionResult events&lt;span style=&#34;color:#f92672&#34;&gt;).&lt;/span&gt;Hot
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>Splitting hot aggregates</title>
      <link>https://jefclaes.be/2014/11/splitting-hot-aggregates.html</link>
      <pubDate>Sun, 09 Nov 2014 19:00:00 +0100</pubDate>
      <guid>https://jefclaes.be/2014/11/splitting-hot-aggregates.html</guid>
      <description>&lt;p&gt;When you visit a real casino, the constant busy-ness is overwhelming;
players spamming buttons, pulling levers, spinning the wheel, gambling
on the outcome of sports games, playing cards, feeding the machine,
cashing out, breaking bills, ordering drinks or even buying a souvenir.
A single player will easily generate a thousand transactions in one
sitting.&lt;/p&gt;
&lt;p&gt;When you look at an online casino, this isn&amp;rsquo;t very different. In the
system we inherited, the biggest and busiest aggregate by far is a
user&amp;rsquo;s account. Basically every action that has money involved, leads to
activity on this aggregate.&lt;br&gt;
This makes sense. An account is an important consistency boundary, if
not the most important one. Casino&amp;rsquo;s can&amp;rsquo;t afford to have people spend
more than their account&amp;rsquo;s worth.&lt;/p&gt;
&lt;p&gt;Since we&amp;rsquo;re applying optimistic concurrency, bursts of activity would
occasionally lead to transactional failures. Looking at a real casino,
it&amp;rsquo;s easy to see why they aren&amp;rsquo;t running into these types of issues.&lt;br&gt;
In a physical casino, it&amp;rsquo;s only the owner of the wallet that gets to
access it. Casino employees are not allowed to take a player&amp;rsquo;s wallet
out of his pocket to make a transaction. There is no concurrent use of a
player&amp;rsquo;s wallet: single spender principle.&lt;br&gt;
Online on the other hand, we aren&amp;rsquo;t constrained by common courtesy and
have no problem reaching into a user&amp;rsquo;s pocket. It&amp;rsquo;s common to have a
user playing the slots, while we automatically try to pay out a
sportsbetting win once the results of a game are in.&lt;/p&gt;
&lt;p&gt;Mapping out an aggregate&amp;rsquo;s eventstream on a timeline is a great way to
visualize its lifecycle and usage patterns. When we did this for an
account, we came up with something that looked like this.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-11-09-splitting-hot-aggregates-AggregateTimeline.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-11-09-splitting-hot-aggregates-AggregateTimeline.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Activity peaks when a user starts a game. Each bet and each win drags in
the account aggregate. When you know that some players make thirty bets
per minute, it should be of no surprise that other processes accessing
the account in the background might introduce transactional failures.&lt;/p&gt;
&lt;p&gt;Inspired by a real casino, I wonder if users online would appreciate it
if we stayed out of their pockets and let them do it for us instead.&lt;br&gt;
Instead of paying out sportsbetting winnings automatically, we could
notify a user that his bet was settled and that he can head over to his
bet and cash out the winnings to his account any time.&lt;br&gt;
The same goes for games; instead of cashing out wins to a player&amp;rsquo;s
account after each bet, we could - like in a casino - cumulate all
winnings in the slot machine itself, also known as a game session, for
the player to cash out by pushing a button once he&amp;rsquo;s done playing. To
reduce the amount of small bets taken from the account, we could also
encourage users to feed the slot machine before they start playing.&lt;/p&gt;
&lt;p&gt;In practice, we would extract behaviour out of the account aggregate and
move it into the sportsbet and game session aggregates. It wouldn&amp;rsquo;t be
until the end of their lifecycles, that we would involve the account
aggregate to move money around.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-11-09-splitting-hot-aggregates-AggregateTimeline2.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-11-09-splitting-hot-aggregates-AggregateTimeline2.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;By spreading activity to other and shorter lived aggregates, and having
the player do a bit of our work, we could reduce the amount of
concurrency on the account aggregate and end up with less transactional
failures.&lt;/p&gt;
&lt;p&gt;But can we really expect of users to cash out manually? Probably not,
but we can still use most of the mechanics we just came up with, but
cash out automatically. We can cash out winnings automatically when a
user leaves a game session. We can queue up sportsbetting winnings and
cash out when a user isn&amp;rsquo;t playing a game.&lt;/p&gt;
&lt;p&gt;By exploring alternatives, we discovered that we can work the model to
reduce activity and concurrency on the account aggregate, lowering the
chances for transactional failures. Now, it&amp;rsquo;s only fair to say that
there are other, more technical, options. The most obvious one would
probably be making the existing transactions on the account aggregate
shorter, also lowering the chance of concurrent use of the account.&lt;/p&gt;
&lt;p&gt;I can&amp;rsquo;t help but guess the actor model might be a better fit for this
type of problem.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Programmatically force create a new LocalDB database</title>
      <link>https://jefclaes.be/2014/10/programmatically-force-create-new.html</link>
      <pubDate>Sun, 26 Oct 2014 16:59:00 +0100</pubDate>
      <guid>https://jefclaes.be/2014/10/programmatically-force-create-new.html</guid>
      <description>&lt;p&gt;I have spent the last week working in an integration test suite that
seemed to be taking ages to run its first test. I ran a profiler on the
setup, and noticed a few things that were cheap to improve. The first
one was how a new LocalDB database was being created.&lt;br&gt;
An empty database file was included into the project. When running the
setup, this file would replace the existing test database. However, when
there were open connections to the test database - SQL Server Management
Studio for example - replacing it would fail. To avoid this, the SQL
server process was being killed before copying the file, waiting for it
to come back up.&lt;/p&gt;
&lt;p&gt;Another way to create a new database, is by running a script on master.
You can force close open connections to the existing database, by
putting the database in single user mode and rolling back open
transactions. You can also take advantage of creation by script to set
up a sane size to avoid the database having to grow while running your
tests. When you specify the database size, you need to also specify the
filename; I&amp;rsquo;m using the default location.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; conn = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; SqlConnection(&lt;span style=&#34;color:#e6db74&#34;&gt;@&amp;#34;Data Source=(LocalDb)\v11.0;Initial Catalog=Master;Integrated Security=True&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    conn.Open();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; cmd = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; SqlCommand();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    cmd.Connection = conn;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    cmd.CommandText =  &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.Format(&lt;span style=&#34;color:#e6db74&#34;&gt;@&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;	IF EXISTS(SELECT * FROM sys.databases WHERE name=&amp;#39;{0}&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;	BEGIN
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;		ALTER DATABASE [{0}]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;		SET SINGLE_USER
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;		WITH ROLLBACK IMMEDIATE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;		DROP DATABASE [{0}]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;	END
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;	DECLARE @FILENAME AS VARCHAR(255)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;	SET @FILENAME = CONVERT(VARCHAR(255), SERVERPROPERTY(&amp;#39;instancedefaultdatapath&amp;#39;)) + &amp;#39;{0}&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;	EXEC (&amp;#39;CREATE DATABASE [{0}] ON PRIMARY 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;		(NAME = [{0}], 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;		FILENAME =&amp;#39;&amp;#39;&amp;#39; + @FILENAME + &amp;#39;&amp;#39;&amp;#39;, 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;		SIZE = 25MB, 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;		MAXSIZE = 50MB, 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;		FILEGROWTH = 5MB )&amp;#39;)&amp;#34;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	databaseName);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    cmd.ExecuteNonQuery();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Switching to this approach shaved seven seconds of database creation.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Print out the maximum depth of recursion allowed</title>
      <link>https://jefclaes.be/2014/10/print-out-maximum-depth-of-recursion.html</link>
      <pubDate>Sun, 19 Oct 2014 17:33:00 +0200</pubDate>
      <guid>https://jefclaes.be/2014/10/print-out-maximum-depth-of-recursion.html</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://twitter.com/karlseguin&#34;&gt;Karl Seguin&lt;/a&gt; tweeted the following
earlier this week: &amp;ldquo;An interview question I sometimes ask: Write code
that prints out the maximum depth of recursion allowed.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;This question is interesting for a couple of reasons. First, it&amp;rsquo;s a
shorter
&lt;a href=&#34;http://blog.codinghorror.com/why-cant-programmers-program/&#34;&gt;FizzBuzz&lt;/a&gt;;
can the candidate open an IDE, write a few lines of code, compile and
run them? And second, does he know what recursion is?&lt;/p&gt;
&lt;p&gt;Now let&amp;rsquo;s say, the interviewee knows how to write code and is familiar
with the concept of recursion. If he had to do this exercise in C#, he
might come up with something along these lines.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Main()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Recursive(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Recursive(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; i)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Console.WriteLine(i);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Recursive(i + &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Before you let him run his code, you ask him to guess the output of this
little program. If he&amp;rsquo;s smart, he won&amp;rsquo;t give you much of an answer.
Instead he will point out that the result depends on the runtime,
compiler, compiler switches, machine architecture, the amount of
available memory and what not.&lt;/p&gt;
&lt;p&gt;If he&amp;rsquo;s not familiar with the C# compiler and runtime, he might even
say there&amp;rsquo;s a chance the integer will overflow before the call stack
does.&lt;br&gt;
The recursive method call is the last call in this method, making it
tail-recursive. A smart compiler might detect the tail-recursion and
convert the recursive call into a plain loop, avoiding recursion.&lt;/p&gt;
&lt;p&gt;Running this program shows that the C# compiler isn&amp;rsquo;t that smart, and
will yield the maximum depth of recursion just before crashing.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;...
171424
171425
171426
171427
Process is terminated due to StackOverflowException.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If we were to port this snippet to F#, a functional language in which
recursion is a first class citizen, the results are a bit different.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; rec recursiveFun i &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Console.WriteLine&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;i&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ToString()&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    recursiveFun &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;i &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;recursiveFun 0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This just kept running until I killed it when the count was far over
171427. Looking at the generated IL, you can see that the compiler was
smart enough to turn this recursive function into a loop.&lt;/p&gt;
&lt;p&gt;If we want the F# implementation to behave more like the C# one, we
need to make sure the compiler doesn&amp;rsquo;t optimize for tail recursion.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; rec recursiveFun i &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Console.WriteLine&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;i&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ToString()&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    recursiveFun &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;i &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;recursiveFun 0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Running this also ends in a StackOverflowException pretty early on.&lt;/p&gt;
&lt;p&gt;I love how this question seems shallow at the surface, but gives away
more and more depth the harder you look.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Read an Event Store stream as a sequence of slices using F#</title>
      <link>https://jefclaes.be/2014/10/read-event-store-stream-as-sequence-of.html</link>
      <pubDate>Sun, 05 Oct 2014 15:21:00 +0200</pubDate>
      <guid>https://jefclaes.be/2014/10/read-event-store-stream-as-sequence-of.html</guid>
      <description>&lt;p&gt;I&amp;rsquo;m slowly working on some ideas I&amp;rsquo;ve been playing around with whole
Summer. Since that&amp;rsquo;s taking me to unknown territory, I guess I&amp;rsquo;ll be
putting out more technical bits here in the next few weeks.&lt;/p&gt;
&lt;p&gt;Using the &lt;a href=&#34;http://geteventstore.com/&#34;&gt;Event Store&lt;/a&gt;, I tried to read all
events of a specific event type. This stream turned out to be a tad too
large to be sent over the wire in one piece, leading to a
&lt;code&gt;PackageFramingException: Package size is out of bounds&lt;/code&gt;.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[07,09:57:30.489,ERROR] TcpPackageConnection: [127.0.0.1:1113, L127.0.0.1:55697, {d9265236-f72b-4418-a470-780ab7ef2af9}]. Invalid TCP frame received.
EXCEPTION(S) OCCURRED:
EventStore.ClientAPI.Transport.Tcp.PackageFramingException: Package size is out of bounds: 186992564 (max: 67108864). 
   at EventStore.ClientAPI.Transport.Tcp.LengthPrefixMessageFramer.Parse(ArraySegment`1 bytes)
   at EventStore.ClientAPI.Transport.Tcp.LengthPrefixMessageFramer.UnFrameData(IEnumerable`1 data)
   at EventStore.ClientAPI.Transport.Tcp.TcpPackageConnection.OnRawDataReceived(ITcpConnection connection, IEnumerable`1 data)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The Event Store already has a concept of reading slices, allowing you to
read a range of events in the stream, avoiding sending too much over the
wire at once. This means that if you want to read all slices, you have
to read from the start, moving up one slice at a time, until you&amp;rsquo;ve
reached the end of the stream.&lt;/p&gt;
&lt;p&gt;Avoiding mutability, I ended up with a recursive function that returns a
sequence of slices.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fsharp&#34; data-lang=&#34;fsharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; rec read stream startFrom &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;conn &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; IEventStoreConnection&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    seq &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; size &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 10000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; slice &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; conn&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;ReadStreamEventsForwardAsync&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;stream&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; startFrom&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; size&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;).&lt;/span&gt;Result
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;slice&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;IsEndOfStream&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#66d9ef&#34;&gt;yield&lt;/span&gt; slice
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#66d9ef&#34;&gt;yield&lt;/span&gt; slice
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#66d9ef&#34;&gt;yield&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt; read stream &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;startFrom &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; size&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; conn 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; slices &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; read &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;$et-event-name&amp;#34;&lt;/span&gt; 0 conn
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>The road to Großglockner</title>
      <link>https://jefclaes.be/2014/09/the-road-to-groglockner.html</link>
      <pubDate>Sun, 14 Sep 2014 21:01:00 +0200</pubDate>
      <guid>https://jefclaes.be/2014/09/the-road-to-groglockner.html</guid>
      <description>&lt;p&gt;Sixteen days after leaving home, we&amp;rsquo;re now on our way back to Antwerp.
After Croatia, we&amp;rsquo;ve driven through Slovenia, Italy, Austra and
Switzerland, arriving in France to meet up with my parents for a few
days.&lt;/p&gt;
&lt;p&gt;France offered us the typical vineyards and chateaux. What, next to the
good company, will stick with me the most is the High Alpine road in
Austria. We paid 34 euros to be allowed on the road, but the
surroundings of that piece of asphalt are extraordinary.&lt;br&gt;
The drive is rough, maybe even more so coming down than going up. No
wonder car manufacturers use it to test drive their close to
production-ready prototypes.&lt;/p&gt;
&lt;p&gt;It has been quite the trip. I had never expected to give my eyes such a
show so close to home.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-09-14-the-road-to-grossglockner-grossglockner_1.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-09-14-the-road-to-grossglockner-grossglockner_1.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-09-14-the-road-to-grossglockner-gross_glockner2.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-09-14-the-road-to-grossglockner-gross_glockner2.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-09-14-the-road-to-grossglockner-gross_glockner3.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-09-14-the-road-to-grossglockner-gross_glockner3.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-09-14-the-road-to-grossglockner-gross_glockner4.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-09-14-the-road-to-grossglockner-gross_glockner4.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Northbound again</title>
      <link>https://jefclaes.be/2014/09/northbound-again.html</link>
      <pubDate>Wed, 10 Sep 2014 11:25:00 +0200</pubDate>
      <guid>https://jefclaes.be/2014/09/northbound-again.html</guid>
      <description>&lt;p&gt;&lt;a href=&#34;http://www.jefclaes.be/2014/09/tolkiens-inspiration.html&#34;&gt;Leaving Plitvice behind
us&lt;/a&gt;, we
crossed the country heading for the sea. We didn&amp;rsquo;t need to cover a lot
of distance, to discover how diverse the Croatian landscape and climate
is. In only two hours we went from the cold, foggy lakes and waterfalls
to green meadows to dusty mountains to sunbathing coasts.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-09-10-northbound-again-1.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-09-10-northbound-again-1.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-09-10-northbound-again-2.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-09-10-northbound-again-2.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We followed the coastline for a little while, strolling through old
coast towns, eating seafood, drinking something cold. Driving up North
and more inland, we spent two days in Motovun, a picturesque town high
on a mountain.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-09-10-northbound-again-3.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-09-10-northbound-again-3.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ll be continuing up North, slowly making our way home.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Tolkien&#39;s inspiration</title>
      <link>https://jefclaes.be/2014/09/tolkiens-inspiration.html</link>
      <pubDate>Sun, 07 Sep 2014 10:36:00 +0200</pubDate>
      <guid>https://jefclaes.be/2014/09/tolkiens-inspiration.html</guid>
      <description>&lt;p&gt;The next morning we woke up to another rainy day. We caught up with the
rain in Austria and we have been following it ever since. Or the other
way around. Even the locals can&amp;rsquo;t seem to stop talking about how much
rain is falling.&lt;/p&gt;
&lt;p&gt;Between showers, we were able to hike the
&lt;a href=&#34;http://en.wikipedia.org/wiki/Bled_Gorge&#34;&gt;Vintgar&lt;/a&gt; trail. The one hour
hike takes you along dangerous rapid waters, bringing you to a big
waterfall. If I ever wondered how J.R.R. Tolkien came up with
inspiration for his famous novels, now I have a good idea.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-09-07-tolkiens-inspiration-Vintgar1.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-09-07-tolkiens-inspiration-Vintgar1.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-09-07-tolkiens-inspiration-Vintgar2.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-09-07-tolkiens-inspiration-Vintgar2.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-09-07-tolkiens-inspiration-Vintgar3.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-09-07-tolkiens-inspiration-Vintgar3.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-09-07-tolkiens-inspiration-Vintgar4.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-09-07-tolkiens-inspiration-Vintgar4.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;On Tuesday, exploring the &lt;a href=&#34;http://en.wikipedia.org/wiki/Postojna_Cave&#34;&gt;Postojna cave
system&lt;/a&gt; by train and on foot
offered similar enchanting images.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-09-07-tolkiens-inspiration-Postojna1.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-09-07-tolkiens-inspiration-Postojna1.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;After exchanging the Slovenian scenery for that of Croatia - still
raining - we visited the &lt;a href=&#34;http://en.wikipedia.org/wiki/Plitvice_Lakes_National_Park&#34;&gt;Plitvice
Lakes&lt;/a&gt; on
Thursday. The non-stop rain had caused a big part of the park to flood.
If you didn&amp;rsquo;t mind getting wet up  to your knees, wading through the
lakes that were now on top of the trails was definitely an option - one
that we took.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-09-07-tolkiens-inspiration-Plitvice1.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-09-07-tolkiens-inspiration-Plitvice1.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-09-07-tolkiens-inspiration-Plitvice2.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-09-07-tolkiens-inspiration-Plitvice2.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ll spend our last few days in Croatia along the coastline, hoping to
at least warm up a little after our wet and cold experience in the
national park.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Porsches and a setting that sells them</title>
      <link>https://jefclaes.be/2014/09/porsches-and-setting-that-sells-them.html</link>
      <pubDate>Tue, 02 Sep 2014 22:24:00 +0200</pubDate>
      <guid>https://jefclaes.be/2014/09/porsches-and-setting-that-sells-them.html</guid>
      <description>&lt;p&gt;With the Belgian &amp;lsquo;Summer&amp;rsquo; ending, we are exploring South Eastern Europe.
This trip will take us through Germany, Austria, Slovenia and Croatia.&lt;/p&gt;
&lt;p&gt;On Saturday, we stopped in Stuttgart to complete our list of visits to
the three most popular European sports car museums, &lt;a href=&#34;http://www.jefclaes.be/2012/07/ferrari-red-lamborghini-yellow.html&#34;&gt;after visiting
Lamborghini and Ferrari two years
ago&lt;/a&gt;:
the Porsche museum. In my teens, my affinity to fast cars was ignited by
spending rainy afternoons at one of my best friends&amp;rsquo;s, attempting to
crush each other&amp;rsquo;s track records playing &lt;a href=&#34;http://en.wikipedia.org/wiki/Need_for_Speed:_Porsche_Unleashed&#34;&gt;Need For Speed Porsche
Unleashed&lt;/a&gt;.
The brand has succeeded in making its way into my subconscious early on.
It would still be a Porsche I&amp;rsquo;d buy today, if I would have too much
money to spend.&lt;/p&gt;
&lt;p&gt;In the meanwhile, my interest for fast cars has tempered, making place
for a more general interest in the combination of good design and raw
engineering. There was certainly a place for this at the Porsche museum.
The architecture sets high expectations. Every detail in the building
met Porsche&amp;rsquo;s standards; from the toilet pictograms to the elevator
interior.&lt;/p&gt;
&lt;p&gt;Unfortunately, like in most car museums, they fail to really capture the
driving experience. Not once did I hear the trademark roar of a Porsche
engine, which I learned to love playing video games.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-09-02-porsches-and-a-setting-that-sells-them-Stuttgart1.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-09-02-porsches-and-a-setting-that-sells-them-Stuttgart1.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-09-02-porsches-and-a-setting-that-sells-them-Stuttgart2.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-09-02-porsches-and-a-setting-that-sells-them-Stuttgart2.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-09-02-porsches-and-a-setting-that-sells-them-Stuttgart3.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-09-02-porsches-and-a-setting-that-sells-them-Stuttgart3.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Leaving Stuttgart behind us, we set out for Bled, Slovenia. This took us
through Austria, where we diverged far from the optimal route to visit
Hallstatt. This small village, famous around the world, even coined as
one of the most beautiful places on earth, is hidden deep into the
inhospitable landscape of Austria. Being so out-of-the-way might just be
what has made it possible to preserve the charm of this little place.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-09-02-porsches-and-a-setting-that-sells-them-Hallstatt1.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-09-02-porsches-and-a-setting-that-sells-them-Hallstatt1.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-09-02-porsches-and-a-setting-that-sells-them-Hallstatt2.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-09-02-porsches-and-a-setting-that-sells-them-Hallstatt2.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Getting back into the car, it started
raining, and it didn&amp;rsquo;t stop until we crossed the Slovenian border. The
type of rain that gives you that claustrophobic car wash feeling. We
arrived in Bled well after dark, and went to bed curious of what our
surroundings would look like in the morning sun. &lt;/span&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Solomon, the architect</title>
      <link>https://jefclaes.be/2014/08/solomon-architect.html</link>
      <pubDate>Tue, 26 Aug 2014 19:52:00 +0200</pubDate>
      <guid>https://jefclaes.be/2014/08/solomon-architect.html</guid>
      <description>&lt;p&gt;Two junior developers who started working for the company at the same
time, had been quite competitive with each other from the get-go. They
had once been assigned to the same team, but because of the constant
bickering, which had put a serious amount of stress on the team, one of
them was pulled off the project and reassigned.&lt;/p&gt;
&lt;p&gt;A good year later, just the two of them were assigned to a new smallish,
but interesting in-house project. When management assigned them to the
same project again, they had just been shuffling resources around, and
had no idea of the history these two had. An architect was also assigned
to the project, but this was not more than a formality. As soon as the
enterprise architecture diagram was updated and the paper work was out
of the way, he would do an official hand over, but he would only
occasionally check in on the project from then on.&lt;/p&gt;
&lt;p&gt;The Friday morning after the hand over, the architect was making small
talk with one of the project managers in the coffee corner. His agenda
for the day was almost empty - exactly how he liked it on Fridays. He
planned on making the rounds this morning to check in on projects he was
involved with, to attend a meeting at noon, and to spend the afternoon
reading up on micro services, for then to go home early. While he
charged the coffee machine with another coffee pod, he heard an uproar
that had to be coming from the other side of the floor. He couldn&amp;rsquo;t
quite make out what it was about, but he recognized the voices
immediately: the two juniors.&lt;/p&gt;
&lt;p&gt;He hurried over to the source of the noise. Prying eyes looked curiously
over their monitors, ignoring the architect as he passed by. He found
the two juniors standing next to the white board, yelling at each other,
gesturing vigorously, crossing out parts of the drawings. The architect
broke up the fight, and commanded them to get in the meeting room right
away. Startled at first, but red-faced just a few seconds later, they
shuffled towards the meeting room, not saying one more word, staring at
their shoes.&lt;/p&gt;
&lt;p&gt;The architect closed the door behind him, and started questioning them.
What was this all about? He learned they had a big disagreement on how
they should design a part of the new system. The architect, after
hearing them out, thought he understood both their solutions. Given the
information he had at that time, he thought both solutions were good
enough for now - each made trade-offs, and only time would tell them
more.&lt;br&gt;
&amp;ldquo;There are still dozens of possible alternatives out there. I should try
to show them how to come to a consensus together,&amp;rdquo; he thought. &amp;ldquo;Before I
do that, I&amp;rsquo;m curious to discover their incentives though, so let me try
something here.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;He told them that he liked both of their solutions, but that he couldn&amp;rsquo;t
decide  which was the better one. Instead, he would take random parts of
each solution and throw them together, to come up with a hybrid
solution. This way, nobody loses.&lt;/p&gt;
&lt;p&gt;Junior number one seemed relieved. He nodded and glanced at his partner.
To his surprise, his partner didn&amp;rsquo;t look very happy. Junior number two
blurted out that he&amp;rsquo;d rather see his own solution in the bin, than to
give up conceptual integrity, just because two people can&amp;rsquo;t agree.&lt;/p&gt;
&lt;p&gt;With that, the architect learned that junior number one had fallen into
the trap of making it personal, and was trying to save face. Number two
however, was wise enough to favor conceptual integrity over getting his
way. The architect complimented the kid, and acknowledged that sometimes
giving in might be the wise thing to do - not always, you have to pick
your battles. Then he rolled up his sleeves, picked up a bunch of
post-its and a pen for both of them and said that it was time for them
to &amp;ldquo;fight the problem together instead of fighting each other&amp;rdquo;. But not
before he made another coffee.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Thinking No Computers</title>
      <link>https://jefclaes.be/2014/08/thinking-no-computers/</link>
      <pubDate>Tue, 19 Aug 2014 20:09:00 +0200</pubDate>
      <guid>https://jefclaes.be/2014/08/thinking-no-computers/</guid>
      <description>&lt;p&gt;The other day I happened to see a curious exchange in one of our
businesses. The cashier swapped a torn, but carefully restored by taping
it together again, Euro bill for a new one with the manager.
Inquisitive, I asked the manager what he was planning to do with that
Euro bill. &amp;ldquo;Once a month, I take all those ripped up or badly worn bills
to the National Bank, and trade them for new ones. All you need is one
piece of the bank note for them to give you a newly printed one.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;While he started taking care of some other paper work, my mind started
racing towards how the National Bank made this system work. I had
noticed before that bank notes have an identifier on each side. I
figured the National Bank probably stores the identifier of each note
they trade, so people don&amp;rsquo;t go ripping up bank notes with the intent of
trading them twice. That seems easy enough, no?&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-08-19-thinking-no-computers-Papernote.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-08-19-thinking-no-computers-Papernote.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once the manager finished up his paperwork, I wanted to confirm my idea
and asked if he knew how that system worked. How do they avoid people
cheating? &amp;ldquo;It&amp;rsquo;s really simple actually, you need to own more than 50% of
a bill for it to be tradable.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Well&amp;hellip; that&amp;rsquo;s a much simpler solution. No need to store all the traded
notes somewhere, you probably don&amp;rsquo;t even need a computer at all.&lt;/p&gt;
&lt;p&gt;I catch myself regularly defaulting to wanting to solve problems using
computers. While taking a step back and thinking of how it would be done
without, often exposes a simpler model. Sometimes you will realize that
you don&amp;rsquo;t need a computer at all. If not that, you get to steal from
models that have been molded and battle tested for years.&lt;/p&gt;
&lt;p&gt;Look at existing organizational structures and search for boundaries.
You might find that aligning your software with existing boundaries
makes the pieces of the puzzle fit. Learn how departments communicate;
passing forms, by phone or by email. Maybe it shows that you need
synchronous communication with strong consistency based on a formal
protocol or that you might just get away with asynchronous communication
with a less strong schema. Go through paper work, formulas, legislation,
research papers, books and what not, and that hard to crack nut might
become a bit softer. Look at where people are making decisions and how
they are deciding on them, do you spot the patterns?&lt;/p&gt;
&lt;p&gt;People have been solving problems for hundreds of years, tinkering with
and perfecting models, way before computers were a commodity. Natural
selection made sure only the strongest made it this far. Those solutions
didn&amp;rsquo;t stop working all of a sudden, nor should they be discarded as a
whole. A great deal of them will likely survive another few hundred
years, in one form or the other.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Paper notes: A Study and Toolkit for Asynchronous Programming in C#</title>
      <link>https://jefclaes.be/2014/06/paper-notes-study-and-toolkit-for.html</link>
      <pubDate>Sun, 08 Jun 2014 18:33:00 +0200</pubDate>
      <guid>https://jefclaes.be/2014/06/paper-notes-study-and-toolkit-for.html</guid>
      <description>&lt;p&gt;The .NET framework mainly provides two models for asynchronous
programming: (1) the Asynchronous Programming Model (APM), that uses
callbacks, and (2) the Task Asynchronous Pattern (TAP), that uses Tasks,
which are similar to the concept of futures.&lt;/p&gt;
&lt;p&gt;The Task represents the operation in progress, and its future result.
The Task can be (1) queried for the status of the operation, (2)
synchronized upon to wait for the result of the operation, or (3) set up
with a continuation that resumes in the background when the task
completes.&lt;/p&gt;
&lt;p&gt;When a method has the async keyword modifier in its signature, the await
keyword can be used to define pausing points. The code following the
await expression can be considered a continuation of the method, exactly
like the callback that needs to be supplied explicitly when using APM or
plain TAP.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do Developers Misuse async/await?&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;One in five async methods violate the principle that an async method
should be awaitable unless it is the top level event handler.&lt;/li&gt;
&lt;li&gt;Adding the async modifier comes at a price: the compiler generates
some code in every async method and generated code complicates the
control flow which results in decreased performance. There is no
need to use async/await in 14% of async methods.&lt;/li&gt;
&lt;li&gt;1 out of 5 apps miss opportunities in at least one async method to
increase asynchronicity.&lt;/li&gt;
&lt;li&gt;99% of the time, developers did not use ConfigureAwait(false) where
this was needed.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The async/await feature is a powerful abstraction. asynchronous methods
are more complicated than regular methods in three ways. (1) Control
flow of asynchronous methods. Control is returned to the caller when
awaiting, and the continuation is resumed later on. (2) Exception
handling. Exceptions thrown in asynchronous methods are automatically
captured and returned through the Task. The exception is then re-thrown
when the Task is awaited. (3) Non-trivial concurrent behavior.&lt;/p&gt;
&lt;p&gt;Each of these is a leak in the abstraction, which requires an
understanding of the underlying technology - which developers do not yet
seem to grasp.&lt;/p&gt;
&lt;p&gt;Another problem might simply be the naming of the feature: asynchronous
methods. However, the first part of the method executes synchronously,
and possible the continuations do as well. Therefore, the name
asynchronous method might be misleading: the term pauseable could be
more appropriate.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://swerl.tudelft.nl/twiki/pub/Main/TechnicalReports/TUD-SERG-2013-016.pdf&#34;&gt;Source&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Not about the UI and the database</title>
      <link>https://jefclaes.be/2014/06/not-about-ui-and-database.html</link>
      <pubDate>Sun, 01 Jun 2014 17:55:00 +0200</pubDate>
      <guid>https://jefclaes.be/2014/06/not-about-ui-and-database.html</guid>
      <description>&lt;p&gt;When you ask an outsider which components an average application
consists of, he will most likely be able to identify the user interface
and the database. He will also recognize that there is something in
between that takes the input from the user interface, applies some logic
and persists the result in the database.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-06-01-not-about-the-ui-and-the-database-1.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-06-01-not-about-the-ui-and-the-database-1.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In the past, trying to make sense of what goes on the middle, we started&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;with the best intentions - layering things. Each layer had its own
responsibility and would build upon previous layers. Although there was
a layer for business logic, we never really succeeded in capturing the
essence. In the end we would still be orchestrating database calls, but
now we would be forced to go through a bunch of indirections in the form
of anemic layers and objects.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-06-01-not-about-the-ui-and-the-database-2.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-06-01-not-about-the-ui-and-the-database-2.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Some people saw these designs for what they were, broke free and started
optimizing for the shortest path - from user interface to database with
the least amount of effort. By aiming to serve the common denominator
and by putting their trust in dark magic, frameworks popped up that
would allow you to slap together an application in a matter of hours.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-06-01-not-about-the-ui-and-the-database-3.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-06-01-not-about-the-ui-and-the-database-3.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The problem with these frameworks is that they leave you with very
little room for your own, and you often end up jumping through hoops
when you need to deviate from the path carved out for you.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-06-01-not-about-the-ui-and-the-database-4.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-06-01-not-about-the-ui-and-the-database-4.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s not the only problem though - applications are a lot more than a
user interface and a database. What lives between those two is more than
a technical necessity - it&amp;rsquo;s a place where you get to build a model of
the problem you are solving. The model gives you an opportunity to learn
from and to communicate with domain experts, peers and users. And that&amp;rsquo;s
exactly where most businesses make the difference, not by having a fancy
user interface or a carefully designed database schema, but by really
understanding and by being absorbed by the problem they are solving.
It&amp;rsquo;s the user interface and the database that are the necessary evil we
bring upon ourselves by solving problems using computers.&lt;/p&gt;
&lt;p&gt;The state that lives in your database is a side effect - the result of
the model&amp;rsquo;s behavior. The user interface tries to make it as easy as
possible for users to drive and use the model.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-06-01-not-about-the-ui-and-the-database-5.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-06-01-not-about-the-ui-and-the-database-5.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Although the user interface and the database are important, it&amp;rsquo;s the
model that is the heart and soul of your application.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(*) Disclaimer: all these drawings are simplistic by design.&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Eventual consistency in the Wild West</title>
      <link>https://jefclaes.be/2014/05/eventual-consistency-in-wild-west.html</link>
      <pubDate>Sun, 25 May 2014 18:01:00 +0200</pubDate>
      <guid>https://jefclaes.be/2014/05/eventual-consistency-in-wild-west.html</guid>
      <description>&lt;p&gt;San Francisco, 1852. With the California Gold Rush at its peak,
successful gold-seekers wanted to protect all their precious gold
nuggets by storing them in a strong safe. At the time, it wasn&amp;rsquo;t that
easy to have access to a safe though. At the very beginning, it were
just a few local merchants that owned one. Not much later, bankers
swamped the area hoping to get their piece of the pie - bringing the
strongest safes money can buy.&lt;/p&gt;
&lt;p&gt;James King of William - who had made a fortune himself mining gold - was
one of the first to found a trustworthy bank in San Francisco.&lt;br&gt;
With the city growing from a small 200 residents in 1846 to about 36.000
in 1852, it became harder and harder for the bank to accommodate all
their customers in that one office. It needed to expand its
operations.&lt;br&gt;
Three months later a new branch opened up on the other side of town.
James determined to build a strong brand, wanted to allow customers to
go to any of the two branches to deposit and withdraw their money. This
meant that the books of the two branches had to be kept consistent. To
maintain the books, James commanded all the clerks to duplicate all new
records. Two hired horsemen would then come in every few hours and bring
those records to the other branch. Since the books were now the same in
both branches, customers could deposit and withdraw money in both sides
of town. For James, life was good, he was now raking in twice as much.&lt;/p&gt;
&lt;p&gt;Pancho and Lefty, two bandits fled from Mexico, trying their luck in
California, were instead of spending their Friday afternoon in search of
gold, trying to forget their gold drought by playing cards and drinking
cheap Whiskey in the local saloon. While Lefty kept rambling on about
how unlucky they had been these last few weeks, Pancho paid closer
attention to the conversation going on between the saloon keeper and
this well-dressed rider that had just entered. The leather bound
notebook the rider was carrying stood out immediately - it carried this
familiar looking mark and looked expensive. Even though Lefty kept on
rambling, Pancho could make up quite a bit eavesdropping on the saloon
keeper and the rider&amp;rsquo;s conversation. That suddenly came to an end
though, when the rider knocked back his drink and got ready to leave -
&amp;ldquo;Well, I better get going before the boss man notices that his books are
no longer up to date.&amp;rdquo;&lt;br&gt;
Pancho watched the rider step outside and get back on his horse. Once
the rider was out of sight, Pancho with an intense gleam in his eyes,
cut off Lefty and ordered him to shut his mouth - &amp;ldquo;Shut it fool, I have
a plan that&amp;rsquo;s going to make us some easy money.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;That same day, Pancho and Lefty gathered all their coins, opened an
account for Pancho at James King&amp;rsquo;s bank and made their first deposit.
Afterwards, they stuck around the bank&amp;rsquo;s side entrance just to make sure
one of the horsemen came by to pick up the books. Twenty minutes later,
the same rider they saw at the saloon showed up - Pancho and Lefty
spontaneously looked the other way, avoiding to be seen by the rider.
They hung around a little longer, to verify that when the driver exited
the bank, he was carrying a notebook - a notebook containing the records
of the account they just opened and their first deposit.&lt;/p&gt;
&lt;p&gt;The next day, Pancho and Lefty got up early. They only got a few hours
of shut-eye in, they had been up all night sneaking around, scouting the
biggest ranch in town. To make their plan work, they needed to borrow a
fast horse.&lt;br&gt;
Impatiently waiting in front of the bank, Lefty breathed a sigh of
relief when the clerk opened the bank at nine AM sharp. Before he
entered, he looked one more time to the left, where Lefty was standing
in the shadows holding the horse - ready to go. Being the first customer
to enter the bank, he walked straight up to the counter, pulled out his
token of authentication and told the clerk he wanted to make a
withdrawal for all that was on his balance. The clerk looked at the
token carefully, but didn&amp;rsquo;t ask any further questions - he still
remembered seeing Pancho yesterday, it wasn&amp;rsquo;t like he owned a fortune.&lt;/p&gt;
&lt;p&gt;Money in hand, Pancho firmly walked out of the bank. To make the plan
work, he now needed to jump on that horse as quickly as possible and
ride off to the branch on the other side of town - if he made it there
before the hired horsemen had the chance to transfer the latest records,
he might be able to double his assets in a single morning.&lt;/p&gt;
&lt;p&gt;Pancho didn&amp;rsquo;t spare the horse at all, frantically digging his spurs into
its sides. He made sure to take the dirt road through town, avoiding
obstacles and people where he could.&lt;br&gt;
Tying the horse down next to the bank, he watched one of the horsemen
walk out of the bank. Damn. Had he been too slow, were the books already
consistent again?&lt;br&gt;
Pancho broke out in a cold sweat, but he had to try. He shuffled into
the bank and got in line - there were three customers in front of him.
Every time he looked up at the clock, he got more anxious. By the time
his turn came, he was terrified. Without looking up, he pulled out his
token of authentication once more, and mumbled to the clerk that he
wanted to withdraw all of his money. The clerk noticed the drops of
sweat on Pancho&amp;rsquo;s forehead and how Pancho&amp;rsquo;s hands were shaking. &amp;ldquo;Poor
soul,&amp;rdquo; the clerk thought, &amp;ldquo;he must have caught cholera like many others,
they&amp;rsquo;re falling like flies.&amp;rdquo; The clerk went into the back, looked into
the books, opened the safe and handed Pancho everything he was worth.&lt;/p&gt;
&lt;p&gt;James King spent very little of his time at one of his banks - he was
too busy looking for new ventures to fund. When he was in town and had
the time, he did make a habit of jumping by to look in the books right
before closing time. Today, one of the clerks walked up to James King as
soon as he arrived; &amp;ldquo;I&amp;rsquo;m afraid there has been made a mistake in the
books, sir. The books show that one customer withdrew all of his money
twice today. First here, and then in the other branch. Something must
have gone wrong copying the records.&amp;rdquo; Going through the records, it was
obvious to James King what had happened; they had been robbed.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Thank the lord that it&amp;rsquo;s only for a small amount. Let&amp;rsquo;s make sure this
doesn&amp;rsquo;t happen again.&amp;rdquo; James started by hiring two extra horsemen, but
to be even more sure he also had to introduce some new rules. A customer
could now only withdraw $5 a day, unless he had proven to be a good and
reliable customer. If a customer needed to withdraw extraordinary large
amounts, he needed to inform a specific branch one day in advance. This
allowed both branches to keep serving all customers smoothly while not
giving up on operating in a semi-autonomous fashion. James was even
considering opening a new branch in the famous city of angels, Los
Angeles.&lt;/p&gt;
&lt;p&gt;Next time; isolation levels in the Wild West.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>NCrafts Eventstorming slides</title>
      <link>https://jefclaes.be/2014/05/ncrafts-eventstorming-slides.html</link>
      <pubDate>Fri, 16 May 2014 15:22:00 +0200</pubDate>
      <guid>https://jefclaes.be/2014/05/ncrafts-eventstorming-slides.html</guid>
      <description>&lt;p&gt;Me and &lt;a href=&#34;https://twitter.com/tojans&#34;&gt;Tom&lt;/a&gt; just finished doing our Event
storming workshop at &lt;a href=&#34;http://ncrafts.io/&#34;&gt;NCrafts Paris&lt;/a&gt;. Although we
made a few mistakes along the way, feedback on the workshop was great. I
hope to put something out about what we learned facilitating later this
week. People talked, discovered and eventually learned a new domain in
under two hours. The domain? Two minutes before the workshop we found a
domain expert prepared to talk about his coupon start-up.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Modeling a business process is often associated with people in suits
having long and dull meetings. Way too much time gets wasted for an
outcome that&amp;rsquo;s far from reality and which will be obsolete in weeks.
Event storming is a workshop format that brings modeling back to all
stakeholders, and aims to create usable models.  &lt;/p&gt;
&lt;p&gt;In this workshop, you won&amp;rsquo;t be writing any code, but you will be using
lots of paper, post-its and a marker. After going over a bit of theory
and a small example, we will present you with a real business problem,
and in a few short playful sessions you will experience how powerful
event storming can be in helping a team gain insight into complex
problems.
  
The techniques you will learn in this workshop will pay off
immediately. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The slides we used are now up on
&lt;a href=&#34;https://www.slideshare.net/jclaes/ncrafts-eventstorming-workshop&#34;&gt;Slideshare&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To learn more, you can join the &lt;a href=&#34;https://plus.google.com/communities/113258571348605620818&#34;&gt;EventStormers
community&lt;/a&gt;,
but more importantly, you should start experimenting yourself!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>What if we stored events instead of state? - slides</title>
      <link>https://jefclaes.be/2014/05/what-if-we-stored-events-instead-of.html</link>
      <pubDate>Mon, 12 May 2014 17:41:00 +0200</pubDate>
      <guid>https://jefclaes.be/2014/05/what-if-we-stored-events-instead-of.html</guid>
      <description>&lt;p&gt;I just returned from Croatia, where I got to speak twice at the second edition of &lt;a href=&#34;http://2014.thegeekgathering.org/&#34;&gt;The Geek Gathering&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Being such a young conference, I had no idea what to expect. Turns out they have a good thing going on; a small, local and very personal approach to conferences. Speakers both local and international,
covering topics that serve the community, not their employer.&lt;/p&gt;
&lt;p&gt;Together with Tom, I preached &lt;a href=&#34;https://twitter.com/ziobrando&#34;&gt;Alberto&lt;/a&gt;&amp;rsquo;s
Event Storming during a four hour long workshop. As always, people were
impressed by how quick you can gain an understanding of a new domain
using this technique. Slides of this workshop will be online after I
make some tweaks, and try it in Paris on Friday.&lt;/p&gt;
&lt;p&gt;In my second talk, I got to share what I&amp;rsquo;ve learned these last two years
on event sourcing. You can find the slides of that talk on &lt;a href=&#34;http://www.slideshare.net/jclaes/what-if-we-stored-events-instead-of-state&#34;&gt;Slideshare&lt;/a&gt;.
Thanks &lt;a href=&#34;https://twitter.com/ToJans&#34;&gt;Tom&lt;/a&gt;,
&lt;a href=&#34;https://twitter.com/mathiasverraes&#34;&gt;Mathias&lt;/a&gt;,
&lt;a href=&#34;https://twitter.com/one75&#34;&gt;Stijn&lt;/a&gt;,
&lt;a href=&#34;https://twitter.com/yreynhout&#34;&gt;Yves&lt;/a&gt; and
&lt;a href=&#34;https://twitter.com/bwaterschoot&#34;&gt;Bart&lt;/a&gt; for reviewing them!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Glueing the browser and POS devices together </title>
      <link>https://jefclaes.be/2014/05/glueing-browser-and-pos-devices-together.html</link>
      <pubDate>Sun, 04 May 2014 18:23:00 +0200</pubDate>
      <guid>https://jefclaes.be/2014/05/glueing-browser-and-pos-devices-together.html</guid>
      <description>&lt;p&gt;I have been occupied building a modest Point of Sale system over these
last few weeks. Looking at implementing the client, there were two
constraints; it needed to run on Windows and it should be able to talk
to devices such as a ticket printer and a card reader.&lt;/p&gt;
&lt;p&gt;Although we could use any Windows client framework, we like building
things in the browser better for a number of reasons;
platform-independence, familiar user experience, JavaScript&amp;rsquo;s
asynchronous programming model and its incredible rich ecosystem. Having
to talk to devices ruled out leveraging the browser to deliver our
application though - or didn&amp;rsquo;t it?&lt;/p&gt;
&lt;p&gt;Most Windows client frameworks give you a browser component which can be
used to host web applications inside of your application. We used this
component to host our web application, which turned the hosting
application into not much more than a bridge between our web application
and the devices.&lt;/p&gt;
&lt;p&gt;This bridge processes commands sent by the browser (or the application
itself), and produces events which are returned to the browser. I ended
up not needing much code to implement this.&lt;/p&gt;
&lt;p&gt;I defined &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/dd267312(v=vs.110).aspx&#34;&gt;two thread-safe
queues&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;one to put commands on, and one to put events on. &lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; BlockingCollection&amp;lt;ICommand&amp;gt; _commandQueue = 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; BlockingCollection&amp;lt;ICommand&amp;gt;(); 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; BlockingCollection&amp;lt;IEvent&amp;gt; _eventQueue = 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; BlockingCollection&amp;lt;IEvent&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then I start consuming the command queue in the background by turning it
into an observable and subscribing to it. Processing commands in the
background ensures that command processing never blocks the UI thread.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Task.Factory.StartNew(() =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; processor = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; CommandProcessor(_eventQueue);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    _commandQueue
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .GetConsumingEnumerable()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .ToObservable()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .Subscribe(processor.Execute);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When a command is dequeued, the associated handler will be invoked. The
handler then does its work while raising events when appropriate.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DoSomethingHandler&lt;/span&gt; : IHandle&amp;lt;DoSomething&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; BlockingCollection&amp;lt;IEvent&amp;gt; _eventQueue;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; SleepCommandHandler(BlockingCollection&amp;lt;IEvent&amp;gt; eventQueue) 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _eventQueue = eventQueue;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Execute(DoSomething cmd)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _eventQueue.Add(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; DoingSomething());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// do work&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _eventQueue.Add(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; FinishedDoingSomething());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the meanwhile the event queue is being processed in the background as
well - sending events to the browser as fast as they can be dequeued.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Task.Factory.StartNew(() =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    _eventQueue
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .GetConsumingEnumerable()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .ToObservable()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .Subscribe(SendToBrowser);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Sending events to the browser is done by invoking a script through the
browser control.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; SendToBrowser(IEvent @event)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;object&lt;/span&gt;[] args = { &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.Format(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;app.bus.send({0})&amp;#34;&lt;/span&gt;, EventSerializer.Serialize(@event)) };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (WebBrowser.InvokeRequired)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        WebBrowser.BeginInvoke((MethodInvoker)&lt;span style=&#34;color:#66d9ef&#34;&gt;delegate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (WebBrowser.Document != &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                WebBrowser.Document.InvokeScript(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;eval&amp;#34;&lt;/span&gt;, args);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (WebBrowser.Document != &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            WebBrowser.Document.InvokeScript(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;eval&amp;#34;&lt;/span&gt;, args);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the browser, we can now transparently subscribe to these events. As
an implementation detail on that side, we&amp;rsquo;re using
&lt;a href=&#34;https://github.com/aaronpowell/Postman&#34;&gt;Postman&lt;/a&gt; for pub-sub in the
browser.&lt;/p&gt;
&lt;p&gt;With this, we&amp;rsquo;ve come full circle; commands come in, they get processed,
leading to events being produced, which eventually go out to the
browser.&lt;/p&gt;
&lt;p&gt;With this, we provide a consistent web experience for users and for
developers, while not having to jump through too much hoops to make it
work.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-05-04-glueing-the-browser-and-pos-devices-together-BrowserIntegration.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-05-04-glueing-the-browser-and-pos-devices-together-BrowserIntegration.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I also thought of hosting communication with the devices in a Windows
service while having that component expose its functionalities over HTTP
so that the browser could talk to a local endpoint instead of being
hosted in an application. While this is a valid alternative, it raised
some concerns towards deployment in our scenario (we can&amp;rsquo;t push changes
towards these clients, they need to come get them). With the existing
set-up, I think even if we would like to change to such a model, it
wouldn&amp;rsquo;t be that much trouble.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve pieced together a similar solution, feel free to let me know
what I&amp;rsquo;m getting myself into.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Solving Mavericks with VMware Fusion 6 and Windows 8.1 hangs</title>
      <link>https://jefclaes.be/2014/04/solving-mavericks-with-vmware-fusion-6.html</link>
      <pubDate>Mon, 21 Apr 2014 12:07:00 +0200</pubDate>
      <guid>https://jefclaes.be/2014/04/solving-mavericks-with-vmware-fusion-6.html</guid>
      <description>&lt;p&gt;Since I intended to avoid Windows at home, I got a Macbook Pro starting
out at my new job. Overall it has been a great machine for doing
development; it&amp;rsquo;s fast, light enough to carry around, its battery life
is outstanding, it has a screen that&amp;rsquo;s gentle to the eyes, and full
screen apps together with powerful mouse gestures allow me to quickly
shuffle between things not missing touch or a second monitor.&lt;/p&gt;
&lt;p&gt;Most of my professinal work is still on the Microsoft stack though, so
I&amp;rsquo;m running a Windows 8.1 VM on VMWare Fusion 6. Much to my frustration,
this setup would gradually slow down my system until it would completely
grind to a halt every few hours. After complaining about it on Twitter,
people said that having 8GB of RAM with half of that allocated to the VM
might not be enough.&lt;/p&gt;
&lt;p&gt;However after applying some tweaks, I got my system to chug away for a
week without any hangs.&lt;/p&gt;
&lt;p&gt;Here is what I changed:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://communities.vmware.com/thread/460957&#34;&gt;Turn off App Nap for
VMware&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://lifehacker.com/memory-clean-frees-up-your-macs-unused-system-reserve-1486621856&#34;&gt;Install Memory
Clean&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Disable Windows visual effects (Advanced System Settings - Visual
Effects)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://confluence.jetbrains.com/display/NETCOM/Ultimate+Guide+to+Speeding+Up+ReSharper+(and+Visual+Studio)#UltimateGuidetoSpeedingUpReSharper%28andVisualStudio%29-TurnoffSolutionWideAnalysis&#34;&gt;Turn off Resharper Solution-Wide
Analysis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://confluence.jetbrains.com/display/NETCOM/Ultimate+Guide+to+Speeding+Up+ReSharper+(and+Visual+Studio)#UltimateGuidetoSpeedingUpReSharper%28andVisualStudio%29-Speedupeditorscrolling&#34;&gt;Turn off Visual Studio rich client visual
experience &lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Hope it helps.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Rebinding a knockout view model</title>
      <link>https://jefclaes.be/2014/04/rebinding-knockout-viewmodel.html</link>
      <pubDate>Sun, 06 Apr 2014 18:43:00 +0200</pubDate>
      <guid>https://jefclaes.be/2014/04/rebinding-knockout-viewmodel.html</guid>
      <description>&lt;p&gt;As you might have noticed reading my last two posts, I have been doing a
bit of front-end work using &lt;a href=&#34;http://knockoutjs.com/&#34;&gt;knockout.js&lt;/a&gt;. Here
is something that had me scratching my head for a little while..&lt;/p&gt;
&lt;p&gt;In one of our pages we&amp;rsquo;re subscribing to a specific event. As soon as
that event arrives, we need to reinitialize the model that is bound to
our container element. Going through snippets earlier, I remembered
seeing the &lt;code&gt;cleanNode&lt;/code&gt; function being used a few times - which I thought
would remove all knockout data and event handlers from an element. I
used this function to clean the element the view model was bound to, for
then to reapply the bindings to that same element.&lt;/p&gt;
&lt;p&gt;This seemed to work fine, until I used a foreach binding. If you look at
the snippet below, what is the result you would expect?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;books&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ul&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;bind&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;foreach: booksImReading&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;li&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;bind&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;text: name&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/li&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/ul&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;bookModel&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;booksImReading&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        { &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Effective Akka&amp;#34;&lt;/span&gt; }, 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        { &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Node.js the Right Way&amp;#34;&lt;/span&gt; }]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;applyBindings&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;bookModel&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;el&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;bookModel2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;booksImReading&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        { &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SQL Performance Explained&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        { &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Code Connected&amp;#34;&lt;/span&gt; }]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;cleanNode&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;books&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;applyBindings&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;bookModel2&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;books&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Two list-items? One for &amp;ldquo;SQL Performance Explained&amp;rdquo; and one for &amp;ldquo;Code
Connected&amp;rdquo;? That&amp;rsquo;s what I would expect too. The actual result shows two
list-items for &amp;ldquo;SQL Performance Explained&amp;rdquo; and two for &amp;ldquo;Code Connected&amp;rdquo;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;four in total. The &lt;code&gt;cleanNode&lt;/code&gt; function is apparently not cleaning the
foreach binding completely.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Looking for documentation on the cleanNode function, I couldn&amp;rsquo;t find
any. What I did find was a year old Stackoverflow answer advising
against using this function - since it&amp;rsquo;s intended for internal use
only.&lt;/p&gt;
&lt;p&gt;I ended up making the book model itself an observable. The element is
now being bound to a parent model that contains my original book model
as an observable. When the event arrives now, I create a new book model
and set it to that observable property. This results in my list being
rerendered with just two items - like expected.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;books&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ul&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;bind&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;foreach: bookModel().booksImReading&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;li&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;bind&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;text: name&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/li&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/ul&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;page&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;bookModel&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;booksImReading&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            { &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Effective Akka&amp;#34;&lt;/span&gt; }, 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            { &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Node.js the Right Way&amp;#34;&lt;/span&gt; }]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;applyBindings&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;page&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;el&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;page&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;bookModel&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;booksImReading&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        { &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SQL Performance Explained&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        { &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Code Connected&amp;#34;&lt;/span&gt; }]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Don&amp;rsquo;t use the &lt;code&gt;cleanNode&lt;/code&gt; function to rebind a model - instead make the
model an observable too.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Sending commands from a knockout.js view model</title>
      <link>https://jefclaes.be/2014/03/sending-commands-from-knockoutjs-view.html</link>
      <pubDate>Sun, 23 Mar 2014 18:31:00 +0100</pubDate>
      <guid>https://jefclaes.be/2014/03/sending-commands-from-knockoutjs-view.html</guid>
      <description>&lt;p&gt;While I got to use &lt;a href=&#34;http://angularjs.org/&#34;&gt;angular.js&lt;/a&gt; for a good while
last year, I found myself returning to
&lt;a href=&#34;http://knockoutjs.com/&#34;&gt;knockout.js&lt;/a&gt; for the current application I&amp;rsquo;m
working on. Where angular.js is a heavy, intrusive, opinionated, but
also very complete framework, knockout.js is a small and lightweight
library giving you not much more than a dynamic model binder. So instead
of blindly following the angular-way, I&amp;rsquo;ll have to introduce my own set
of abstractions and plumbing again; I assume that I&amp;rsquo;ll end up with a lot
less.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s say that I have a view model for making a deposit.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DepositViewModel&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;account&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;amount&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;depositEnabled&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;computed&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;account&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;!==&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;amount&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;deposit&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;depositEnabled&lt;/span&gt;()) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Error(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Deposit should be enabled.&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ajax&lt;/span&gt;({ 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/Commands/Deposit&amp;#39;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; { &lt;span style=&#34;color:#a6e22e&#34;&gt;account&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;account&lt;/span&gt;(), &lt;span style=&#34;color:#a6e22e&#34;&gt;amount&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;amount&lt;/span&gt;() }, 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;success&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() { &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;amount&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;); }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;type&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;dataType&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;json&amp;#39;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;applyBindings&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DepositViewModel&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Writing a test for this, it was obvious that I couldn&amp;rsquo;t have my deposit
function make requests directly. An abstraction that has served me well
in the past, is a command executor. &lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;CommandExecutor&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;execute&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;command&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;success&lt;/span&gt;) { };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can have an implementation that handles each command individually, or
we can have it send requests to our server by convention. The
implementation below assumes that the name of our command has a
corresponding endpoint on the server. &lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;CommandExecutor&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;execute&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;command&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;success&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;console&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;console&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Executing command..&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;console&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;command&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ajax&lt;/span&gt;({ 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;/Commands/&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;command&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;command&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;success&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;success&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;type&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;dataType&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;json&amp;#39;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While angular.js has dependency management built in, we can get away by
injecting dependencies manually and a bit of bootstrapping - it&amp;rsquo;s not
that I often have large dependency graphs in the browser, or that I care
much about the life cycles of my components.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DepositViewModel&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;dependencies&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;account&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;amount&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;depositEnabled&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;computed&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;account&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;!==&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;amount&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;deposit&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;depositEnabled&lt;/span&gt;()) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Error(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Deposit should be enabled.&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;command&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; { 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Deposit&amp;#39;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; { &lt;span style=&#34;color:#a6e22e&#34;&gt;account&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;account&lt;/span&gt;(), &lt;span style=&#34;color:#a6e22e&#34;&gt;amount&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;amount&lt;/span&gt;() } };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;callback&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() { &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;amount&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;); };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;dependencies&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;commandExecutor&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;execute&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;command&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;callback&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;applyBindings&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DepositViewModel&lt;/span&gt;({ &lt;span style=&#34;color:#a6e22e&#34;&gt;commandExecutor&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CommandExecutor&lt;/span&gt;() }));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;See, very little magic required.&lt;/p&gt;
&lt;p&gt;Writing a test, we now only need to replace the command executor with an
implementation that will record commands instead of actually sending
them to the server.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CommandExecutorMock&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;commands&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;execute&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;command&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;success&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;commands&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;command&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;success&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;verifyCommandWasExecuted&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;command&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;commands&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;JSON&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;stringify&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;commands&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;]) &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;JSON&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;stringify&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;command&lt;/span&gt;)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;                        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;describe&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;When a deposit is invoked&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;commandExecutor&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CommandExecutorMock&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;model&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DepositViewModel&lt;/span&gt;({ &lt;span style=&#34;color:#a6e22e&#34;&gt;commandExecutor&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;commandExecutor&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;model&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;account&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;MyAccount&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;model&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;amount&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;model&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;deposit&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;it&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;a deposit command is sent.&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;command&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Deposit&amp;#39;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; { &lt;span style=&#34;color:#a6e22e&#34;&gt;account&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;MyAccount&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;amount&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;expect&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;commandExecutor&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;verifyCommandWasExecuted&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;command&lt;/span&gt;)).&lt;span style=&#34;color:#a6e22e&#34;&gt;toBe&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    });  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I did something similar for queries, and ended up with not that much
code, that didn&amp;rsquo;t even take that long to write. I&amp;rsquo;m curious to see how
this application will evolve.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Building a live dashboard with some knockout</title>
      <link>https://jefclaes.be/2014/03/building-live-dashboard-with-some.html</link>
      <pubDate>Sun, 16 Mar 2014 21:23:00 +0100</pubDate>
      <guid>https://jefclaes.be/2014/03/building-live-dashboard-with-some.html</guid>
      <description>&lt;p&gt;Last week, we added a dashboard to our back office application that
shows some actionable data about what&amp;rsquo;s going on in our system. Although
we have infrastructure in place to push changes to the browser, it
seemed more reasonable to have the browser fetch fresh data every few
minutes.&lt;/p&gt;
&lt;p&gt;We split the dashboard up in a few functional cohesive widgets. On the
server, we built a view-optimized read model for each widget. On the
client, we wrote a generic view model that would fetch the raw read
models periodically.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ajaxWidgetModel&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;options&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;tick&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;options&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;mapping&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;fromJS&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;tick&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;setInterval&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;tick&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;options&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;interval&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We then used &lt;a href=&#34;http://knockoutjs.com/index.html&#34;&gt;knockout.js&lt;/a&gt; to bind the
view models to the widgets.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;applyBindings&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ajaxWidgetModel&lt;/span&gt;({ &lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/api/dashboard/tickets&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;interval&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;30000&lt;/span&gt; }), 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    document.&lt;span style=&#34;color:#a6e22e&#34;&gt;getElementById&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;widget_tickets&amp;#39;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;widget-title&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;h5&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Tickets&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/h5&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;widget-content&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;widget_tickets&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;bind&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;with: data&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;table&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;table&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/table&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;a href=&#34;http://knockoutjs.com/documentation/with-binding.html&#34;&gt;with
data-binding&lt;/a&gt;
ensures that the content container only gets shown when the read model
data has been fetched from the server.&lt;/p&gt;
&lt;p&gt;Building dumb view-optimized read models on the server, binding them to
a widget with one line of code, and some templating, allowed us to
quickly build a live dashboard in a straightforward fashion.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Tests as part of your code</title>
      <link>https://jefclaes.be/2014/03/tests-as-part-of-your-code.html</link>
      <pubDate>Sun, 09 Mar 2014 18:13:00 +0100</pubDate>
      <guid>https://jefclaes.be/2014/03/tests-as-part-of-your-code.html</guid>
      <description>&lt;p&gt;In the last project I worked on - processing financial batches - we put
a lot of effort in avoiding being silently wrong. The practice that
contributed most was being religious about avoiding structures to ever
be in an invalid state. Preconditions, invariants, value objects and
immutability were key.&lt;/p&gt;
&lt;p&gt;One of the things we had to do with these structures was writing them to
disk in a specific banking format; all the accounts with their
transactions for a specific day. To verify the outcome of these
functions, we had a decent test suite in place. But still, we felt like
we had to do more; the person on the team that had been working in this
domain for thirthy years had been relentlessy empathizing - nagging -
that bugs here would be disastrous, and would have us end up in the
newspaper. That&amp;rsquo;s when we decided to add postconditions, putting the
tests closer to the production code. These would make sure we crashed
hard, instead of silently producing something that was wrong.&lt;/p&gt;
&lt;p&gt;To make sure we correctly wrote all transactions for one account to
disk, we added a postcondition that looked something like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Ensure.That(txSumWrittenToDisk.Equals(account.Balance.Difference()));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A few weeks later, running very large batches in test, we had this
assertion fail randomly. An account can have hundred thousands of
transactions a day. This is why the account structure did not contain
its transactions - there were too many to hold them in memory. To make
sure an account and its transactions added up, we did do set validations
earlier on - no faulty state there. Since the assertion would only fail
randomly, and the function had no dependencies on time or mutable state,
the only culprit could be data feeded into the function. Since all
transactions for one account wouldn&amp;rsquo;t fit in memory, we were streaming
them in pages from the database, and this is where we forgot to sort the
whole result first, resulting in random pages - doh.&lt;/p&gt;
&lt;p&gt;Without this postcondition, we probably would have ended up in the
newspaper. While putting your code under test is super valuable, having
some crucial assertions as integral part of your code might strengthen
it even more(*).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;* This concept is central to
the &lt;a href=&#34;http://en.wikipedia.org/wiki/Eiffel_(programming_language)#Design_by_Contract&#34;&gt;Eiffel&lt;/a&gt; programming
language.&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Alternatives to Udi&#39;s domain events</title>
      <link>https://jefclaes.be/2014/03/alternatives-to-udis-domain-events.html</link>
      <pubDate>Sun, 02 Mar 2014 18:21:00 +0100</pubDate>
      <guid>https://jefclaes.be/2014/03/alternatives-to-udis-domain-events.html</guid>
      <description>&lt;p&gt;Almost four years ago &lt;a href=&#34;http://www.udidahan.com/2009/06/14/domain-events-salvation/&#34;&gt;Udi Dahan introduced an elegant
technique&lt;/a&gt;
that allows you to have your domain model dispatch events without
injecting a dispatcher into the model - keeping your model focused on
the business at hand.&lt;/p&gt;
&lt;p&gt;This works by having a static DomainEvents class which dispatches raised
events.&lt;/p&gt;
&lt;p&gt;This customer aggregate raises an event when a customer moves to a new
address.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Customer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; _id;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Address _address;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Name _name;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Customer(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; id, Name name, Address address)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNullOrEmpty(id, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNull(name, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNull(address, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;address&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _id = id;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _name = name;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _address = address;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Move(Address newAddress)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNull(newAddress, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;newAddress&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _address = newAddress;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        DomainEvents.Raise(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; CustomerMoved(_id));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By having a dispatcher implementation that records the events instead of
dispatching them, we can test whether the aggregate raised the correct
domain event.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; recordingDispatcher = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; RecordingDispatcher();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;DomainEvents.Dispatcher = recordingDispatcher;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; customer = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Customer(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;customer/1&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Name(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Jef&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Claes&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Address(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Main Street&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;114B&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Antwerp&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2018&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;customer.Move(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Address(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Baker Street&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;89&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Antwerp&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2018&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;recordingDispatcher.Raised(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; CustomerMoved(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;customer/1&amp;#34;&lt;/span&gt;)); &lt;span style=&#34;color:#75715e&#34;&gt;// true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While this worked out great for a good while, I bumped into difficulties
scoping my unit of work and such when I redid some of my infrastructure.
While there are ways to have your container address these issues,
getting rid of the static components is simpler throughout.  &lt;/p&gt;
&lt;p&gt;A popular event sourcing pattern is to have your aggregate record
events. There is no reason why we couldn&amp;rsquo;t apply the same pattern here.
Using this technique, we still avoid having to inject something into our
models, plus we get rid of that static DomainEvents component.
Reponsibility of dispatching the events is now delegated to an upper
layer.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Customer&lt;/span&gt; : IRecordEvents
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; EventRecorder _recorder = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; EventRecorder();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; _id;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Address _address;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Name _name;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Customer(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; id, Name name, Address address)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNullOrEmpty(id, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNull(name, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNull(address, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;address&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _id = id;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _name = name;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _address = address;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; EventStream RecordedEvents() 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; _recorder.RecordedEvents();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Move(Address newAddress)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNull(newAddress, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;newAddress&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _address = newAddress;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _recorder.Record(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; CustomerMoved(_id));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; customer = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Customer(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;customer/1&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Name(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Jef&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Claes&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Address(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Main Street&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;114B&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Antwerp&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2018&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;customer.Move(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Address(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Baker Street&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;89&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Antwerp&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2018&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;customer.RecordedEvents().Contains(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; CustomerMoved(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;customer/1&amp;#34;&lt;/span&gt;)); &lt;span style=&#34;color:#75715e&#34;&gt;// true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Another altnernative is to &lt;a href=&#34;http://www.jayway.com/2013/06/20/dont-publish-domain-events-return-them/&#34;&gt;return events from your
methods&lt;/a&gt;.
This technique puts the responsibility of aggregating all events on to a
higher layer. Better to put that closer to the aggregate.&lt;/p&gt;
&lt;p&gt;What patterns are you using?&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Strategic DDD in a nutshell </title>
      <link>https://jefclaes.be/2014/02/strategic-ddd-in-nutshell.html</link>
      <pubDate>Sun, 23 Feb 2014 18:21:00 +0100</pubDate>
      <guid>https://jefclaes.be/2014/02/strategic-ddd-in-nutshell.html</guid>
      <description>&lt;p&gt;There are two big parts to Domain Driven Design; strategy and tactics.
Strategy helps setting out a high-level grand design, while tactics
enable us to execute on the strategy.&lt;/p&gt;
&lt;p&gt;Practicing strategic design, we generally first try to list all of the
different parts that make our business a whole; these are sub-domains.
When you look at a supermarket chain, you would find sub-domains like
real estate management, advertising, suppliers, stock, sales, human
resources, finance, security and so on. Sub-domains will often relate to
existing structures like departments and functions.&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;ve defined your sub-domains, it&amp;rsquo;s useful to determine how
important of a role they play. First of all, you should figure out which
sub-domain is most important to your business; the core domain. This is
the sub-domain that differentiates you from other businesses, or more
bluntly put; this is where the money is at. For our super market chain,
this might not be that obvious for an outsider. A first uneducated guess
would be sales, but if you gave it some more thought, you would realize
that sales are very similar for most supermarkets. Digging deeper, we
would find that supermarkets really compete with each other by squeezing
the last bit of value out of suppliers and by collecting data to use for
targeted advertising. Supplier management and advertising can&amp;rsquo;t stand on
their own though; they need other sub-domains like stock and sales.
These are supporting sub-domains; they are not core, but our business
couldn&amp;rsquo;t do without them either - they still add a bunch of value. Other
sub-domains like property management, human resources or security are
generic sub-domains; these problems have been widely addressed and
solving them yourself won&amp;rsquo;t make you any money.&lt;/p&gt;
&lt;p&gt;Having a map of which areas are most important to your business makes it
easy to distribute brain power accordingly. Make sure your core domain
gets the most capable team assigned, before any other supporting
sub-domain. Try to buy solutions of the shelve for generic
sub-domains.&lt;/p&gt;
&lt;p&gt;The concept of sub-domains lives in the problem space. The solution
space on the other hand is where bounded contexts are at. Domain Driven
Design tries to define natural boundaries between parts of your solution
by putting the language first. These boundaries allow us to keep a
language and model consistent inside of them, protecting conceptual
integrity.&lt;br&gt;
If you would ask a marketer what a product is, he would talk about
images, campaigns, weekly promotions and so on. If you&amp;rsquo;d ask sales on
the other hand, they would only mention price, quantity and loyalty
points. The same concept can turn into something completely different
depending on how you look at it. Bounded contexts enable us to build a
ubiquitous understanding of concepts in a clearly defined context.&lt;/p&gt;
&lt;p&gt;Mapping a bounded context to exactly one sub-domain would be DDD
nirvana; addressing one problem with one focused solution. In the real
world, things are more messy though. There will always be systems out of
our control; for example legacy and third party software. As our
understanding of the business grows, keeping our software aligned can be
hard too. If we would lay out a map of sub-domains and bounded contexts
we would see lots of overlap.&lt;/p&gt;
&lt;p&gt;Bounded contexts will often be worthless on their own though; most
useful systems exist of interconnected parts. If you have worked in the
enterprise, you know how complex communication between teams and
departments can be. This isn&amp;rsquo;t very different while integrating bounded
contexts; you need to consider politics. This is where concepts like
up-stream, down-stream, bandwidth, partnership, shared kernel,
customer-supplier, conformist, anti-corruption layer etc come into play.
The activity of thinking about and capturing how all these systems play
together is called context mapping.&lt;br&gt;
In our example, we notice that supplier- and stock management would fail
or succeed together; they have a partnership where the bandwidth is very
high - the teams sit across the hall from each other. Human resources
and security on the other hand have a very different relationship. A
product was bought for human resources, while a solution for security
was outsourced. Security relies quite heavily on what the human
resources&amp;rsquo; open host service is exposing. If a product version bump
changes those exposed contracts, security needs to comply as soon as
possible; security is down-stream from human resources - shit floats
down-stream.&lt;/p&gt;
&lt;p&gt;For me, strategic DDD in one sentence, is the constant exercise of
trying to see and understand your business at large, and aligning your
software as efficiently as possible.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>DDDBE slides on the Ubiquitous Language</title>
      <link>https://jefclaes.be/2014/02/dddbe-slides-on-ubiquitous-language.html</link>
      <pubDate>Sun, 16 Feb 2014 18:04:00 +0100</pubDate>
      <guid>https://jefclaes.be/2014/02/dddbe-slides-on-ubiquitous-language.html</guid>
      <description>&lt;p&gt;Monday, I and four others did a &lt;a href=&#34;http://domaindriven.be/&#34;&gt;DDDBE&lt;/a&gt; session on the strategic side of Domain Driven Design.&lt;/p&gt;
&lt;p&gt;My talk covered the Ubiquitous Language, and can be found &lt;a href=&#34;https://www.slideshare.net/jclaes/the-ubiquitous-language&#34;&gt;on Slideshare&lt;/a&gt;. I might end up writing down the content of the talk as well - some images are meaningless without words. &lt;/p&gt;
&lt;p&gt;Evaluating feedback, I think the biggest mistake we made was keeping some things too abstract - curse of knowledge at work. If we get the chance to repeat the session, we need to make sure to weave a practical
story through our talks to make them stick.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Reading an EventStore stream using JavaScript</title>
      <link>https://jefclaes.be/2014/02/reading-an-eventstore-stream-using-javascript/</link>
      <pubDate>Sun, 09 Feb 2014 18:07:00 +0100</pubDate>
      <guid>https://jefclaes.be/2014/02/reading-an-eventstore-stream-using-javascript/</guid>
      <description>&lt;p&gt;Over Christmas break, I set out three days to play with the
&lt;a href=&#34;http://geteventstore.com/&#34;&gt;EventStore&lt;/a&gt;. One of the things I wanted to
do was visualize the timeline of a stream in the browser. Since the
EventStore exposes its event streams over atom in JSON, I could directly
consume them from JavaScript.&lt;/p&gt;
&lt;p&gt;An event stream can contain quite a few events. Since caching parts of
that stream benefits all components in the system, the atom feed is
split in multiple pages - where all full pages are cacheable. Thus if
you want to read the entire event stream, you should work your way
through all pages. What confused me at first, but what actually is quite
logical, is that the last entry on the last page contains the first
event. If you want to read the entire stream, you need to start at the
last page, and work your way forward following the link to the previous
page until there are no pages left to read.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2014-02-09-reading-an-eventstore-stream-using-javascript-eventstoreatom.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2014-02-09-reading-an-eventstore-stream-using-javascript-eventstoreatom.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I came up with something like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;StreamFeedReader&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;feedUri&lt;/span&gt;) {   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;feedUri&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Error(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;feedUri missing.&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;readLastFromHead&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;streamName&lt;/span&gt;) {                                        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;dfd&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Deferred&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ajax&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;feedUri&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;streamName&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;?embed=body&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }).&lt;span style=&#34;color:#a6e22e&#34;&gt;done&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;) {                
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;lastLinks&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;links&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;filter&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;link&lt;/span&gt;) { 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;link&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;relation&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;last&amp;#39;&lt;/span&gt;; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            });                       
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;lastLinks&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;) {               
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;dfd&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;resolve&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;lastLinks&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;].&lt;span style=&#34;color:#a6e22e&#34;&gt;uri&lt;/span&gt;);           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;dfd&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;resolve&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;feedUri&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;streamName&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }).&lt;span style=&#34;color:#a6e22e&#34;&gt;fail&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {                           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;dfd&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;reject&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;dfd&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;promise&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };              
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;traverseToFirst&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;uri&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;entries&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;dfd&lt;/span&gt;) {                                                       
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ajax&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;uri&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;?embed=body&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }).&lt;span style=&#34;color:#a6e22e&#34;&gt;done&lt;/span&gt;( &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;) {       
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;reversedEntries&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;entries&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;reverse&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;reversedEntries&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;entries&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;reversedEntries&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;previousLinks&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;links&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;filter&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;link&lt;/span&gt;) { 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;link&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;relation&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;previous&amp;#39;&lt;/span&gt;; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            });            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;previousLinks&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;traverseToFirst&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;previousLinks&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;].&lt;span style=&#34;color:#a6e22e&#34;&gt;uri&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;entries&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;dfd&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {                
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;dfd&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;resolve&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;entries&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }).&lt;span style=&#34;color:#a6e22e&#34;&gt;fail&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;dfd&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;reject&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        });                    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;read&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;streamName&lt;/span&gt;) {                   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;streamName&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Error(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;streamName missing.&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;dfd&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Deferred&lt;/span&gt;();                           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;readLastFromHead&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;streamName&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;done&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;lastUri&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;entries&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [];                        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;traverseToFirst&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;lastUri&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;entries&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;dfd&lt;/span&gt;);                        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }).&lt;span style=&#34;color:#a6e22e&#34;&gt;fail&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() { 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;dfd&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;reject&lt;/span&gt;(); 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        });    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;dfd&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;promise&lt;/span&gt;();              
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;First read the link to the last page. From there, read the entries on
that page, look at the links on that page and start making your way
forward, traversing the pages to the first one. All events on the page
should also be reversed before they get pushed to the result.&lt;/p&gt;
&lt;p&gt;Using this snippet, you can read a stream and have all events returned
in the sequence they were appended.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;es&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StreamFeedReader&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;http://127.0.0.1:2113/streams/&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;read&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;account-35&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .&lt;span style=&#34;color:#a6e22e&#34;&gt;fail&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;test&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;reading the stream failed.&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;test&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;done&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .&lt;span style=&#34;color:#a6e22e&#34;&gt;done&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;streamContainsAllEvents&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;test&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;equal&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;651&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;expecting 651 events in stream.&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;eventsInStreamAreOrdered&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ordered&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;].&lt;span style=&#34;color:#a6e22e&#34;&gt;eventNumber&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;].&lt;span style=&#34;color:#a6e22e&#34;&gt;eventNumber&lt;/span&gt;) {                            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#a6e22e&#34;&gt;ordered&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;test&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ordered&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;event numbers out of order.&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;streamContainsAllEvents&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;eventsInStreamAreOrdered&lt;/span&gt;();                                
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;test&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;done&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This code is also available on
&lt;a href=&#34;https://github.com/JefClaes/eventstore-streamfeedreader&#34;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Thinking in Systems</title>
      <link>https://jefclaes.be/2014/02/thinking-in-systems.html</link>
      <pubDate>Sun, 02 Feb 2014 18:19:00 +0100</pubDate>
      <guid>https://jefclaes.be/2014/02/thinking-in-systems.html</guid>
      <description>&lt;p&gt;We are surrounded by systems day in, day out. As software developers, we
even get to spend a big portion of our day actively building and
changing systems - be it software, teams, communities or businesses.
Seeing the whole, but more importantly understanding how systems exist
of inter-related parts that affect each other in all kinds of
interesting ways, is crucial to growing sustainable systems.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.amazon.com/gp/product/1603580557/ref=as_li_tf_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=1603580557&amp;amp;linkCode=as2&amp;amp;tag=diofanedebyje-20&#34;&gt;Thinking in
Systems&lt;/a&gt;
is a primer on the subject of system thinking written by &lt;a href=&#34;http://en.wikipedia.org/wiki/Donella_Meadows&#34;&gt;Donella H.
Meadows&lt;/a&gt;. The book is
divided into three parts. The first part explains the basic concepts of
system thinking using everyday systems. The second part covers why
systems work so well, why they still surprise us, how to avoid common
system traps and how to take advantage of some of the opportunities they
present. The last part, and for me the most interesting part, shows
where to intervene in a system and how to live in a world of systems.&lt;/p&gt;
&lt;p&gt;Although the subject is pretty involved, the material is presented in a
very consumable fashion, preparing you for more academic material. This
is probably &lt;em&gt;the book&lt;/em&gt; to read when you want to be introduced to systems
thinking.&lt;/p&gt;
&lt;p&gt;Here are the sections I highlighted.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Everyone or everything in a system can act dutifully and rationally,
yet all these well-meaning actions too often add up to a perfectly
terrible result.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;You think that because you understand &amp;ldquo;one&amp;rdquo; that you must therefore
understand &amp;ldquo;two&amp;rdquo; because one and one make two. But you forget that you
must also understand &amp;ldquo;and&amp;rdquo;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Purposes are deducted from behavior, not from rhetoric or stated
goals. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Enough central control to achieve coordination toward the large-system
goal, and enough autonomy to keep all subsystems flourishing,
functioning and self-organizing. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;If you become a manager, you probably will stop seeing labor as a
deserving partner in production, and start seeing it as a cost to be
minimized. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The structure of a commons systems makes selfish behavior much more
convenient and profitable than behavior that is responsible to the
whole community and to the future. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;If the desired system state is good education, measuring that goal by
the amount of money spent per student will ensure money spent per
student. If the quality of education is measured by performance on
standardized tests, the system will produce performance on
standardized tests. Whether either of these measures is correlated
with good education is at least worth thinking about. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;There is a systematic tendency on the part of human beings to avoid
accountability for their own decisions. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;If you want to understand the deepest malfuctions of systems, pay
attention to the rules and who has power over them. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;So how do you change paradigms? You keep pointing at the anomalies and
failures in the old paradigms. You keep speaking and acting, loudly
and with assurance, from the new one. You insert people with the new
paradigm in places of public visibility and power. You don&amp;rsquo;t waste
time with reactionaries; rather, you work with active change agents
and with the vast middle ground of people who are open-minded. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;If no paradigm is right, you can choose whatever one will help to
achieve your purpose.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;There&amp;rsquo;s something within the human mind that is attracted to straight
lines and not curves, to whole numbers and not fractions, to
uniformity and not diversity, and to certainties and not mystery.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    
    <item>
      <title>Repositories, where did we go wrong?</title>
      <link>https://jefclaes.be/2014/01/repositories-where-did-we-go-wrong_26.html</link>
      <pubDate>Sun, 26 Jan 2014 18:00:00 +0100</pubDate>
      <guid>https://jefclaes.be/2014/01/repositories-where-did-we-go-wrong_26.html</guid>
      <description>&lt;p&gt;In essence, repositories are a simple abstraction over aggregate
storage. A repository will insert, update, delete or fetch an aggregate
from the underlying persistence mechanism. This abstraction avoids that
databases, SQL statements, Object Mappers and the like leak into your
domain. Next to that, swapping out repositories for an in-memory version
makes testing easier.&lt;/p&gt;
&lt;p&gt;Recently, the use of repositories is being questioned again.&lt;/p&gt;
&lt;p&gt;Why would we wrap Object Mappers in yet another abstraction? Aren&amp;rsquo;t
Object Mappers already an implementation of the repository pattern? In a
recent project, we left out repositories. In that project we&amp;rsquo;re using
RavenDB, which already has an expressive API, and which can be
configured to use an in-memory database for testing. Even though LINQ
and indexes help make simple queries expressive, a lot of cruft still
leaks in, not doing the language any justice. In other projects, we did
make use of repositories over our ORM. Partly because setting up
in-memory tests without was awkward at best, but also because it removed
constraints trying to capture the language. Next to testing and
expressiveness, you should also consider how comfortable you feel gluing
everything to a library or framework. When it comes to aggregate
storage, having those repositories is a small price to pay to keep
technicalities out.&lt;/p&gt;
&lt;p&gt;Another remark is that a repository makes it hard to control eager- and
lazy loading, which is contextual. In general I think that lazy loading
introduces unpredictable behaviour. Getting in trouble without lazy
loading is a strong indication that your aggregates are just too big.&lt;/p&gt;
&lt;p&gt;The last and loudest argument is that once you have a view heavy
application things get dirty really fast. It starts by adding a few
badly named query methods on your repositories. Then, you start to see
use cases where you need to query over multiple aggregates and deal with
projections or aggregations. In these situations repositories won&amp;rsquo;t help
you.&lt;br&gt;
Truth is that repositories were never intended for complex reads. Views
on the data that your application needs rarely resemble the structure of
your aggregates. Making your aggregates suited for querying inevitably
steers away from behaviour thinking, back to data thinking. The trick is
to separate read concerns from your domain. Instead of trying to use
repositories for querying, make use of the best tool for the job,
something as close to the database as possible. The implementation
depends on your flavor, but what has worked for me is having use case
optimized read models, a query object and a query handler that reads
from the database and converts the result into a read model. The
implementation of each query handler can differ; from raw SQL, to
hibernate query language, to a micro ORM&amp;hellip; whatever works best
really.&lt;br&gt;
Doing this, you allow your domain model to stay focused on the task at
hand - handling complex business problems, staying far away from read
concerns. Before you know it you&amp;rsquo;re successfully applying &lt;a href=&#34;http://www.jefclaes.be/2013/02/adding-r-to-cqs-some-storage-options.html&#34;&gt;that popular
four letter
acronym&lt;/a&gt;,
enabling you to even try &lt;a href=&#34;http://www.jefclaes.be/2013/10/my-understanding-of-event-sourcing.html&#34;&gt;other
concepts&lt;/a&gt;
without having to rewrite your model completely.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>new YearPassed(2013);</title>
      <link>https://jefclaes.be/2014/01/new-yearpassed2013.html</link>
      <pubDate>Sun, 19 Jan 2014 17:54:00 +0100</pubDate>
      <guid>https://jefclaes.be/2014/01/new-yearpassed2013.html</guid>
      <description>&lt;p&gt;I normally write this up at the end of the year, but circumstances made
me push back this post for a few weeks. I use this annual post to look
back at the year passed, and to look ahead to the year to come. I gave
up on making resolutions in
&lt;a href=&#34;http://www.jefclaes.be/2011/12/2011-annual-review.html&#34;&gt;2011&lt;/a&gt;. This
year, I&amp;rsquo;m going to be naively ambitious again going into 2014.&lt;/p&gt;
&lt;p&gt;Compared to previous years, I feel more confident that I have a pretty
good idea of what I want next. Just before the holidays, my fiancée and
I spent the weekend out of town where we took a whole evening to
modelstorm 2013 and the future. We used green and red post-its to list
all positive and negative memories of 2013. We then categorized those,
and defined concrete actions to avoid repeating negative experiences,
and to increase the number of positive ones in 2014. Next to this
technique, we used a timeline to plan some key milestones a few years
ahead of time.&lt;/p&gt;
&lt;h3 id=&#34;my-career&#34;&gt;My career&lt;/h3&gt;
&lt;p&gt;September 2013 marked the two year anniversary working for Euricom. It
also marked the second year at my first client. There, I spent last year
deeply immersed working on what has been coined by upper management as
the most important project of 2014. Having invested much, and despite
having a bunch of ingredients for failure, I&amp;rsquo;m relieved the project went
out the door yesterday. I look back at the project with mixed feelings;
there were several periods of intense learning and going fast, but way
too much time and energy was wasted fighting the system. After spending
more than five years in the bowels of the beast, I don&amp;rsquo;t feel as if the
enterprise is a healthy place for me to live in, let alone a place
capable of cultivating good software.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m going to try really hard to avoid these breeds of working
environments for a while. Unfortunately, they make up a good portion of
Euricom&amp;rsquo;s customer base. This led me to resign at Euricom last month.
Four weeks from now, I will start at a much smaller gig where I hope to
find more autonomy, skin in the game and entrepreneurship. I&amp;rsquo;m also
extremely curious to discover and learn about the insides of the domain.&lt;/p&gt;
&lt;h3 id=&#34;blog&#34;&gt;Blog&lt;/h3&gt;
&lt;p&gt;I published a bit less compared to previous years, but I found a
sustainable pace for writing: one post a week. &lt;a href=&#34;http://www.jefclaes.be/2013/12/2013s-most-read-posts.html&#34;&gt;Like I said
earlier&lt;/a&gt;,
traffic has stagnated, but the number of subscriptions and the average
time spent reading has increased. &lt;/p&gt;
&lt;p&gt;The topics I write about have drifted away from mostly technical ones to
Domain Driven Design, modeling, personal experiences, conferences and
book notes.&lt;/p&gt;
&lt;h3 id=&#34;community&#34;&gt;Community&lt;/h3&gt;
&lt;p&gt;Although I only spoke twice myself, I got to meet up with inspiring
people more than once; the &lt;a href=&#34;http://www.jefclaes.be/2013/05/iddd-tour-notes-22.html&#34;&gt;IDDD
Tour&lt;/a&gt;, DDD
Exchange, CQRSBeers,
&lt;a href=&#34;http://www.jefclaes.be/2013/12/buildstuff-2013.html&#34;&gt;BuildStuff&lt;/a&gt; and
most importantly the birth of &lt;a href=&#34;http://domaindriven.be/&#34;&gt;the Belgian DDD
Community&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;Meeting up with likeminded souls, exchanging ideas, war stories and
hopes, sharing food and beer is something that has been a source of true
bliss. There are too many people to thank, but I&amp;rsquo;d like to name a few in
particular: &lt;a href=&#34;https://twitter.com/mathiasverraes&#34;&gt;Mathias&lt;/a&gt;,
&lt;a href=&#34;https://twitter.com/ziobrando&#34;&gt;Alberto&lt;/a&gt;,
&lt;a href=&#34;https://twitter.com/cgeers&#34;&gt;Christophe&lt;/a&gt;,
&lt;a href=&#34;https://twitter.com/BWaterschoot&#34;&gt;Bart&lt;/a&gt;,
&lt;a href=&#34;https://twitter.com/One75&#34;&gt;Stijn&lt;/a&gt;,
&lt;a href=&#34;https://twitter.com/yreynhout&#34;&gt;Yves&lt;/a&gt;,
&lt;a href=&#34;https://twitter.com/tojans&#34;&gt;Tom&lt;/a&gt;,
&lt;a href=&#34;https://twitter.com/Heimeshoff&#34;&gt;Marco&lt;/a&gt; and
&lt;a href=&#34;https://twitter.com/tjaskula&#34;&gt;Thomas&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;Next month, I&amp;rsquo;m attending &lt;a href=&#34;https://fosdem.org/2014/&#34;&gt;FOSDEM&lt;/a&gt; and I&amp;rsquo;ll be
talking at
&lt;a href=&#34;http://www.eventbrite.com/e/dddbe-5-ddd-basics-registration-9912037170&#34;&gt;DDDBE&lt;/a&gt;.
I also already bought tickets for &lt;a href=&#34;http://buildstuff.lt/&#34;&gt;buildstuff&lt;/a&gt;
later this year.&lt;/p&gt;
&lt;h3 id=&#34;travel&#34;&gt;Travel&lt;/h3&gt;
&lt;p&gt;I got spoiled this year; I got to visit six different countries,
spending more than five weeks abroad:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;England&lt;/li&gt;
&lt;li&gt;Spain&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.jefclaes.be/2013/09/cz-trilogy.html&#34;&gt;Czech Republic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Lithuania&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.jefclaes.be/2013/07/the-last-cowboy.html&#34;&gt;USA&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Luxembourg&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We&amp;rsquo;re still indecisive about whether we should visit Asia or something
closer this summer. Anyone that can recommend locations in Asia?&lt;/p&gt;
&lt;h3 id=&#34;projects&#34;&gt;Projects&lt;/h3&gt;
&lt;p&gt;I killed one side project at the start of this year, and documented it
&lt;a href=&#34;http://www.jefclaes.be/2013/02/my-christmas-holiday-project-postmortem.html&#34;&gt;here&lt;/a&gt;.
I spent a big part of this year working on another project. While I&amp;rsquo;m
not sure if we will get that ever of the ground, I learned a few lessons
though. Contact your potential customers &lt;em&gt;before&lt;/em&gt; you build a close to
finished product. If you&amp;rsquo;re going to work on something in the weekends,
don&amp;rsquo;t make it feel like work.&lt;/p&gt;
&lt;h3 id=&#34;sportshealth&#34;&gt;Sports/Health&lt;/h3&gt;
&lt;p&gt;The fiancée and I have built a habit of regularly doing long hikes -
once every month. This is something we&amp;rsquo;re going to keep up, maybe even
put it in the center of one of our holidays.  &lt;/p&gt;
&lt;p&gt;I ran 705km this year, which is 270km less than last year. After running
three competitions early on in the year, I lost my hunger, and started
slacking. To keep the momentum going and to have something to work
towards, I should probably enroll in a competition every few months. I
already subscribed for the Antwerp Urban Trail run and the Antwerp 10
miles this year. Anyone else subscribing? I haven&amp;rsquo;t found a partner yet.&lt;/p&gt;
&lt;p&gt;I also didn&amp;rsquo;t cancel my gym subscription this year. I have put together
a satisfying routine that mostly consists of lifting heavy things
avoiding modern equipment. It&amp;rsquo;s been fairly successful, bulking up 9kg
the last six months. &lt;/p&gt;
&lt;h3 id=&#34;2014-side-missions&#34;&gt;2014 side missions&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Avoid Windows at home.&lt;/li&gt;
&lt;li&gt;Learn a new (programming) language.&lt;/li&gt;
&lt;li&gt;Build something just for me.&lt;/li&gt;
&lt;li&gt;Spend less time in front of my machine. &lt;/li&gt;
&lt;li&gt;Read more. Watch more conference videos. &lt;/li&gt;
&lt;li&gt;Do nothing. It heals the soul.&lt;/li&gt;
&lt;li&gt;Plan the weekend. &lt;/li&gt;
&lt;li&gt;More dinner parties.&lt;/li&gt;
&lt;li&gt;Plan the wedding.&lt;/li&gt;
&lt;li&gt;Take more guitar lessons.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Thanks for everything, I&amp;rsquo;m very grateful.&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Happiness before success</title>
      <link>https://jefclaes.be/2014/01/happiness-before-success.html</link>
      <pubDate>Sun, 12 Jan 2014 18:57:00 +0100</pubDate>
      <guid>https://jefclaes.be/2014/01/happiness-before-success.html</guid>
      <description>&lt;p&gt;Somewhere in the beginning of last century, two shoes salesmen were sent
to Africa hoping to expand their employer&amp;rsquo;s market. Both salesmen
reported home within days of their arrival. The first salesman wrote:
&amp;ldquo;This trip turned out to be a waste of time; the locals are not wearing
any shoes.&amp;rdquo; The second salesman wrote something similar, yet very
different: &amp;ldquo;This is looking very promising; people aren&amp;rsquo;t wearing any
shoes yet!&amp;rdquo;&lt;/p&gt;
&lt;p&gt;A group of seventy year olds was invited to spend a week in a remote
location where everything was arranged to make it feel as if they went
back in time twenty years; they would get to read old news papers, were
shown recorded television shows etc&amp;hellip; They were also asked to talk
about their jobs and kids as if it were twenty years ago. Once the week
was over, medical exams showed extraordinary results. Their health had
improved noticeably; their eyesight improved, their blood pressure went
down, their posture had changed&amp;hellip;&lt;/p&gt;
&lt;p&gt;In another experiment, a group of people was trained into using a new
piece of software. Half of the class was taught to prevent errors from
happening, while the other half was encouraged to make mistakes. A test
afterwards showed that the group that had learned by making mistakes was
a lot faster and efficient using the software than the group that was
taught to avoid errors at all costs.&lt;/p&gt;
&lt;p&gt;The mind is incredibly powerful; it&amp;rsquo;s in full control of how we perceive
things. One might be poor, having to live off a few dollars a day, and
be perfectly content with his situation. While someone on the other side
of the world might have everything he can imagine at his fingertips, but
be completely miserable.&lt;/p&gt;
&lt;p&gt;Popular belief dictates that if you work hard, you will eventually
become successful, and once you&amp;rsquo;re successful, then you&amp;rsquo;ll be happy.
This recipe is elementally flawed. With each victory, we put our eyes on
that next big thing, never arriving at happiness.&lt;/p&gt;
&lt;p&gt;In &lt;a href=&#34;http://www.amazon.com/gp/product/0307591549/ref=as_li_qf_sp_asin_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0307591549&amp;amp;linkCode=as2&amp;amp;tag=diofanedebyje-20&#34;&gt;The Happiness
Advantage&lt;/a&gt;,
Shawn Achor starts by claiming that we have it all wrong, and that it&amp;rsquo;s
actually the other way round; happiness leads to success. Positive
brains make us more efficient, creative, thoughtful and productive,
boosting performance at work and at home. While the first few pages make
a great sales pitch, the rest of the book differs from the usual life
improvement charlatans backing up this hypothesis with narratives and
DIY practices extracted from modern happiness research.&lt;/p&gt;
&lt;p&gt;The book turned out to be a very casual read; the writing is easy and it
only counts two hundred small pages - I finished it in a few hours. It
has inspired me to try and be more conscious about how I deal with
certain things, to always focus on the good, not allowing negativity to
slowly poison me.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quotes from the book&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If all you strive is diminishing the bad, you&amp;rsquo;ll only attain the
average and you&amp;rsquo;ll miss out entirely on the opportunity to exceed the
average. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Happiness is not just a mood - it&amp;rsquo;s a work ethic. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;It takes about three positive comments, experiences, or expressions to
fend off the languishing effects of one negative. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Happiness is not about lying to ourselves, or turning a blind eye to
the negative, but about adjusting our brain so that we see the ways to
rise above our circumstances.&lt;br&gt;
The fastest way to disengage an employee is to tell him his work is
meaningful only because of the paycheck. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Constantly scanning the world for the negative comes with a great
cost. It undercuts our creativity, raises our stress levels, and
lowers our motivation and ability to accomplish goals. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Common sense is not common action. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Couldn&amp;rsquo;t the key to sustaining positive change be to turn each desired
action into a habit, so that it would come automatically, without much
effort, thought, or choice? &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;This invisible pull toward the path of least resistance can dictate
more of our lives than we realize, creating an impassible barrier to
change and positive growth. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Lower the activation energy for habits you want to adopt, and raise it
for habits you want to avoid.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    
    <item>
      <title>Command and event semantics</title>
      <link>https://jefclaes.be/2014/01/command-and-event-semantics.html</link>
      <pubDate>Sun, 05 Jan 2014 18:12:00 +0100</pubDate>
      <guid>https://jefclaes.be/2014/01/command-and-event-semantics.html</guid>
      <description>&lt;p&gt;Yesterday, I read &lt;a href=&#34;https://michaelfeathers.silvrback.com/when-it-s-okay-for-a-method-to-do-nothing&#34;&gt;this blog post by Michael
Feathers&lt;/a&gt;.
In the post he goes over a pain point he has often found himself
struggling with while breaking down a large method; conditional
statements. &lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (alarmEnabled) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; alarm = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Alarm();  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    alarm.Sound();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Should we extract the if and the associated block into a new method, or
just the content of the block? Is the condition too important to hide in
a method? How would we name the extracted method? How do we avoid the
code from telling us lies?&lt;/p&gt;
&lt;p&gt;To read up on all the nuances that the answers to these questions bring,
you should read the full post. What&amp;rsquo;s important for this post - spoiler
alert - is that he ends up with two strategies.&lt;/p&gt;
&lt;p&gt;He either gives the method an event-ish name&amp;hellip;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;IntruderDetected();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip;or raises the level of abstraction by giving the method a very
general name, avoiding lies too.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PerformNotifications();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While both options solve the original problem, their semantics are very
different. When I raise an event, I don&amp;rsquo;t care who is listening; one,
multiple or no things might be listening. When I issue a command (the
second strategy), I expect it to go to exactly one destination. Sending
commands indicates a rather strong dependency; you expect something to
happen because of it. Events are more loosely coupled; you broadcast
something happened, and something might or might not happen because of
it.&lt;/p&gt;
&lt;p&gt;With this in mind, you can still make arguments for both options. The
key here is whether notifications are considered to be an essential
component of intrusion detection. Is intrusion detection still
conceptually whole without notifications? Are notifications just a side
effect of an intruder being detected?&lt;br&gt;
Since the alarm is only sounded when it&amp;rsquo;s enabled, it doesn&amp;rsquo;t seem to be
an indispensable part. Intrusion detection can live on its own, unaware
of notifications. This makes a pretty strong case for having the
detection component just raise an event - indirectly resulting in the
notifications being sent.&lt;/p&gt;
&lt;p&gt;In this example, I&amp;rsquo;d probably pull notifications out, add an event and a
bit of infrastructure that dispatches events, making the separate
concepts and messages between them explicit.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Events.Raise(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; IntruderDetected());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;NotificationService&lt;/span&gt; : IHandle&amp;lt;IntruderDetected&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Handle(IntruderDetected &lt;span style=&#34;color:#66d9ef&#34;&gt;event&lt;/span&gt;)    { ... }        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With those extra bits, we could also, instead of listen for the event
and only sounding the alarm when it&amp;rsquo;s enabled, only subscribe to the
event when the alarm is enabled.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>2013&#39;s most read posts</title>
      <link>https://jefclaes.be/2013/12/2013s-most-read-posts.html</link>
      <pubDate>Sun, 29 Dec 2013 17:05:00 +0100</pubDate>
      <guid>https://jefclaes.be/2013/12/2013s-most-read-posts.html</guid>
      <description>&lt;p&gt;This time of year, we&amp;rsquo;re all very busy honoring
traditions. This post is no exception
(&lt;a href=&#34;http://www.jefclaes.be/2009/12/high-5-five-most-popular-blog-posts-of.html&#34;&gt;2009&lt;/a&gt;,
&lt;a href=&#34;http://www.jefclaes.be/2010/12/top-5-popular-posts-of-2010.html&#34;&gt;2010&lt;/a&gt;,
&lt;a href=&#34;http://www.jefclaes.be/2011/12/2011s-most-read-posts.html&#34;&gt;2011&lt;/a&gt;,
&lt;a href=&#34;http://www.jefclaes.be/2012/12/2012s-most-read-posts.html&#34;&gt;2012&lt;/a&gt;).&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Today was probably the first time this year that I
took some time to study my blog&amp;rsquo;s Google Analytics metrics. If I keep
last year&amp;rsquo;s &lt;a href=&#34;http://www.jefclaes.be/2012/03/how-web-application-can-download-and.html&#34;&gt;black swan posts&lt;/a&gt;
out of the equation, traffic seems to be comparable to last year&amp;rsquo;s. The
most meaningful metrics to me are the number of subscriptions and the
average time spent reading. Both of them increased - happy about
that!&lt;/p&gt;
&lt;p&gt;The actor model has been gaining in popularity more
and more. Next to addressing more infrastructural concerns, it can also
be used as a framework for modeling and reasoning about complex systems.
Working with a team of mainframe programmers over the last year, I
observed a few similarities in how they have been designing their
systems. &lt;a href=&#34;http://www.jefclaes.be/2013/09/actor-model-in-cobol.html&#34;&gt;Actor Model in
COBOL&lt;/a&gt; is the
third most read post of 2013.&lt;/p&gt;
&lt;p&gt;The second most read post was &lt;a href=&#34;http://www.jefclaes.be/2013/06/not-handling-edge-cases-making-them.html&#34;&gt;Not handling edge
cases, making them explicit
instead&lt;/a&gt;.
Inspired by a talk with Greg Young at DDDX, I tried to create a
narrative that uncovered an edge case in a green field project. Instead
of handling the edge case, we use an event to make it explicit, allowing
a human to intervene. This way we can go to market more quickly, with
less code, and we might even end up with happier customers.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Number one is &lt;a href=&#34;http://www.jefclaes.be/2013/08/but-i-already-wrote-it.html&#34;&gt;But I already wrote
it&lt;/a&gt;. In this
post I shared my motivation having an argument with a colleague about
whether to dump some code that did too much. Don&amp;rsquo;t cherish your code.
It&amp;rsquo;s nothing but a means to an end; the side product of creating a
solution. Aim for simple and lean solutions; nobody likes bulky
software, nobody likes fighting complexity all day. Don&amp;rsquo;t neglect the
hidden cost of that extra small feature you&amp;rsquo;re throwing in.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thank you&lt;/strong&gt; for reading!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Databases are growing on me</title>
      <link>https://jefclaes.be/2013/12/databases-are-growing-on-me.html</link>
      <pubDate>Sun, 22 Dec 2013 21:53:00 +0100</pubDate>
      <guid>https://jefclaes.be/2013/12/databases-are-growing-on-me.html</guid>
      <description>&lt;p&gt;I learned all about logical design of relational databases back in
school; tables, columns, data types, views, normalization, constraints,
primary keys, foreign keys&amp;hellip; At the same time, I learned how to use SQL
to put data in, and how to get it out again; &lt;code&gt;INSERT INTO, SELECT, FROM, WHERE, JOIN, GROUP...&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;In the first project I worked on just out of school, we weren&amp;rsquo;t doing
anything interesting with databases; we didn&amp;rsquo;t have that many users, or
that much data. A database veteran on the team took it on him to
maintain the schema and to provide stored procedures we could do work
with.&lt;/p&gt;
&lt;p&gt;All that time, I consciously was very ignorant of the database. I had no
idea what was in the box, and I didn&amp;rsquo;t care either; databases were
boring, applications were where the fun was at.&lt;/p&gt;
&lt;p&gt;Since then, I have rarely worked with a team that had a dedicated role
for database design. Why invest in another person when you can do
without? Database basics are not rocket science; with 20% of the
knowledge, you get very far. Definitely now that it&amp;rsquo;s probably easier
and cheaper to throw hardware at the problem.&lt;/p&gt;
&lt;p&gt;That being said, it&amp;rsquo;s a good idea to keep a DBA close. Time and time
again I see them only being called in when it&amp;rsquo;s too late and much needed
improvements are often too far-reaching and expensive. No wonder DBA&amp;rsquo;s
are grumpy all the time.&lt;/p&gt;
&lt;p&gt;Being exposed to databases more and more, I got to pick up a few things
here and there - mostly cargo-cult best practices. It wasn&amp;rsquo;t until last
year that I got really curious for what was in the box. Working on an
application with a decent amount of data crunching for a year forced me
to open up the lid. Also my ventures in NoSQL land, overhearing
discussions on Twitter between
&lt;a href=&#34;https://twitter.com/kellabyte&#34;&gt;kellabyte&lt;/a&gt;,
&lt;a href=&#34;https://twitter.com/ayende&#34;&gt;ayende&lt;/a&gt;,
&lt;a href=&#34;https://twitter.com/gregyoung&#34;&gt;gregyoung&lt;/a&gt;, &lt;a href=&#34;https://twitter.com/pbailis&#34;&gt;pbailis&lt;/a&gt; and
others had much to do with it.&lt;/p&gt;
&lt;p&gt;On opening the lid, I found a lot more than I expected. It had never
occurred to me how much interesting problems databases have to solve.
Making a database execute a query and see results returned in
milliseconds only looks easy on the surface. Memory, disk, CPU, caching,
networking, protocols, concurrency, fault tolerance, data structures,
transactions, compilation&amp;hellip; it&amp;rsquo;s all in there.&lt;/p&gt;
&lt;p&gt;The book &lt;a href=&#34;http://www.amazon.com/gp/product/0123693896/ref=as_li_qf_sp_asin_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0123693896&amp;amp;linkCode=as2&amp;amp;tag=diofanedebyje-20&#34;&gt;Physical Database
Design&lt;/a&gt;
and the &lt;a href=&#34;http://www.sqlite.org/docs.html&#34;&gt;SQLite technical
documentation&lt;/a&gt; were the first good
reads that helped me understand what was going on closer to the metal.
From there, I now try reading a paper (or a reference) from the
&lt;a href=&#34;http://redbook.cs.berkeley.edu/bib4.html&#34;&gt;Readings in Database Systems&lt;/a&gt;
collection once in a while. This collection of papers is supposed to
contain the most important papers in database research. Maybe academic,
but delicious brain food nonetheless - stretching my mind in ways I&amp;rsquo;m
not used to.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Buildstuff 2013</title>
      <link>https://jefclaes.be/2013/12/buildstuff-2013.html</link>
      <pubDate>Sun, 15 Dec 2013 22:03:00 +0100</pubDate>
      <guid>https://jefclaes.be/2013/12/buildstuff-2013.html</guid>
      <description>&lt;p&gt;Last night, I returned from Vilnius, after seven intensive days of
&lt;a href=&#34;http://buildstuff.lt/&#34;&gt;Buildstuff&lt;/a&gt;. After a few long months, I was
looking forward to be influenced and inspired by concepts and
experiences strange to my day-to-day job - surrounded by people hungry
to build better software. Because of the diversity of the program, the
high level of the speakers and the presence of some familiar
DDD-community faces, my expectations were easily met. Also, the location
and low rates for tickets, transport and beer make it a very reasonable
investment.&lt;/p&gt;
&lt;p&gt;I expect the videos to be uploaded over the next few weeks and thus I
will not bore you with session summaries. Instead I picked out some
quotes which stood out for me in one way or the other; because they were
spot on, summarize a concept in just a few words, or because they
challenge me and give me food for thought.&lt;/p&gt;
&lt;p&gt;Hope to see you again next year, Buildstuff.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://en.wikipedia.org/wiki/Bertrand_Meyer&#34;&gt;Bertrand Meyer&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Code contracts help generating tests. Pre-condition failed? Not a
useful test. Post -condition failed? We found a bug.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Documenting assumptions outside of code lead to rapid unscheduled
disassembly of the Arianne 5.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Why separate tests from your program? &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;http://codeofrob.com/&#34;&gt;&lt;s&gt;R&lt;/s&gt;Bob Ashton&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If I have to download the internet to use your module, I&amp;rsquo;m not going
to use it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;http://codebetter.com/iancooper/&#34;&gt;Ian Cooper&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The test is the unit, not the object under test. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;If you use tests to drive the implementation that couple to the
inside, remove them once you&amp;rsquo;re finished.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Devs often find outside-in testing too hard because they don&amp;rsquo;t master
the good setup techniques.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;http://joearms.github.io/&#34;&gt;Joe Armstrong&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A program is the most precise description of the problem that we have.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Paper systems are far more fault tolerant than what we&amp;rsquo;re replacing
them with.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Failure should not be handled in each piece of code but let it be
handled externally.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://twitter.com/jboner&#34;&gt;Jonas Bonér&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Isolate the failure, compartmentalize, manage failures locally, avoid
cascading failure.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Synchronous RPC, distributed transactions and shared mutable state are
the graveyard of distributed systems. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Synchronous RPC give you a very high abstraction that ignores all
problems. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;It&amp;rsquo;s all about message passing; let that be the programming model.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://twitter.com/simonbrown&#34;&gt;Simon Brown&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can have micro-services without them being different physical
artifacts. Pull them out when it pays off.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Package by component instead of by layer. Components can have layering
too.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;If your code doesn&amp;rsquo;t match the architecture, it becomes very hard to
do architectural refactoring.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Good architecture enables agility.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://twitter.com/LeHoff&#34;&gt;Torben Hoffmann&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Technical arguments are never enough, you need economical ones.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;You need to experience pain to have the willingness to change.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://twitter.com/aras_p&#34;&gt;Aras Pranckevicius&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Better hardware and software is the cheapest way to get more work
done.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Stupidity adds up, intelligence multiplies.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Guidelines, not rules.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://twitter.com/ziobrando&#34;&gt;Alberto Brandolini&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Watching the ceiling while making decisions is forbidden; visualize.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Time-box decisions. Be happy with a decision, although it&amp;rsquo;s probably
not the best solution.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The easiest way to remove crap from your system is not to put crap in.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;http://goodenoughsoftware.net/&#34;&gt;Greg Young&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An append-only model can be cached forever.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Wrong models cause massive accidental complexity. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;http://en.wikipedia.org/wiki/Pieter_Hintjens&#34;&gt;Pieter Hintjens&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You are defined by what you say online, not by who you are.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;You can&amp;rsquo;t avoid getting your information stolen, but we can make it
extremely expensive.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;As information centralizes, it gets easier to spy on us.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    
    <item>
      <title>Book review: Antifragile</title>
      <link>https://jefclaes.be/2013/12/book-review-antifragile.html</link>
      <pubDate>Sun, 08 Dec 2013 17:30:00 +0100</pubDate>
      <guid>https://jefclaes.be/2013/12/book-review-antifragile.html</guid>
      <description>&lt;p&gt;When things are fragile, they break easily. We often see fragility as a
bad thing and design things to be robust. But this isn&amp;rsquo;t what we&amp;rsquo;re
really after either; things that are robust might be hard to break, but
they&amp;rsquo;re also hard to change, making them fail to adapt to new stressors
over time. The model that we&amp;rsquo;re really after is antifragility; when
something is antifragile it will benefit from stressors and get better
over time.&lt;/p&gt;
&lt;p&gt;A cup is fragile; drop it and it breaks. A skyscraper on the other hand
is robust; it is designed to resist the forces of nature; from
hurricanes to earthquakes. A perfect example of antifragility is the
human body; go to the gym, work your ass off, and you will grow
stronger.&lt;/p&gt;
&lt;p&gt;In this book, Taleb takes this model and applies it to a wide variety of
systems; biological, medical, economic and political. Most concepts are
easily relatable to software too.&lt;/p&gt;
&lt;p&gt;While the core concepts could be summarized in a few pages, Taleb uses
anecdotes, ancient texts, narratives and formulas to prove his point -
resulting in a 519 pages thick book. Not all passages are a smooth read
though. Some parts read as if they were written in one sitting, dumping
everything that had been building for years on paper, without being
proofread after. Mixing that with Taleb&amp;rsquo;s extremely rich (= hard)
vocabulary makes for reading sessions where your full concentration is a
must - not suitable for after work commutes. It took me six weeks to
finish the book - well worth it though.&lt;/p&gt;
&lt;p&gt;There are a lot of things that stuck with me. Instead of sharing those
in my own words, I revisited some quotes I highlighted and copied them
below. I hope they give a better feel of what to expect from the book.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Remember that you need a name for the color blue when you build a
narrative, but not in action - the thinker lacking a word for &amp;ldquo;blue&amp;rdquo;
is handicapped; not the doer. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;It would have taken a bit of heroic courage to justify inaction in a
democracy where the incentive is to always promise a better promise
than the other guy, regardless of the actual, delayed cost. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;It&amp;rsquo;s much easier to sell &amp;ldquo;Look what I did for you&amp;rdquo; than &amp;ldquo;Look what I
avoided for you.&amp;rdquo; Of course a bonus system based on &amp;ldquo;performance&amp;rdquo;
exacerbates the problem. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The benefits of procrastination apply similarly to medical procedures:
we saw that procrastination protects you from error as it gives nature
a chance to do its job, given the inconvenient fact that nature is
less error-prone than scientists. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;People who build their strength using these modern expensive gym
machines can lift extremely large weights, show great numbers and
develop impressive looking muscles, but fail to lift a stone; they get
completely hammered in a street fight by someone trained in more
disorderly settings.  &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;In project management, Bent Flyvbjerg has shown firm evidence that an
increase in the size of projects maps to poor outcomes and higher and
higher costs of delays as a proportion of the total budget. But there
is a nuance: it is the size per segment of the project that matters,
not the entire project. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;What survives must be good at serving some purpose that time can see
but our eyes and logical faculties can&amp;rsquo;t capture. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;We notice what varies and changes more than what plays a large role
but doesn&amp;rsquo;t change. We rely more on water than on cell phones but
because water does not change and cell phones do, we are prone to
thinking that cell phones play a larger role than they do. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Corporations that are large today should be gone, as they have always
been weakened by what they think is their strength: size.  &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;There are secrets to our world that only practice can reveal, and no
opinion or analysis will ever capture in full. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Recall that under nonlinearities, the simple statements &amp;ldquo;harmful&amp;rdquo; or
&amp;ldquo;beneficial&amp;rdquo; break down: it is all in the dosage. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;When you think you have found a free lunch, say, steroids or trans
fat, something that helps the healthy without visible downside, it is
most likely that there is a concealed trap somewhere. Actually, my
days in trading, it was called a &amp;ldquo;sucker&amp;rsquo;s trade.&amp;rdquo; &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;What made medicine mislead people for so long is that its successes
were prominently displayed, and its mistakes literally buried - just
like so many other interesting stories in the cemetery of history. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;We are built to be dupes of theories. But theories come and go;
experience stays. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The English went further and had the families of the engineers spend
time with them under the bridge after it was built. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;In the old days, privilege came with obligations. You want war? First
in battle.&lt;br&gt;
Never ask anyone for their opinion, forecast, or recommendation. Just
ask them what they have - or don&amp;rsquo;t - in their portfolio. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Corporate managers have incentives without disincentives - something
the general public doesn&amp;rsquo;t quite get, as they have the illusion that
managers are properly &amp;ldquo;incentivized.&amp;rdquo; &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Third layer, the even more serious violation: companies trying to
misrepresent the product they sell by playing with our cognitive
biases, our unconscious associations, and that&amp;rsquo;s sneaky. The latter is
done by, say, showing a poetic picture of a sunset with a cowboy
smoking and forcing an association between great romantic moments and
some given product that, logically, has no possible connection to it.
You seek a romantic moment and what you get is cancer. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Don&amp;rsquo;t be fooled by money. These are just numbers. Being self-owned is
a state of mind.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;http://www.amazon.com/gp/product/1400067820/ref=as_li_qf_sp_asin_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=1400067820&amp;amp;linkCode=as2&amp;amp;tag=diofanedebyje-20&#34;&gt;Antifragile by Nassim Nicholas
Taleb.&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Observations over assumptions</title>
      <link>https://jefclaes.be/2013/11/observations-over-assumptions.html</link>
      <pubDate>Sun, 24 Nov 2013 18:08:00 +0100</pubDate>
      <guid>https://jefclaes.be/2013/11/observations-over-assumptions.html</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;I heard a story once about an engineer who worked on the Disneyland
site when it opened in Anaheim, CA in 1955.  &lt;/p&gt;
&lt;p&gt;A month before the park opened, the new grass and sod were being
applied to the grounds as one of the last items to be completed before
the big grand opening. The parking lot was some distance from the
park&amp;rsquo;s gates and required a lot of turf.  However, the sidewalks had
not been planned or constructed to accommodate patterns. &lt;/p&gt;
&lt;p&gt;Before engineers would validate the proper placement of the sidewalks,
a heated internal discussion grew among landscape designers and park
developers over how and what to build.  One engineer suggested they
allow visitors to walk on the grass for months in order to observe the
paths they created themselves. Then they would build over those paths
that showed the most foot traffic. &lt;/p&gt;
&lt;p&gt;Those sidewalks are still there today. &lt;/p&gt;
&lt;p&gt;One engineer&amp;rsquo;s focus on meeting the guests&amp;rsquo; needs saved the park
millions of dollars&amp;rsquo; worth of error and political positioning.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I found &lt;a href=&#34;http://www.quora.com/Disneyland/What-are-some-amazing-secrets-hidden-within-Disneyland-and-Disney-World/answer/Nic-DiPalma?srid=3XUe&amp;amp;share=1&#34;&gt;this story on
Quora&lt;/a&gt;
a few weeks ago, and thought it was a testament to how observing -
instead of assuming - can save you a lot of effort, and will end up
serving the users best.&lt;/p&gt;
&lt;p&gt;In the first product I helped building, there had been lots and lots of
requirements gathering before we got to build the first functionality.
Once we rolled out the pieces to the first set of users, they were
disappointed to say the least - enraged actually; &amp;ldquo;This not usable at
all! Do you even know what you&amp;rsquo;re doing?&amp;rdquo;. Apparently requirements were
made up by people higher in rank, without consulting those who would
have to use the software on a day-to-day basis. Not the best move
getting buy-in from actual users, but I can&amp;rsquo;t really blame them either;
requirements are hard, often times you&amp;rsquo;re just making stuff up as you go
along - with best intentions. Being in a crisis, we got to learn a lot
the next few months. One of us got sent out to the customer location a
few times, and got to observe how they were trying to use our software.
That information proved to be invaluable, and gave us enough to start
shipping better and more useful software. Users felt empowered by our
software, eventually leading to earning their trust and approval.&lt;/p&gt;
&lt;p&gt;Another example can be found in my current project - which is not that
visible to users, but more behind the scenes. Instead of guessing
performance targets, it&amp;rsquo;s by observing production metrics that we&amp;rsquo;re
able to set realistic goals.&lt;/p&gt;
&lt;p&gt;Observing instead of assuming usually leads to better results. Keep in
mind that you can misinterpret what you&amp;rsquo;re observing too, and that there
often is no other option than to assume. You can still avoid overly
expensive mistakes, by validating these assumptions as early as
possible.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Event storming workshop slides</title>
      <link>https://jefclaes.be/2013/11/event-storming-workshop-slides.html</link>
      <pubDate>Sun, 17 Nov 2013 19:56:00 +0100</pubDate>
      <guid>https://jefclaes.be/2013/11/event-storming-workshop-slides.html</guid>
      <description>&lt;p&gt;At &lt;a href=&#34;http://euri.com/&#34;&gt;Euricom&lt;/a&gt;, we quarterly all retreat to headquarters
for a day of sharing and learning. This time, I and others organized and
facilitated an event storming workshop.&lt;/p&gt;
&lt;p&gt;After a short introduction on event storming participants were initiated
to the domain of &lt;a href=&#34;http://en.wikipedia.org/wiki/Cambio_CarSharing&#34;&gt;Cambio
CarSharing&lt;/a&gt; - which is
packed with behaviour. After that, seven groups of five (+ one domain
expert) spread out across the office, and spent two slots of twenty
minutes modeling the domain - with two extra slots for feedback.&lt;/p&gt;
&lt;p&gt;Even after an afternoon of taxing sessions, people were willing to tap
out of their energy reserves, and ended up presenting great results.&lt;/p&gt;
&lt;p&gt;You can find the slides (heavily based on
&lt;a href=&#34;https://twitter.com/ziobrando&#34;&gt;Alberto&lt;/a&gt;&amp;rsquo;s material) I used
&lt;a href=&#34;http://www.slideshare.net/jclaes/workshop-event-storming&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re interested in running your first event storming workshop, I&amp;rsquo;d
love to come over and help you get started.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-11-17-event-storming-workshop-slides-EventStorming.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-11-17-event-storming-workshop-slides-EventStorming.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-11-17-event-storming-workshop-slides-EventStorming2.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-11-17-event-storming-workshop-slides-EventStorming2.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>An event store with optimistic concurrency</title>
      <link>https://jefclaes.be/2013/11/an-event-store-with-optimistic.html</link>
      <pubDate>Sun, 10 Nov 2013 18:25:00 +0100</pubDate>
      <guid>https://jefclaes.be/2013/11/an-event-store-with-optimistic.html</guid>
      <description>&lt;p&gt;Like I mentioned &lt;a href=&#34;http://www.jefclaes.be/2013/11/event-source-all-things.html&#34;&gt;last
week&lt;/a&gt; -
after only five posts on the subject - there still are a great deal of
event sourcing nuances left to be discovered.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.jefclaes.be/2013/10/an-event-store.html&#34;&gt;My current event store
implementation&lt;/a&gt; only
supports a single user. Due to an aggressive file lock, concurrently
accessing an aggregate will throw an exception. Can we allow multiple
users to write to and read from an event stream? Also, what can we do
about users making changes to the same aggregate; can we somehow detect
conflicts and avoid changes to be committed?&lt;/p&gt;
&lt;h2 id=&#34;multi-user&#34;&gt;Multi-user&lt;/h2&gt;
&lt;p&gt;In the current version, concurrently appending to or reading from an
aggregate&amp;rsquo;s event stream will throw since the file will already be
locked.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Parallel.For(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;, (i) =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    _eventStore.CreateOrAppend(aggregateId, &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; EventStream(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; List&amp;lt;IEvent&amp;gt;() 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    { 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ConcurrencyTestEvent() 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    _eventStore.GetStream(aggregateId);    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The exception looks like this: &lt;code&gt;&amp;quot;System.IO.IOException: The process cannot access the file &#39;C:\\EventStore\\92f42a08-8583-4dcf-98a5-440b06f34719.txt&#39; because it is being used by another process.&amp;quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;To prevent concurrent file access, we can lock code accessing the
aggregate&amp;rsquo;s event stream. Instead of using a global lock, we maintain a
dictionary of lock objects; one lock object per aggregate.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;lock&lt;/span&gt; (Lock.For(aggregateId))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; stream = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; FileStream(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        path, FileMode.Append, FileAccess.Write, FileShare.Read))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// Access the aggregate&amp;#39;s event stream&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Lock&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; ConcurrentDictionary&amp;lt;Guid, &lt;span style=&#34;color:#66d9ef&#34;&gt;object&lt;/span&gt;&amp;gt; _locks = 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ConcurrentDictionary&amp;lt;Guid, &lt;span style=&#34;color:#66d9ef&#34;&gt;object&lt;/span&gt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;object&lt;/span&gt; For(Guid aggregateId)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; aggregateLock = _locks.GetOrAdd(aggregateId, &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;object&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; aggregateLock;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}     
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;optimistic-concurrency&#34;&gt;Optimistic concurrency&lt;/h3&gt;
&lt;p&gt;Before committing changes, we want to verify that no other changes
have been committed in the meanwhile. These changes could have
influenced the behaviour of our aggregate significantly. Appending the
last changes without considering what might have happened in the
meanwhile might corrupt our aggregate&amp;rsquo;s state.&lt;/p&gt;
&lt;p&gt;One way to verify this is by using a number (or a timestamp - clocks,
bah) to keep track of an aggregate&amp;rsquo;s version. It&amp;rsquo;s up to the client to
tell us which version he expects when appending to a stream. To
accommodate for this, we need to change the contract of our event store.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IEventStore&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Create(Guid aggregateId, EventStream eventStream);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Append(Guid aggregateId, EventStream eventStream, &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; expectedVersion);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ReadEventStream GetStream(Guid aggregateId);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Clients now need to pass in the expected version when appending to a
stream. The result of reading a stream will include the current
version.&lt;/p&gt;
&lt;p&gt;In the event store, we now store an index with every event.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-11-10-an-event-store-with-optimistic-concurrency-EventsWithIndex.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-11-10-an-event-store-with-optimistic-concurrency-EventsWithIndex.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If we append to an event stream, we will get the current version by
reading the highest index - storing this in aggregate meta data would be
faster for reading. If the current version doesn&amp;rsquo;t match the expected
version, we throw an exception.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; currentVersion = GetCurrentVersion(path);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (currentVersion != expectedVersion)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; OptimisticConcurrencyException(expectedVersion, currentVersion);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; stream = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; FileStream(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    path, FileMode.Append, FileAccess.Write, FileShare.Read))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; streamWriter = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; StreamWriter(stream))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; @event &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; eventStream)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            currentVersion++;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            streamWriter.WriteLine(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Record(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                aggregateId, @event, currentVersion).Serialized());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A test for that looks something like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    GivenEventStore();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    GivenAggregateId();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    GivenEventStreamCreated();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    WhenAppendingTwoEventStreamsWithTheSameExpectedVersion();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (OptimisticConcurrencyException ocex) 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    _expectedConcurrencyException = ocex;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[TestMethod]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; ThenTheConcurrencyExceptionHasANiceMessage()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; expected = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Version found: 3, expected: 1&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; actual = _expectedConcurrencyException.Message
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Assert.AreEqual(expected, actual);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Reading the event stream doesn&amp;rsquo;t change much; we now also read the
current version, and return it with the event stream. &lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; lines = File.ReadAllLines(path);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (lines.Any())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; records = lines.Select(x =&amp;gt; Record.Deserialize(x, _assembly));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; currentVersion = records.Max(x =&amp;gt; x.Version);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; events = records.Select(x =&amp;gt; x.Event).ToList();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ReadEventStream(events, currentVersion);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And that&amp;rsquo;s one way to implement optimistic concurrency. The biggest
bottleneck in this approach is how we read the current version; having
to read all the events to find the current version isn&amp;rsquo;t very
efficient.&lt;/p&gt;
&lt;p&gt;Transactional behaviour is also missing. I&amp;rsquo;ve been thinking about adding
a &lt;code&gt;COMMIT&lt;/code&gt; flag after appending a set of events, and using that to resolve
corruption on reads, or is this fundamentally flawed?&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Event source all the things?</title>
      <link>https://jefclaes.be/2013/11/event-source-all-things.html</link>
      <pubDate>Sun, 03 Nov 2013 18:45:00 +0100</pubDate>
      <guid>https://jefclaes.be/2013/11/event-source-all-things.html</guid>
      <description>&lt;p&gt;Having covered
&lt;a href=&#34;http://www.jefclaes.be/2013/10/event-projections.html&#34;&gt;projections&lt;/a&gt;
last week, I think I have come full circle in these posts that turned
out to be a small preliminary series on event sourcing. Even though
there are still a vast amount of nuances to discover, I think I&amp;rsquo;ve
captured the gist of it. Even without running an event sourced system in
production - I feel as if I somewhat have an idea of what event sourcing
can bring to the table.&lt;/p&gt;
&lt;p&gt;Event sourcing gives you a complete history of events that caused an
aggregate to be in its current state. In some scenarios this will add an
enormous amount of value, in other scenarios it will give you nothing -
it might even steal time and effort.&lt;/p&gt;
&lt;p&gt;The first thing you do - before even considering implementing event
sourcing - is talking to your business. Do they feel as if events are a
natural way to represent what&amp;rsquo;s going on in their domain? Event sourcing
is a lot more than just a technical implementation detail, discovering
and understanding all of what goes on in a domain is a big investment -
from both sides. Is it worth the trouble?&lt;/p&gt;
&lt;p&gt;In my first job I worked on software for fire departments. I just now
realize in how many bits of our solution event sourcing could have
helped us:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the life cycle of a vehicle assigned to an emergency: vehicle dispatched, vehicle left the station, vehicle en route, vehicle arrived on the scene, vehicle back in the station&amp;hellip;&lt;/li&gt;
&lt;li&gt;a person&amp;rsquo;s career: person was promoted, person was detached to another station, person learned a new skill&amp;hellip;&lt;/li&gt;
&lt;li&gt;a shift&amp;rsquo;s schedule: person attached to unit, person returned to person pool, unit dispatched&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This data had to be made available in a set of diverse read models.
Getting the data out was complex at times, often even impossible. A lot
of these changes had to be propagated to external systems; there was no
way to get that info out in real-time, and external systems had no
notion of &lt;em&gt;what&lt;/em&gt; happened.&lt;/p&gt;
&lt;p&gt;In one of the functionalities of a system I&amp;rsquo;m currently working on,
users also wanted to know what happened in the past, but for completely
different reasons. Being in a financial context, they wanted to know who
was responsible for changing system settings. Here it&amp;rsquo;s not an event log
they need, but a simple audit trail.&lt;/p&gt;
&lt;p&gt;If it is just a passive log your business wants, you can get away with
cheaper alternatives; a command journal, an audit trail and so on.&lt;/p&gt;
&lt;h3 id=&#34;benefits&#34;&gt;Benefits&lt;/h3&gt;
&lt;p&gt;Event sourcing goes hand-in-hand with Domain Driven Design. Events are
a great tool to go from a structural model to a behavioural model,
helping you to capture the true essence of a domain model.&lt;/p&gt;
&lt;p&gt;Building and maintaining an event store should be doable. It&amp;rsquo;s an
append-only data model, storing serialized DTO&amp;rsquo;s with some meta data.
This makes - compared to ORM&amp;rsquo;s and relational databases - tooling easier
as well.&lt;/p&gt;
&lt;p&gt;In traditional systems, you have to keep a lot of things in your head at
once; how do I write my data, but also how do I query my data, and more
importantly how do I get my data out in all these different use cases
without making things too hard. In event sourced systems, separating
writes from reads makes for more granular bits, easing the cognitive
load.&lt;/p&gt;
&lt;p&gt;Events can be projected into anything: a relational database, a document
store, memory, files&amp;hellip; This allows you to build a read model for each
separate use case, while also giving you a lot of freedom in how you&amp;rsquo;re
going to persist them.&lt;/p&gt;
&lt;p&gt;You can replay projections, rebuilding a read model from scratch. Forget
about difficult data migrations.&lt;/p&gt;
&lt;p&gt;Testing feels consistent and very complete. A test will assert if all
the expected events were raised, but will also implicitly assert that
unexpected events were &lt;em&gt;not&lt;/em&gt; raised. Testing projections is also
straight-forward.&lt;/p&gt;
&lt;p&gt;Events provide a natural way of integrating with other systems.
Committed events can be published to external subscribers.&lt;/p&gt;
&lt;p&gt;Troubleshooting becomes easier since a developer can copy an event
stream from production, and replay it locally - reproducing the exact
issue without jumping through hoops getting the system in a specific
state.&lt;/p&gt;
&lt;p&gt;Instead of patching corrupted production data directly, you can send a
compensating event or fix the projection and replay everything. This way
nothing gets lost, and consistency between code and outcome is
guaranteed.&lt;/p&gt;
&lt;h3 id=&#34;downsides&#34;&gt;Downsides&lt;/h3&gt;
&lt;p&gt;Defining events is hard. Defining good events takes a lot of practice
and insight. If you&amp;rsquo;re forcing a structural model into a behavioural
one, it might even be impossible. So don&amp;rsquo;t even consider turning CRUD
into an event sourced model.&lt;/p&gt;
&lt;p&gt;There are a few places you need to be on the look out for performance
bottlenecks. Event streams of long lived aggregates might grow very big.
Loading a giant event stream from a data store might take a while -
snapshots can help here. Projecting giant event streams might get you
into trouble too - how long will it take to rebuild your read model,
will it even fit into memory? Making projections immediate consistent
might become a problem if you do a lot of them. Parallelization or
giving up on immediate consistency might bring solace.&lt;/p&gt;
&lt;p&gt;Events don&amp;rsquo;t change, versioning might get awkward. Are you going to
create a new event type for each change, or will you relax
deserialization? Or maybe you want to implement event migrations?&lt;/p&gt;
&lt;p&gt;Since you&amp;rsquo;re persisting multiple models; events and one or more read
models, you&amp;rsquo;re going to consume more storage, which will cost you.&lt;/p&gt;
&lt;h3 id=&#34;adaptation-in-the-wild&#34;&gt;Adaptation in the wild&lt;/h3&gt;
&lt;p&gt;Although there are - from a a business and engineering perspective -
some good arguments to be made for event sourcing, those arguments only
apply to a modest percentage of projects. Even when there&amp;rsquo;s a strong
case to be made for event sourcing, there are very few people with
actual experience implementing an event sourced system and prescriptive
frameworks that you can just drop into a project and feel good about,
are lacking. Most won&amp;rsquo;t even care about event sourcing to start with,
but even if they do, it&amp;rsquo;s a fight upstream; it introduces a risk most
might not be comfortable with.&lt;/p&gt;
&lt;p&gt;Having said that, there are some really good projects out there that are
steadily gaining popularity and maturity. Pioneers in the field are
sharing and documenting their experiences, lowering the barriers for
others. Things are moving for sure.&lt;/p&gt;
&lt;p&gt;As always, event sourcing is not a paradigm to blindly apply to each and
every scenario, but definitely one worth considering.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Since I&amp;rsquo;m not running any of it in production, tell me what I&amp;rsquo;m
missing, there must be more things that turn out to be harder than they
sound at first right? If you&amp;rsquo;re not running it in production, but
thinking about it, what are some of your concerns? What are your
predictions for the future of event sourcing?&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Event projections</title>
      <link>https://jefclaes.be/2013/10/event-projections.html</link>
      <pubDate>Sun, 27 Oct 2013 17:43:00 +0100</pubDate>
      <guid>https://jefclaes.be/2013/10/event-projections.html</guid>
      <description>&lt;p&gt;In my first two posts on event sourcing, I implemented &lt;a href=&#34;http://www.jefclaes.be/2013/10/an-event-sourced-aggregate.html&#34;&gt;an event sourced
aggregate from
scratch&lt;/a&gt;.
After being able to have an aggregate record and play events, I looked
at persisting them in &lt;a href=&#34;http://www.jefclaes.be/2013/10/an-event-store.html&#34;&gt;an event
store&lt;/a&gt;. Logically,
the next question is: how do I query my aggregates, how do I get my
state out?&lt;/p&gt;
&lt;p&gt;In traditional systems, write and read models are not separated, they
are one and the same. Event sourced systems on the other hand have a
write model - event streams, and a separate read model. The read model
is built from events committed to the write model; events are projected
into one or more read models.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-10-27-event-projections-Projections.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-10-27-event-projections-Projections.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An interface for a projection could look like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IProjection&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Handle(EventStream eventStream);                     
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A projection takes in an event stream, and projects it to &lt;em&gt;some&lt;/em&gt; read
model.&lt;/p&gt;
&lt;p&gt;A read model can be anything; a cache, a document store, a key value
store, a relational database, a file, or even some evil global state.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;EvilStatisticsReadModel&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; WithdrawalAmountExceededCount { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; AmountDepositedCount { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this model, we want to maintain statistics of events that happened.
For that to happen, we need to define a projection of our event stream.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ProjectionsToEvilStaticsReadModel&lt;/span&gt; : IProjection {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Handle(EventStream eventStream) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; @event &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; eventStream)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            When((&lt;span style=&#34;color:#66d9ef&#34;&gt;dynamic&lt;/span&gt;)@event);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; When(WithdrawalAmountExceeded @event) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        EvilStatisticsReadModel.WithdrawalAmountExceededCount++;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; When(AmountDeposited @event) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        EvilStatisticsReadModel.AmountDepositedCount++;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we now let this projection handle an event stream, our read model
will be kept up-to-date.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[TestMethod]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; ReadModelIsKeptUpToDateWhileProjectingTheEventStream() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; events = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; List&amp;lt;IEvent&amp;gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; WithdrawalAmountExceeded(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Amount(&lt;span style=&#34;color:#ae81ff&#34;&gt;3000&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; AmountDeposited(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Amount(&lt;span style=&#34;color:#ae81ff&#34;&gt;300&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; AmountDeposited(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Amount(&lt;span style=&#34;color:#ae81ff&#34;&gt;500&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; AmountWithdrawn(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Amount(&lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; stream = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; EventStream(events);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ProjectionsToEvilStaticsReadModel().Handle(stream);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Assert.AreEqual(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, EvilStatisticsReadModel.WithdrawalAmountExceededCount);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Assert.AreEqual(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, EvilStatisticsReadModel.AmountDepositedCount);    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One could argue that all of this is too much - not worth the effort.
Where you first just persisted the structure of an aggregate, and could
query that same structure, you now first have to persist events for then
to write projections that maintain separate read models that can be
queried.&lt;/p&gt;
&lt;p&gt;You have to look beyond that though. Those that have done any serious
work on a traditional stack have felt the pain of migrations, complex
queries that take up three pages, obscure stored procedures that run for
hours, optimizing while having to consider a handful of different use
cases, finding the balance between write- and read performance, database
servers that can&amp;rsquo;t handle the load on special events, expensive licenses
and so on. While these first few concerns are mostly technical,
personally I&amp;rsquo;m often overwhelmed by how much concepts these designs
force you to keep in your head all at once.&lt;/p&gt;
&lt;p&gt;Separating reads from writes using event sourcing might bring some
relief. Reducing cognitive overload by separating responsibilities into
smaller, more granular bits might be the only argument you need.
However, there&amp;rsquo;s a lot more. Running an event store should be
low-maintenance; it&amp;rsquo;s an append-only data model storing simple
serialized DTO&amp;rsquo;s with some meta data - forget about big migrations (not
completely though), schemas, indexes and so on. Even if you project into
a relational database, being able to re-run projections should make
migration scripts and versioning avoidable. An event can be projected
into multiple read models, allowing you to optimize per use case,
without having to take other use cases into account. Since it should be
easy to rebuild read models, they can be stored in cheap and volatile
storage - think key-value store, in-memory and so on, allowing for crazy
fast reads.&lt;/p&gt;
&lt;p&gt;Letting go of the single-model dogma seems to enable so much more,
giving you a whole new set of possibilities. Another extremely useful
use case that suddenly becomes a lot easier to support is business
intelligence; when business experts think of new ways to look at the
past, you just create a new projection and project events from day one.
Getting statistics of how your users are using your system doesn&amp;rsquo;t sound
that hard now, does it?&lt;/p&gt;
&lt;p&gt;One of the obvious drawbacks next to writing a bit more, boring code is
that storage costs will increase - you are now persisting the same data
in multiple representations. But storage is cheap, right? Maybe money
isn&amp;rsquo;t an issue, but what about performance? It&amp;rsquo;s slower to do three
writes instead of one, right? For a lot of scenarios this won&amp;rsquo;t be much
of an issue, but if it is, there is a lot of room for optimiziations
doing projections; parallelization, eventual consistency and so on.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Next week: event source all the things?&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>An event store</title>
      <link>https://jefclaes.be/2013/10/an-event-store.html</link>
      <pubDate>Sun, 20 Oct 2013 17:30:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/10/an-event-store.html</guid>
      <description>&lt;p&gt;Last week, I implemented &lt;a href=&#34;http://www.jefclaes.be/2013/10/an-event-sourced-aggregate.html&#34;&gt;an event sourced aggregate from
scratch&lt;/a&gt;.
There I learned, that there isn&amp;rsquo;t much to a naively implemented event
sourced aggregate; it should be able to initialize itself from a stream
of events, and it should be able to record all the events it raises.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IEventSourcedAggregate&lt;/span&gt; : IAggregate {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Initialize(EventStream eventStream);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    EventStream RecordedEvents();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The question I want to answer today is: how do I persist those event
sourced aggregates?&lt;/p&gt;
&lt;p&gt;In traditional systems, aggregate persistence is not a trivial topic.
Especially relational databases have the reputation to make things hard
on us. Even though tools such as ORM&amp;rsquo;s have tried to help in making the
gap between the relational and object oriented model as small as
possible, there is still a lot of friction associated with the notorious
impedance mismatch.&lt;br&gt;
The last two years I have done some work using one of the popular NoSQL
variants: a document store. In this paradigm, each aggregate
materializes into a single document. Structure, constraints and
referential integrity are not enforced by the database, but by code. The
advantage of relaxing consistency at the database, is that it makes it
easier to scale outside a single machine, and that developers feel more
empowered. Giving in on consistency guarantees is not acceptable for
each system though. Again, pick the right tool for the job.&lt;br&gt;
What both paradigms have in common is that they both focus on structure
instead of behaviour.&lt;/p&gt;
&lt;p&gt;Event sourced systems on the other hand, don&amp;rsquo;t care about the structure
of an aggregate, but about the events that caused the aggregate to be in
its current state. Only having to store events - which are represented
as DTO&amp;rsquo;s - makes persistence and tooling much easier compared to
traditional systems.&lt;/p&gt;
&lt;p&gt;There are three things a minimalistic event store should be able to
do:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Store a new event stream &lt;/li&gt;
&lt;li&gt;Append to an existing event stream&lt;/li&gt;
&lt;li&gt;Retrieve an existing event stream&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;An interface for that could look like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IEventStore&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; CreateOrAppend(Guid aggregateId, EventStream eventStream);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    EventStream GetStream(Guid aggregateId);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice that there is no update or delete - events happen, we can&amp;rsquo;t jump
in a time machine and alter the past. This allows us to get by with an
append-only data model. Can you imagine how much easier to implement,
optimize and distribute this must be compared to traditional models?&lt;/p&gt;
&lt;p&gt;As an exercise, I took the interface I just defined and implemented a
durable, non-transactional, non-scalable (&lt;a href=&#34;http://stackoverflow.com/questions/7722130/what-is-the-max-number-of-files-that-can-be-kept-in-a-single-folder-on-win7-mac&#34;&gt;up to 4294967295
streams&lt;/a&gt;),
single-user event store that persists event streams in raw text files.
Each record on disk represents a serialized event with a tiny bit of
metadata. &lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;FileEventStore&lt;/span&gt; : IEventStore {    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; Dir = &lt;span style=&#34;color:#e6db74&#34;&gt;@&amp;#34;C:\EventStore&amp;#34;&lt;/span&gt;;            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; CreateOrAppend(Guid aggregateId, EventStream eventStream) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        EnsureDirectoryExists();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; path = EventStoreFilePath.From(Dir, aggregateId).Value;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; stream = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; FileStream(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            path, FileMode.Append, FileAccess.Write, FileShare.None))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; streamWriter = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; StreamWriter(stream))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                streamWriter.AutoFlush = &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; @event &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; eventStream)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    streamWriter.WriteLine(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Record(aggregateId, @event).Serialized());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; EventStream GetStream(Guid aggregateId) {           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; path = EventStoreFilePath.From(Dir, aggregateId).Value;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (!File.Exists(path))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; lines = File.ReadAllLines(path);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; events = lines
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .Select(x =&amp;gt; Record.Deserialize(x))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .Select(x =&amp;gt; x.Event)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .ToList();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (events.Any())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; EventStream(events);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; EnsureDirectoryExists()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (!Directory.Exists(Dir))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Directory.CreateDirectory(Dir);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A long-ish test proves that I can create a stream, append to it and read
it again without losing any data.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[TestMethod]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; EventStoreCanCreateAppendAndRetrieveEventStreams() 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; eventStore = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; FileEventStore();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; aggregateId = Guid.NewGuid();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; account = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Account(aggregateId);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    account.Deposit(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Amount(&lt;span style=&#34;color:#ae81ff&#34;&gt;3000&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    account.Withdraw(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Amount(&lt;span style=&#34;color:#ae81ff&#34;&gt;400&lt;/span&gt;));    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Assert.AreEqual(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, account.RecordedEvents().Count());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Assert.AreEqual(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Amount(&lt;span style=&#34;color:#ae81ff&#34;&gt;2600&lt;/span&gt;), account.Amount);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    eventStore.CreateOrAppend(aggregateId, account.RecordedEvents());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; eventStream = eventStore.GetStream(aggregateId);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Assert.AreEqual(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, eventStream.Count());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; anotherAccount = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Account(aggregateId);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    anotherAccount.Initialize(eventStream);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Assert.AreEqual(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Amount(&lt;span style=&#34;color:#ae81ff&#34;&gt;2600&lt;/span&gt;), anotherAccount.Amount);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    anotherAccount.Withdraw(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Amount(&lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Assert.AreEqual(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Amount(&lt;span style=&#34;color:#ae81ff&#34;&gt;2400&lt;/span&gt;), anotherAccount.Amount);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Assert.AreEqual(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, anotherAccount.RecordedEvents().Count());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    eventStore.CreateOrAppend(aggregateId, anotherAccount.RecordedEvents());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; finalEventStream = eventStore.GetStream(aggregateId);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Assert.AreEqual(&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, finalEventStream.Count());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This produced the following artifact on disk.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-10-20-an-event-store-AnEventStore.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-10-20-an-event-store-AnEventStore.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;While this implementation is far from ideal - dangerous really, it does
show that implementing a minimalistic event store is doable - especially
if you can build on top of existing data stores.&lt;/p&gt;
&lt;p&gt;Doable, but not trivial. &lt;a href=&#34;https://twitter.com/gregyoung&#34;&gt;Greg Young&lt;/a&gt; -
having actually implemented an event store, on the CLR too - recently
shared &lt;a href=&#34;http://ayende.com/blog/159105/introducing-rhino-events&#34;&gt;some invaluable
insights&lt;/a&gt; into
what it takes to build a real-world event store.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I have always said an event store is a fun project because you can go
anywhere from an afternoon to years on an implementation. &lt;/p&gt;
&lt;p&gt;I think there is a misunderstanding how people normally use an event
stream for event sourcing. They read from it. Then they write to it.
They expect optimistic concurrency from another thread having read
from then written to the same stream. This is currently not handled.
This could be handled as simply as checking the expected previous
event but this wouldn&amp;rsquo;t work because the file could be scavenged in
between. The way this is generally worked around is a monotonically
increasing sequence that gets assigned to an event. This would be
relatively trivial to add. &lt;/p&gt;
&lt;p&gt;The next issue is that I can only read the stream from the beginning
to the end or vice versa. If I have a stream with 20m records in it
and I have read 14m of them and the power goes out; when I come back
up I want to start from 14m (stream.Position = previous; is a Seek()
and 14m can be very expensive if you happen to be working with files
the OS has not cached for you). This is a hugely expensive operation
to redo and the position I could have saved won&amp;rsquo;t help me as the file
could get compacted in between. To allow arbitrary access to the
stream is a bit more difficult. The naive way would be to use
something like a sorted dictionary or dictionary of lists as an index
but you will very quickly run out of memory. B+Trees/LSM are quite
useful here. &lt;/p&gt;
&lt;p&gt;Even with the current index (stream name to current position) there is
a fairly large problem as it gets large. With 5m+ streams you will
start seeing large pauses from the serializing out the dictionary. At
around 50m your process will blow up due to 1gb object size limit in
CLR&lt;br&gt;
Similar to the index issue is that with a dictionary of all keys being
stored in memory and taking large numbers of writes per second it is
quite likely you will run out of memory if people are using small
streams (say I have 10000 sensors and I do a stream every 5 seconds
for their data to partition). Performance will also drastically
decrease as you use more memory due to GC.&lt;br&gt;
A more sinister problem is the scavenge / compaction. It stops the
writer. When I have 100mb of events this may be a short pause. When I
have 50gb of events this pause may very well turn into minutes. &lt;/p&gt;
&lt;p&gt;There is also the problem of needing N * N/? disk space in order to
do a scavenge (you need both files on disk). With write speeds of
10MB/second it obviously wouldn&amp;rsquo;t take long to make these kinds of
huge files especially in a day where we consider a few TB to be small.
The general way of handling this is the file gets broken into chunks
then each chunk can be scavenged independently (while still allowing
reads off it). Chunks can for instance be combined as well as they get
smaller (or empty). &lt;/p&gt;
&lt;p&gt;Another point to bring up is someone wanting to write N events
together in a transactional fashion to a stream. This sounds like a
trivial addition but its less than trivial to implement (especially
with some of the other things discussed here). As was mentioned in a
previous thread a transaction starts by definition when there is more
than one thing to do. &lt;/p&gt;
&lt;p&gt;There are decades worth of previous art in this space. It might be
worth some time looking through it. LSM trees are a good starting
point as is some of the older material on various ways of implementing
transaction logs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Playing with &lt;a href=&#34;http://geteventstore.com/&#34;&gt;Greg&amp;rsquo;s event store&lt;/a&gt; is
something that has been on my list for a long time.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Next week: but how do we query our aggregates now?&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>An event sourced aggregate</title>
      <link>https://jefclaes.be/2013/10/an-event-sourced-aggregate.html</link>
      <pubDate>Sun, 13 Oct 2013 18:36:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/10/an-event-sourced-aggregate.html</guid>
      <description>&lt;p&gt;Last week I shared &lt;a href=&#34;http://www.jefclaes.be/2013/10/my-understanding-of-event-sourcing.html&#34;&gt;my theoretical understanding of event
sourcing&lt;/a&gt;.
Today, I want to make an attempt at making that theory tangible by
implementing an event sourced aggregate.&lt;/p&gt;
&lt;p&gt;In traditional systems, we only persist the current state of an
object.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-10-13-an-event-sourced-aggregate-TraditionalStorage.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-10-13-an-event-sourced-aggregate-TraditionalStorage.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In event sourced systems, we don&amp;rsquo;t persist the current state of an
object, but &lt;strong&gt;the sequence of events that caused the object to be in the
current state&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-10-13-an-event-sourced-aggregate-EventSourcingStorage.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-10-13-an-event-sourced-aggregate-EventSourcingStorage.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If we want an aggregate to be event sourced, it should be able to
rebuild itself from a stream of events, and it should be able to record
all the events it raises.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IEventSourcedAggregate&lt;/span&gt; : IAggregate
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Initialize(EventStream eventStream);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    EventStream RecordedEvents();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s implement the example aggregate we used last week: an account. An
account owner can deposit and withdraw an amount from his account. There
is a maximum amount policy for withdrawals though.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Account&lt;/span&gt; : IEventSourcedAggregate {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; Guid _id;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Account(Guid id) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _id = id;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Guid Id { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt; { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; _id; } }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Initialize(EventStream eventStream) { 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; NotImplementedException();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; EventStream RecordedEvents() { 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; NotImplementedException(); 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Deposit(Amount amount) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Withdraw(Amount amount) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next to the Initialize and RecordedEvents method, our aggregate facade
hasn&amp;rsquo;t changed. We still have a Deposit and a Withdraw operation like we
would have in a traditional aggregate. How those two methods get
implemented differs though.&lt;/p&gt;
&lt;p&gt;When we deposit or withdraw an amount, we want to - instead of changing
the state directly - apply events. When an event gets applied its
handler will first be invoked, for the event then to be recorded.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Deposit(Amount amount) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Apply(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; AmountDeposited(amount));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Withdraw(Amount amount) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (amount.IsOver(AmountPolicy.Maximum))     {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Apply(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; WithdrawalAmountExceeded(amount));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Apply(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; AmountWithdrawn(amount));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Apply(IEvent @event) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    When((&lt;span style=&#34;color:#66d9ef&#34;&gt;dynamic&lt;/span&gt;)@event);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    _eventRecorder.Record(@event);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;An event recorder is a small object that keeps track of recorded events.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;EventRecorder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; List&amp;lt;IEvent&amp;gt; _events = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; List&amp;lt;IEvent&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Record(IEvent @event) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _events.Add(@event);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; EventStream RecordedEvents() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; EventStream(_events);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This object will be used to have our aggregate return a stream of
recorded events.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; EventStream RecordedEvents() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; _eventRecorder.RecordedEvents();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can now also implement initializing the aggregate from a stream of
events.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Initialize(EventStream eventStream) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; @event &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; eventStream)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        When((&lt;span style=&#34;color:#66d9ef&#34;&gt;dynamic&lt;/span&gt;)@event);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here too, event handlers are invoked by using the dynamic run-time to
find the best overload.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s the event handlers that will change the aggregate&amp;rsquo;s state. In this
example, they can be implemented like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; When(AmountWithdrawn @event) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    _amount = _amount.Substract(@event.Amount);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; When(AmountDeposited @event) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    _amount = _amount.Add(@event.Amount);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; When(WithdrawalAmountExceeded @event) { }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A test verifies that when I invoke operations on the aggregate, all the
events are recorded, and the state has changed. When I use those
recorded events to rebuild the same aggregate, we end up with the same
state.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;    [TestMethod]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; ICanReplayTheEventsAndHaveTheStateRebuilt() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; account = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Account(Guid.NewGuid());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        account.Deposit(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Amount(&lt;span style=&#34;color:#ae81ff&#34;&gt;2500&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        account.Withdraw(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Amount(&lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        account.Withdraw(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Amount(&lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Assert.AreEqual(&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, account.RecordedEvents().Count());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Assert.AreEqual(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Amount(&lt;span style=&#34;color:#ae81ff&#34;&gt;2200&lt;/span&gt;), account.Amount);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; events = account.RecordedEvents();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; secondAccount = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Account(Guid.NewGuid());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        secondAccount.Initialize(events);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Assert.AreEqual(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Amount(&lt;span style=&#34;color:#ae81ff&#34;&gt;2200&lt;/span&gt;), secondAccount.Amount);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Assert.AreEqual(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, secondAccount.RecordedEvents().Count());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And this is all there is to an event sourced aggregate.&lt;/p&gt;
&lt;p&gt;For this exercise I tried to keep the number of concepts low. Many will
have noticed that extracting a few concepts would benefit re-use and
explicitness.&lt;/p&gt;
&lt;p&gt;Also using the DLR to invoke the correct event handlers might be frowned
upon; it&amp;rsquo;s not the most performant method, each event must have a
handler, and in case a handler is missing the exception is not pretty.
Experienced readers will also have noticed concepts such as versioning
and snapshots are not implemented yet. I hope limiting the amount of
concepts and indirections made this blog post easier to read.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Next week: where do I persist these events?&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>My understanding of event sourcing</title>
      <link>https://jefclaes.be/2013/10/my-understanding-of-event-sourcing.html</link>
      <pubDate>Sun, 06 Oct 2013 18:32:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/10/my-understanding-of-event-sourcing.html</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been studying event sourcing from a distance for little over a year
now; reading online material and going through some of the excellent OS
code. Unfortunately, there would be no value introducing it into my
current project - it would even be a terrible idea, so I decided to
satisfy my inquisitiveness by consolidating and sharing my understanding
of the concept.&lt;/p&gt;
&lt;h3 id=&#34;domain-events&#34;&gt;Domain events&lt;/h3&gt;
&lt;p&gt;An event is something that happened in the past.&lt;/p&gt;
&lt;p&gt;Events are described as verbs in the past tense. For example; amount
withdrawn, amount deposited, maximum withdrawal amount exceeded. Listen
for them when talking to your domain experts; events are as much a part
of the ubiquitous language as commands, aggregates, value objects
etc&amp;hellip;&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;ve captured a few events, you will notice how these concepts
have always implicitly been there, but by making them explicit you
introduce a whole new set of power tools to work with.&lt;/p&gt;
&lt;h3 id=&#34;event-sourcing&#34;&gt;Event sourcing&lt;/h3&gt;
&lt;p&gt;Having defined domain events one more time, we can now look at event
sourcing. By the name alone, it should be obvious events are going to
play the lead role.&lt;/p&gt;
&lt;p&gt;In traditional systems, we only persist the current state of an object.
In event sourced systems, we don&amp;rsquo;t persist the current state of an
object, but the &lt;strong&gt;sequence of events&lt;/strong&gt; that caused the object to be in
the current state.&lt;/p&gt;
&lt;p&gt;In traditional systems, every time a change happens, we retrieve the old
state, mutate it, and store the result as our current state. In this
example, only the last column would be persisted.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Old amount      Command         Current amount
                CreateAccount   $0
$0	            Deposit $2000	$2000
$2000	        Withdraw $100	$1900
$1900	        Withdraw $500	$1400
$1400	        Withdraw $2000	$1400
$1400	        Withdraw $300	$1100
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In event sourced systems on the other hand, we store the changes that
happened - the second column, not the current state. To arrive at the
current state again, we take all these events - and replay them.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Command	        Event	                                Current amount
CreateAccount	AccountCreated	                        $0
Deposit $2000	Deposited $2000	                        $2000
Withdraw $100	Withdrawn $100	                        $1900
Withdraw $500	Withdrawn $500	                        $1400
Withdraw $2000	Maximum withdrawal amount exceeded! 	$1400
Withdraw $300	Withdrawn $300	                        $1100
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Notice how we already gain better insights into what&amp;rsquo;s happening by
seeing an explicit &lt;em&gt;maximum amount exceeded&lt;/em&gt; event.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Next time; what does this look like in code?&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>CZ The Trilogy</title>
      <link>https://jefclaes.be/2013/09/cz-trilogy.html</link>
      <pubDate>Sun, 29 Sep 2013 18:15:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/09/cz-trilogy.html</guid>
      <description>&lt;p&gt;Over the weekend, we visited the Czech Republic for the third time
(&lt;a href=&#34;http://www.jefclaes.be/2010/04/trip-report-czech-republic.html&#34;&gt;one&lt;/a&gt;
and &lt;a href=&#34;http://www.jefclaes.be/2011/04/prague-impressions.html&#34;&gt;two&lt;/a&gt;). It&amp;rsquo;s
mostly chance that sends us that way every time though. This time, we
were invited by friends to accompany them in staying over at their
family&amp;rsquo;s house - who made it their job to lead guided tours through
Prague.&lt;/p&gt;
&lt;p&gt;We left Thursday right after work, hoping to get there in eight hours. A
decent traffic jam, a missed exit, and some bad map reading decided
otherwise; it added three hours to the trip.&lt;/p&gt;
&lt;p&gt;We stayed in a small town just twenty minutes outside of Prague, which
has been able to preserve all of its rural character. We took one day to
go out hiking, and were surprised by the local fauna; we were lucky
enough to spot wild deer, wild boars and a viper (that last one already
crushed to death though). Next to those species, the forest was heavily
occupied by locals gathering mushrooms - must be the season?&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-09-29-cz-the-trilogy-IMG_7298.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-09-29-cz-the-trilogy-IMG_7298.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We used the remaining two days to stroll through Prague, and to live
like kings getting the most out of the favorable prices. Food and drinks
cost less than half of what they do in Belgium. There is a
zero-tolerance alcohol policy for drivers though - I got pulled over
too, so they seem to be pretty serious about it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-09-29-cz-the-trilogy-IMG_7479.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-09-29-cz-the-trilogy-IMG_7479.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-09-29-cz-the-trilogy-IMG_7190.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-09-29-cz-the-trilogy-IMG_7190.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-09-29-cz-the-trilogy-IMG_7418.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-09-29-cz-the-trilogy-IMG_7418.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Actor Model in COBOL</title>
      <link>https://jefclaes.be/2013/09/actor-model-in-cobol.html</link>
      <pubDate>Sun, 22 Sep 2013 16:38:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/09/actor-model-in-cobol.html</guid>
      <description>&lt;p&gt;In an Actor system, each Actor acts as a self-contained and autonomous
component. An Actor can only communicate with other Actors by exchanging
messages - they are not allowed to share state. Messages are handled
asynchronously, and are nondeterministic. The location of Actors should
be transparent; they can either live on the same machine, or on a
distributed system. These properties make the Actor Model a great fit
for parallel and distributed computing.&lt;/p&gt;
&lt;p&gt;Even without considering parallelism and distribution, the Actor Model
appeals to me. If you take an existing system, and make each aggregate
in that system an Actor, what would the impact be? You can get rid of
all the messaging and queuing infrastructure; messages and asynchrony
are now first class citizens. Where you had to have discipline abiding
the aggregate rules of thumb - modifying one aggregate per transaction,
no references to other aggregates, Tell Don&amp;rsquo;t Ask&amp;hellip; - the very nature
of Actors will guide you into doing the right thing.&lt;br&gt;
Next to these implementation concerns, the model itself can be used as a
framework for modeling and reasoning about complex systems. Once they
are well educated on the constraints, it must come natural for domain
experts as well.&lt;/p&gt;
&lt;p&gt;Having worked with a team of mainframe programmers over the last year,
it recently came to me that how they have designed their systems over
the years is compatible with a good amount of Actor laws.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-09-22-actor-model-in-cobol-ActorModelInCOBOL.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-09-22-actor-model-in-cobol-ActorModelInCOBOL.JPG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;composition&#34;&gt;Composition&lt;/h3&gt;
&lt;p&gt;A good thing about COBOL seems to be that it&amp;rsquo;s nearly impossible to
write maintainable big programs, so you&amp;rsquo;re forced to decompose your
program into smallish autonomous components - into jobs.&lt;/p&gt;
&lt;h3 id=&#34;messages&#34;&gt;Messages&lt;/h3&gt;
&lt;p&gt;Communication between these jobs happens by passing flat files around&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the only format that&amp;rsquo;s supported out-of-the-box. Messages come in, and new messages go out. Jobs will never mutate the incoming payload, a new copy is created instead; pipes and filters. Folders serve as a queue, allowing files to be processed asynchronously and deterministic.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Staying clear of mutating messages makes debugging extremely easy;
you&amp;rsquo;ll never hear someone on the team asking for reproduction steps,
they just restore the production archives locally.&lt;/p&gt;
&lt;h3 id=&#34;addresses&#34;&gt;Addresses&lt;/h3&gt;
&lt;p&gt;Actors send messages to other Actors using their addresses. This can
be a memory or disk address, a network address, email address, whatever
really. In mainframe land, file system paths serve as addresses.&lt;/p&gt;
&lt;h3 id=&#34;no-shared-state&#34;&gt;No shared state&lt;/h3&gt;
&lt;p&gt;In general they stay away from jobs sharing state; the default is to
lock files exclusively, so sharing them is highly impractical. Even most
static data gets synchronized instead of shared - banking reference
data, customer addresses, configuration etc&amp;hellip;&lt;/p&gt;
&lt;h3 id=&#34;scheduling&#34;&gt;Scheduling&lt;/h3&gt;
&lt;p&gt;A scheduler sits on top of all these jobs. Its responsibility is to
start a job when a new file arrives. If a job fails, the scheduler acts
as a supervisor and will notify operations, which will investigate the
issue - probably look at what&amp;rsquo;s on the file system, and use the same
scheduler to restart the failed job. Notice that one failing job doesn&amp;rsquo;t
impact other jobs.&lt;/p&gt;
&lt;p&gt;All of this gives you an automated, highly observable and fault-tolerant
system.&lt;/p&gt;
&lt;p&gt;*Although COBOL remains to be a horrible language, mainframe systems do
have their strengths. There must be some good reason a lot of core
business functions are still running on mainframes, right? Maybe
similarities with the Actor Model are far-fetched and merely a figment
of my imagination. Feel free to share your thoughts. *&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Slides from my talk on the Ubiquitous Language</title>
      <link>https://jefclaes.be/2013/09/slides-from-my-talk-on-ubiquitous.html</link>
      <pubDate>Sun, 15 Sep 2013 16:34:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/09/slides-from-my-talk-on-ubiquitous.html</guid>
      <description>&lt;p&gt;I just returned from our yearly &lt;a href=&#34;http://euri.com/&#34;&gt;Euricom&lt;/a&gt; retreat.
This year, all forty of us got to spend four days in the South of Spain.
Where we had longish sessions and a few workshops last year, we
experimented with shorter talks this year - a la lightning talks, TEDx
style.&lt;/p&gt;
&lt;p&gt;This format made it possible for everyone to speak, but also forced the
speaker to keep the scope of the talk focused, and to organize the
information in a way that attendees can get the gist of it in only
twelve minutes. This makes for high-energy talks designed to peak one&amp;rsquo;s
interest, to share useful tips, to plant a seed or to pitch an idea.&lt;br&gt;
Covering more than just technical ground alone made topics extremely
diverse; from query tuning to empathy, from automated testing to how to
explain your kids what you do for a living, from personal kanban to
juggling with a diabolo. Going back and forth between these technical
and less technical sessions kept my brain from being oversaturated.&lt;/p&gt;
&lt;p&gt;Definitely an experiment that only yielded positive results; we will be
using this format more frequently when organizing internal events.&lt;/p&gt;
&lt;p&gt;Initially, I planned on doing a session on the DDD strategic patterns;
the ubiquitous language, subdomains, bounded contexts, context
mapping&amp;hellip; but I couldn&amp;rsquo;t capture all of that in a meaningful way in
less than twelve minutes. That&amp;rsquo;s why I started over, focusing on the
ubiquitous language alone.&lt;/p&gt;
&lt;p&gt;You can find my slides &lt;a href=&#34;http://www.slideshare.net/jclaes/refactoring-towards-the-ubiquitous-language&#34;&gt;on
Slideshare&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>The first DDDBE Modellathon</title>
      <link>https://jefclaes.be/2013/09/the-first-dddbe-modellathon.html</link>
      <pubDate>Fri, 06 Sep 2013 13:24:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/09/the-first-dddbe-modellathon.html</guid>
      <description>&lt;p&gt;On our way back from DDD Exchange, heavily influenced by yet another
immersive DDD experience, we searched for ways to keep the momentum
going. Sure, we met up regularly for CQRS beers, but we felt that we
could do more, better. That&amp;rsquo;s when we coined the term modellathon,
something like a hackathon, but instead of writing code, we would build
models.&lt;/p&gt;
&lt;p&gt;Thanks to the effort of &lt;a href=&#34;https://twitter.com/mathiasverraes&#34;&gt;Mathias&lt;/a&gt;,
&lt;a href=&#34;https://twitter.com/stijnvnh&#34;&gt;Stijn&lt;/a&gt; and
&lt;a href=&#34;https://twitter.com/yreynhout&#34;&gt;Yves&lt;/a&gt;, Tuesday marked the first
get-together of &lt;a href=&#34;http://domaindriven.be/&#34;&gt;the Belgian DDD user group&lt;/a&gt; in
its official form. Combell was kind enough to provide us with a
location, while Mathias fronted paper - lots of it too, post-its and
markers.&lt;/p&gt;
&lt;p&gt;Mathias and Stijn took the lead introducing themselves as domain experts
of the day. The domain? The United Schools of Kazachstan.&lt;/p&gt;
&lt;p&gt;We split up into groups of four, and used our first pomodoro trying to
understand the domain. The second pomodoro, we threw everything away and
started fresh.&lt;/p&gt;
&lt;p&gt;The first modeling technique our group tried was &lt;a href=&#34;https://twitter.com/ziobrando&#34;&gt;Alberto
Brandolini&lt;/a&gt;&amp;rsquo;s event storming. We took
what we thought was the most important event &lt;em&gt;report approved&lt;/em&gt;, wrote it
on a post-it, and posted it on the center of our sheet of paper. Then we
worked our way back to how we got there, but also looked at what
happened next. This modeling approach yielded results very quickly; we
all gained a decent understanding of everything what&amp;rsquo;s going on in the
domain. Talking to the domain expert made it obvious what the hotspots
were, he kept referring to two post-its in particular.&lt;/p&gt;
&lt;p&gt;We might have zoomed in right there, but for the sake of experimenting
with event storming, we stuck to events a little longer. We added
commands, looked for clusters, made aggregate boundaries based on that,
and looked where they were talking to each other.&lt;/p&gt;
&lt;p&gt;We initially used a sheet of paper and stayed seated, but this was
holding us back. Once we stood up and moved to the wall, our synergy
increased. Space and blood circulation seem to be important.&lt;/p&gt;
&lt;p&gt;Flow is important too. Since we only had two domain experts, we often
had to make assumptions and come up with a name that made sense. This
slowed us down. We should just write down whatever we come up with, and
make doubts explicit on the post-it. You can always verify and fix the
language consulting the domain experts later.&lt;/p&gt;
&lt;p&gt;The next visualization technique, initiated by Yves, took a UI-first
approach. While this quickly gives you something concrete to chat about
with the domain expert, I learned it can also lead you to bounded
context boundaries by helping you answer the question &amp;ldquo;Where is all this
data coming from, which &lt;em&gt;contexts&lt;/em&gt; does this data belong to?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I thought this first experiment went really well - a lot better than I
expected. It proves once again the value of visualization and
collaboration. All models were probably wrong, but turned out to be
useful. The end result probably doesn&amp;rsquo;t matter that much, discovery and
learning along the way does.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-09-06-the-first-dddbe-modellathon-Modellathon.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-09-06-the-first-dddbe-modellathon-Modellathon.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Note to self: make pictures of the end results; they would help
explaining some of the experiments.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Inheritance is like Jenga</title>
      <link>https://jefclaes.be/2013/08/inheritance-is-like-jenga.html</link>
      <pubDate>Sun, 25 Aug 2013 18:18:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/08/inheritance-is-like-jenga.html</guid>
      <description>&lt;p&gt;These last few days, I have been working on a piece of our codebase that
accidentally got very inheritance heavy.&lt;/p&gt;
&lt;p&gt;When it comes to inheritance versus composition, there are a few widely
accepted rules of thumb out there. While &lt;em&gt;prefer composition over
inheritance&lt;/em&gt; doesn&amp;rsquo;t cover the nuances, it&amp;rsquo;s not terrible advice;
composition will statistically often be the better solution. Steve
McConnell&amp;rsquo;s &lt;em&gt;composition defines a &amp;lsquo;has a&amp;rsquo;- relationship while
inheritance defines an &amp;lsquo;is a&amp;rsquo;-relationship&lt;/em&gt;, gives you a more nuanced
and simple tool to apply to a scenario. The Liskov substitution
principle which states that, &lt;em&gt;if S is a subtype of T, then objects of T
may be replaced with objects of type S without any of the desirable
properties of that program&lt;/em&gt;, is probably the most complete advice.&lt;/p&gt;
&lt;p&gt;Inheritance, when applied with the wrong motivations - reuse and such,
often leads to fragile monster class hierarchies which are too big to
wrap your head around and extremely hard to change.&lt;/p&gt;
&lt;p&gt;When I was working on such a monstrous hierarchy, it reminded me of
playing &lt;a href=&#34;http://en.wikipedia.org/wiki/Jenga&#34;&gt;Jenga&lt;/a&gt;. Some time not that
long ago, someone had built this tower from the ground, laying block
over block, layer over layer. On the surface it appears to be stable and
rigid, but as soon as someone wants to winkle out one block, it becomes
obvious one block can bring down the whole structure. The lower the
block in the structure, the more layers rest on it, the greater the risk
of breaking everything on top. Even if you do succeed in pulling one
block out, chances are you had to touch the surrounding blocks to
prevent the tower from tumbling over.&lt;/p&gt;
&lt;p&gt;Instead of Jenga, I&amp;rsquo;d prefer a puzzle made of just a few pieces -
designed for toddlers. A puzzle is flat, you can see the big picture in
one glance, while you can reason about each piece individually as well.
As long as the edges of the pieces fit together, you can assemble
whatever picture you want.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>But I already wrote it</title>
      <link>https://jefclaes.be/2013/08/but-i-already-wrote-it.html</link>
      <pubDate>Sun, 18 Aug 2013 16:24:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/08/but-i-already-wrote-it.html</guid>
      <description>&lt;p&gt;A few weeks ago, we set out to implement a feature that enabled back
office users to set a new rate ahead of time. With our analyst and the
involved user being out of the office for days, we had to solely rely on
written requirements. Two of us skimmed the documents, but didn&amp;rsquo;t take
the time to assure there wasn&amp;rsquo;t any ambiguity - it looked trivial
really. I went back to what I was doing, while my colleague set out to
implement this feature. Going over the implementation together the next
day, he had built something a lot more advanced than I had anticipated.
While I argued that this was a lot more than we needed, we agreed to
wait for feedback from our analyst to return from her holiday.&lt;/p&gt;
&lt;p&gt;When our analyst returned, she confirmed that the implementation did a
lot more than we needed. I suggested removing what we didn&amp;rsquo;t really
need. My colleague argued that he now already had put in the effort to
write it, and we should just leave it as is.&lt;/p&gt;
&lt;p&gt;I can relate to feeling good about freshly written code, but that
shouldn&amp;rsquo;t stop you from throwing it away. Code is just a means to an
end; the side product of creating a solution or learning about a
problem. If you really can&amp;rsquo;t let go, treasure it in a gist.&lt;/p&gt;
&lt;p&gt;In this particular scenario, one could argue that making the solution
more advanced than it should be, isn&amp;rsquo;t strong enough of an argument to
make a big deal out of it. We&amp;rsquo;re giving the users a little extra for
free, right? &lt;/p&gt;
&lt;p&gt;I cannot stress the importance of simplicity enough; to be simple is to
be great, perfection is achieved not when there is nothing more to add,
but when there&amp;rsquo;s is nothing left to take away, and all of that. Nobody
likes bulky software. Nobody likes fighting complexity all day.&lt;/p&gt;
&lt;p&gt;But by only considering the cost of initially writing it, you are also
ignorant of the &lt;em&gt;true&lt;/em&gt; cost of what appears to be a small little extra
on the surface. Users, developers, designers and analysts alike have yet
another thing to wrap their heads around. More code is not a good thing;
more code to test, more code to maintain. Each feature, how small it may
seem, needs to be taken into account when planning on new ones. Each
feature, definitely an advanced one, makes the cost of training and
support go up. The cost of implementing a feature is just a tiny portion
of what it costs to support that feature through its entire lifetime.&lt;/p&gt;
&lt;p&gt;Using this argument, I eventually succeeded in persuading my peer to
dump the ballast. The real lesson for me however, is probably that how
trivial it might have seemed, we could have ruled out any possible
ambiguity in advance by using one of the various tools we have to our
disposal; a smallish white board session or maybe pairing on some high
level tests.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Eventual consistent domain events with RavenDB and IronMQ</title>
      <link>https://jefclaes.be/2013/08/eventual-consistent-domain-events-with.html</link>
      <pubDate>Thu, 15 Aug 2013 14:03:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/08/eventual-consistent-domain-events-with.html</guid>
      <description>&lt;p&gt;Working on side projects, I often find myself using
&lt;a href=&#34;http://ravendb.net/&#34;&gt;RavenDB&lt;/a&gt; for storage and
&lt;a href=&#34;http://www.iron.io/mq&#34;&gt;IronMQ&lt;/a&gt; for queueing. I wrote about that last
one before
&lt;a href=&#34;http://www.jefclaes.be/2013/03/first-ironmq-impressions.html&#34;&gt;here&lt;/a&gt; and
&lt;a href=&#34;http://www.jefclaes.be/2013/03/putting-my-ironmq-experiment-under.html&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One project I&amp;rsquo;m working on right now makes use of domain events. As an
example, I&amp;rsquo;ll use the usual suspect: the &lt;code&gt;BookingConfirmed&lt;/code&gt; event. When a
booking has been confirmed, I want to notify my customer by sending him
an email.&lt;/p&gt;
&lt;p&gt;I want to avoid that persisting a booking fails because an eventhandler
throws - the mail server is unavailable. I also don&amp;rsquo;t want that an
eventhandler executes an operation that can&amp;rsquo;t be rolled back - sending
out an email - without first making sure the booking was persisted
succesfully. If an eventhandler fails, I want to give it the opportunity
to fix what&amp;rsquo;s wrong and retry.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Confirm()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Status = BookingStatus.Accepted;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Events.Raise(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; BookingConfirmed(Id));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;get-in-line&#34;&gt;Get in line&lt;/h3&gt;
&lt;p&gt;The idea is, instead of dealing with the domain events in memory, to
push them out to a queue so that  eventhandlers can deal with them
asynchronously. If we&amp;rsquo;re trusting IronMQ with our queues, we get in
trouble guaranteeing that the events aren&amp;rsquo;t sent out unless the booking
is persisted succesfully; you can&amp;rsquo;t make IronMQ enlist in a
transaction.&lt;/p&gt;
&lt;h3 id=&#34;avoiding-false-events&#34;&gt;Avoiding false events&lt;/h3&gt;
&lt;p&gt;To avoid pushing out events, and alerting our customer, without having
succesfully persisted the booking, I want to commit my events in the
same transaction. Since IronMQ can&amp;rsquo;t be enlisted in a transaction, we
have to take a detour; instead of publishing the event directly, we&amp;rsquo;re
going to persist it as a RavenDB document. This guarantees the event is
committed in the same transaction as the booking.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DomainEvent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; DomainEvent(&lt;span style=&#34;color:#66d9ef&#34;&gt;object&lt;/span&gt; body)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNull(body, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;body&amp;#34;&lt;/span&gt;);          
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Type = body.GetType();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Body = body;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Published = &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        TimeStamp = DateTimeProvider.Now();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; DomainEvent() { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; Id { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; DateTime TimeStamp { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Type Type { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;object&lt;/span&gt; Body { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; Published { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; MarkAsPublished()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Published = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DomainEvents&lt;/span&gt; : IDomainEvents
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; IDocumentSession _session;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; DomainEvents(IDocumentSession session)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _session = session;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Raise&amp;lt;T&amp;gt;(T args) &lt;span style=&#34;color:#66d9ef&#34;&gt;where&lt;/span&gt; T : IDomainEvent
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {       
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _session.Store(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; DomainEvent(args));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-08-15-eventual-consistent-domain-events-with-ravendb-and-ironmq-RavenDBDomainEvents.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-08-15-eventual-consistent-domain-events-with-ravendb-and-ironmq-RavenDBDomainEvents.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;getting-the-events-out&#34;&gt;Getting the events out&lt;/h3&gt;
&lt;p&gt;Now we still need to get the events out of RavenDB. Looking into this,
I found this to be a very good use of the &lt;a href=&#34;http://ayende.com/blog/157121/awesome-feature-of-the-day-ravendb-changes-api&#34;&gt;Changes
API&lt;/a&gt;.
Using the Changes API, you can subscribe to all changes made to a
certain document. If you&amp;rsquo;re familiar with relation databases, the
Changes API might remind you of triggers - except for that the Changes
API doesn&amp;rsquo;t live in the database, nor does it run in the same
transaction. In this scenario, I use it to listen for changes to the
domain events collection. On every change, I&amp;rsquo;ll load the document, push
the content out to IronMQ, and mark it as published.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DomainEventPublisher&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; IQueueFactory _queueFactory;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; DomainEventPublisher(IQueueFactory queueFactory)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _queueFactory = queueFactory;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Start()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        DocumentStore
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .Get()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .Changes()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .ForDocumentsStartingWith(&lt;span style=&#34;color:#66d9ef&#34;&gt;typeof&lt;/span&gt;(DomainEvent).Name)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .Subscribe(PublishDomainEvent);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; PublishDomainEvent(DocumentChangeNotification change)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Task.Factory.StartNew(() =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (change.Type != DocumentChangeTypes.Put)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; session = DocumentStore.Get().OpenSession())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; domainEvent = session.Load&amp;lt;DomainEvent&amp;gt;(change.Id);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (domainEvent.Published)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; queue = _queueFactory.CreateQueue(domainEvent.Type.Name);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                queue.Push(JsonConvert.SerializeObject(domainEvent.Body));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                domainEvent.MarkAsPublished();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                session.SaveChanges();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I tested this by raising 10,000 events on my machine, and got up to an
average of pushing out 7 events a second. With an average of 250ms per
request, the major culprit is posting messages to IronMQ. Since I&amp;rsquo;m
posting these messages over the Atlantic, IronMQ is not really to blame.
Once you get closer, response times go down to the 10ms - 100ms range.&lt;/p&gt;
&lt;h3 id=&#34;a-back-up-plan&#34;&gt;A back-up plan&lt;/h3&gt;
&lt;p&gt;If the subscriber goes down, events won&amp;rsquo;t be pushed out, so you need
to have a back-up plan. I planned for missing events by scheduling a
Quartz job that periodically queries for old unpublished domain events
and publishes them.&lt;/p&gt;
&lt;h3 id=&#34;in-conclusion&#34;&gt;In conclusion&lt;/h3&gt;
&lt;p&gt;You don&amp;rsquo;t need expensive infrastructure or a framework to enable
handling domain events in an eventual consistent fashion. Using RavenDB
as an event store, the Changes API as an event listener, and IronMQ for
queuing, we landed a rather light-weight solution. It won&amp;rsquo;t scale
endlessly, but it doesn&amp;rsquo;t have to either.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m interested in hearing which homegrown solutions you have come up
with, or how I could improve mine.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>When your commands spell CUD</title>
      <link>https://jefclaes.be/2013/08/when-your-commands-spell-cud.html</link>
      <pubDate>Sun, 04 Aug 2013 19:08:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/08/when-your-commands-spell-cud.html</guid>
      <description>&lt;p&gt;A good while ago, I blogged on commands (and queries). After exploring
various flavors, I eventually settled on this one; &lt;a href=&#34;http://www.jefclaes.be/2013/01/separating-command-data-from-logic-and.html&#34;&gt;commands, handlers
and an in-memory bus that serves as a command
executor&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Commands help you in supporting the ubiquitous language by explicitly
capturing user intent at the boundaries of your system - think use
cases. You can look at them as messages that are being sent to your
domain. In this regard, they also serve as a layer over your domain -
decoupling the inside from the outside, allowing you to gradually
introduce concepts on the inside, without breaking the outside. The
command executor gives you a nice pipeline you can take advantage of to
centralize security, performance metrics, logging, session management
and so on.&lt;/p&gt;
&lt;p&gt;We always need to be critical of abstractions though, and regularly
assess their value. A smell that might indicate that commands might not
be working for you, or are adding little value, is that the first
letters of your commands spell CUD - Create Update Delete.&lt;/p&gt;
&lt;p&gt;For example; CreateCarCommand, UpdateCarCommand and DeleteCarCommand.&lt;/p&gt;
&lt;h3 id=&#34;the-language-needs-attention&#34;&gt;The language needs attention&lt;/h3&gt;
&lt;p&gt;Possibly, your team doesn&amp;rsquo;t fully grasp the power of cultivating the
ubiquitous language. If you start listening to your domain experts, you
might end up with totally different command names; &lt;code&gt;TakeInNewCarCommand&lt;/code&gt;,
&lt;code&gt;RepaintCarCommand&lt;/code&gt;, &lt;code&gt;InstallOptionCommand&lt;/code&gt; and &lt;code&gt;RemoveCarFromFleetCommand&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Maybe though, there is no language at all, and you&amp;rsquo;re really just doing
CRUD. If the context you are working on is implementing a generic or
supporting subdomain this might not be terrible.&lt;/p&gt;
&lt;h3 id=&#34;if-im-doing-crud-do-i-still-need-commands&#34;&gt;If I&amp;rsquo;m doing CRUD, do I still need commands?&lt;/h3&gt;
&lt;p&gt;Commands help you decouple the inside from the outside. If there is no
domain on the inside though, they can still help you decouple the
application layer from other concerns. You might prefer to use another
facade to separate concerns though, such as a thin service layer. I
don&amp;rsquo;t think the service layer abstraction gives you anything commands
don&amp;rsquo;t though. Maybe you don&amp;rsquo;t find any value in separating things at
all, and just dump everything in the the application layer.&lt;/p&gt;
&lt;p&gt;All of these approaches are valid. You just have to consider the
trade-offs. With these last approaches, next to losing decoupling in
from out, you also lose that central pipeline that a command executor
gives you.&lt;/p&gt;
&lt;h3 id=&#34;doesnt-my-application-layer-give-me-this-pipeline-for-free&#34;&gt;Doesn&amp;rsquo;t my application layer give me this pipeline for free?&lt;/h3&gt;
&lt;p&gt;It sure can. Looking at modern networking stacks, these all have
interception points built in. For example; NancyFx allows you to hook in
the request pipeline using before and after hooks; Web API gives your
message handlers and action filters; and WCF has a concept of
interceptors.&lt;/p&gt;
&lt;p&gt;Not all application frameworks do though - think of frameworks targeting
desktop software.&lt;/p&gt;
&lt;p&gt;The advantage of having your own pipeline, instead of solely having to
rely on your application framework&amp;rsquo;s interception points, is that you&amp;rsquo;re
boss and don&amp;rsquo;t have to study the ins and outs of each framework, and
hope for the framework to have thought of your needs. Also when you need
to support multiple application layers, you don&amp;rsquo;t have to implement all
features twice.&lt;/p&gt;
&lt;h3 id=&#34;what-about-using-aspects-instead-of-a-pipeline-to-centralize-all-these-concerns&#34;&gt;What about using aspects instead of a pipeline to centralize all these concerns?&lt;/h3&gt;
&lt;p&gt;You can - instead of a pipeline - use aspects to take care of
croscutting concerns such as security, logging, session management.. and
have them woven into your executable at compile- or runtime. I think of
aspects as if they were macros, which save you on lines of code written,
but also often conceal the real problem; missing concepts. While they
try to sell you on separation of concerns, notice that you&amp;rsquo;re actually
still producing procedural code, but instead of writing it by hand,
you&amp;rsquo;re now letting an AOP framework do it for you. Add harder testing,
debugging and readability to the bunch, and you can understand why I&amp;rsquo;m
not a fan of AOP. There are scenarios where this all doesn&amp;rsquo;t matter much
though, and to strengthen the cliche; granular logging is a good use
case.&lt;/p&gt;
&lt;p&gt;When your commands spell CUD, it might indicate you could do without
them. Do realize what the consequences are of taking them away though;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;you lose the opportunity to capture user intent at the boundaries of your system, to strengthen the ubiquitous language&lt;/li&gt;
&lt;li&gt;you may need an alternative facade to decouple in from out&lt;/li&gt;
&lt;li&gt;you lose that command executor serving as your own pipeline&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>The last cowboy</title>
      <link>https://jefclaes.be/2013/07/to-live-die-in-la.html</link>
      <pubDate>Tue, 16 Jul 2013 05:46:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/07/to-live-die-in-la.html</guid>
      <description>&lt;p&gt;After seventeen days, 2000 miles (3220km), seven states, eight national
parks and fifteen motels, our
&lt;a href=&#34;http://www.jefclaes.be/2011/09/once-upon-time-in-west.html&#34;&gt;second&lt;/a&gt; USA
road trip has come to an end. Inspired, and with new insights, we&amp;rsquo;re
leaving for Belgium in the morning.&lt;/p&gt;
&lt;p&gt;Along the way, we documented our journey in these posts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.jefclaes.be/2013/07/to-live-die-in-la.html&#34;&gt;To Live &amp;amp; Die in L.A&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.jefclaes.be/2013/07/fireworks-tequila-and-silvertown-blues.html&#34;&gt;Fireworks, Tequila and Silvertown Blues&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.jefclaes.be/2013/07/she-said-yes.html&#34;&gt;She said yes!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.jefclaes.be/2013/07/stairway-to-heaven.html&#34;&gt;Stairway to heaven&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.jefclaes.be/2013/07/the-long-highway.html&#34;&gt;The long highway&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.jefclaes.be/2013/07/the-road-goes-on-forever.html&#34;&gt;The road goes on forever&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thanks for reading! When I return, I&amp;rsquo;ll get back to more technical
writing.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-16-the-last-cowboy-San+Diego+Joshua+Three+061_2.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-16-the-last-cowboy-San+Diego+Joshua+Three+061_2.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.youtube.com/watch?v=rou4IJsIIPo&#34;&gt;The last cowboy song&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>The road goes on forever</title>
      <link>https://jefclaes.be/2013/07/the-road-goes-on-forever.html</link>
      <pubDate>Mon, 15 Jul 2013 04:51:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/07/the-road-goes-on-forever.html</guid>
      <description>&lt;p&gt;We didn’t get to see a lot of Salt Lake City. Before heading to Idaho
Falls, we hung around at the mall, feasted on Sushi, and bought new
hiking shoes since ours literally fell apart.&lt;br&gt;
Since Idaho Falls just served as a launching point to Yellowstone, we
filled the hole in our schedule with a date night; we had BBQ and went
to see &lt;a href=&#34;http://en.wikipedia.org/wiki/World_War_Z_(film)&#34;&gt;WorldWar Z&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After another long drive the next day, we exchanged the dirt for greener
scenery. We drove through Grand Teton, to get to of one our last and
most anticipated destinations; &lt;a href=&#34;http://en.wikipedia.org/wiki/Yellowstone_National_Park&#34;&gt;Yellowstone National
Park&lt;/a&gt;. We spent
two days here, in which we drove across the extensive volcanic area,
stopping at all popular attractions (geysers, pools, waterfalls…),
spotting and stalking wildlife on the way. &lt;/p&gt;
&lt;p&gt;Instead of a motel, we slept in the wild - in bear country, in a Tipi.
Although our host armed us with bear spray, we got a good night’s sleep.
Today however, we did spot a baby Grizzly bear from afar!&lt;/p&gt;
&lt;p&gt;Tomorrow will be our last day, which we will spend in Cody, Wyoming.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-15-the-road-goes-on-forever-Yellowstone1.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-15-the-road-goes-on-forever-Yellowstone1.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-15-the-road-goes-on-forever-Yellowstone2.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-15-the-road-goes-on-forever-Yellowstone2.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-15-the-road-goes-on-forever-Yellowstone3.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-15-the-road-goes-on-forever-Yellowstone3.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-15-the-road-goes-on-forever-Yellowstone4.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-15-the-road-goes-on-forever-Yellowstone4.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.youtube.com/watch?v=dj6HfWp-eh0&#34;&gt;The road goes on forever&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>The long highway</title>
      <link>https://jefclaes.be/2013/07/the-long-highway.html</link>
      <pubDate>Fri, 12 Jul 2013 07:13:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/07/the-long-highway.html</guid>
      <description>&lt;p&gt;We’re past halfway our trip and we need to make headway if we want to
stay on schedule and reach Yellowstone by Sunday. Long, but pleasant
drives; &lt;a href=&#34;http://www.forbes.com/sites/jimgorzelany/2013/04/25/the-worlds-most-traffic-congested-cities/&#34;&gt;if you’re used to Belgian
traffic&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Yesterday we visited &lt;a href=&#34;http://en.wikipedia.org/wiki/Capitol_Reef_National_Park&#34;&gt;Capitol Reef National
Park&lt;/a&gt;. We
originally planned on doing the Hickman Bridge Trail, but apparently
there had recently been a big rock fall, blocking access at the
trailhead. As an alternative we did the Narrows trail at Grand Wash
Road, which was carved by a stream ages ago and is now still sometimes
victim to flashfloods. Afterwards, we followed the scenic route, which
made us zigzag between big boulders, on- and off-road.&lt;/p&gt;
&lt;p&gt;In the evening we arrived at
touristy &lt;a href=&#34;http://www.moabcity.state.ut.us/&#34;&gt;Moab&lt;/a&gt;, going to dinner felt
a lot like home, being surrounded by Dutch-speaking people. The
temperature and the view gave away our true location though.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-12-the-long-highway-blog3.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-12-the-long-highway-blog3.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-12-the-long-highway-blog4.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-12-the-long-highway-blog4.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-12-the-long-highway-blog5.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-12-the-long-highway-blog5.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This morning, instead of hiking, we chose another means of
transportation: we rented a UTV (Utility Vehicle). This allowed us to
explore the Sand Flats Recreation Area, maneuvering over slick rocks and
small desert dunes, following a trail of black skid marks. We completed
the Hell’s Revenge Trail, which lives up to its name; it was
frighteningly exciting.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-12-the-long-highway-blog2.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-12-the-long-highway-blog2.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-12-the-long-highway-blog1.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-12-the-long-highway-blog1.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Since this already took up a big chunk of our day and we still had a
four hour drive to Salt Lake City ahead of us, we had to do the &lt;a href=&#34;http://en.wikipedia.org/wiki/Arches_National_Park&#34;&gt;Arches
National Park&lt;/a&gt; scenic
drive in the fast lane.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.youtube.com/watch?v=vdjv__uKSHM&#34;&gt;The long highway&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Stairway to heaven</title>
      <link>https://jefclaes.be/2013/07/stairway-to-heaven.html</link>
      <pubDate>Wed, 10 Jul 2013 07:04:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/07/stairway-to-heaven.html</guid>
      <description>&lt;p&gt;These last two days have been rather tiring. Yesterday we drove up to
&lt;a href=&#34;https://en.wikipedia.org/wiki/Bryce_Canyon_National_Park&#34;&gt;Bryce
Canyon&lt;/a&gt;, where
we did the Queen’s Garden and Navajo Loop hike, which was only 3 miles
(5km) but was rather strenuous because the trail takes you all the way
down and all the way up again.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-10-stairway-to-heaven-blog1.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-10-stairway-to-heaven-blog1.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-10-stairway-to-heaven-blog4.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-10-stairway-to-heaven-blog4.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Today we followed the advice of the kind lady at the visitor center and
hiked along Calfs Creek. It was a 6 miles (10km) round trip through
loose sand in over 100°F (38°C), but halfway you’re rewarded with a
stunningly beautiful waterfall and a refreshing dip in the basin.
Driving up there, we got to witness the grandeur of the Utah plateau.
When we finally got back to the air conditioned car, we made a detour to
see the &lt;a href=&#34;http://en.wikipedia.org/wiki/Grand_Staircase-Escalante_National_Monument&#34;&gt;Grand Staircase – Escalante National
Monument&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-10-stairway-to-heaven-blog2.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-10-stairway-to-heaven-blog2.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-10-stairway-to-heaven-blog3.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-10-stairway-to-heaven-blog3.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-10-stairway-to-heaven-blog5.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-10-stairway-to-heaven-blog5.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.youtube.com/watch?v=8pPvNqOb6RA&#34;&gt;Stairway to heaven&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>She said yes!</title>
      <link>https://jefclaes.be/2013/07/she-said-yes.html</link>
      <pubDate>Tue, 09 Jul 2013 07:42:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/07/she-said-yes.html</guid>
      <description>&lt;p&gt;Since our stay in Vegas was rather short, we selected some things &lt;a href=&#34;http://www.jefclaes.be/2011/09/fear-and-loathing-in-las-vegas.html&#34;&gt;we
failed to do last
time&lt;/a&gt;.
For me, shooting a gun was definitely on that list. Although I&amp;rsquo;m not
that big on gun culture - seems to me that if you live by the gun,
you&amp;rsquo;re more likely to die by the gun - it&amp;rsquo;s still a thrill holding such
a powerful weapon. We headed to Vegas&amp;rsquo;s most popular shooting range: The
Gun Store. At the entrance, I got to pick a gun and a target to point it
at. The heavy &lt;a href=&#34;http://en.wikipedia.org/wiki/IMI_Desert_Eagle&#34;&gt;Desert
Eagle&lt;/a&gt; became my weapon
of choice to blow a zombie&amp;rsquo;s head off. Being guided to the shooting
range by a professional, he ensured that I didn&amp;rsquo;t shoot my foot, and
helped me land five headshots. &lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-09-she-said-yes-blog5.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-09-she-said-yes-blog5.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;span id=&#34;goog_402305940&#34;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;In the evening we got a players card hoping Lady Luck would bend
variance to our benefit for once - those hopes were in vain. It didn&amp;rsquo;t
take too long before we busted our 20$ gambling budget on virtual Poker.
It earned us a free buffet though. We decided to drown our losses at the
lounge with beer and cocktails.&lt;/p&gt;
&lt;p&gt;Checking out late, we set out for &lt;a href=&#34;http://www.nps.gov/cebr/index.htm&#34;&gt;Cedar Breaks National
Monument&lt;/a&gt;. We waited till the evening
to drive up because we were hoping for a clear night sky to do some
stargazing. When we drove off, it was pouring rain, so things weren&amp;rsquo;t
looking up. Reaching the top of the mountain, skies cleared up and a
rainbow appeared. There we were, just the two of us, standing on top of
the world. Finally, after an overcrowded observatory and barely making
the 4th of July fireworks, I got to complete my quest and be freed of
the one ring that had been burning in my backpack for over a week. I
went down on one knee and asked my girlfriend of seven years to marry
me. And she said yes!&lt;br&gt;
We spent the rest of our evening looking at the impressive stellar sky
as a happy newly engaged couple.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-09-she-said-yes-blog4.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-09-she-said-yes-blog4.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-09-she-said-yes-blog2.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-09-she-said-yes-blog2.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-09-she-said-yes-blog3.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-09-she-said-yes-blog3.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-09-she-said-yes-blog1.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-09-she-said-yes-blog1.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Fireworks, Tequila and Silvertown Blues</title>
      <link>https://jefclaes.be/2013/07/fireworks-tequila-and-silvertown-blues.html</link>
      <pubDate>Sun, 07 Jul 2013 06:30:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/07/fireworks-tequila-and-silvertown-blues.html</guid>
      <description>&lt;p&gt;After a strenuous drive from Los Angeles to San Diego, we took advantage
of the mild climate to unwind at San Diego’s
&lt;a href=&#34;http://seaworldparks.com/en/aquatica-sandiego&#34;&gt;Aquatica&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Being the 4&lt;sup&gt;th&lt;/sup&gt; of July, we joined the festivities and watched
the fireworks from the car. Sadly we didn’t get to see a redo of last
year’s spectacle, when &lt;a href=&#34;http://www.youtube.com/watch?v=ndVhgq1yHdA&#34;&gt;San Diego accidentally launched all its
fireworks in 30 seconds&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-07-fireworks-tequila-and-silvertown-blues-blog1.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-07-fireworks-tequila-and-silvertown-blues-blog1.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Next we headed for &lt;a href=&#34;http://en.wikipedia.org/wiki/Joshua_Tree_National_Park&#34;&gt;Joshua Tree National
Park&lt;/a&gt;. With
temperatures flirting with 100°F (38°C), we took on one small hike and
drove up to two viewpoints; Skull Rock and Key’s View. Driving through
cities of the plain in the California desert, we stopped in Barstow for
some Mexican food and Corona, to finally faceplant in our pillows. &lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-07-fireworks-tequila-and-silvertown-blues-blog2.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-07-fireworks-tequila-and-silvertown-blues-blog2.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-07-fireworks-tequila-and-silvertown-blues-blog3.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-07-fireworks-tequila-and-silvertown-blues-blog3.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-07-fireworks-tequila-and-silvertown-blues-blog4.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-07-fireworks-tequila-and-silvertown-blues-blog4.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This morning we got up early to hunt down some ghosts in the silver town
of &lt;a href=&#34;http://cms.sbcounty.gov/parks/Parks/CalicoGhostTown.aspx&#34;&gt;Calico&lt;/a&gt;.
Too bad they couldn’t keep the ghost town more authentic. &lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-07-fireworks-tequila-and-silvertown-blues-blog5.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-07-fireworks-tequila-and-silvertown-blues-blog5.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-07-fireworks-tequila-and-silvertown-blues-blog6.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-07-fireworks-tequila-and-silvertown-blues-blog6.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Tonight: Sin City.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.youtube.com/watch?v=-K8JxgTGrKs&#34;&gt;Fireworks&lt;/a&gt;,
&lt;a href=&#34;http://www.youtube.com/watch?v=tG6P2rBU-ho&#34;&gt;Tequila&lt;/a&gt; and &lt;a href=&#34;http://www.youtube.com/watch?v=OyFYk4p8ABQ&#34;&gt;Silvertown
Blues&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>To Live &amp; Die in L.A.</title>
      <link>https://jefclaes.be/2013/07/to-live-die-in-la.html</link>
      <pubDate>Thu, 04 Jul 2013 08:51:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/07/to-live-die-in-la.html</guid>
      <description>&lt;p&gt;After exploring the USA’s West Coast &lt;a href=&#34;http://www.jefclaes.be/2011/09/once-upon-time-in-west.html&#34;&gt;two years
ago&lt;/a&gt;, we
felt like we had to pay a second visit to fill in some blanks.&lt;/p&gt;
&lt;p&gt;We left Antwerp Sunday 7AM to touch down 25 hours later in LAX, after an
eight hour cross-Atlantic flight to Newark and a six hour overlay
waiting for a connecting flight.&lt;/p&gt;
&lt;p&gt;We were welcomed by a rental car salesman who strongly advised us to
upgrade to a bigger SUV which would give us tinted windows since &lt;em&gt;it’s
gonna be hot, you know&lt;/em&gt;. After politely blowing him off, we drove off to
our first hotel. Arriving at an airport motel, we got to check off the
clichés with a lost empty beer bottle in the room, and us playing ‘the
stained carpet is lava’.&lt;/p&gt;
&lt;p&gt;We started off our first day with a real American breakfast; eggs and
steak. Saturated, we continued our path to the California Science
Center, driving through LA’s colorful suburbs. Arriving there, we found
the highly welcomed Space Shuttle named
&lt;a href=&#34;http://en.wikipedia.org/wiki/Space_Shuttle_Endeavour&#34;&gt;Endeavour&lt;/a&gt; in its
retirement home. We also visited the IMAX theatre, which is always worth
your while. This time we got to see &lt;a href=&#34;http://en.wikipedia.org/wiki/Blue_Planet_(film)&#34;&gt;Blue
Planet&lt;/a&gt;. We followed
this up with a small lunch at LA’s real farmer’s market.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-04-to-live-die-in-l-a-blog1.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-04-to-live-die-in-l-a-blog1.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-04-to-live-die-in-l-a-blog5.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-04-to-live-die-in-l-a-blog5.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Yesterday we took part in a Warner Bros VIP tour. With a group of only
eleven, the guide did a great job making the tour a lot more intimate
than the one Universal offers. Cruising through the outdoor sets, he
emphasized once again how fake everything is. A small patch of grass
serves as Central Park; outdoor stages can be stripped down and rebuilt
to go from 18&lt;sup&gt;th&lt;/sup&gt;century San Francisco to nowadays New York in
a couple of days; leaves are plucked from trees to make it Winter and
sewed back on to fast-forward to Spring; cracks are drilled into new
pavements, and patches of tar are put on, to make them look worn out.
Besides the outdoor stages we got a close look at the Big Bang Theory
set and the retired Friends props, we even got to sit on the famous
couch. Our final look behind the scenes went to the retired car museum,
which was a real treat for me as a Batman fan, since it housed all
Batmobiles, even the Tumbler.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-04-to-live-die-in-l-a-blog6.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-04-to-live-die-in-l-a-blog6.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-04-to-live-die-in-l-a-blog7.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-04-to-live-die-in-l-a-blog7.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;After that, we drove up to Hollywood Boulevard, to be washed over by
thousands of tourists walking around Hollywood’s two most famous
theatres - the Dolby (former Kodak) theatre, and the Chinese theatre –
just to stand where the stars once stood. &lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-04-to-live-die-in-l-a-blog4.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-04-to-live-die-in-l-a-blog4.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;After nightfall we drove up to the observatory, just to put the size of
LA in perspective. We were also hoping for some romance, but so were
hundreds of others apparently.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-04-to-live-die-in-l-a-blog3.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-04-to-live-die-in-l-a-blog3.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Today we left central LA for Santa Monica and Venice Beach. We started
our boardwalk in Venice Beach, embracing beach culture: street
performers, medical marihuana offices, hustlers and amateurs pumping
iron at Muscle Beach.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-07-04-to-live-die-in-l-a-blog2.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-07-04-to-live-die-in-l-a-blog2.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Next up; San Diego.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.youtube.com/watch?v=1Jp20gOwlS4&#34;&gt;To Live &amp;amp; Die in L.A&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Multiplayer Enterprise Architect</title>
      <link>https://jefclaes.be/2013/06/multiplayer-enterprise-architect.html</link>
      <pubDate>Sun, 30 Jun 2013 17:00:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/06/multiplayer-enterprise-architect.html</guid>
      <description>&lt;p&gt;Hanging around in the pub after DDDX, I ended up talking to &lt;a href=&#34;https://twitter.com/ziobrando&#34;&gt;Alberto
Brandolini&lt;/a&gt;. For those who have never met
him; he&amp;rsquo;s very much into visualization. You will always see him carrying
a drawing pad, with a dash of permanent marker on his cheek, and a few
lost sticky notes on his back. I don&amp;rsquo;t know if it was the Italian accent
and the strong gestures, or my mildly intoxicated condition, but the
idea of visualization as an important tool grew on me even more that
evening.&lt;/p&gt;
&lt;p&gt;During the conversation Alberto shared a recent experience where he was
brought in as a facilitator to assist in planning multiple projects
spread over a bunch of teams spanning multiple months. The bottom line
was that with a big wall of paper, some hand drawn boxes, and lots of
sticky notes, they had enabled intense and efficient collaboration,
achieving what upper management had expected to take weeks, in a single
day.&lt;/p&gt;
&lt;p&gt;In my current project, we also could have taken advantage of these
tools. Early on in the project, a team member was charged with the task
of documenting all existing payment file transfers in the company. This
isn&amp;rsquo;t as trivial as it sounds though; these files come in through a
handful of specialized secure gateways, are then transferred internally
by a few different propriety transfer platforms - of which some still
stem from the mainframe era, to be processed, and returned to the
customer through one of the gateways in one of the available output
formats. To make matters worse, all of these systems are owned by
different teams.&lt;br&gt;
We probably tackled this in the worst way possible; with a spreadsheet
and meetings. We could have tried occupying a meeting room, plastering
the wall with paper; drawing all the systems on, and inviting all
involved teams to come in and help us visualize all the transfers
between systems. We could draw arrows between the systems, and stick
post-it notes on top that represent a file with its constraints (source
and destination folders, schedules etc&amp;hellip;).&lt;br&gt;
Too late for that now, but I&amp;rsquo;m curious to set out such an experiment in
the future.&lt;/p&gt;
&lt;p&gt;As you&amp;rsquo;re reading this, I&amp;rsquo;m traveling for three weeks - which I&amp;rsquo;ll
surely write about, and in my backpack are two books that should help
keep me occupied during the flight, and long overlays: &lt;a href=&#34;http://www.amazon.com/gp/product/0470601787/ref=as_li_qf_sp_asin_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0470601787&amp;amp;linkCode=as2&amp;amp;tag=diofanedebyje-20&#34;&gt;Visual
Meetings&lt;/a&gt;,
and &lt;a href=&#34;http://www.amazon.com/gp/product/1591842697/ref=as_li_qf_sp_asin_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=1591842697&amp;amp;linkCode=as2&amp;amp;tag=diofanedebyje-20&#34;&gt;The Back of the
Napkin&lt;/a&gt;.
I&amp;rsquo;m confident there&amp;rsquo;s a lot of value to be found in visualization,
either to make sense of a complex problem, or as a tool to support
collaboration. Going forward I plan to get a lot better at it.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Not handling edge cases, making them explicit instead</title>
      <link>https://jefclaes.be/2013/06/not-handling-edge-cases-making-them.html</link>
      <pubDate>Sun, 23 Jun 2013 16:49:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/06/not-handling-edge-cases-making-them.html</guid>
      <description>&lt;p&gt;When I wrote about &lt;a href=&#34;http://www.jefclaes.be/2013/06/accidental-entities-what-about-ui.html&#34;&gt;accidental
entities&lt;/a&gt;
earlier, we followed a consultant building software for a car rental
company. In the meanwhile, he has finished implementing the registration
of new cars. Next on the list is allowing customers to make a booking.&lt;/p&gt;
&lt;p&gt;We managed to get the CEO to set a whole hour apart to walk us over how
the booking system should work.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;CEO&lt;/strong&gt;: &amp;ldquo;I&amp;rsquo;m not sure this meeting is going to take a whole hour
though. Making a booking is rather trivial. Do you have any idea on how
a booking would work?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Us&lt;/strong&gt;: &amp;ldquo;Well, as far as I understand - and don&amp;rsquo;t be too hard on me - a
customer makes a booking, we allocate the car for the requested period,
send the customer a confirmation email and we&amp;rsquo;re done.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CEO&lt;/strong&gt;: &amp;ldquo;Hold your horses, it&amp;rsquo;s not &lt;em&gt;that&lt;/em&gt; trivial. When we receive a
booking, we first need to verify the customer&amp;rsquo;s credit card.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Us&lt;/strong&gt;: &amp;ldquo;How do I verify a credit card?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CEO&lt;/strong&gt;: &amp;ldquo;You don&amp;rsquo;t. We use a third party electronic verification system
that does just that; they check if the credit card is valid and has
sufficient credit.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Us&lt;/strong&gt;: &amp;ldquo;What happens if the credit card is declined?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CEO&lt;/strong&gt;: &amp;ldquo;That&amp;rsquo;s easy; we just cancel the booking, and inform the
customer.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Us&lt;/strong&gt;: &amp;ldquo;And what happens when the credit card gets verified?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CEO&lt;/strong&gt;: &amp;ldquo;Then we approve the booking.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Us&lt;/strong&gt;: &amp;ldquo;Let me stop you right there. Should we allocate the car
immediately as soon as the customer makes the booking?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CEO&lt;/strong&gt;: &amp;ldquo;Hell no! Verification of the credit card can take a while; we
might lose business if the credit card turns out to get declined.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Us&lt;/strong&gt;: &amp;ldquo;Hmmm, what happens if someone else has made a booking for the
same car in the meanwhile?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CEO&lt;/strong&gt;: &amp;ldquo;That&amp;rsquo;s a good question. In the past, we&amp;rsquo;ve hardly encountered
this problem, but it does happen though; we should probably take care of
this edge case.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Us&lt;/strong&gt;: &amp;ldquo;How do you want to take care of these double bookings? I can
imagine you don&amp;rsquo;t just want to cancel the second booking, and lose
business over this, right?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CEO&lt;/strong&gt;: &amp;ldquo;No, exactly; I like your thinking! There are a few options
here; if they only overlap for 30 minutes or so, we don&amp;rsquo;t do anything.
When the customer comes to get his car, we apologize for the small delay
and offer him a frappuccino to soothe him. If the overlap is bigger, and
we have bigger or more expensive cars just sitting in the parking lot
for that period, we often give the customer a free upgrade. When we
don&amp;rsquo;t have any expensive cars left, we let our best sales person call
the customer, and try to work something out. Sometimes we give them a
small discount, and they&amp;rsquo;ll happily reschedule their plans a few hours
instead of having to look for another rental car. We try to avoid
canceling a booking as much as possible; we want to build a reputation
where we always deliver.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Us&lt;/strong&gt;: &amp;ldquo;Wow, interesting. It&amp;rsquo;s going to cost me some time to get that
right though. You said that this almost never happens. Since deciding on
a good solution for the double booking seems to be non-trivial, how
about we don&amp;rsquo;t handle this edge case right now, but make it explicit
instead? We can mark the booking as double, make the system raise its
hand, and ask for human intervention. Backoffice users already have the
tools, and have the experience to decide on the best solution for the
double booking. Leaving this out for now would also make it possible to
go to market a few weeks earlier.&amp;rdquo; &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CEO&lt;/strong&gt;: &amp;ldquo;I really like this idea; let&amp;rsquo;s keep our first version as lean
as possible. It really doesn&amp;rsquo;t make much sense trying to automate this
right off the bat. It&amp;rsquo;s not like you&amp;rsquo;re cheap, you know. It would be
useful for the system to keep count of every double booking though. Can
we do that?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Us&lt;/strong&gt;: &amp;ldquo;Yep, that shouldn&amp;rsquo;t be too hard.&amp;rdquo;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;After this talk with the CEO, we set out to model the solution in code. &lt;/p&gt;
&lt;p&gt;In our first iteration, a booking has multiple representations, a
representation for each state. One of the advantages of modeling it as
such, is that it allows us to make all possible state changes per
representation explicit; you can&amp;rsquo;t accept a booking if the credit card
hasn&amp;rsquo;t been approved etc&amp;hellip; Alternatives could be the classic state
pattern, or something workflowish, but that isn&amp;rsquo;t really the focus of
this post.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; booking = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Booking(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    bookingId, carId,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Customer(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; CreditCard(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;343705171682875&amp;#34;&lt;/span&gt;), &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; CustomerName(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Jef&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Claes&amp;#34;&lt;/span&gt;)), 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Period(DateTime.Now.AddDays(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;), DateTime.Now.AddDays(&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;)));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; bookingWithVerifiedCreditCard = booking.CreditcardVerified();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; doubleBooking = bookingWithVerifiedCreditCard.Double();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Each state change triggers an event. If we output each event, and run
the snippet above we end up with this.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;(EVENT) BookingCreditCardVerificiationPending
(EVENT) BookingCreditCardVerified
(EVENT) DoubleBooked`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The BookingCreditCardVerified event triggers us to detect doubles.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BookingCreditCardVerifiedHandler&lt;/span&gt; : IHandle&amp;lt;BookingCreditCardVerified&amp;gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; IBus _bus;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; BookingCreditCardVerifiedHandler(IBus bus)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _bus = bus;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Handle(BookingCreditCardVerified @event)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _bus.Send(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; DetectDoubleBooking(@event.BookingId));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If a double booking is detected, we want to make the system raise its
hand, and notify a human. This can be done through an email, a
notification in the backoffice portal, or whatever really.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DoubleBookedHandler&lt;/span&gt; : IHandle&amp;lt;DoubleBooked&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Handle(DoubleBooked @event)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        NotifyHumans();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; NotifyHumans() { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Although, the technical implementation isn&amp;rsquo;t very special, I think it
does show how events can help support the language and distribute
responsibility to where it belongs.&lt;/p&gt;
&lt;p&gt;There is this misconception that because we now have computers, they
should solve &lt;em&gt;all&lt;/em&gt; our problems, even all the edge cases. Edge cases -
by definition - only happen at extreme conditions, and are regularly
hard to take care of in a satisfactory manner, without a considerable
investment. By making edge cases explicit, we allow a human to
intervene, and decide on the best solution for the problem. This way we
can go to market more quickly, with less code, and we might ironically
even end up with happier customers. By collecting statistics on how
often these edge cases occur, we can make a better informed decision on
whether it&amp;rsquo;s worth the investment.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Angular.js and IE8 caching</title>
      <link>https://jefclaes.be/2013/06/angularjs-and-ie8-caching.html</link>
      <pubDate>Sun, 09 Jun 2013 16:52:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/06/angularjs-and-ie8-caching.html</guid>
      <description>&lt;p&gt;Older Internet Explorer versions are notorious for agressively caching
AJAX requests. In this post, you&amp;rsquo;ll find two techniques that combat this
behaviour.&lt;/p&gt;
&lt;p&gt;The first option is to have your server explicitly set the caching
headers.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Response.Cache.SetValidUntilExpires(&lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Response.Cache.SetCacheability(HttpCacheability.NoCache);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Response.Cache.SetNoStore();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Since you don&amp;rsquo;t necessarily own the server, or clients might already
have cached some requests, you can trick the browser into thinking each
request is a fresh one by making each url unique. Our old pal jQuery
already learned &lt;a href=&#34;http://stackoverflow.com/questions/4303829/how-to-prevent-jquery-ajax-caching-in-internet-explorer&#34;&gt;this
trick&lt;/a&gt;
years ago. Angular.js on the other hand seems to have forgotten. We can
get around though.&lt;/p&gt;
&lt;p&gt;If you merge &lt;span id=&#34;goog_2113062658&#34;&gt;&lt;/span&gt;&lt;a href=&#34;https://github.com/angular/angular.js/pull/2130&#34;&gt;this pull
request&lt;/a&gt; &lt;span
id=&#34;goog_2113062659&#34;&gt;&lt;/span&gt;(or wait for angular.js version 1.2), you
will find angular&amp;rsquo;s HTTP provider augmented with request interceptors,
enabling you to mold the request before it goes out.&lt;/p&gt;
&lt;p&gt;The interceptor we&amp;rsquo;re adding to kill the cache only touches GET
requests, appending a &amp;lsquo;cacheSlayer&amp;rsquo; querystring parameter with a
timestamp to each url, making it unique and thus bypassing the cache. A
factory is responsible for creating it, while a config block pushes it
into a collection of interceptors.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;AppInfrastructure&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;angular&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;module&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;App.Infrastructure&amp;#39;&lt;/span&gt;, []);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;AppInfrastructure&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .&lt;span style=&#34;color:#a6e22e&#34;&gt;config&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;$httpProvider&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;$httpProvider&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;requestInterceptors&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;httpRequestInterceptorCacheBuster&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    })    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .&lt;span style=&#34;color:#a6e22e&#34;&gt;factory&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;httpRequestInterceptorCacheBuster&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;promise&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;promise&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;then&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;request&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;method&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;GET&amp;#39;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sep&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;request&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;indexOf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;?&amp;#39;&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;?&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;amp;&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#a6e22e&#34;&gt;request&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;request&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sep&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;cacheSlayer=&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Date().&lt;span style=&#34;color:#a6e22e&#34;&gt;getTime&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;request&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    });    
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I hope this helps someone spending time on more important matters.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Accidental entities - what about the UI?</title>
      <link>https://jefclaes.be/2013/06/accidental-entities-what-about-ui.html</link>
      <pubDate>Sun, 02 Jun 2013 16:24:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/06/accidental-entities-what-about-ui.html</guid>
      <description>&lt;p&gt;This post is a follow-up to my previous blog post &amp;ldquo;&lt;a href=&#34;http://www.jefclaes.be/2013/05/accidental-entities-you-dont-need-that.html&#34;&gt;Accidental entities - you don&amp;rsquo;t need that identity&lt;/a&gt;&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;In that post, we followed a consultant building an application for a car
rental. One of the requirements was that the CEO could manage a
collection of available colors. Although the tools at our disposal - a
relational database and NHibernate - wanted to trick us into making a
car reference one of these available colors by its identifier, we found
out that the CEO really thinks of a car&amp;rsquo;s color as a value, and does not
care about a color&amp;rsquo;s identity. This means that we didn&amp;rsquo;t make a car
reference an available color, but we copied its value instead. This
allows the CEO to remove available colors, without it having an impact
on cars that already came in that color.&lt;/p&gt;
&lt;p&gt;The solution we&amp;rsquo;re building contains a public facing web application
that allows customers to make reservations online, and a backoffice web
application - hosted on the intranet, that employees will use to manage
the cars.&lt;/p&gt;
&lt;p&gt;When a new car arrives at the car rental, a backoffice user will
register it. Once the car is registered - and in use, backoffice users
should still be able to change some of its characteristics; brand,
model, color, engine size, etc&amp;hellip;&lt;/p&gt;
&lt;p&gt;Instinct tells us to add a page that enables editing all the car&amp;rsquo;s
properties. Some of these properties are free text, some radio buttons,
but for the car color, it&amp;rsquo;s a dropdownlist.&lt;br&gt;
Halfway through implementing this new functionality, we notice that
changing the color gets us into trouble. We populate the dropdownlist
with all available colors, but when we want to bind the car&amp;rsquo;s current
color as the selected value, it&amp;rsquo;s not in the list of available colors.
The CEO has removed the car&amp;rsquo;s current color out of the list of available
colors.&lt;br&gt;
After a bit of tinkering, we come up with a workaround that adds the
car&amp;rsquo;s current color to the available colors with a default value of -1.
This allows us to determine if the color needs to be changed.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-06-02-accidental-entities-what-about-the-ui-EditCar.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-06-02-accidental-entities-what-about-the-ui-EditCar.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Relational databases, RAD tools, scaffolding and anemic models have
poisoned our minds, making us throw up the database schema all over the
UI. We can do a lot more though.&lt;br&gt;
If we take a step back, and make an effort to discover what changing
these properties really means to our business users, we might come up
with a totally different user experience.&lt;/p&gt;
&lt;p&gt;We leave the UI as is, and ping the CEO on Lync, inviting her for a
coffee break.&lt;/p&gt;
&lt;p&gt;After a bit of obligatory small talk, we start asking questions about
what we&amp;rsquo;re really after.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Us&lt;/strong&gt;: &amp;ldquo;Can all of the car&amp;rsquo;s characteristics change after the initial
registration?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CEO&lt;/strong&gt;: &amp;ldquo;No, have you ever seen a car change brand, or model through
its lifecycle?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Us&lt;/strong&gt;: &amp;ldquo;I can imagine the engine size also belongs to the list of
characteristics that can&amp;rsquo;t be changed after registration?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CEO&lt;/strong&gt;: &amp;ldquo;Oh, it can! We sometimes have the engine of our sports models
tuned to have an edge over the competition. Guys are crazy for
horsepower.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Us&lt;/strong&gt;: &amp;ldquo;What about changing the color?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CEO&lt;/strong&gt;: &amp;ldquo;If a car has some nasty scratches on it, we sometimes get it
repainted. If we do get it repainted, it&amp;rsquo;s always in one of the colors
available at that moment.&amp;rdquo;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;We return to our desk with a far better understanding of what it really
means to change each of the car&amp;rsquo;s characteristics. We discovered a whole
new language, with some important constraints. Neither brands nor models
change after registration. Engines get tuned, increasing their engine
size. A car&amp;rsquo;s color doesn&amp;rsquo;t change; a car gets repainted - always in one
of the available colors.&lt;/p&gt;
&lt;p&gt;After iterating on this feedback, we&amp;rsquo;re far more satisfied with the
model; it captures the language far better. Our backend implementation
is not the most important part of the solution though; it&amp;rsquo;s useful to
invest in improving the UI.&lt;/p&gt;
&lt;p&gt;After some experimentation we come up with a more &lt;a href=&#34;http://cqrs.wordpress.com/documents/task-based-ui/&#34;&gt;task-based
UI&lt;/a&gt;, something that
looks like this.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-06-02-accidental-entities-what-about-the-ui-EditCarExplicit.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-06-02-accidental-entities-what-about-the-ui-EditCarExplicit.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The UI now does a far better job supporting the language and
communicating its constraints. And with that, we also solved the
original problem that motivated us to ask these extra questions. There
is no value in having the current color in the dropdownlist; we are
better off making the process of having a car repainted explicit.&lt;/p&gt;
&lt;p&gt;When we make an effort to really capture the language, this will be
reflected in our model, but also in the UI. This can add tremendous
value. It&amp;rsquo;s not only about making the user experience more intuitive,
but about making a language consistent for thousands of users,
supporting processes and communication throughout the company.&lt;/p&gt;
&lt;p&gt;As a disclaimer; sometimes it&amp;rsquo;s fine to just throw up your database.
There&amp;rsquo;s a place and time for anything. But don&amp;rsquo;t let CRUD be the only
tool in your toolbox; you can do much more. Make sure to invest this
extra effort where it matters, where it makes a difference.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Accidental entities - you don&#39;t need that identity</title>
      <link>https://jefclaes.be/2013/05/accidental-entities-you-dont-need-that.html</link>
      <pubDate>Sun, 26 May 2013 16:27:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/05/accidental-entities-you-dont-need-that.html</guid>
      <description>&lt;p&gt;An entity is identified by an identifier, while value objects are
identified by their value.&lt;/p&gt;
&lt;p&gt;If I make a living renting cars to tourists, I might not care the least
about the identity of the colors the cars came in. I just care about
their value; Rosso Corsa, Azurro Metallic&amp;hellip; If I repaint the car, the
color changes, and the previous color is abandoned as a whole.&lt;br&gt;
However, if I were a car paint manufacturer, I would care a great deal
about the identity of a color. My first action might be to make up a
marketable name for the color, something that I can identify it with - a
la Burnt Sienna or Iceberg Blue. The color might have a certain
structure from the get-go, but I might experiment with the structure
along the way, while I&amp;rsquo;m still referring to it as the same color.&lt;/p&gt;
&lt;p&gt;Imagine that I&amp;rsquo;m implementing a tool to manage the car rental&amp;rsquo;s fleet,
and that the CEO told me that color is one of the specifications that
seems to matter a lot to their customers. The list of available colors
is rather limited though; black, dark gray, and blue. Yet the CEO
insists on managing this collection by herself; this should avoid having
to call in another expensive consultant a few years down the road.&lt;/p&gt;
&lt;h3 id=&#34;color-as-an-entity&#34;&gt;Color as an entity&lt;/h3&gt;
&lt;p&gt;So we define a collection of colors that will be persisted by
NHibernate. Since NHibernate, and our relational database don&amp;rsquo;t play
nice without a primary key, we add an identifier to the colors.&lt;/p&gt;
&lt;p&gt;We end up with two classes; one entity that defines a color, and another
entity that defines a car. A car references a color.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Car&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Car(Color color) 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (color == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ArgumentNullException(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;color&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Color = color;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; Car() { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;virtual&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; Id { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;virtual&lt;/span&gt; Color Color { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; Equals(&lt;span style=&#34;color:#66d9ef&#34;&gt;object&lt;/span&gt; obj)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (obj == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; car = obj &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; Car;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (car == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; car.Id == Id;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; GetHashCode()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Id.GetHashCode();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Color&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Color(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; name, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; hexadecimalNotation)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.IsNullOrEmpty(name))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ArgumentNullException(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.IsNullOrEmpty(hexadecimalNotation))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ArgumentNullException(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hexadecimalNotation&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Name = name;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        HexadecimalNotation = hexadecimalNotation;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; Color() { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;virtual&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; Id { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;virtual&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; Name { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;virtual&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; HexadecimalNotation { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; Equals(&lt;span style=&#34;color:#66d9ef&#34;&gt;object&lt;/span&gt; obj)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (obj == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; color = obj &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; Color;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (color == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; color.Id == Id;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; GetHashCode()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Id.GetHashCode();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CarClassMap&lt;/span&gt; : ClassMap&amp;lt;Car&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; CarClassMap()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Id(x =&amp;gt; x.Id).GeneratedBy.HiLo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        References(x =&amp;gt; x.Color);          
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ColorClassMap&lt;/span&gt; : ClassMap&amp;lt;Color&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; ColorClassMap()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Id(x =&amp;gt; x.Id).GeneratedBy.HiLo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Map(x =&amp;gt; x.Name).Length(&lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;).Not.Nullable();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Map(x =&amp;gt; x.HexadecimalNotation).Length(&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;).Not.Nullable();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The generated schema looks like this.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-05-26-accidental-entities-you-dont-need-that-identity-V1.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-05-26-accidental-entities-you-dont-need-that-identity-V1.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And while this looks innocent at first, accidentally creating an entity
raises a bunch of new concerns and questions. What happens if a color is
no longer available, and the CEO wants to remove it from the collection?
Does that mean we should delete all models that came in this color? No,
those colors still exist, we&amp;rsquo;re not going to repaint all the vehicles;
those colors just aren&amp;rsquo;t available anymore. This hints towards a concept
that might be missing.&lt;/p&gt;
&lt;h3 id=&#34;fighting-symptoms&#34;&gt;Fighting symptoms&lt;/h3&gt;
&lt;p&gt;We see the CEO heading over to the cafeteria, so we jump up, and ask
her whether it makes sense for her to mark those colors as unavailable,
instead of deleting them. After a short delay she shrugs and replies:
&amp;ldquo;Well, I could do that if that makes things easier for you.&amp;rdquo; We go ahead
and model our solution to reflect this new information. &lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Color&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Color(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; name, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; hexadecimalNotation)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.IsNullOrEmpty(name))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ArgumentNullException(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.IsNullOrEmpty(hexadecimalNotation))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ArgumentNullException(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hexadecimalNotation&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Name = name;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        HexadecimalNotation = hexadecimalNotation;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Available = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; Color() { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;virtual&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; Id { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;virtual&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; Name { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;virtual&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; HexadecimalNotation { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;virtual&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; Available { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;virtual&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; MakeUnavailable() 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Available = &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; Equals(&lt;span style=&#34;color:#66d9ef&#34;&gt;object&lt;/span&gt; obj)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (obj == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; color = obj &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; Color;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (color == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; color.Id == Id;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; GetHashCode()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Id.GetHashCode();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A few days later we show off what we came up with to the CEO. She looks
content with what we built over the last few days, until we show her the
user interface that manages the colors. &amp;ldquo;I&amp;rsquo;m rather busy so I often make
mistakes when I take care of these administrative tasks, could you add a
button to really delete a color from this list anyway?&amp;rdquo; This brings us
back to square one. First thing we think about is soft deleting the
colors. We could also only make it possible to remove a color if it
hasn&amp;rsquo;t been referenced yet. A voice in the back of our heads keeps
telling us that we must be missing something though, and that this seems
to be harder than it should be. A few hours later, driving home after a
tough day, it becomes obvious that the CEO really thinks of a color as a
value instead of an entity, so we should really be modeling it as
such.&lt;/p&gt;
&lt;h3 id=&#34;color-as-a-component&#34;&gt;Color as a component&lt;/h3&gt;
&lt;p&gt;Luckily, NHibernate makes this pretty simple. The next day, we arrive
early at the office, and change our mapping to use a
&lt;a href=&#34;http://ayende.com/blog/3937/nhibernate-mapping-component&#34;&gt;component&lt;/a&gt;,
so that instead of the car referencing a color, we store the value, and
lose the id.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CarClassMap&lt;/span&gt; : ClassMap&amp;lt;Car&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; CarClassMap()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Id(x =&amp;gt; x.Id).GeneratedBy.HiLo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Component(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            x =&amp;gt; x.Color,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            m =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                m.Map(x =&amp;gt; x.Name).Column(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ColorName&amp;#34;&lt;/span&gt;).Length(&lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;).Not.Nullable();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                m.Map(x =&amp;gt; x.HexadecimalNotation).Column(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ColorHex&amp;#34;&lt;/span&gt;).Length(&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;).Not.Nullable();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The generated schema now looks like this; we&amp;rsquo;re no longer referencing
the Color table.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-05-26-accidental-entities-you-dont-need-that-identity-V2.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-05-26-accidental-entities-you-dont-need-that-identity-V2.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;When we store a color now, it&amp;rsquo;s an entity. But as soon as we put it on a
car, it&amp;rsquo;s a value object. When we pull the car back out of our
persistence store, we have lost the identity. We should modify our code
so that the color&amp;rsquo;s behaviour reflects these changes. We modify the
default constructor so that the object gets initialized with a default
identifier. The default constructor will get used by NHibernate when it
hydrates the object after getting it out the persistence store. We
override the Equals and GetHashCode methods so that the identifiers are
compared when there&amp;rsquo;s an identity, but when the identifier isn&amp;rsquo;t
hydrated, the values are compared.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Color&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Color(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; name, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; hexadecimalNotation)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.IsNullOrEmpty(name))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ArgumentNullException(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.IsNullOrEmpty(hexadecimalNotation))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ArgumentNullException(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hexadecimalNotation&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Name = name;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        HexadecimalNotation = hexadecimalNotation;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; Color() 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Id = -&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;virtual&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; Id { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;virtual&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; Name { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;virtual&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; HexadecimalNotation { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; Equals(&lt;span style=&#34;color:#66d9ef&#34;&gt;object&lt;/span&gt; obj)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (obj == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; color = obj &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; Color;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (color == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (Id != -&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Id == color.Id;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Name == color.Name &amp;amp;&amp;amp; HexadecimalNotation == color.HexadecimalNotation;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; GetHashCode()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (Id != -&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Id.GetHashCode();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Name.GetHashCode() &amp;amp; HexadecimalNotation.GetHashCode();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This feels off though; using one concept in two different contexts makes
things rather confusing. Is color an entity, or value object? Or does it
depend?&lt;/p&gt;
&lt;h3 id=&#34;separate-concepts&#34;&gt;Separate concepts&lt;/h3&gt;
&lt;p&gt;We extract two explicit concepts instead; a color as a value object,
and an available color as an entity. &lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;AvailableColor&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; AvailableColor(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; name, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; hexadecimalNotation)            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.IsNullOrEmpty(name))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ArgumentNullException(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.IsNullOrEmpty(hexadecimalNotation))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ArgumentNullException(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hexadecimalNotation&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Name = name;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        HexadecimalNotation = hexadecimalNotation;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; AvailableColor()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;virtual&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; Id { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;virtual&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; Name { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;virtual&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; HexadecimalNotation { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;explicit&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;operator&lt;/span&gt; Color(AvailableColor &lt;span style=&#34;color:#66d9ef&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Color(&lt;span style=&#34;color:#66d9ef&#34;&gt;value&lt;/span&gt;.Name, &lt;span style=&#34;color:#66d9ef&#34;&gt;value&lt;/span&gt;.HexadecimalNotation);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; Equals(&lt;span style=&#34;color:#66d9ef&#34;&gt;object&lt;/span&gt; obj)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (obj == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; color = obj &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; AvailableColor;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (color == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; color.Id == Id;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; GetHashCode()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Id.GetHashCode();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Color&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Color(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; name, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; hexadecimalNotation)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.IsNullOrEmpty(name))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ArgumentNullException(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.IsNullOrEmpty(hexadecimalNotation))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ArgumentNullException(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hexadecimalNotation&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Name = name;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        HexadecimalNotation = hexadecimalNotation;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; Color()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;virtual&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; Name { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;virtual&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; HexadecimalNotation { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; Equals(&lt;span style=&#34;color:#66d9ef&#34;&gt;object&lt;/span&gt; obj)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (obj == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; color = obj &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; Color;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (color == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Name == color.Name &amp;amp;&amp;amp; HexadecimalNotation == color.HexadecimalNotation;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; GetHashCode()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Name.GetHashCode() &amp;amp; HexadecimalNotation.GetHashCode();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This looks better. We now have two explicit concepts. An explicit
conversion allows you to get a color out of an available color, losing
the identifier.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; availableColorOrange = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; AvailableColor(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Orange&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;#CC3232&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; car = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Car((Color)availableColorOrange);                    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Console.WriteLine(car.Color.Equals(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Color(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Orange&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;#CC3232&amp;#34;&lt;/span&gt;))); &lt;span style=&#34;color:#75715e&#34;&gt;// true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;We meet up with the CEO one last time, and show her what we reworked.
When we demo how she can manage the collection of available colors by
just adding and deleting them - without caring whether one of the cars
came in that color, a smile shows up on her face; &amp;ldquo;This is exactly what
I needed, it really shouldn&amp;rsquo;t be harder than this.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Tools often trick us into creating entities. These accidental entities
then go on to introduce expensive coupling, introducing questions and
problems that could easily be avoided by copying values around
instead.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Next week: but what about the UI?&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Validating composite models with knockout validation</title>
      <link>https://jefclaes.be/2013/05/validating-composite-models-with.html</link>
      <pubDate>Mon, 20 May 2013 17:02:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/05/validating-composite-models-with.html</guid>
      <description>&lt;p&gt;When you use &lt;a href=&#34;https://github.com/Knockout-Contrib/Knockout-Validation&#34;&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;/p&gt;
&lt;p&gt;To extract all of the error messages out of a composite model, you can
use a grouping function.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BookingModel&lt;/span&gt;() {      
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;contact&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ContactModel&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;departure&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DepartureModel&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;isValid&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;contact&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;isValid&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;departure&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;isValid&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;validate&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {                           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;isValid&lt;/span&gt;()) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;errors&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;validation&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;group&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;);                           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;errors&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;showAllMessages&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;          
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };                    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DepartureModel&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;street&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({ &lt;span style=&#34;color:#a6e22e&#34;&gt;required&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;houseNumber&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({ &lt;span style=&#34;color:#a6e22e&#34;&gt;required&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;city&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({ &lt;span style=&#34;color:#a6e22e&#34;&gt;required&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({ &lt;span style=&#34;color:#a6e22e&#34;&gt;required&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; });            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;isValid&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;street&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;isValid&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;houseNumber&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;isValid&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;city&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;isValid&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;isValid&lt;/span&gt;();                
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ContactModel&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;firstName&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({ &lt;span style=&#34;color:#a6e22e&#34;&gt;required&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;lastName&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({ &lt;span style=&#34;color:#a6e22e&#34;&gt;required&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;phoneNumber&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;firstName&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({ &lt;span style=&#34;color:#a6e22e&#34;&gt;required&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;email&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({ &lt;span style=&#34;color:#a6e22e&#34;&gt;required&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; });   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;isValid&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;firstName&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;isValid&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;lastName&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;isValid&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;phoneNumber&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;isValid&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;email&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;isValid&lt;/span&gt;();                
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&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 &lt;code&gt;validatedObservable&lt;/code&gt; function instead.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;applyBindings&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;validatedObservable&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BookingModel&lt;/span&gt;()));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;validatedObservable&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;initialValue&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;exports&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;utils&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;isObject&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;initialValue&lt;/span&gt;)) { 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;initialValue&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({ &lt;span style=&#34;color:#a6e22e&#34;&gt;validatable&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; }); }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;obsv&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;initialValue&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;obsv&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;errors&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;exports&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;group&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;initialValue&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;obsv&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;isValid&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;computed&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;obsv&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;errors&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;obsv&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;validatedObservable&lt;/code&gt; 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 &lt;code&gt;showAllMessages&lt;/code&gt;
function that will display an error message next to each invalid
element. The &lt;code&gt;isValid&lt;/code&gt; function only asserts if there are any errors.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BookingModel&lt;/span&gt;() {      
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;contact&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ContactModel&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;departure&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DepartureModel&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;validate&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {                           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;isValid&lt;/span&gt;()) {                                         
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;errors&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;showAllMessages&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;          
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };             
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DepartureModel&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;street&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({ &lt;span style=&#34;color:#a6e22e&#34;&gt;required&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;houseNumber&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({ &lt;span style=&#34;color:#a6e22e&#34;&gt;required&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;city&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({ &lt;span style=&#34;color:#a6e22e&#34;&gt;required&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({ &lt;span style=&#34;color:#a6e22e&#34;&gt;required&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; });            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ContactModel&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;firstName&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({ &lt;span style=&#34;color:#a6e22e&#34;&gt;required&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;lastName&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({ &lt;span style=&#34;color:#a6e22e&#34;&gt;required&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;phoneNumber&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;firstName&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({ &lt;span style=&#34;color:#a6e22e&#34;&gt;required&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;email&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;extend&lt;/span&gt;({ &lt;span style=&#34;color:#a6e22e&#34;&gt;required&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; });        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Removing that cruft results in less bulky, cheaper models.&lt;/p&gt;
&lt;p&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;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ko&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;validation&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;init&lt;/span&gt;({ &lt;span style=&#34;color:#a6e22e&#34;&gt;grouping&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; { &lt;span style=&#34;color:#a6e22e&#34;&gt;deep&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;observable&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; } });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>IDDD Tour notes (2/2)</title>
      <link>https://jefclaes.be/2013/05/iddd-tour-notes-22.html</link>
      <pubDate>Sun, 12 May 2013 15:44:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/05/iddd-tour-notes-22.html</guid>
      <description>&lt;p&gt;This is the second and last part of my notes I scribbled down attending
the IDDD Tour. &lt;a href=&#34;http://www.jefclaes.be/2013/05/iddd-tour-notes-12.html&#34;&gt;The first
part&lt;/a&gt; was
published last week.&lt;/p&gt;
&lt;h3 id=&#34;a-better-model&#34;&gt;A better model&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&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;/p&gt;
&lt;/blockquote&gt;
&lt;p&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&amp;rsquo;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;/p&gt;
&lt;h3 id=&#34;elegance&#34;&gt;Elegance&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Elegance is for dressing, not for delivering software.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is one to remember; I&amp;rsquo;ll be using this one next time someone uses
elegance as an argument for gold plating.&lt;/p&gt;
&lt;h3 id=&#34;cultivating-models&#34;&gt;Cultivating models&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Models grow; you will never have the best model from the start.
Improve them every time you pass by.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Your first attempt at it is hardly ever right. Don&amp;rsquo;t beat yourself up
over it. The best models are the result of multiple iterations. 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. 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;/p&gt;
&lt;h3 id=&#34;reuse&#34;&gt;Reuse&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Lots of people use a shared kernel just for reuse. It&amp;rsquo;s often not
worth it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&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;/p&gt;
&lt;h3 id=&#34;rest-and-ddd&#34;&gt;REST and DDD&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Don&amp;rsquo;t expose your domain model over REST: expose use cases. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&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;/p&gt;
&lt;h3 id=&#34;published-language&#34;&gt;Published language&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;How is the language agreed upon; over lunch or by a committee?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt; A great question which reveals if a language should be really
considered as published.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;And that&amp;rsquo;s the last of it. If you thought some of these were
interesting, you should probably &lt;a href=&#34;http://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&#34;&gt;get the
book&lt;/a&gt;.
I finished &lt;a href=&#34;http://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&#34;&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;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>IDDD Tour notes (1/2)</title>
      <link>https://jefclaes.be/2013/05/iddd-tour-notes-12.html</link>
      <pubDate>Sun, 05 May 2013 17:10:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/05/iddd-tour-notes-12.html</guid>
      <description>&lt;p&gt;Two weeks ago I got to spend four days attending the &lt;a href=&#34;http://idddtour.com/&#34;&gt;IDDD
Tour&lt;/a&gt; by &lt;a href=&#34;https://twitter.com/VaughnVernon&#34;&gt;Vaughn
Vernon&lt;/a&gt;. Although my book queue has
only allowed me to shallowly browse &lt;a href=&#34;http://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&#34;&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=&#34;https://twitter.com/ziobrando&#34;&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&amp;rsquo;m grateful to those who
got this show on the road; it was more than worth your trouble.&lt;/p&gt;
&lt;p&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&amp;rsquo;s where
I acquired most new insights.&lt;/p&gt;
&lt;h3 id=&#34;complexity&#34;&gt;Complexity&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;If we really understood the complexity of a system, we would very
often make different decisions from when designing new systems. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&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&amp;rsquo;t sabotage growing your design by picking an architecture or
framework that doesn&amp;rsquo;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&amp;hellip;&lt;/p&gt;
&lt;h3 id=&#34;change&#34;&gt;Change&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&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;/p&gt;
&lt;/blockquote&gt;
&lt;p&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;/p&gt;
&lt;h3 id=&#34;brown&#34;&gt;Brown&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;There is always brown, even when it&amp;rsquo;s under the green. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&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;/p&gt;
&lt;h3 id=&#34;another-brick-in-the-wall&#34;&gt;Another brick in the wall&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Break down that paper wall between domain experts and developers.
Learn the favorite coffee of the domain expert.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Lots of organizations still build this paper wall between domain experts
and developers. But paper doesn&amp;rsquo;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;/p&gt;
&lt;h3 id=&#34;one-language&#34;&gt;One language&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Which language do you use when naming things in code? Yours. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I don&amp;rsquo;t think native English speakers understand just how awkward it is
to write code in something other than English. Keywords, API&amp;rsquo;s,
documentation&amp;hellip; it&amp;rsquo;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&amp;hellip; but use their mother tongue in
scenarios where nuances would be lost in translation. This seems to be
an attractive compromise.&lt;/p&gt;
&lt;h3 id=&#34;defining-a-bounded-context&#34;&gt;Defining a bounded context&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;A bounded context is where one ubiquitous language is consistent.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is by far the simplest definition of a bounded context. &lt;span
class=&#34;Apple-tab-span&#34; style=&#34;white-space: pre;&#34;&gt; &lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&#34;bounded-context-relations&#34;&gt;Bounded context relations&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;You say please, so I am upstream.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The &lt;a href=&#34;http://www.markhneedham.com/blog/2009/03/30/ddd-recognising-relationships-between-bounded-contexts/&#34;&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;/p&gt;
&lt;h3 id=&#34;rewrites&#34;&gt;Rewrites&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;When you rewrite an application, you have to look at the existing
forces in an organization; chances are the previous team wasn&amp;rsquo;t
terrible either.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Tons of factors influence the outcome of a project; it&amp;rsquo;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&amp;hellip; So don&amp;rsquo;t assume your rewrite
will fix everything.&lt;/p&gt;
&lt;h3 id=&#34;surprise&#34;&gt;Surprise&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Adding surprise value is often not that valuable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This seems to be related to the mantra of &amp;lsquo;good enough&amp;rsquo;. 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;/p&gt;
&lt;p&gt;&lt;em&gt;These were some notes I wrote down the first two days. I&amp;rsquo;ll try to go
through the other half over these next few days. I hope you found some
of them valuable too.&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Designing entities: immutability first</title>
      <link>https://jefclaes.be/2013/04/designing-entities-immutability-first.html</link>
      <pubDate>Sun, 07 Apr 2013 17:35:00 +0200</pubDate>
      <guid>https://jefclaes.be/2013/04/designing-entities-immutability-first.html</guid>
      <description>&lt;p&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&amp;rsquo; and outs&amp;rsquo; of a proprietary UI
technology.&lt;/p&gt;
&lt;p&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;/p&gt;
&lt;p&gt;Allow me to demonstrate this using a customer entity - I know this is
cliché, but I have a hard time coming up with original examples.&lt;/p&gt;
&lt;h3 id=&#34;a-constructor&#34;&gt;A constructor&lt;/h3&gt;
&lt;p&gt;This one might sound rather obvious, but you would be surprised how many
classes don&amp;rsquo;t have the decency of a simple constructor, especially since
C# introduced &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/vstudio/bb384062.aspx&#34;&gt;object
initializers&lt;/a&gt;.
While object initializers definitely look good, they make your code
harder to maintain; classes don&amp;rsquo;t communicate what they need to get by,
nor do they get the opportunity to protect their invariants as early as
possible.&lt;/p&gt;
&lt;p&gt;Like I said, I design my classes to be immutable from the start; after
initialization they can&amp;rsquo;t be modified. I&amp;rsquo;m not even exposing any state
for now.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Customer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Customer(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guid id,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; firstName,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; lastName,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; street,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; city,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; country,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        DateTime birthdate,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;decimal&lt;/span&gt; balance)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        FirstName = firstName;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        LastName = lastName;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Street = street;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        City = city;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Country = country;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        BirthDate = birthdate;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Balance = balance;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Guid Id { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; FirstName { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; LastName { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; Street { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; City { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; Country { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; DateTime BirthDate { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;decimal&lt;/span&gt; Balance { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;comparing-identities&#34;&gt;Comparing identities&lt;/h3&gt;
&lt;p&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&amp;rsquo;re not guided
into doing this by our object&amp;rsquo;s immutability though, but by common
sense.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; Equals(&lt;span style=&#34;color:#66d9ef&#34;&gt;object&lt;/span&gt; obj)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (obj == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt; || GetType() != obj.GetType())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; other = obj &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; Customer;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Id == other.Id;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; GetHashCode()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.Id.GetHashCode();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;defaults&#34;&gt;Defaults&lt;/h3&gt;
&lt;p&gt;When a new customer is created, its balance is still empty. The
constructor is the perfect place to initialize this default.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Customer(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Guid id,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; firstName,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; lastName,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; street,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; city,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; country,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    DateTime birthdate)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    FirstName = firstName;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    LastName = lastName;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Street = street;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    City = city;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Country = country;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    BirthDate = birthdate;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Balance = &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;protecting-invariants&#34;&gt;Protecting invariants&lt;/h2&gt;
&lt;p&gt;The next thing I&amp;rsquo;ll do is use the constructor to guard for arguments
that don&amp;rsquo;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;/p&gt;
&lt;p&gt;We expect a customer to have a first name, last name, street, city and
country which isn&amp;rsquo;t empty. We also expect its birth date not to be in
the future.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Customer(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Guid id,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; firstName,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; lastName,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; street,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; city,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; country,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    DateTime birthdate)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Guard.ForNullOrEmpty(firstName, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;first name&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Guard.ForNullOrEmpty(lastName, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;last name&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Guard.ForNullOrEmpty(street, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;street&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Guard.ForNullOrEmpty(city, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;city&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Guard.ForNullOrEmpty(country, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;country&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Guard.ForDatesInTheFuture(birthdate, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;birthdate&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Id = id;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    FirstName = firstName;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    LastName = lastName;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Street = street;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    City = city;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Country = country;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    BirthDate = birthdate;            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Balance = &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Guard&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; ForNullOrEmpty(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;value&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; desc)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.IsNullOrEmpty(&lt;span style=&#34;color:#66d9ef&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; NullReferenceException(desc);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; ForDateInTheFuture(DateTime &lt;span style=&#34;color:#66d9ef&#34;&gt;value&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; desc)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;value&lt;/span&gt; &amp;gt; DateTimeProvider.Now())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ArgumentException(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.Format(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{0} can&amp;#39;t be a date in the future.&amp;#34;&lt;/span&gt;, desc))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;composition-and-extracting-value-objects&#34;&gt;Composition and extracting value objects&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;m fairly confident that every self-respecting programmer is annoyed
by the fact that the obvious concepts name and address haven&amp;rsquo;t been
extracted yet. Especially since that bloated constructor is all up in
your face. Let&amp;rsquo;s go ahead and extract two value objects: name and
address.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Customer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Customer(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guid id,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Name name,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Address address,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        DateTime birthdate)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNull(name, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNull(address, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;address&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForDateInTheFuture(birthdate, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;birthdate&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Id = id;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Name = name;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Address = address;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Balance = &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Guid Id { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Name Name { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Address Address { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; DateTime BirthDate { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;decimal&lt;/span&gt; Balance { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Name(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; first, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; last)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNullOrEmpty(first, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;first name&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNullOrEmpty(last, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;last name&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        First = first;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Last = last;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; First { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; Last { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; Full 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.Format(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{0} {1}&amp;#34;&lt;/span&gt;, First, Last);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; Equals(Object obj)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; GetHashCode()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Address&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Address(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; street, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; city, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; country)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNullOrEmpty(street, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;street&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNullOrEmpty(city, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;city&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNullOrEmpty(country, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;country&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Street = street;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        City = city;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Country = country;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; Street { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; City { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; Country { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; Equals(Object obj)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; GetHashCode()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There, that looks better.&lt;/p&gt;
&lt;h3 id=&#34;tell-dont-ask&#34;&gt;Tell, don&amp;rsquo;t ask&lt;/h3&gt;
&lt;p&gt;In good OOP we tell objects what to do, we don&amp;rsquo;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;/p&gt;
&lt;p&gt;Since our immutable object isn&amp;rsquo;t exposing any state yet, we are forced
to ask ourselves why we want to expose something. This way, disregarding
&amp;ldquo;tell don&amp;rsquo;t ask&amp;rdquo; becomes a deliberate choice.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;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;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (!customer.HasSufficientFunds())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; InsufficientFundsException();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s better to encapsulate data and behaviour, and tell it what to do
instead.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Customer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Customer(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guid id,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Name name,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Address address,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        DateTime birthdate)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNull(name, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNull(address, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;address&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForDateInTheFuture(birthdate, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;birthdate&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Id = id;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Name = name;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Address = address;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Balance = &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Guid Id { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Name Name { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Address Address { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; DateTime BirthDate { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;decimal&lt;/span&gt; Balance { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; HasSufficientFunds(&lt;span style=&#34;color:#66d9ef&#34;&gt;decimal&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;value&lt;/span&gt;) 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Balance - &lt;span style=&#34;color:#66d9ef&#34;&gt;value&lt;/span&gt; &amp;gt;= &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; DecreaseBalance(&lt;span style=&#34;color:#66d9ef&#34;&gt;decimal&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (HasSufficientFunds(&lt;span style=&#34;color:#66d9ef&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; InsufficientFundsException();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Balance -= &lt;span style=&#34;color:#66d9ef&#34;&gt;value&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;making-operations-explicit&#34;&gt;Making operations explicit&lt;/h3&gt;
&lt;p&gt;Next thing we want to do is change the address of a customer. Since
we&amp;rsquo;re not exposing the address property directly, we&amp;rsquo;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;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Customer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Customer(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guid id,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Name name,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Address address,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        DateTime birthdate)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNull(name, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNull(address, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;address&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForDateInTheFuture(birthdate, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;birthdate&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Id = id;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Name = name;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Address = address;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Balance = &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Guid Id { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Name Name { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Address Address { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; DateTime BirthDate { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;decimal&lt;/span&gt; Balance { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; MoveTo(Address newAddress)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNull(newAddress, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;new address&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Address = newAddress;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; customer = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Customer(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Guid.NewGuid(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Name(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Jef&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Claes&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Address(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Ergens&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Antwerp&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Belgium&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; DateTime(&lt;span style=&#34;color:#ae81ff&#34;&gt;1987&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;18&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;customer.MoveTo(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Address(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Quelque part&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Brussels&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Belgium&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;opening-up-bit-by-bit&#34;&gt;Opening up bit by bit&lt;/h3&gt;
&lt;p&gt;In the meanwhile our entity is no longer immutable, but we&amp;rsquo;re doing a
good job of not exposing any state. If you&amp;rsquo;re using the same model for
reads as you do for writes, you&amp;rsquo;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 &amp;ldquo;Tell, don&amp;rsquo;t
ask&amp;rdquo; since that became a lot easier now.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Customer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Customer(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guid id,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Name name,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Address address,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        DateTime birthdate)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNull(name, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNull(address, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;address&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForDateInTheFuture(birthdate, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;birthdate&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Id = id;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Name = name;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Address = address;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Balance = &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Guid Id { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Name Name { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Address Address { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; DateTime BirthDate { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;decimal&lt;/span&gt; Balance { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; HasSufficientFunds(&lt;span style=&#34;color:#66d9ef&#34;&gt;decimal&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;value&lt;/span&gt;) 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Balance - &lt;span style=&#34;color:#66d9ef&#34;&gt;value&lt;/span&gt; &amp;gt;= &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; DecreaseBalance(&lt;span style=&#34;color:#66d9ef&#34;&gt;decimal&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;value&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (HasSufficientFunds(&lt;span style=&#34;color:#66d9ef&#34;&gt;value&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; InsufficientFundsException();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Balance -= &lt;span style=&#34;color:#66d9ef&#34;&gt;value&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; MoveTo(Address newAddress)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNull(newAddress, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;new address&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Address = newAddress;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;summarized&#34;&gt;Summarized&lt;/h3&gt;
&lt;p&gt;By making my entities immutable from the start I am guided into adhering
to a bunch of good practices:&lt;/p&gt;
&lt;ul&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&amp;rsquo;t ask &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;
</description>
    </item>
    
    <item>
      <title>Reading large files in chunks with proper encapsulation</title>
      <link>https://jefclaes.be/2013/03/reading-large-files-in-chunks-with.html</link>
      <pubDate>Sun, 24 Mar 2013 18:16:00 +0100</pubDate>
      <guid>https://jefclaes.be/2013/03/reading-large-files-in-chunks-with.html</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been doing some work lately which involves sequentially reading
large files (&amp;gt; 2 to 5GB). This entails that it&amp;rsquo;s not an option to
read the whole structure in memory; it&amp;rsquo;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;/p&gt;
&lt;p&gt;There is no reason to let it come to this though; you can use the often
overlooked &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/vstudio/9k7k7cf0.aspx&#34;&gt;yield return
keyword&lt;/a&gt;
to improve encapsulation.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&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;/p&gt;
&lt;/blockquote&gt;
&lt;p&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;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Reader&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; _chunkSize;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Reader(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; chunkSize) 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _chunkSize = chunkSize;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; IEnumerable&amp;lt;Chunk&amp;gt; Read(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; path)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.IsNullOrEmpty(path))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; NullReferenceException(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;path&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; lines = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; List&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; reader = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; StreamReader(path))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; line;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; ((line = reader.ReadLine()) != &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                lines.Add(line);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (lines.Count == _chunkSize)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#66d9ef&#34;&gt;yield&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Chunk(lines);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    lines.Clear();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }                
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;yield&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Chunk(lines);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Chunk&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Chunk(List&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&amp;gt; lines) 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Lines = lines;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; List&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&amp;gt; Lines { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And that&amp;rsquo;s one way to achieve clean encapsulation without starving your
machine&amp;rsquo;s memory.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; reader = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Reader(chunkSize: &lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; chunks = reader.Read(&lt;span style=&#34;color:#e6db74&#34;&gt;@&amp;#34;C:\big_file.txt&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; chunk &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; chunks)            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Console.WriteLine(chunk.Lines.Count);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>Putting my IronMQ experiment under stress</title>
      <link>https://jefclaes.be/2013/03/putting-my-ironmq-experiment-under.html</link>
      <pubDate>Sun, 17 Mar 2013 16:10:00 +0100</pubDate>
      <guid>https://jefclaes.be/2013/03/putting-my-ironmq-experiment-under.html</guid>
      <description>&lt;p&gt;Two weeks ago, &lt;a href=&#34;http://www.jefclaes.be/2013/03/first-ironmq-impressions.html&#34;&gt;I shared my first impressions of
IronMQ&lt;/a&gt;.
Last week, &lt;a href=&#34;http://www.jefclaes.be/2013/03/some-experimental-infrastructure-for.html&#34;&gt;I looked at some infrastructure to facilitate pulling from
IronMQ&lt;/a&gt;.
This implementation worked, but I hadn&amp;rsquo;t put it under stress yet; &amp;ldquo;First
make it work, then make it fast&amp;rdquo;, and all of that.&lt;/p&gt;
&lt;p&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;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MessageSleepForOneSecond&lt;/span&gt; { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MessageSleepForOneSecondHandler&lt;/span&gt; : IMessageHandler&amp;lt;MessageSleepForOneSecond&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Handle(MessageSleepForOneSecond message)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Thread.Sleep(&lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&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;/p&gt;
&lt;p&gt;The constraint in this story is the &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.threading.threadpool.aspx&#34;&gt;CLR&amp;rsquo;s thread
pool&lt;/a&gt;.
Every time a queue consumer&amp;rsquo;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&amp;rsquo;re all in use, it will
have to start new ones, which is rather expensive. More importantly
though, when you&amp;rsquo;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&amp;rsquo;t do you any good.&lt;/p&gt;
&lt;p&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;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IQueueConsumerConfiguration&lt;/span&gt;&amp;lt;T&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; PollingInterval { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; BatchSize { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; messages = (IEnumerable&amp;lt;Message&amp;gt;)&lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (!_queue.TryGet(&lt;span style=&#34;color:#66d9ef&#34;&gt;out&lt;/span&gt; messages, _queueConsumerConfiguration.BatchSize))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; message &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; messages)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; messageBody = (T)JsonConvert.DeserializeObject(message.Body, &lt;span style=&#34;color:#66d9ef&#34;&gt;typeof&lt;/span&gt;(T));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            _messageDispatcher.Dispatch&amp;lt;T&amp;gt;(messageBody);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            _queue.Delete(message.Id);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (Exception ex)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            _errorHandler.Handle(ex, message);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (Exception ex)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    _errorHandler.Handle(ex, &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}                
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&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&amp;rsquo;s almost an improvement of 100%.&lt;/p&gt;
&lt;p&gt;This throughput isn&amp;rsquo;t sustainable though if we had a lot more messages
to process. We&amp;rsquo;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&amp;rsquo;s not
only invoking the handlers, but the HTTP requests also take time). We&amp;rsquo;re
burning through threads quicker than we&amp;rsquo;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;/p&gt;
&lt;p&gt;In my previous post I also considered a smart polling algorithm, but I
haven&amp;rsquo;t looked at that yet, what&amp;rsquo;s in place is more than good enough for
me at the moment.&lt;/p&gt;
&lt;p&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&amp;rsquo;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&amp;hellip; I
ran these tests with empty messages, .NET 4 installed on my own Windows
7 box with an Intel i7 on board.&lt;/p&gt;
&lt;p&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;/p&gt;
</description>
    </item>
    
    <item>
      <title>Some experimental infrastructure for IronMQ pull </title>
      <link>https://jefclaes.be/2013/03/some-experimental-infrastructure-for.html</link>
      <pubDate>Sun, 10 Mar 2013 17:29:00 +0100</pubDate>
      <guid>https://jefclaes.be/2013/03/some-experimental-infrastructure-for.html</guid>
      <description>&lt;p&gt;I wrote about using &lt;a href=&#34;http://www.jefclaes.be/2013/03/first-ironmq-impressions.html&#34;&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  also introduces other concerns: security,
local debugging and scalability.&lt;/p&gt;
&lt;p&gt;Out-of-the-box there is no infrastructure in the client libraries to
facilitate periodic pull - polling, that&amp;rsquo;s why I took a stab at doing it
myself. It&amp;rsquo;s still rough, not production tested, and hasn&amp;rsquo;t considered a
bunch of niche scenarios, but it should give you an idea of the
direction it&amp;rsquo;s going.&lt;/p&gt;
&lt;p&gt;A high-level overview of the components looks like this.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-03-10-some-experimental-infrastructure-for-ironmq-pull-IronMQPoll.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-03-10-some-experimental-infrastructure-for-ironmq-pull-IronMQPoll.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&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;/p&gt;
&lt;p&gt;I&amp;rsquo;m going to look at each component, starting with the smallest, and
slowly assemble them into bigger components.&lt;/p&gt;
&lt;p&gt;Each queue consumer can be configured independently. For now, only the
polling interval can be changed. By default it&amp;rsquo;s one second, or 1000
milliseconds.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IQueueConsumerConfiguration&lt;/span&gt;&amp;lt;T&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; PollingInterval { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;QueueConsumerConfiguration&lt;/span&gt;&amp;lt;T&amp;gt; : IQueueConsumerConfiguration&amp;lt;T&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{     
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; PollingInterval
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt; { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }       
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A queue can push messages, get raw messages, and delete them. The
implementation makes use of the &lt;a href=&#34;https://github.com/odeits/IronTools&#34;&gt;OSS IronIO client
libraries&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IQueue&lt;/span&gt;&amp;lt;T&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; TryGet(&lt;span style=&#34;color:#66d9ef&#34;&gt;out&lt;/span&gt; Message message);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Delete(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; messageId);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Push(T message);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Queue&lt;/span&gt;&amp;lt;T&amp;gt; : IQueue&amp;lt;T&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; IronIO.IronMQ _queue;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Queue(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; projectId, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; token)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForEmptyString(projectId, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;projectId&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForEmptyString(token, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;token&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; queueName = &lt;span style=&#34;color:#66d9ef&#34;&gt;typeof&lt;/span&gt;(T).Name; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _queue = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; IronMQ(queueName, projectId, token);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; TryGet(&lt;span style=&#34;color:#66d9ef&#34;&gt;out&lt;/span&gt; Message message) 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        message = _queue.Get();            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; message != &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Delete(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; messageId)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNull(messageId, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;messageId&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _queue.Delete(messageId);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Push(T message)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNull(message, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _queue.Push(JsonConvert.SerializeObject(message));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A message dispatcher dispatches messages to the relevant handlers.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IMessageDispatcher&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Dispatch&amp;lt;T&amp;gt;(T message);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MessageDispatcher&lt;/span&gt; : IMessageDispatcher
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; IKernel _kernel;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; MessageDispatcher(IKernel kernel)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _kernel = kernel;            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Dispatch&amp;lt;T&amp;gt;(T message)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; handlers = _kernel.GetAll&amp;lt;IMessageHandler&amp;lt;T&amp;gt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; handler &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; handlers)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            handler.Handle(message);                        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&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&amp;rsquo;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;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IErrorHandler&lt;/span&gt;&amp;lt;T&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Handle(Exception exception, Message message);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ErrorHandler&lt;/span&gt;&amp;lt;T&amp;gt; : IErrorHandler&amp;lt;T&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{       
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Handle(Exception exception, Message message)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; exception;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }     
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&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&amp;rsquo;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;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IQueueConsumer&lt;/span&gt;&amp;lt;T&amp;gt; : IQueueConsumer &lt;span style=&#34;color:#66d9ef&#34;&gt;where&lt;/span&gt; T : &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IQueueConsumer&lt;/span&gt; : IDisposable
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Start();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;QueueConsumer&lt;/span&gt;&amp;lt;T&amp;gt; : IQueueConsumer&amp;lt;T&amp;gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;where&lt;/span&gt; T : &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; IQueue&amp;lt;T&amp;gt; _queue;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; IErrorHandler&amp;lt;T&amp;gt; _errorHandler;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; IQueueConsumerConfiguration&amp;lt;T&amp;gt; _queueConsumerConfiguration;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; IMessageDispatcher _messageDispatcher;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Timer _timer;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; QueueConsumer(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        IQueue&amp;lt;T&amp;gt; queue, 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        IErrorHandler&amp;lt;T&amp;gt; errorHandler,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        IQueueConsumerConfiguration&amp;lt;T&amp;gt; queueConsumerConfiguration,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        IMessageDispatcher messageDispatcher)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _queue = queue;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _errorHandler = errorHandler;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _queueConsumerConfiguration = queueConsumerConfiguration;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _messageDispatcher = messageDispatcher;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Start()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _timer = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Timer((x) =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; message = (Message)&lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; messageBody = (T)&lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (!_queue.TryGet(&lt;span style=&#34;color:#66d9ef&#34;&gt;out&lt;/span&gt; message))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                messageBody = (T)JsonConvert.DeserializeObject(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    message.Body, &lt;span style=&#34;color:#66d9ef&#34;&gt;typeof&lt;/span&gt;(T));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                _messageDispatcher.Dispatch&amp;lt;T&amp;gt;(messageBody);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                _queue.Delete(message.Id);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (Exception ex)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                _errorHandler.Handle(ex, message);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }                
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }, &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, _queueConsumerConfiguration.PollingInterval);            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Dispose()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (_timer == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _timer.Dispose();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&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;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;QueueHostConfiguration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; QueueHostConfiguration(IEnumerable&amp;lt;Type&amp;gt; messageTypes)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.ForNull(messageTypes, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;messageTypes&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        MessageTypes = messageTypes;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; IEnumerable&amp;lt;Type&amp;gt; MessageTypes { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;QueueHost&lt;/span&gt; : IDisposable
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; IKernel _kernel;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; QueueHostConfiguration _configuration;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; List&amp;lt;IQueueConsumer&amp;gt; _consumers;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; QueueHost(IKernel kernel, QueueHostConfiguration configuration)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _kernel = kernel;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _configuration = configuration;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _consumers = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; List&amp;lt;IQueueConsumer&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Start()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; messageType &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; _configuration.MessageTypes)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; queueConsumerType = &lt;span style=&#34;color:#66d9ef&#34;&gt;typeof&lt;/span&gt;(IQueueConsumer&amp;lt;&amp;gt;).MakeGenericType(messageType);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; queueConsumer = (IQueueConsumer)_kernel.Get(queueConsumerType);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            _consumers.Add(queueConsumer);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            queueConsumer.Start();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Dispose()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (_consumers == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; consumer &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; _consumers)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            consumer.Dispose();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In your application, you&amp;rsquo;ll end up doing something like this to start
the queue host. &lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; host = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; QueueHost(kernel, &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; QueueHostConfiguration(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt;[] { &lt;span style=&#34;color:#66d9ef&#34;&gt;typeof&lt;/span&gt;(MyMessage) })))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    host.Start();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Console.ReadLine();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;All the components are glued together using Ninject and some
conventions. &lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Bootstrapper&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Run(IKernel kernel)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        kernel.Bind(x =&amp;gt; x
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .FromThisAssembly()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .SelectAllClasses()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .InheritedFrom(&lt;span style=&#34;color:#66d9ef&#34;&gt;typeof&lt;/span&gt;(IMessageHandler&amp;lt;&amp;gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .BindAllInterfaces());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        kernel.Bind&amp;lt;Infrastructure.IMessageDispatcher&amp;gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .To&amp;lt;Infrastructure.MessageDispatcher&amp;gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .InTransientScope();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        kernel.Bind(x =&amp;gt; x
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .FromAssemblyContaining(&lt;span style=&#34;color:#66d9ef&#34;&gt;typeof&lt;/span&gt;(IQueue&amp;lt;&amp;gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .SelectAllClasses()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .InheritedFrom(&lt;span style=&#34;color:#66d9ef&#34;&gt;typeof&lt;/span&gt;(IQueue&amp;lt;&amp;gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .BindAllInterfaces()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .Configure(y =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                y.WithConstructorArgument(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;projectId&amp;#34;&lt;/span&gt;, z =&amp;gt; { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;your_project_id&amp;#34;&lt;/span&gt;; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                y.WithConstructorArgument(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;token&amp;#34;&lt;/span&gt;, z =&amp;gt; { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;your_token&amp;#34;&lt;/span&gt;; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        kernel
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .Bind(&lt;span style=&#34;color:#66d9ef&#34;&gt;typeof&lt;/span&gt;(Infrastructure.IQueueConsumer&amp;lt;&amp;gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .To(&lt;span style=&#34;color:#66d9ef&#34;&gt;typeof&lt;/span&gt;(Infrastructure.QueueConsumer&amp;lt;&amp;gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        kernel
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .Bind(&lt;span style=&#34;color:#66d9ef&#34;&gt;typeof&lt;/span&gt;(Infrastructure.IQueueConsumerConfiguration&amp;lt;&amp;gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .To(&lt;span style=&#34;color:#66d9ef&#34;&gt;typeof&lt;/span&gt;(Infrastructure.QueueConsumerConfiguration&amp;lt;&amp;gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        kernel
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .Bind(&lt;span style=&#34;color:#66d9ef&#34;&gt;typeof&lt;/span&gt;(Infrastructure.IErrorHandler&amp;lt;&amp;gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .To(&lt;span style=&#34;color:#66d9ef&#34;&gt;typeof&lt;/span&gt;(MyErrorHandler&amp;lt;&amp;gt;));    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&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&amp;rsquo;m going to run into?&lt;/p&gt;
&lt;p&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&amp;rsquo;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;/p&gt;
</description>
    </item>
    
    <item>
      <title>First IronMQ impressions</title>
      <link>https://jefclaes.be/2013/03/first-ironmq-impressions.html</link>
      <pubDate>Sun, 03 Mar 2013 16:45:00 +0100</pubDate>
      <guid>https://jefclaes.be/2013/03/first-ironmq-impressions.html</guid>
      <description>&lt;p&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=&#34;http://www.intergraph.com/&#34;&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&amp;rsquo;t allow
you to queue or retry messages; if you weren&amp;rsquo;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&amp;rsquo;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;/p&gt;
&lt;p&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&amp;rsquo;s still a pity when you see solutions struggle to solve a problem in
a decent way because they&amp;rsquo;re stuck with synchronous communication.&lt;/p&gt;
&lt;p&gt;Imagine a public website that&amp;rsquo;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&amp;rsquo;s so expensive to fetch this data, it&amp;rsquo;s being
cached, and as a result, it&amp;rsquo;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&amp;rsquo;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&amp;rsquo;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;/p&gt;
&lt;p&gt;Anyways, in this blog post, I wanted to share some first impressions on
&lt;a href=&#34;http://www.iron.io/mq&#34;&gt;IronMQ&lt;/a&gt;. I admittedly kind of accidentally
discovered this service browsing through
&lt;a href=&#34;https://appharbor.com/&#34;&gt;AppHarbor&lt;/a&gt;&amp;rsquo;s add-ons. Here it is described as
&amp;ldquo;a scalable cloud-based message queue&amp;rdquo;.&lt;/p&gt;
&lt;p&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&amp;rsquo;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&amp;rsquo;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&amp;rsquo;ll just keep retrying for a while.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;http://dev.iron.io/mq/reference/api/&#34;&gt;REST API&lt;/a&gt; is simple, yet
there are &lt;a href=&#34;http://dev.iron.io/mq/libraries/&#34;&gt;client libraries available for most popular
languages&lt;/a&gt;. They don&amp;rsquo;t provide that
much extra functionality though. Here&amp;rsquo;s the gist.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; queue = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; IronMQ(queueName, projectId, token);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;queue.Push(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{ hello: world }&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; message = queue.Get();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;queue.Delete(message.Id);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this scenario you&amp;rsquo;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;/p&gt;
&lt;ul&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&amp;rsquo;ll need to give your machine a public IP and set up something like &lt;a href=&#34;http://dyn.com/dns/&#34;&gt;dyndns&lt;/a&gt;. &lt;/li&gt;
&lt;li&gt;Scalability: depending on the expected message volume, and the web stack you&amp;rsquo;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;
&lt;p&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;/p&gt;
&lt;p&gt;When the expected volume of messages is rather small, it makes more
sense to opt for push; you don&amp;rsquo;t waste that many HTTP requests.&lt;/p&gt;
&lt;p&gt;IronMQ makes it extremely simple to get started; &lt;a href=&#34;http://www.iron.io/&#34;&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&amp;rsquo;s. But
it also seems to be all you&amp;rsquo;re going to get; there is no infrastructure
that addresses operational concerns, error queues, retry strategies,
local queues,&amp;hellip; IronMQ provides you with raw queueing infrastructure,
not a framework.&lt;/p&gt;
&lt;p&gt;Their site does give you a look into your queues though; you can&amp;rsquo;t look
at the messages, but you do get a nice overview.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-03-03-first-ironmq-impressions-IronMq.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-03-03-first-ironmq-impressions-IronMq.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t mind that it&amp;rsquo;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;/p&gt;
&lt;p&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&amp;rsquo;s probably time to shake off the doctrine. It&amp;rsquo;s so comfy to not have
to understand a new protocol, and HTTP just seems such a sensible thing
to do when you&amp;rsquo;re off-premise.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m going to conduct some more experiments this week, I&amp;rsquo;ll see what
gives.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>My Christmas holiday project postmortem</title>
      <link>https://jefclaes.be/2013/02/my-christmas-holiday-project-postmortem.html</link>
      <pubDate>Sun, 24 Feb 2013 16:42:00 +0100</pubDate>
      <guid>https://jefclaes.be/2013/02/my-christmas-holiday-project-postmortem.html</guid>
      <description>&lt;p&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=&#34;http://www.markknopfler.com/&#34;&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&amp;rsquo;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=&#34;http://en.wikipedia.org/wiki/Fender_Stratocaster&#34;&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&amp;rsquo;m in love with it. Yet, I have also become
very fond of the sound of a &lt;a href=&#34;http://en.wikipedia.org/wiki/Gibson_Les_Paul&#34;&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;/p&gt;
&lt;p&gt;I set out to find one on &lt;a href=&#34;http://www.2dehands.be/&#34;&gt;the most popular Belgian online secondhand
marketplace&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&amp;hellip; It didn&amp;rsquo;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;/p&gt;
&lt;p&gt;Doing a bit of research over the weekend, I found out that they expose,
what I call, an &lt;em&gt;accidental&lt;/em&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=&#34;http://quartznet.sourceforge.net/&#34;&gt;Quartz
job&lt;/a&gt; which periodically queries their
service, parses the results and stores them in a
&lt;a href=&#34;http://ravendb.net/&#34;&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=&#34;http://www.mailgun.com/&#34;&gt;MailGun&lt;/a&gt;. All of this running for free on
&lt;a href=&#34;https://appharbor.com/&#34;&gt;AppHarbor&lt;/a&gt;.&lt;/p&gt;
&lt;p&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;/p&gt;
&lt;p&gt;Two weeks later, I had something working online.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-02-24-my-christmas-holiday-project-postmortem-tweedehandsmeldingen.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-02-24-my-christmas-holiday-project-postmortem-tweedehandsmeldingen.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&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&amp;rsquo;t sign up too often
though..&lt;/p&gt;
&lt;p&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&amp;rsquo;t care.
As a side note; secondhand seems to be quite an expensive keyword!&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-02-24-my-christmas-holiday-project-postmortem-meldingenblog.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-02-24-my-christmas-holiday-project-postmortem-meldingenblog.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-02-24-my-christmas-holiday-project-postmortem-adwords_results.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-02-24-my-christmas-holiday-project-postmortem-adwords_results.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In hindsight, I can think of plenty of reasons why this somewhat useful
project has no success:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The problem it is trying to solve obviously isn&amp;rsquo;t enough of a pain!&lt;/li&gt;
&lt;li&gt;People don&amp;rsquo;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&amp;rsquo;t situated on these sites. &lt;/li&gt;
&lt;li&gt;People don&amp;rsquo;t like giving away their email address, definitely not to strangers they don&amp;rsquo;t trust. &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;p&gt;Damn, it&amp;rsquo;s always evident in hindsight.&lt;/p&gt;
&lt;p&gt;Here are a few things I learned/got confirmed:&lt;/p&gt;
&lt;ul&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&amp;rsquo;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;p&gt;(*) Take some time to explore his work: &lt;a href=&#34;http://www.youtube.com/watch?v=5vUDmFjWgVo&#34;&gt;brothers in
arms&lt;/a&gt;, &lt;a href=&#34;http://www.youtube.com/watch?v=aXXemzIo1ao&#34;&gt;postcards from
Paraguay&lt;/a&gt;, &lt;a href=&#34;http://www.youtube.com/watch?v=VyOW8lQOG8Q&#34;&gt;song for Sonny
Liston&lt;/a&gt;, &lt;a href=&#34;http://www.youtube.com/watch?v=-0T-JVeYXxs&#34;&gt;you and your
friend&lt;/a&gt;, and so many more
are worth a listen.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Adding the R to CQS: some storage options</title>
      <link>https://jefclaes.be/2013/02/adding-r-to-cqs-some-storage-options.html</link>
      <pubDate>Sun, 17 Feb 2013 17:57:00 +0100</pubDate>
      <guid>https://jefclaes.be/2013/02/adding-r-to-cqs-some-storage-options.html</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been writing &lt;a href=&#34;http://www.jefclaes.be/2013/01/separating-command-data-from-logic-and.html&#34;&gt;quite a
bit&lt;/a&gt;
about
&lt;a href=&#34;http://en.wikipedia.org/wiki/Command%E2%80%93query_separation&#34;&gt;CQS&lt;/a&gt; (or
command and query separation) lately. In &lt;a href=&#34;http://www.jefclaes.be/2013/02/raising-events-in-commandhandlers.html&#34;&gt;my last post on using
events&lt;/a&gt;,
I already hinted towards bringing in the R; command and query
&lt;strong&gt;r&lt;/strong&gt;esponsibility separation.&lt;/p&gt;
&lt;p&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;/p&gt;
&lt;p&gt;I like &lt;a href=&#34;https://twitter.com/clemensv&#34;&gt;Clemens Vasters&lt;/a&gt; definition
best.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&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,  thus, high-scale read access. In simple terms, you don’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. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A nice drawing also helps in understanding CQRS (from &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/jj591573&#34;&gt;the CQRS journey
material&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-02-17-adding-the-r-to-cqs-some-storage-options-CQRS_drawing.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-02-17-adding-the-r-to-cqs-some-storage-options-CQRS_drawing.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&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&amp;rsquo;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&amp;rsquo;t only result in being able to show
a list faster on a user&amp;rsquo;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;/p&gt;
&lt;p&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;em&gt;in practice&lt;/em&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;/p&gt;
&lt;h3 id=&#34;the-compromise&#34;&gt;The compromise&lt;/h3&gt;
&lt;p&gt;CQRS doesn&amp;rsquo;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;/p&gt;
&lt;h3 id=&#34;norm&#34;&gt;NORM&lt;/h3&gt;
&lt;p&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&amp;rsquo;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;/p&gt;
&lt;h3 id=&#34;event-sourcing&#34;&gt;Event Sourcing&lt;/h3&gt;
&lt;p&gt;When you look at most OSS CQRS implementations, &lt;a href=&#34;http://martinfowler.com/eaaDev/EventSourcing.html&#34;&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&amp;rsquo;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;/p&gt;
&lt;p&gt;These three techniques aren&amp;rsquo;t mutually exclusive. There are a bunch of
arguments to consider, and everything is highly dependent on your
technical and operational requirements.&lt;/p&gt;
&lt;p&gt;What is your experience with CQRS? Which techniques have you applied &lt;em&gt;in
practice&lt;/em&gt;?&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Premature judgement</title>
      <link>https://jefclaes.be/2013/02/premature-judgment.html</link>
      <pubDate>Sun, 10 Feb 2013 16:46:00 +0100</pubDate>
      <guid>https://jefclaes.be/2013/02/premature-judgment.html</guid>
      <description>&lt;p&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&amp;rsquo;t differentiate
good from bad. Over the years that has changed a bit, but with that,
I&amp;rsquo;ve also slowly become more judgemental towards peers, often
prematurely, and not always deservedly.&lt;/p&gt;
&lt;p&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&amp;rsquo;t really add up though.
When I looked at the commit history of some of the offending modules, I
found names that I didn&amp;rsquo;t expect; those people were still around, and I
actually thought of them pretty highly.&lt;/p&gt;
&lt;p&gt;Judging someone&amp;rsquo;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&amp;rsquo;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&amp;rsquo;t matured, some patterns and practices
weren&amp;rsquo;t commonplace yet, etc&amp;hellip; 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;/p&gt;
&lt;p&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;/p&gt;
&lt;ol&gt;
&lt;li&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;/li&gt;
&lt;li&gt;The last influencer is someone&amp;rsquo;s online presence. When I learn of someone new joining ranks, I can&amp;rsquo;t resist to look up what he&amp;rsquo;s doing online. Twitter, Facebook or a blog can give away quite a bit.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&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;/p&gt;
&lt;p&gt;&lt;em&gt;Have you experienced similar behavior? When do you judge prematurely?&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Raising events in commandhandlers</title>
      <link>https://jefclaes.be/2013/02/raising-events-in-commandhandlers.html</link>
      <pubDate>Sun, 03 Feb 2013 17:49:00 +0100</pubDate>
      <guid>https://jefclaes.be/2013/02/raising-events-in-commandhandlers.html</guid>
      <description>&lt;p&gt;I&amp;rsquo;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=&#34;http://www.jefclaes.be/2013/01/separating-command-data-from-logic-and.html&#34;&gt;this
approach&lt;/a&gt;.
The example used in that post looked like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CreateSubscriptionCommandHandler&lt;/span&gt; : ICommandHandler&amp;lt;CreateSubscriptionCommand&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; IDocumentSession _session;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; CreateSubscriptionCommandHandler(IDocumentSession session)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _session = session;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Handle(CreateSubscriptionCommand command)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; subscription = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Documents.Subscription(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            command.Value, command.Category, command.EmailAddress);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _session.Store(subscription);    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now imagine I would want to do some extra stuff &lt;em&gt;after&lt;/em&gt; creating the
subscription; update the sales statistics, append the email address to a
mailing list, send out a confirmation email, etc..&lt;/p&gt;
&lt;p&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;/p&gt;
&lt;p&gt;One solution could be to introduce events to decouple things in smaller
pieces, and to help communicate intent more clearly.&lt;/p&gt;
&lt;p&gt;The infrastructure to handle events is rather straightforward, and can
be based on &lt;a href=&#34;http://www.udidahan.com/2009/06/14/domain-events-salvation/&#34;&gt;Udi Dahan&amp;rsquo;s Domain Events
Salvation&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Events&lt;/span&gt; : IEvents
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; IKernel _kernel;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Events(IKernel kernel)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _kernel = kernel;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Raise&amp;lt;T&amp;gt;(T @event) &lt;span style=&#34;color:#66d9ef&#34;&gt;where&lt;/span&gt; T : IEvent
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; handlers = _kernel.GetAll&amp;lt;IEventHandler&amp;lt;T&amp;gt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; handler &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; handlers)        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            handler.Handle(@event);        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }     
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&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;/p&gt;
&lt;p&gt;Raising an event from the commandhandler can be done by injecting this
extra piece of infrastructure.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CreateSubscriptionCommandHandler&lt;/span&gt; : ICommandHandler&amp;lt;CreateSubscriptionCommand&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; IDocumentSession _session;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; IEvents _events;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; CreateSubscriptionCommandHandler(IDocumentSession session, IEvent events)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _session = session;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _events = events;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Handle(CreateSubscriptionCommand command)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; subscription = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Documents.Subscription(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            command.Value, command.Category, command.EmailAddress);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _session.Store(subscription);    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _events.Raise(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; SubscriptionCreatedEvent(query.Id));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;SubscriptionCreatedEvent&lt;/code&gt; class is a simple value object, which
exposes the subscription identifier.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SubscriptionCreatedEvent&lt;/span&gt; : IEvent
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; SubscriptionCreatedEvent(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; subscriptionId)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        SubscriptionId = subscriptionId;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; SubscriptionId { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; Equals(Object other)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (other == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; otherEvent = other &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; SubscriptionCreatedEvent;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (otherEvent == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; otherEvent.SubscriptionId == SubscriptionId;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; GetHashCode()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; SubscriptionId.GetHashCode();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To subscribe to this event, implement the &lt;code&gt;IEventHandler&lt;/code&gt; interface, and
register the implemenation in the container.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IEventHandler&lt;/span&gt;&amp;lt;T&amp;gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;where&lt;/span&gt; T : IEvent
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Handle(T @event);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SendConfirmationMailOnSubscriptionCreated&lt;/span&gt; : IEventHandler&amp;lt;SubscriptionCreatedEvent&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt;  Handle(SubscriptionCreatedEvent @event)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;UpdateSalesStatisticsOnSubscriptionCreated&lt;/span&gt; : IEventHandler&amp;lt;SubscriptionCreatedEvent&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt;  Handle(SubscriptionCreatedEvent @event)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Eventhandlers are invoked synchronously, and participate in the
commandhandler&amp;rsquo;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;/p&gt;
&lt;p&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;/p&gt;
&lt;h3 id=&#34;summary&#34;&gt;Summary&lt;/h3&gt;
&lt;p&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;em&gt;when&lt;/em&gt; you
do x or &lt;em&gt;on&lt;/em&gt; doing y, also do z.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Are you using events? If so, domain events, or its big brother Event
Sourcing?&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Organizing commands and queries</title>
      <link>https://jefclaes.be/2013/01/organizing-commands-and-queries.html</link>
      <pubDate>Sun, 27 Jan 2013 18:23:00 +0100</pubDate>
      <guid>https://jefclaes.be/2013/01/organizing-commands-and-queries.html</guid>
      <description>&lt;p&gt;In the last few posts I settled on an architecture for handling commands
and queries. A byproduct of &lt;a href=&#34;http://www.jefclaes.be/2013/01/separating-command-data-from-logic-and.html&#34;&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;/p&gt;
&lt;p&gt;There are a few ways you can go at organizing things.&lt;/p&gt;
&lt;h3 id=&#34;everything-in-one-location&#34;&gt;Everything in one location&lt;/h3&gt;
&lt;p&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;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-01-27-organizing-commands-and-queries-DumpedEverything.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-01-27-organizing-commands-and-queries-DumpedEverything.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;folder-per-functionality&#34;&gt;Folder per functionality&lt;/h3&gt;
&lt;p&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=&#34;http://www.markhneedham.com/blog/2012/02/20/coding-packaging-by-vertical-slice/&#34;&gt;sold me on
structuring my code based on functionality instead of technical
concepts&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2013-01-27-organizing-commands-and-queries-PerFolder.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2013-01-27-organizing-commands-and-queries-PerFolder.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&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=&#34;https://github.com/ravendb/ravendb/tree/master/Raven.Studio/Commands&#34;&gt;Take a look at the RavenDB
codebase&lt;/a&gt;
to get an idea of what that could look like.&lt;/p&gt;
&lt;p&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;/p&gt;
&lt;h3 id=&#34;composing-a-service-class&#34;&gt;Composing a service class&lt;/h3&gt;
&lt;p&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&amp;rsquo;t do a whole lot but
translating and forwarding your invocation.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SubscriptionService&lt;/span&gt; : 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ICommandHandler&amp;lt;SubscribeCommand&amp;gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ICommandHandler&amp;lt;UnsubscribeCommand&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Handle(SubscibeCommand command)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; NotImplementedException();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Handle(UnsubscribeCommand command)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; NotImplementedException();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Use the hints your dependency graph gives you to find a composition that
makes sense.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;How do you go at organizing commands and queries?&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>RavenDB: Drop all collections</title>
      <link>https://jefclaes.be/2013/01/ravendb-drop-all-collections.html</link>
      <pubDate>Thu, 24 Jan 2013 20:08:00 +0100</pubDate>
      <guid>https://jefclaes.be/2013/01/ravendb-drop-all-collections.html</guid>
      <description>&lt;p&gt;I never stub or mock the database when I&amp;rsquo;m
using &lt;a href=&#34;http://ravendb.net/&#34;&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;/p&gt;
&lt;p&gt;First I create the default DocumentsByEntityName index to make sure it&amp;rsquo;s
there - it normally gets created when you open the studio for the first
time. Then I use one of the &lt;a href=&#34;http://ravendb.net/docs/client-api/advanced/databasecommands&#34;&gt;advanced database
commands:&lt;/a&gt; DeleteByIndex,
and query all the tags.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; session = _documentStore.OpenSession())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; RavenDocumentsByEntityName().Execute(_documentStore);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        session.Advanced.DatabaseCommands.DeleteByIndex(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Raven/DocumentsByEntityName&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; IndexQuery { Query = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Tag: *&amp;#34;&lt;/span&gt; });                
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This technique doesn&amp;rsquo;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;/p&gt;
</description>
    </item>
    
    <item>
      <title>Separating command data from logic and sending it on a bus</title>
      <link>https://jefclaes.be/2013/01/separating-command-data-from-logic-and.html</link>
      <pubDate>Sun, 20 Jan 2013 22:03:00 +0100</pubDate>
      <guid>https://jefclaes.be/2013/01/separating-command-data-from-logic-and.html</guid>
      <description>&lt;p&gt;In &lt;a href=&#34;http://www.jefclaes.be/2012/10/commands-queries-and-testing.html&#34;&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=&#34;http://www.jefclaes.be/2012/10/commands-with-dependencies.html&#34;&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=&#34;http://www.jefclaes.be/2013/01/self-contained-commands-with.html&#34;&gt;I
revisited the first
approach&lt;/a&gt;,
and added an unconventional implementation of injecting dependencies by
an Inject method convention.&lt;/p&gt;
&lt;p&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&amp;rsquo;s look at an alternative architecture which pulls all
the bits apart, and should be better equipped to handle change.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s first separate command data from logic.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CreateSubscriptionCommand&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{     
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; CreateSubscriptionCommand(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;value&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; category, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; emailAddress)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.StringIsNullOrEmpty(&lt;span style=&#34;color:#66d9ef&#34;&gt;value&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;value&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.StringIsNullOrEmpty(category, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;category&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Guard.StringIsNullOrEmpty(emailAddress, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;emailAddress&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Value = &lt;span style=&#34;color:#66d9ef&#34;&gt;value&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Category = category;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        EmailAddress = emailAddress;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; Value { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; Category { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; EmailAddress { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; Equals(Object other)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (other == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; otherCommand = other &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; CreateSubscriptionCommand;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (otherCommand == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; otherCommand.Value == Value &amp;amp;&amp;amp; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            otherCommand.Category == Category &amp;amp;&amp;amp; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            otherCommand.EmailAddress == EmailAddress;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; GetHashCode()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Value.GetHashCode() ^ 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Category.GetHashCode() ^ 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            EmailAddress.GetHashCode();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The data is just a POCO. Notice the equality overrides; this comes in
handy when you&amp;rsquo;re testing.&lt;/p&gt;
&lt;p&gt;The class that handles on the data needs to implement the
&lt;code&gt;ICommandHandler&lt;/code&gt; interface.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CreateSubscriptionCommandHandler&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    : ICommandHandler&amp;lt;CreateSubscriptionCommand&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; IDocumentSession _session;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; CreateSubscriptionCommandHandler(IDocumentSession session)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _session = session;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Handle(CreateSubscriptionCommand command)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; subscription = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Documents.Subscription(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            command.Value, command.Category, command.EmailAddress);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _session.Store(subscription);    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Compared to the previous approach, we&amp;rsquo;re now injecting the session
instead of having it handy as a property; that coupling is now
completely gone.&lt;/p&gt;
&lt;p&gt;Last thing left to do is create an interface that consumers can use to
send commands on: a bus.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Bus&lt;/span&gt; : IBus
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; IKernel _kernel;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; IDocumentSession _session;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Bus(IKernel kernel, IDocumentSession session)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _kernel = kernel;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _session = session;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; ExecuteCommand&amp;lt;T&amp;gt;(T command) &lt;span style=&#34;color:#66d9ef&#34;&gt;where&lt;/span&gt; T : &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; handler = _kernel.Get&amp;lt;ICommandHandler&amp;lt;T&amp;gt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        handler.Handle(command);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _session.SaveChanges();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;ExecuteCommand&lt;/code&gt; method dispatches data to the correct handler by
resolving it from the container, and also commits the unit of work.&lt;/p&gt;
&lt;p&gt;The consumer can execute commands like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bus.ExecuteCommand(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; CreateQueryCommand(queryValue, category, emailAddress));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&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;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; ConfigureRequestContainer(IKernel container, NancyContext context)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// you don&amp;#39;t want to register them all individually&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        container
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .Bind&amp;lt;ICommandHandler&amp;lt;CreateSubscriptionCommand&amp;gt;&amp;gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .To&amp;lt;CreateSubscriptionCommandHandler&amp;gt;();        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// snip..&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        container.Bind&amp;lt;IDocumentSession&amp;gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .ToMethod((ctx) =&amp;gt; { 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; ctx.Kernel.Get&amp;lt;IDocumentStore&amp;gt;().OpenSession();    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .InSingletonScope();                          
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&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;/p&gt;
</description>
    </item>
    
    <item>
      <title>Self-contained commands with dependencies </title>
      <link>https://jefclaes.be/2013/01/self-contained-commands-with.html</link>
      <pubDate>Sun, 13 Jan 2013 18:17:00 +0100</pubDate>
      <guid>https://jefclaes.be/2013/01/self-contained-commands-with.html</guid>
      <description>&lt;p&gt;&lt;em&gt;Also read: &lt;a href=&#34;http://www.jefclaes.be/2013/01/separating-command-data-from-logic-and.html&#34;&gt;separating command data from logic and sending it on a
bus&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In October I looked at &lt;a href=&#34;http://www.jefclaes.be/2012/10/commands-queries-and-testing.html&#34;&gt;an architecture that limits abstractions to
solely commands and
queries&lt;/a&gt;. In
that post, I had some infrastructure that looked like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Command&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Execute();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Query&lt;/span&gt;&amp;lt;T&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; T Execute();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ICommandHandler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Execute(Command command);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CommandHandler&lt;/span&gt; : ICommandHandler
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Execute(Command command)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        command.Execute();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IQueryHandler&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    T Execute&amp;lt;T&amp;gt;(Query&amp;lt;T&amp;gt; query);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;QueryHandler&lt;/span&gt; : IQueryHandler
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; T Execute&amp;lt;T&amp;gt;(Query&amp;lt;T&amp;gt; query)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; query.Execute();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&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;/p&gt;
&lt;p&gt;Let&amp;rsquo;s look at the infrastructure, and particularly the handlers of a
project that uses RavenDB to store its data.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Command&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; IDocumentSession Session { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Execute();           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Query&lt;/span&gt;&amp;lt;T&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; IDocumentSession Session { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; T Execute();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CommandHandler&lt;/span&gt; : ICommandHandler
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Execute(Command command)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; store = DocumentStore.Get();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; session = store.OpenSession())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            command.Session = session;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            command.Execute();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            session.SaveChanges();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;QueryHandler&lt;/span&gt; : IQueryHandler
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; T Execute&amp;lt;T&amp;gt;(Query&amp;lt;T&amp;gt; query)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; store = DocumentStore.Get();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; session = store.OpenSession())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            query.Session = session;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; query.Execute();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&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;/p&gt;
&lt;p&gt;An actual command could look like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ConfirmOrderCommand&lt;/span&gt; : Command
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Guid _token;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; ConfirmOrderCommand(Guid token)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _token = token;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Execute()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; order = Session.Query&amp;lt;Documents.Order&amp;gt;().Where(x =&amp;gt; x.Token == _token).First();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        order.ChangeStatus(Documents.Status.Confirmed);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I really like this style of command and queries; very little ceremony.
The downside though, is that you can&amp;rsquo;t use constructor dependency
injection. &lt;a href=&#34;http://www.jefclaes.be/2012/10/commands-with-dependencies.html&#34;&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;/p&gt;
&lt;p&gt;I wasn&amp;rsquo;t that keen on that approach. Also, now that I&amp;rsquo;m so accustomed to
having fast in-memory integration tests with RavenDB, it&amp;rsquo;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;/p&gt;
&lt;p&gt;Instead of injecting the dependencies through the constructor, we&amp;rsquo;re
going to use an Inject method. This is a convention; there is no
interface that enforces this. Returning to our ConfirmOrderCommand,
we&amp;rsquo;ll add support for creating a new folder on the file system.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ConfirmOrderCommand&lt;/span&gt; : Command
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; IFileSystem _fileSystem;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Guid _token;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; ConfirmOrderCommand(Guid token)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _token = token;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Execute()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; order = Session.Query&amp;lt;Documents.Order&amp;gt;().Where(x =&amp;gt; x.Token == _token).First();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _fileSystem.CreateDirectory(Path.Combine(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;D:\&amp;#34;, order.Customer.Id));
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        order.ChangeStatus(Documents.Status.Confirmed);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Inject(IFileSystem fileSystem) 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _fileSystem = fileSystem;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&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. &lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CommandHandler&lt;/span&gt; : ICommandHandler
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; IKernel _kernel;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; CommandHandler() { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; CommandHandler(IKernel kernel)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _kernel = kernel;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Execute(Command command)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (_kernel != &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ResolveDependenciesIfNeeded(command);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; store = DocumentStore.Get();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;using&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; session = store.OpenSession())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            command.Session = session;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            command.Execute();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            session.SaveChanges();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; ResolveDependenciesIfNeeded(Command command)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; method = command.GetType().GetMethod(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Inject&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (method != &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; parameters = method.GetParameters();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; parameterInstances = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; List&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;object&lt;/span&gt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; parameter &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; parameters)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; type = parameter.ParameterType;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; instance = _kernel.Get(type);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                parameterInstances.Add(instance);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            method.Invoke(command, parameterInstances.ToArray());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Consumers now don&amp;rsquo;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 take advantage of having
discoverable dependencies though the Inject convention.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[TestClass]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;When_confirming_an_order&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Mock&amp;lt;IFileSystem&amp;gt; _fileSystem;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;    [TestInitialize]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; When()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        DocumentStore.InitializeEmbedded();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; cmd = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ConfirmOrderCommand(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;_token_&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// Inject mock&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _fileSystem = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Mock&amp;lt;IFileSystem&amp;gt;();    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        cmd.Inject(_fileSystem.Object);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; CommandHandler().Execute(cmd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;    [TestMethod]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; the_status_is_changed_to_confirmed()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;    [TestMethod]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; a_new_folder_is_created()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _fileSystem.Verify(...);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Although I haven&amp;rsquo;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;/p&gt;
&lt;p&gt;&lt;em&gt;I&amp;rsquo;d like to hear your opinion.&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>2012 Annual Review</title>
      <link>https://jefclaes.be/2012/12/2012-annual-review.html</link>
      <pubDate>Mon, 31 Dec 2012 15:58:00 +0100</pubDate>
      <guid>https://jefclaes.be/2012/12/2012-annual-review.html</guid>
      <description>&lt;p&gt;It&amp;rsquo;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;/p&gt;
&lt;p&gt;The biggest personal changes this year were moving out of my parents&amp;rsquo;
place, and my girlfriend&amp;rsquo;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;/p&gt;
&lt;h3 id=&#34;my-career&#34;&gt;My career&lt;/h3&gt;
&lt;p&gt;September marked one year working for
&lt;a href=&#34;http://www.linkedin.com/company/euricom?trk=hb_tab_compy_id_30393/&#34;&gt;Euricom&lt;/a&gt;.
I&amp;rsquo;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;em&gt;it&lt;/em&gt; for me though.&lt;/p&gt;
&lt;h3 id=&#34;blog&#34;&gt;Blog&lt;/h3&gt;
&lt;p&gt;I published 66 posts this year, which seems to be consistent with
previous years.&lt;/p&gt;
&lt;p&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&amp;hellip; But I still feel like I should add
value and contribute something worthwhile when I spend time on this
blog.&lt;/p&gt;
&lt;p&gt;The topics haven&amp;rsquo;t changed that much this year. I still write often on
Web technologies (ASP.NET, NancyFx and REST) - something I didn&amp;rsquo;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;/p&gt;
&lt;p&gt;Page views have more than doubled (173k) compared to 2011, which I&amp;rsquo;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;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-12-31-2012-annual-review-traffic.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-12-31-2012-annual-review-traffic.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;community&#34;&gt;Community&lt;/h3&gt;
&lt;p&gt;It very much depends on what I&amp;rsquo;m doing that day, but I still spend
quite some time on &lt;a href=&#34;http://twitter.com/JefClaes&#34;&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&amp;rsquo;s how I get value
out of Twitter. That, and animated GIFs of course.&lt;/p&gt;
&lt;p&gt;In real life, I went to see a few interesting speakers at local user
groups, and &lt;a href=&#34;http://www.jefclaes.be/2012/10/slides-and-code-from-my-webnet-europe.html&#34;&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=&#34;http://www.jefclaes.be/2012/10/post-webnet-europe.html&#34;&gt;they did a great
job&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In general, I started to value artificial sponsored user groups less.
They have their place, and they do add value, but it&amp;rsquo;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;/p&gt;
&lt;h3 id=&#34;travelling&#34;&gt;Travelling&lt;/h3&gt;
&lt;p&gt;Buying an apartment and all of that, we didn&amp;rsquo;t get to make any epic
travels this year. I got to visit three different countries though:
&lt;a href=&#34;http://www.jefclaes.be/2012/07/finito.html&#34;&gt;Italy&lt;/a&gt;,
&lt;a href=&#34;http://www.jefclaes.be/2012/09/slides-and-code-from-my-tunisia-rest.html&#34;&gt;Tunisia&lt;/a&gt;,
&lt;a href=&#34;http://www.jefclaes.be/2012/10/slides-and-code-from-my-webnet-europe.html&#34;&gt;Italy again&lt;/a&gt;,
and &lt;a href=&#34;http://www.jefclaes.be/2012/10/cote-dopale.html&#34;&gt;France&lt;/a&gt;. Two out
of four were sponsored by my job; not bad.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re setting out for a big trip again in 2013. &lt;a href=&#34;http://www.jefclaes.be/2011/09/once-upon-time-in-west.html&#34;&gt;We fell in love with
America two years
ago&lt;/a&gt;, so
we&amp;rsquo;ve been researching the South-West again - but closer to the Mexican
border this time. Other destinations are still open for discussion
though.&lt;/p&gt;
&lt;h3 id=&#34;projects&#34;&gt;Projects&lt;/h3&gt;
&lt;p&gt;I spent a considerate part of 2012 &lt;a href=&#34;http://www.jefclaes.be/2011/09/building-small-things.html&#34;&gt;building small things on the
side&lt;/a&gt;. This
didn&amp;rsquo;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, &amp;hellip;).&lt;/p&gt;
&lt;p&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&amp;rsquo;t commit to using it myself. Technically I played with &lt;a href=&#34;http://www.jefclaes.be/2011/11/programming-for-future-of-mobile.html&#34;&gt;early
versions of jQuery
mobile&lt;/a&gt;
and EF, and learned why you shouldn&amp;rsquo;t overlayer your MVC application -
or any web application for the matter.&lt;/p&gt;
&lt;p&gt;For the second project, I and &lt;a href=&#34;https://twitter.com/davybrion&#34;&gt;Davy
Brion&lt;/a&gt; worked on
&lt;a href=&#34;https://github.com/JefClaes/topdevlinks&#34;&gt;TopDevLinks&lt;/a&gt;. This was
supposed to be a linkblog implementation on top of ASP.NET MVC,
&lt;a href=&#34;http://www.jefclaes.be/2012/10/commands-queries-and-testing.html&#34;&gt;CQS&lt;/a&gt;
and MongoDB. We both lost interest in the concept eventually.&lt;/p&gt;
&lt;p&gt;I made my girlfriend a &lt;a href=&#34;https://github.com/JefClaes/kristienbehets-portfolio&#34;&gt;petite portfolio
site&lt;/a&gt; built on top
of NancyFx, the FlickR API, and some jQuery plug-ins. Right now, it&amp;rsquo;s
actually &lt;a href=&#34;http://kristienbehets.be/&#34;&gt;running as a static site on GitHub
pages&lt;/a&gt; though.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.jefclaes.be/2012/11/released-kill-long-meetings.html&#34;&gt;I already blogged about the next
project&lt;/a&gt;:
Kill Long Meetings. This one is still around, but quickly floundered
into forgetfulness after its five minutes of Twitter fame.&lt;/p&gt;
&lt;p&gt;Now that I look back at it, I did write quite some code after my hours
this year&amp;hellip; Next to being in the moment of building and shipping stuff,
I genuinely believe it makes me better at my job.&lt;/p&gt;
&lt;p&gt;I hope to be able to do as much in 2013, but to also let it be something
worthwhile. I&amp;rsquo;ll be actually already shipping something new in a few
weeks if all goes well.&lt;/p&gt;
&lt;h3 id=&#34;sporthealth&#34;&gt;Sport/Health&lt;/h3&gt;
&lt;p&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;/p&gt;
&lt;p&gt;Moving to Antwerp, and not having any area to put my weights, I&amp;rsquo;ve
joined a gym again, where I&amp;rsquo;m doing a two times a week compound routine.
That should make me stronger again; I&amp;rsquo;ve lost a lot of beef since
picking up running three years ago.&lt;/p&gt;
&lt;p&gt;I haven&amp;rsquo;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&amp;rsquo;m far from complaining.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-12-31-2012-annual-review-nikerunning.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-12-31-2012-annual-review-nikerunning.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t know what I hope for in this area in 2013. It&amp;rsquo;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&amp;rsquo;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 can.&lt;/p&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&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&amp;rsquo;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;/p&gt;
&lt;p&gt;I plan to keep course in 2013, but as a better man.&lt;/p&gt;
&lt;p&gt;How was your year? What do you plan for in 2013?&lt;/p&gt;
&lt;p&gt;Now, if you&amp;rsquo;ll excuse me, I&amp;rsquo;m going to help a hand in preparing the
festivities before the girlfriend really gets in a faul mood.&lt;/p&gt;
&lt;p&gt;*Holy crap, when I sat down to write this, I didn&amp;rsquo;t expect to write a
whole book. I&amp;rsquo;m wondering how many people actually made it down here. *&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>2012&#39;s most read posts</title>
      <link>https://jefclaes.be/2012/12/2012s-most-read-posts.html</link>
      <pubDate>Sun, 23 Dec 2012 15:53:00 +0100</pubDate>
      <guid>https://jefclaes.be/2012/12/2012s-most-read-posts.html</guid>
      <description>&lt;p&gt;I look forward to writing this post each year; it&amp;rsquo;s by far the easiest
one to write, and it provides me with an occasion to look back on
previous years
(&lt;a href=&#34;http://www.jefclaes.be/2009/12/high-5-five-most-popular-blog-posts-of.html&#34;&gt;2009&lt;/a&gt;,
&lt;a href=&#34;http://www.jefclaes.be/2010/12/top-5-popular-posts-of-2010.html&#34;&gt;2010&lt;/a&gt;,
&lt;a href=&#34;http://www.jefclaes.be/2011/12/2011s-most-read-posts.html&#34;&gt;2011&lt;/a&gt;). It&amp;rsquo;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;/p&gt;
&lt;p&gt;The most read post this year, with 37.797 page views, is &lt;a href=&#34;http://www.jefclaes.be/2012/03/how-web-application-can-download-and.html&#34;&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&amp;rsquo;t addressed these concerns in the
meanwhile; the browser still behaves exactly the same. I&amp;rsquo;m guessing
usage stats might prove that it&amp;rsquo;s not worth the effort.&lt;/p&gt;
&lt;p&gt;The second most read post, with 14.371 page views, is &lt;a href=&#34;http://www.jefclaes.be/2012/03/learning-hacker-way.html&#34;&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&amp;rsquo;s crucial to supplement passive learning with a high volume
of getting your hands dirty.&lt;/p&gt;
&lt;p&gt;With 14.085 page views, &lt;a href=&#34;http://www.jefclaes.be/2012/11/commuting-have-you-done-math.html&#34;&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;/p&gt;
&lt;p&gt;Having 5.215 page views, the post &lt;a href=&#34;http://www.jefclaes.be/2012/05/why-i-will-always-love-rss.html&#34;&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&amp;rsquo;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;/p&gt;
&lt;p&gt;With 1000 views less, making it the last item in the list, is the post
&lt;a href=&#34;http://www.jefclaes.be/2012/03/html5-offline-web-applications-as.html&#34;&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=&#34;http://www.jefclaes.be/2012/03/html5-offline-web-applications-as.html&#34;&gt;paid article on
InfoQ&lt;/a&gt;.
I should revisit this topic again, I&amp;rsquo;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;/p&gt;
&lt;p&gt;Thank &lt;em&gt;you&lt;/em&gt; for reading in 2012!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>It&#39;s not cake we are baking</title>
      <link>https://jefclaes.be/2012/12/its-not-cake-we-are-baking.html</link>
      <pubDate>Sun, 09 Dec 2012 16:08:00 +0100</pubDate>
      <guid>https://jefclaes.be/2012/12/its-not-cake-we-are-baking.html</guid>
      <description>&lt;p&gt;I recently watched a talk on Vimeo where &lt;a href=&#34;https://twitter.com/ChristinGorman&#34;&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&amp;rsquo;t watched or
listened to her talk, you should; it&amp;rsquo;s only a few minutes long, and she
brings it really well. &lt;a href=&#34;http://vimeo.com/28885655&#34;&gt;Go ahead&lt;/a&gt;, I&amp;rsquo;ll
wait.&lt;/p&gt;
&lt;p&gt;When I first watched her talk, it rubbed me the wrong way, but I
couldn&amp;rsquo;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&amp;rsquo;t care
which ingredients were used to bake your cake; they only care about how
it tastes, how fast it&amp;rsquo;s served, and how much they&amp;rsquo;re paying for it. And
although the romantic in me really sympathizes with her view, the
realist just can&amp;rsquo;t. Over these few years only, each and every attempt of
a hand-rolled ORM I&amp;rsquo;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=&#34;http://ayende.com/blog/1340/25-reasons-not-to-write-your-own-object-relational-mapper&#34;&gt;not a trivial thing to
do&lt;/a&gt;,
and there are already so many flavors* - from grandma&amp;rsquo;s recipe to
decadent supreme deluxe - to pick from, that it&amp;rsquo;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&amp;rsquo;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;/p&gt;
&lt;p&gt;* &lt;a href=&#34;http://nhforge.org/&#34;&gt;NHibernate&lt;/a&gt;, &lt;a href=&#34;http://msdn.microsoft.com/en-us/data/ef.aspx&#34;&gt;Entity
Framework&lt;/a&gt;,
&lt;a href=&#34;http://code.google.com/p/dapper-dot-net/&#34;&gt;Dapper&lt;/a&gt;,
&lt;a href=&#34;https://github.com/robconery/massive&#34;&gt;Massive&lt;/a&gt;,
&lt;a href=&#34;http://simple.data/&#34;&gt;Simple.Data&lt;/a&gt;, &lt;a href=&#34;http://www.llblgen.com/&#34;&gt;LLBLGen
Pro&lt;/a&gt;,
&lt;a href=&#34;http://www.telerik.com/products/orm.aspx&#34;&gt;OpenAccess&lt;/a&gt;,
&lt;a href=&#34;http://subsonicproject.com/&#34;&gt;SubSonic&lt;/a&gt; &amp;hellip;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Some notes on performance tuning with NHibernate</title>
      <link>https://jefclaes.be/2012/12/some-notes-on-performance-tuning-with.html</link>
      <pubDate>Sun, 02 Dec 2012 17:36:00 +0100</pubDate>
      <guid>https://jefclaes.be/2012/12/some-notes-on-performance-tuning-with.html</guid>
      <description>&lt;p&gt;A few weeks back, I spent an intensive day performance tuning parts of
a, to me, relatively unfamiliar part of our codebase. Like it often is,
the biggest optimizations were to be found in how we work with the
database. Now, I don&amp;rsquo;t consider myself to be an NHibernate expert; I
read &lt;a href=&#34;http://www.jefclaes.be/2012/02/book-review-working-with-nhibernate-30.html&#34;&gt;this book&lt;/a&gt;
and have used it on two projects, but in the end I just do my best to
avoid doing stupid things with it. The topics discussed below are mostly
common knowledge for long time NHibernate users, but I thought it might
be convenient for others to just summarize them, and add references to
other, more in-detail, posts.&lt;/p&gt;
&lt;h3 id=&#34;under-the-covers&#34;&gt;Under the covers&lt;/h3&gt;
&lt;p&gt;When you&amp;rsquo;re looking into optimizing, you probably want to have a look
at what&amp;rsquo;s really going on. You could do this by &lt;a href=&#34;http://nhforge.org/wikis/howtonh/configure-log4net-for-use-with-nhibernate.aspx&#34;&gt;turning on NHibernate&amp;rsquo;s
log4net debug logging&lt;/a&gt;.
This might be good enough for some scenarios, but it&amp;rsquo;s not really
convenient for when there is lots and lots of stuff happening. Instead,
you might want to look into &lt;a href=&#34;http://www.hibernatingrhinos.com/products/NHProf&#34;&gt;NHibernate Profiler&lt;/a&gt;. It&amp;rsquo;s
trivial to get started with, yet the feedback it provides is very
powerful: next to session statistics and executed queries, you also get
alerts which suggest techniques to improve your code. I need to use this
tool more often just to get a better grip of the NHibernate internals.&lt;/p&gt;
&lt;h3 id=&#34;the-fastest-query-is-the-one-that-isnt&#34;&gt;The fastest query is the one that isn&amp;rsquo;t&lt;/h3&gt;
&lt;p&gt;Going to the database is probably one of the slowest things your
application is going to do. If you can avoid it, do so.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re using a stateful session, NHibernate will track your
entities, and store them in its &lt;a href=&#34;http://nhibernate.hibernatingrhinos.com/28/first-and-second-level-caching-in-nhibernate&#34;&gt;first level cache&lt;/a&gt;. When you get these items by id later on, you avoid going to the database. So instead of querying the database for the same entity multiple times in the same session, do it once, and get the entity by its id on subsequent calls.&lt;/p&gt;
&lt;p&gt;When you&amp;rsquo;re having a hard time keeping those ids around, consider
introducing a light-weight datastructure, such as a dictionary, which
can help you build a small look-up cache. This could also be a sign that
you might want to reconsider your identity strategy though.&lt;/p&gt;
&lt;h3 id=&#34;working-with-batches&#34;&gt;Working with batches&lt;/h3&gt;
&lt;p&gt;An ORM really isn&amp;rsquo;t the best tool to do bulk inserts or updates; look
at &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlbulkcopy.aspx&#34;&gt;SqlBulkCopy&lt;/a&gt; instead.&lt;/p&gt;
&lt;p&gt;If your batches are still relatively small, and you opt to stay with
NHibernate anyways, there are two things you can do which will improve
performance tremendously: use a stateless session and configure
batching.&lt;/p&gt;
&lt;p&gt;Switching to a stateless session is simple enough. Do take into account
that &lt;a href=&#34;http://stackoverflow.com/questions/2638950/stateless-nhibernate-for-querying&#34;&gt;some features won&amp;rsquo;t work anymore&lt;/a&gt;: lazy loading, caching, cascading and implicit updates. Setting up batching is also just a matter of
&lt;a href=&#34;http://nhforge.org/blogs/nhibernate/archive/2008/10/27/batching-nhibernate-s-dml-statements.aspx&#34;&gt;configuration&lt;/a&gt;. The most important thing to remember is to use an appropriate identity generator; batching will only work when the application is responsible for generating the ids. I&amp;rsquo;m using a [HiLo
generator](&lt;a href=&#34;http://stackoverflow.com/questions/282099/whats-the-hi-lo-algorithm&#34;&gt;http://stackoverflow.com/questions/282099/whats-the-hi-lo-algorithm&lt;/a&gt;,
but GUIDs or &lt;a href=&#34;http://www.nhforge.org/doc/nh/en/index.html#mapping-declaration-id-assigned&#34;&gt;assigned ids&lt;/a&gt; will work too.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Released: Kill long meetings</title>
      <link>https://jefclaes.be/2012/11/released-kill-long-meetings.html</link>
      <pubDate>Sun, 25 Nov 2012 17:45:00 +0100</pubDate>
      <guid>https://jefclaes.be/2012/11/released-kill-long-meetings.html</guid>
      <description>&lt;p&gt;A lot has already been said and written about meetings, and some have
carried the message above par; &lt;a href=&#34;http://www.codinghorror.com/blog/2012/02/meetings-where-work-goes-to-die.html&#34;&gt;&amp;lsquo;Meetings: where work goes to
die&lt;/a&gt;&amp;rsquo;.
Today, I&amp;rsquo;m not going to foul the internet with another rant, but I&amp;rsquo;d
like to show you a small application built over the last few weeks after
work.&lt;/p&gt;
&lt;p&gt;I regularly find myself &lt;a href=&#34;http://www.jefclaes.be/2011/09/building-small-things.html&#34;&gt;building small
things&lt;/a&gt; as an
antitoxin to the regular periods of not writing and shipping code at
work. This time, me and &lt;a href=&#34;http://twitter.com/cgeers&#34;&gt;@cgeers&lt;/a&gt;, built a
not-so-serious application that aims to kill long meetings by
visualizing the amount of time and money burned in a meeting.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-11-25-released-kill-long-meetings-killlongmeetings.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-11-25-released-kill-long-meetings-killlongmeetings.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;While the application in itself probably will never attract a
sustainable user base, development sprouted two useful Twitter Bootstrap
plug-ins: &lt;a href=&#34;https://github.com/geersch/bootstrap-spinedit&#34;&gt;a spin edit control&lt;/a&gt; and &lt;a href=&#34;https://github.com/geersch/bootstrap-progressbar&#34;&gt;a multi-color progressbar&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;used-technology-stack&#34;&gt;Used technology stack&lt;/h3&gt;
&lt;p&gt;On the server, we&amp;rsquo;re using &lt;a href=&#34;http://nancyfx.org/&#34;&gt;Nancy&lt;/a&gt; on an &lt;a href=&#34;https://github.com/NancyFx/Nancy/wiki/Hosting-nancy-with-asp.net&#34;&gt;ASP.NET host&lt;/a&gt; with Razor views. There is hardly anything going on at the server, so we could have picked any server-side framework I guess. We might just be attracted to the as &amp;rsquo;little friction as possible&amp;rsquo; Nancy ethos though. Returning a view, and setting up a route for it, takes just a few LOC.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;namespace&lt;/span&gt; KillLongMeetings
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;RootModule&lt;/span&gt; : NancyModule
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; RootModule()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Get[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;] = p =&amp;gt; View[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HomeView&amp;#34;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next to returning a correct view, we&amp;rsquo;re also making bundles on the
server. For that, we&amp;rsquo;re using &lt;code&gt;Cassette for Nancy&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;At the client, we chose to use &lt;a href=&#34;http://twitter.github.com/bootstrap/&#34;&gt;Twitter Bootstrap&lt;/a&gt;, because getting a lay-out right that works everywhere these days is hard; we like to spend that time on other things. Next to jQuery - duh, we&amp;rsquo;re using &lt;a href=&#34;http://knockoutjs.com/&#34;&gt;knockout.js&lt;/a&gt; as our client-side MVVM framework. This worked out lovely for our scenario, but overall, I&amp;rsquo;m distancing
myself a bit from this framework. It&amp;rsquo;s simple, and extremely easy to get started with, but lots of companies I heard of seem to adapt this as an application framework, which it is not. It&amp;rsquo;s just two-way model binding in the browser. More complex scenarios benefit from a cleaner separation of concerns for validation, working with remote data, application composition and testing. Right now, I&amp;rsquo;m doing something with &lt;a href=&#34;http://angularjs.org/&#34;&gt;angular.js&lt;/a&gt;, and it seems very promising so far. It&amp;rsquo;s also a lot less intrusive than knockout.js.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re using &lt;a href=&#34;https://appharbor.com/&#34;&gt;AppHarbor&lt;/a&gt; and GitHub for
continuous deployment. The production site however is a static site
hosted on &lt;a href=&#34;http://pages.github.com/&#34;&gt;GitHub pages&lt;/a&gt;. Next to serving
everything really fast, we&amp;rsquo;re now not paying for anything except the
domain name.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The source can be found on &lt;a href=&#34;https://github.com/JefClaes/KillLongMeetings&#34;&gt;GitHub&lt;/a&gt;. Let us know what
you think!&lt;/strong&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Commuting? Have you done the math?</title>
      <link>https://jefclaes.be/2012/11/commuting-have-you-done-math.html</link>
      <pubDate>Sun, 04 Nov 2012 20:24:00 +0100</pubDate>
      <guid>https://jefclaes.be/2012/11/commuting-have-you-done-math.html</guid>
      <description>&lt;p&gt;On my first job interview, over four years ago, I was asked whether I
would relocate if I was hired. Back then, I still lived in the
&lt;a href=&#34;http://en.wikipedia.org/wiki/Campine&#34;&gt;Campine&lt;/a&gt; region with my parents,
while the Ferranti Computer Systems headquarters are in Antwerp. I
thought about it for a few seconds and told the interviewer that I
didn&amp;rsquo;t plan on moving out of my parents&amp;rsquo; place in the first few years.
Besides, the distance isn&amp;rsquo;t that great; it&amp;rsquo;s only 60km (=37 miles) of
highway, how bad could it be? Apparently that reply was good enough
since I was given the job a few days later.&lt;/p&gt;
&lt;p&gt;Well, that commute grew old rather quickly though. Turns out that those
60km of highway are one of the most saturated pieces of asphalt in
Belgium, with up to 20 to 30km (12 to 18 miles) of systematic traffic
jams every damn single day.&lt;/p&gt;
&lt;p&gt;And when you have to take the car to work, the options you have to spend
that time useful are rather limited; the only things I could think of at
the time were listening to podcasts and reflecting on the things of
life. The latter made me hate my situation even more, so that wasn&amp;rsquo;t an
optimal pastime.&lt;/p&gt;
&lt;p&gt;I actually never had the courage to calculate how much time I wasted in
traffic those three years. Today, I&amp;rsquo;m in a far more comfortable
situation, so plucking up courage wasn&amp;rsquo;t that hard anymore. With 52
weeks in one year, and 5 days in a week, there are 260 business days in
one year. In Belgium, we don&amp;rsquo;t work on all of those though, so I had to
subtract 25 vacation days, and 6 holidays; bringing down the number of
working days to 229. My rather optimistic guess is that I was on the
road for somewhere around &lt;strong&gt;140 minutes each day&lt;/strong&gt;. So 229 days
multiplied by 140 minutes comes down to a total of 32060 minutes, or 534
hours, or 66 working days. Gasp! &lt;strong&gt;66 working days per year gone to
waste&lt;/strong&gt;. I knew the numbers were going to be bad, but this is even a lot
worse than I expected.&lt;/p&gt;
&lt;p&gt;Easing this burden isn&amp;rsquo;t trivial though, and I can only think of a few
feasible options, excluded changing jobs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Travel outside rush hours:&lt;/strong&gt; leave for work very early or really late. I experimented with the former for quite some time, but I never really got used to it. It also seems a bit counterproductive to have your rhythm be too different from that of your team members. I&amp;rsquo;m guessing your family life will suffer as well, but I can&amp;rsquo;t be the judge of that.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bring the office to you.&lt;/strong&gt; In this technological day and age there
are hardly any sound arguments not to encourage working from home.
Yet, the classical enterprise shies away from embracing it and seems
to be more comfortable sticking with the status quo than improving
working conditions for their employees. &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Relocate.&lt;/strong&gt; This option might be drastic, yet it&amp;rsquo;s the one with
the biggest probability of success.&lt;/li&gt;
&lt;li&gt;If possible, &lt;strong&gt;use public transport&lt;/strong&gt;. Even if your total time
enroute increases, you will have more time to do something
productive while you take away some of the frustration that comes
along with commuting by car.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Earlier this year, I moved from one of the (work-wise) more remote
corners of Belgium to a far better located area; the heart of Antwerp.
To top that, I&amp;rsquo;m now living and working within walking distance of the
train station, so I&amp;rsquo;m taking the train on a daily basis. In total I&amp;rsquo;m
still on the go more than two hours, but I can now spend 75% of that
time usefully. That&amp;rsquo;s &lt;strong&gt;43 working days extra to spend each year&lt;/strong&gt;! I&amp;rsquo;ve
made a habit out of using that commute time for self-study; reading,
working on side projects and writing. This seems to have considerably
affected my state of mind for the better. I get home at night, and I&amp;rsquo;ve
already spent a considerable amount of time challenging myself
intellectually. I now no longer stress about practicing less
&amp;lsquo;productive&amp;rsquo;, but very enjoyable activities; such as playing the guitar,
working out or doing stuff around the house. I get to have both now.&lt;/p&gt;
&lt;p&gt;There are only so few hours in a day, having to spend a considerable
amount of that time just to get somewhere seems such a waste. Every day
we try tools and techniques which save us a few minutes, and should help
us improve the quality of our day-to-day lives, &lt;strong&gt;yet we often disregard
optimization of the biggest time hog of them all&lt;/strong&gt;. It goes without
saying that those numbing long commutes by car aren&amp;rsquo;t something that
I&amp;rsquo;ll ever decide to go back to lightly.&lt;/p&gt;
&lt;p&gt;When I read my &lt;a href=&#34;https://twitter.com/JefClaes&#34;&gt;Twitter&lt;/a&gt; feed in the
morning, I see a lot of other Belgian people complain about their
commute. Is this a Belgian thing only? Which means of transport do you
use for the commute? How long are you on the road each day? **Have you
done the math? **&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://news.ycombinator.org/item?id=4740839&#34;&gt;More comments on Hacker
News&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Post Web.NET Europe</title>
      <link>https://jefclaes.be/2012/10/post-webnet-europe.html</link>
      <pubDate>Mon, 22 Oct 2012 20:35:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/10/post-webnet-europe.html</guid>
      <description>&lt;p&gt;I attended and &lt;a href=&#34;http://www.jefclaes.be/2012/10/slides-and-code-from-my-webnet-europe.html&#34;&gt;spoke&lt;/a&gt; at &lt;a href=&#34;http://webnetconf.eu/&#34;&gt;Web.NET Europe in Milan&lt;/a&gt; over the weekend. This was only my fourth full day- or more conference (Techdays Belgium, &lt;a href=&#34;http://www.jefclaes.be/2010/11/teched-europe-2010-day-3.html&#34;&gt;TechEd Berlin&lt;/a&gt; and &lt;a href=&#34;http://www.jefclaes.be/2011/04/video-slides-and-source-from-my.html&#34;&gt;HTML5 WebCamps&lt;/a&gt;), but it was undoubtedly the best one so far.&lt;/p&gt;
&lt;p&gt;The quality of the sessions was definitely not inferior to those of
bigger conferences. I especially enjoyed the talks on SignalR, OAuth and
scaling data (I included some of my notes below). The strength of this
conference doesn&amp;rsquo;t lie in the exceptional speakers or sessions though,
but in its cozy size and the type of attendees it attracts. Being hosted
on a Saturday, you already preclude all the developers who merely think
of technology as a job. And when you put together those who care about
what they do, and want to get better at it, good things happen. This was
the first conference where I was able to talk to such a wide range of
people - I guess I even spoke to more than six different nationalities -
and where it didn&amp;rsquo;t feel awkward one bit. What helps in attracting such
a variety of people, is that the conference is practically free and
survives on donations from sponsors and attendees, making it very
affordable even if you fly in from outside of Italy. Freelancers also
seemed to appreciate that it was on a non-billable day.&lt;/p&gt;
&lt;p&gt;In short, I really enjoyed the experience, and it might be just so that
&lt;em&gt;weekend conferences&lt;/em&gt; make for better conferences. Congratulazioni a
&lt;a href=&#34;https://twitter.com/simonech&#34;&gt;Simone Chiaretta&lt;/a&gt; and &lt;a href=&#34;https://twitter.com/imperugo&#34;&gt;Ugo
Lattanzi&lt;/a&gt; for making this happen. I&amp;rsquo;m
already looking forward to the next edition.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-10-22-post-web-net-europe-WebDotNet.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-10-22-post-web-net-europe-WebDotNet.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;real-time-web-applications-with-signalr-in-aspnet-a_giorgetti&#34;&gt;&amp;ldquo;Real Time&amp;rdquo; Web Applications with SignalR in ASP.NET (&lt;a href=&#34;https://twitter.com/A_Giorgetti&#34;&gt;@A_Giorgetti&lt;/a&gt;)&lt;/h3&gt;
&lt;p&gt;Last year I did a talk on &lt;a href=&#34;http://www.jefclaes.be/2011/04/video-slides-and-source-from-my.html&#34;&gt;WebSockets at HTML5 WebCamps&lt;/a&gt; and although I built a few things that worked, the real-time web in the
wild was still very much a mess. &lt;a href=&#34;http://signalr.net/&#34;&gt;SignalR&lt;/a&gt; now
abstracts all that clutter for you, and provides you with a seemingly
clean infrastructure and simple API. Too bad the use for real-time web
applications is rather limited in my world - stock ticker or chat
application anyone?&lt;/p&gt;
&lt;h3 id=&#34;oauth-as-a-service-using-aspnet-web-api-and-windows-azure-access-control-maartenballiauw&#34;&gt;OAuth-as-a-service using ASP.NET Web API and Windows Azure Access Control (&lt;a href=&#34;https://twitter.com/maartenballiauw&#34;&gt;@maartenballiauw&lt;/a&gt;)&lt;/h3&gt;
&lt;p&gt;I had my first serious look at &lt;a href=&#34;http://oauth.net/&#34;&gt;OAuth&lt;/a&gt; in this
session, and while it&amp;rsquo;s probably indispensable for public API&amp;rsquo;s, it
doesn&amp;rsquo;t seem that trivial to implement. &lt;a href=&#34;http://www.windowsazure.com/en-us/develop/net/how-to-guides/access-control/&#34;&gt;Azure ACS&lt;/a&gt; could
make this easier though.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;a href=&#34;http://www.slideshare.net/maartenba/oauthasaservice-using-aspnet-web-api-and-windows-azure-access-control-webnetconf&#34;&gt;Slides&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&#34;scaling-without-going-crazy-ayende&#34;&gt;Scaling without going crazy (&lt;a href=&#34;https://twitter.com/ayende&#34;&gt;@Ayende&lt;/a&gt;)&lt;/h3&gt;
&lt;p&gt;This was one of the talks I really looked forward to, and it didn&amp;rsquo;t
disappoint one bit. I never got to do anything with big data (data that
can&amp;rsquo;t fit on one machine), but there are really interesting problems and
trade-offs in that space - &lt;a href=&#34;http://en.wikipedia.org/wiki/CAP_theorem&#34;&gt;CAP theorem&lt;/a&gt; etc.&lt;/p&gt;
&lt;p&gt;Some quotes worth giving more thought:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Caching often just hides a problem.&lt;/li&gt;
&lt;li&gt;How is Facebook consistent? It&amp;rsquo;s personally consistent.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Slides and code from my Web.NET Europe REST and ASP.NET Web API session</title>
      <link>https://jefclaes.be/2012/10/slides-and-code-from-my-webnet-europe.html</link>
      <pubDate>Sun, 21 Oct 2012 00:16:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/10/slides-and-code-from-my-webnet-europe.html</guid>
      <description>&lt;p&gt;I just returned to the hotel after attending and speaking at &lt;a href=&#34;http://webnetconf.eu/&#34;&gt;Web.NET
Europe 2012&lt;/a&gt;. There were multiple sessions on
ASP.NET Web API today, and I was responsible for delivering the first
one of the day. Being first, and to avoid overlap with others, I tried
to lay a solid foundation by focusing on the REST and ASP.NET Web API
basics: resources, identifiers, representations, verbs and hypermedia.&lt;/p&gt;
&lt;p&gt;More people than I expected showed up for my talk; somewhere around 50
to 70 attendees, I guess. I think it was fairly well received; after 25
votes, the session rating stands at 90%. It&amp;rsquo;s great to see your
preparations have such a fruitful outcome.&lt;/p&gt;
&lt;p&gt;I still have a few thoughts on the conference to materialize, but for
now, I uploaded &lt;a href=&#34;http://www.slideshare.net/jclaes/rest-and-aspnet-web-api-milan&#34;&gt;the slides&lt;/a&gt; and hosted the &lt;a href=&#34;https://github.com/JefClaes/aspnet-webapi-samples-webdotnet&#34;&gt;source code on GitHub&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Commands with dependencies</title>
      <link>https://jefclaes.be/2012/10/commands-with-dependencies.html</link>
      <pubDate>Mon, 15 Oct 2012 16:57:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/10/commands-with-dependencies.html</guid>
      <description>&lt;p&gt;&lt;em&gt;Also read: &lt;a href=&#34;http://www.jefclaes.be/2013/01/separating-command-data-from-logic-and.html&#34;&gt;Separating command data from logic and sending it on a
bus&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Yesterday I wrote about an architecture which limits abstractions &lt;a href=&#34;http://www.jefclaes.be/2012/10/commands-queries-and-testing.html&#34;&gt;by
solely introducing commands and queries&lt;/a&gt;. I shared a dead simple variation of this pattern, the advantages I experienced, and how I could still unit test the controller if I wanted to. At the end of that post I wondered how I would be able to test commands in isolation; suppose the implementation doesn&amp;rsquo;t use a database this time, but a hairy, too low-level, third party webservice.&lt;/p&gt;
&lt;p&gt;Right now, the input arguments are inserted via the constructor, but
this leaves no room to inject dependencies. That is, if we don&amp;rsquo;t want to
do awkward stuff with our Dependency Injection framework, and don&amp;rsquo;t want
to resort to property- or method injection.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;WithdrawAmountCommand&lt;/span&gt; : Command
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; WithdrawAmountCommand(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; user, &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; amount)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.IsNullOrEmpty(user))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; NullReferenceException(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;user&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        User = user;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Amount = amount;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; User { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; Amount { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Execute()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// Implementation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One way to enable injecting dependencies could be to separate the
command in two parts; the handler, and the data.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ICommandHandler&lt;/span&gt;&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; TCommandData&amp;gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Execute(TCommandData commandData);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we could rewrite the WithdrawAmountCommand. One class contains and
verifies the input data&amp;hellip;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;WithdrawAmountCommandData&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; WithdrawAmountCommandData(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; username, &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; amount)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.IsNullOrEmpty(username))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; NullReferenceException(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Username = username;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Amount = amount;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; Username { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; Amount { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip;while the second class actually acts on the data.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;WithdrawAmountCommandHandler&lt;/span&gt; : ICommandHandler&amp;lt;WithdrawAmountCommandData&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; IAccountWebservice _accountWebservice;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; WithdrawAmountCommandHandler(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        IAccountWebservice accountWebservice)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _accountWebservice = accountWebservice;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Execute(WithdrawAmountCommandData data)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _accountWebservice.Invoke(data.Username, data.Amount);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Testing commands in isolation is now straight-forward.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[TestMethod()]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Execute_should_invoke_webservice_with_correct_arguments()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; accountWebService = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Mock&amp;lt;IAccountWebservice&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; command = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; WithdrawAmountCommandHandler(accountWebService.Object); 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    command.Execute(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; WithdrawAmountCommandData(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;JefClaes&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;25&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    accountWebService.Verify(aws =&amp;gt; aws.Invoke(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;JefClaes&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;25&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Don&amp;rsquo;t forget that the controller also needs to accommodate this change.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;HomeController&lt;/span&gt; : Controller
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; IQueryHandler _qryHandler;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; ICommandHandler&amp;lt;WithdrawAmountCommandData&amp;gt; _withdrawAmountCommandHandler; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; HomeController()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _qryHandler = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; QueryHandler();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _withdrawAmountCommandHandler = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; WithdrawAmountCommandHandler(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; AccountWebservice());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; HomeController(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        IQueryHandler qryHandler,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ICommandHandler&amp;lt;WithdrawAmountCommandData&amp;gt; withdrawAmountCommandHandler)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _qryHandler = qryHandler;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _withdrawAmountCommandHandler = withdrawAmountCommandHandler;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;    [HttpPost]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; ActionResult Foo(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; user)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _withdrawAmountCommandHandler.Execute(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; WithdrawAmountCommandData(user, &lt;span style=&#34;color:#ae81ff&#34;&gt;25&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; totalAmount = _qryHandler.Execute&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&amp;gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; TotalAmountQuery(user));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (totalAmount &amp;lt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; RedirectToAction(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Warning&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; RedirectToAction(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Index&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m not all that happy with how this approach will bloat my controller
in the future to be honest. To smooth out this friction, I could - like
in the previous post - introduce a dispatcher, which serves as an
intermediary for the commandhandlers.&lt;/p&gt;
&lt;p&gt;Integration testing wasn&amp;rsquo;t an option in this scenario, so I had to
introduce some extra abstractions just to facilitate unit testing.
Although this particular variation still holds lots of advantages I
talked about in my previous post, there&amp;rsquo;s already a lot more boilerplate
and some more complexity.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I&amp;rsquo;m going to give this topic some more thought. Care to share yours?&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Commands, queries and testing</title>
      <link>https://jefclaes.be/2012/10/commands-queries-and-testing.html</link>
      <pubDate>Sun, 14 Oct 2012 17:45:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/10/commands-queries-and-testing.html</guid>
      <description>&lt;p&gt;&lt;em&gt;Also read:&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;http://www.jefclaes.be/2013/01/self-contained-commands-with.html&#34;&gt;&lt;em&gt;Self-contained commands with dependencies&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.jefclaes.be/2013/01/separating-command-data-from-logic-and.html&#34;&gt;&lt;em&gt;Separating command data from logic and sending it on a bus&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We need abstraction, but the amount of abstraction we really need
depends, and should be assessed on a case-by-case basis. It seems
advisable to grow abstractions, and to introduce them gradually.&lt;/p&gt;
&lt;p&gt;That being said, in this post I want to talk about an architecture that
tries to limit abstractions to solely commands and queries.&lt;/p&gt;
&lt;p&gt;It all starts with two small pieces of infrastructure: a command and a
query. A command performs an action, and can change state, while a query
should only return data, and not alter any state; &lt;a href=&#34;http://en.wikipedia.org/wiki/Command-query_separation&#34;&gt;basic command and
query separation&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Command&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Execute();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Query&lt;/span&gt;&amp;lt;T&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; T Execute();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now imagine, we are doing something with accounts, and we want to have a
command that can withdraw money from an account, and a query that
returns the total amount available on an account. The assumption is that
we&amp;rsquo;re only talking with a database.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;public class WithdrawAmountCommand : Command
{
    public WithdrawAmountCommand(string user, int amount)
    {
        if (string.IsNullOrEmpty(user))
            throw new NullReferenceException(&amp;#34;user&amp;#34;);                
    
        User = user;
        Amount = amount;
    }

    public string User { get; private set; }
    public int Amount { get; private set; }

    public override void Execute()
    {
        // Implementation
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We inherit from the Command class, and pass in its input arguments via
the constructor. We put our actual implementation in the &lt;code&gt;Execute&lt;/code&gt; method
override. For the query, we do something very similar.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;TotalAmountQuery&lt;/span&gt; : Query&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; TotalAmountQuery(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; user)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.IsNullOrEmpty(user))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; NullReferenceException(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;user&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        User = user;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; User { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; Execute()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;// Should be an actual implementation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, if we would use this in ASP.NET MVC, we would end up with clean and
compact controllers. Have a look at the action Foo, which first withdraws 25 euros, to then redirect to a warning action if the balance is negative, or to redirect back to the index action when it&amp;rsquo;s positive. Very readable, right?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[HttpPost]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; ActionResult Foo(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; user)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; WithdrawAmountCommand(user, &lt;span style=&#34;color:#ae81ff&#34;&gt;25&lt;/span&gt;).Execute();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; totalAmount = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; TotalAmountQuery(user).Execute();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (totalAmount &amp;lt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; RedirectToAction(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Warning&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; RedirectToAction(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Index&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There are several advantages I experienced while applying this pattern.
First, there are less layers of abstraction, while not neglecting
readability nor maintainability. In a more conservative approach, I
would end up with an account repository, abstracting my data access, and
probably also an account service, abstracting my business logic. This
repository, and service, would have multiple methods, which probably
solve related, yet different problems. I would have to wade through all
the methods in these classes to find the operation that is relevant for
me.&lt;/p&gt;
&lt;p&gt;When you model each operation as a class on its own, you define it more
explicitly. And you&amp;rsquo;re able to adhere to the Single Responsibility
principle even more. Practically, it&amp;rsquo;s now also easier to locate an
operation in the codebase by just looking at the solution explorer.&lt;/p&gt;
&lt;p&gt;One last, but not unimportant, advantage I see, is that it gets easier
to group queries and commands per functionality and context.&lt;/p&gt;
&lt;p&gt;We could test the example above against the actual implementation, and I
don&amp;rsquo;t see anything wrong with that per se, but it isn&amp;rsquo;t always that
practical; the setup of your queries can be heavy and complex,
performance of your tests might be suffering etc.. One technique would
be to create an interface per query and command and inject them, but
that seems cumbersome, and ceremony heavy, and that isn&amp;rsquo;t something I&amp;rsquo;m
willing to do.&lt;/p&gt;
&lt;p&gt;Something in between could be introducing a Command- and QueryHandler.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ICommandHandler&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Execute(Command command);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CommandHandler&lt;/span&gt; : ICommandHandler
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Execute(Command command)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        command.Execute();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IQueryHandler&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    T Execute&amp;lt;T&amp;gt;(Query&amp;lt;T&amp;gt; query);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;QueryHandler&lt;/span&gt; : IQueryHandler
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; T Execute&amp;lt;T&amp;gt;(Query&amp;lt;T&amp;gt; query)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; query.Execute();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These could be injected into the controller, and be used as an
intermediary to execute queries and commands for us.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;HomeController&lt;/span&gt; : Controller
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; IQueryHandler _qryHandler;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;readonly&lt;/span&gt; ICommandHandler _cmdHandler;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; HomeController()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _qryHandler = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; QueryHandler();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _cmdHandler = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; CommandHandler();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; HomeController(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ICommandHandler cmdHandler, IQueryHandler qryHandler)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _cmdHandler = cmdHandler;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _qryHandler = qryHandler;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;    [HttpPost]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; ActionResult Foo(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; user)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _cmdHandler.Execute(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; WithdrawAmountCommand(user, &lt;span style=&#34;color:#ae81ff&#34;&gt;25&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; totalAmount = _qryHandler.Execute&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&amp;gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; TotalAmountQuery(user));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (totalAmount &amp;lt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; RedirectToAction(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Warning&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; RedirectToAction(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Index&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This technique would make it possible, and easy, to use stubs or mocks
for queries and commands.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[TestMethod()]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Foo_should_withdraw_25_euros_from_the_account_of_jef_claes()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; cmdHandler = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Mock&amp;lt;ICommandHandler&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; qryHandler = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Mock&amp;lt;IQueryHandler&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; controller = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; HomeController(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        cmdHandler.Object, qryHandler.Object);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    controller.Foo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;JefClaes&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    cmdHandler.Verify(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        h =&amp;gt; h.Execute(It.Is&amp;lt;WithdrawAmountCommand&amp;gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            c =&amp;gt; c.Amount == &lt;span style=&#34;color:#ae81ff&#34;&gt;25&lt;/span&gt; &amp;amp;&amp;amp; c.User == &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;JefClaes&amp;#34;&lt;/span&gt;)));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[TestMethod()]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Foo_should_redirect_to_a_warning_page_when_amount_negative()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; cmdHandler = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Mock&amp;lt;ICommandHandler&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; qryHandler = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Mock&amp;lt;IQueryHandler&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    qryHandler
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .Setup(h =&amp;gt; h.Execute&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&amp;gt;(It.IsAny&amp;lt;TotalAmountQuery&amp;gt;()))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .Returns(-&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; controller = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; HomeController(cmdHandler.Object, qryHandler.Object);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; result = (RedirectToRouteResult)controller.Foo(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;JefClaes&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Assert.AreEqual(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Warning&amp;#34;&lt;/span&gt;, result.RouteValues[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;action&amp;#34;&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I don&amp;rsquo;t think this should be introduced as an application-wide thing
necessarily, but it could only be used when testing the actual
implementation becomes hard or awkward.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;But what if I need to inject dependencies into my commands or queries
for testing - there is more to it than a database?&lt;/strong&gt; I gave that some
thought as well, and it seems inevitable to introduce extra abstractions, and make changes to the concepts discussed above; I&amp;rsquo;ll publish these tomorrow.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I&amp;rsquo;ve been entertaining lots of ideas on this topic lately, and I&amp;rsquo;m
curious to hear yours.&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Côte d&#39;Opale</title>
      <link>https://jefclaes.be/2012/10/cote-dopale.html</link>
      <pubDate>Mon, 08 Oct 2012 21:51:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/10/cote-dopale.html</guid>
      <description>&lt;p&gt;The girlfriend, me and another couple, returned from a short weekend at
the &lt;a href=&#34;http://en.wikipedia.org/wiki/C%C3%B4te_d&#39;Opale&#34;&gt;French Opal Coast&lt;/a&gt;
yesterday evening. Although we only planned this trip a  week in
advance, we still failed to anticipate how erratic the weather can be in
October; setting up camp in the dark, on a sloughy underground, with a
soft drizzle on your back, isn&amp;rsquo;t my idea of fun after a long day at
work. The next morning, with destination &lt;a href=&#34;http://en.wikipedia.org/wiki/Cap_Blanc_Nez&#34;&gt;Cape Blanc Nez&lt;/a&gt;, we drove over coastal
routes between vast green fields, towards clearer skies. Passing white
cliffs of clay and untouched beaches, we eventually halted at the
obelisk commemorating the &lt;a href=&#34;http://en.wikipedia.org/wiki/Dover_Patrol&#34;&gt;Dover Patrol&lt;/a&gt; for a while. Here you can clearly see the English coast on the other side of the canal; no
wonder this spot was strategically ideal to safeguard the canal during
World War I. Differing from the main route, we discovered the ramshackle
remainder of a bunker. I think it&amp;rsquo;s fascinating how quickly something
what once played an important role in our history, can lose its
prestige, and be seen for what it is: a massive block of concrete.&lt;/p&gt;
&lt;p&gt;I honestly was taken aback by the beauty of the Northern French coast. I
had always unjustifiably ignored this area, and now I will definitely
have to revisit.&lt;/p&gt;
&lt;p&gt;Sunday, before leaving, we visited a local
&lt;a href=&#34;http://en.wikipedia.org/wiki/Bric-%C3%A0-brac&#34;&gt;bric-à-brac&lt;/a&gt;. Just
before returning to the car, my girlfriend spotted an antique camera
satchel, which she thought would make a unique accessory - you know how
girls are, right? The woman behind the stand wouldn&amp;rsquo;t let it go without
the camera though, and asked too much for both, so we strolled on.
Passing the same spot a few minutes later, she inquired how much we
wanted to give her for it. Mistakenly, my girlfriend said &lt;em&gt;dix-cinq&lt;/em&gt;
(ten five) instead of using the more correct &lt;em&gt;quinze&lt;/em&gt; (fifteen). The
woman understood this as &lt;em&gt;dis cinq&lt;/em&gt; (how about five), and doubled it to
ten. Sold! And that&amp;rsquo;s how my girlfriend saved herself five euros without
even having to haggle.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-10-08-cote-dopale-IMG_2254.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-10-08-cote-dopale-IMG_2254.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-10-08-cote-dopale-IMG_2311.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-10-08-cote-dopale-IMG_2311.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-10-08-cote-dopale-IMG_2341.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-10-08-cote-dopale-IMG_2341.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-10-08-cote-dopale-IMG_2353.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-10-08-cote-dopale-IMG_2353.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thanks to our companion Lars Oliviers for letting me put his pictures in
this post.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>On job titles</title>
      <link>https://jefclaes.be/2012/10/on-job-titles.html</link>
      <pubDate>Sun, 07 Oct 2012 19:22:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/10/on-job-titles.html</guid>
      <description>&lt;p&gt;It didn&amp;rsquo;t take long before I noticed how little job titles mean. In my
first job, you were assured to be granted &lt;a href=&#34;http://www.bullshitjob.com/title/&#34;&gt;a fancy
title&lt;/a&gt; after only having acquired a
minimum seniority, if you knew how to play the game. A more important
sounding job title was HR&amp;rsquo;s default bribe that often kept people from
leaving for greener pastures, for a short while. But even after being
upgraded from a stable cleaner to a Senior Barn Hygiene Technician,
you&amp;rsquo;re still cleaning shit though.&lt;/p&gt;
&lt;p&gt;It goes without saying that I grew a healthy aversion from the hypocrisy
of job titles pretty early on. They are nothing but easy incentives to
provide volatile satisfaction, and are mostly worth just as much as it
costs your company to grant them.&lt;/p&gt;
&lt;p&gt;I always believed that the title you carry is rather meaningless.
Everybody knows of a senior developer, technical lead, or architect, you
wouldn&amp;rsquo;t go to with any remotely technical question. Then again, I also
know of people who can&amp;rsquo;t be bothered to bargain another title, but have
an extensive skill set, and can carry a project to the finish line.
Without them, projects would have crashed and burned before lift off.&lt;br&gt;
How people perceive you isn&amp;rsquo;t something that can be enforced by a title,
it&amp;rsquo;s the result of your everyday actions. When you display mastery in
what you love doing, people will take notice, and the word will spread
like a wildfire. Eventually, work that you love doing will come to you,
regardless of your job title. People want you to be on their team,
because they care about what you bring to the table, not about what your
job title is.&lt;/p&gt;
&lt;p&gt;While I still stand by this view, it might be a bit too naive. Job title
dynamics differ from company to company, and need to be examined
carefully on a case-by-case basis. For example, in the classic
enterprise, a title can influence your job substantially. There, when
assembling a team, management often doesn&amp;rsquo;t see an individual, but they
see a resource playing a role. There, your reputation doesn&amp;rsquo;t always
have the chance to precede itself, but your title does. It would be a
damn shame if such a small detail, a few words on a piece of paper,
would regularly put you off to a bad start. Each organization also has a
distinct opinion on what a certain title entails. It&amp;rsquo;s worth studying
these subtleties to be able to pick one that comes closest to what you
want to do.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s what you do that defines you, not your title. Yet, it&amp;rsquo;s often
indivertible to play along; titles can serve as a means to an end.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I&amp;rsquo;m interested in hearing your opinion. Do you think they are
important, or do you just play along? Have you ever regretted not
caring?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Bonus: &lt;a href=&#34;https://lh6.googleusercontent.com/-KKVe0ReDads/UG0zb-kNxkI/AAAAAAAABZw/YQnJwnmnCk0/s512/Futurama_JobTitle.jpg&#34;&gt;relevant Futurama scene&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>The 7 R&#39;s of Hypermedia</title>
      <link>https://jefclaes.be/2012/09/the-7-rs-of-hypermedia.html</link>
      <pubDate>Mon, 17 Sep 2012 21:42:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/09/the-7-rs-of-hypermedia.html</guid>
      <description>&lt;p&gt;While most &lt;a href=&#34;http://www.jefclaes.be/2012/09/slides-and-code-from-my-tunisia-rest.html&#34;&gt;REST concepts&lt;/a&gt; are rather easy to grok, there is one concept which I found harder to understand at first: Hypermedia. Let it be that without this concept, you&amp;rsquo;re missing out on an extremely important strength of REST. Hypermedia enables you to build dumb - or smart, depending on your perspective - clients, which are mostly driven by the server. Practically, this is implemented as resources embedding links which
allow the client to discover and navigate through your RESTful
service.&lt;/p&gt;
&lt;p&gt;Accidentally actually, I saw &lt;a href=&#34;https://twitter.com/tourismgeek&#34;&gt;someone&lt;/a&gt;
tweet a link over the weekend to a &lt;a href=&#34;http://deepfriedbytes.com/&#34;&gt;Deep Fried Bytes&lt;/a&gt; episode, featuring &lt;a href=&#34;http://www.bizcoder.com/&#34;&gt;Darrel Miller&lt;/a&gt;, where he talks about the seven R&amp;rsquo;s of Hypermedia. I listened to it on my morning commute, and the 56 minutes long show contained one of the best summaries on the uses of Hypermedia I&amp;rsquo;ve heard or read so far.&lt;br&gt;
Here are some of my notes&amp;hellip;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;R&lt;/strong&gt;elations: Make your service discoverable and self-documenting by embedding links to related concepts.&lt;/li&gt;
&lt;li&gt;Embedded &lt;strong&gt;r&lt;/strong&gt;esources: Instead of embedding resources (for example: a company logo) into your client, and having to deal with specific storage techniques, make them available through your service and use built-in HTTP caching.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;R&lt;/strong&gt;eference data: Provide links to where your client can find optional or required reference data. Populating a dropdownlist is a good example. &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;R&lt;/strong&gt;edistribution of effort: Instead of putting a dumb load balancer in front of your machines, you can use your links to refer certain functionality to a specific machine.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;R&lt;/strong&gt;eduction of payload size: Show clients where they can get extra data. Think endless scrolling, or more detailed resources.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;R&lt;/strong&gt;eflow: Allow the server to control the flow. The server can use links to dictate the next available steps in a business process. &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;R&lt;/strong&gt;estriction of functionality: The client can derive from the presence of a certain link whether a certain functionality is enabled or disabled.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can find the full show &lt;a href=&#34;http://deepfriedbytes.com/podcast/episode-90-going-through-the-7-r-rsquo-s-of-hypermedia-with-darrel-miller/&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Slides and code from my Tunisia REST and ASP.NET Web API session</title>
      <link>https://jefclaes.be/2012/09/slides-and-code-from-my-tunisia-rest.html</link>
      <pubDate>Thu, 13 Sep 2012 08:55:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/09/slides-and-code-from-my-tunisia-rest.html</guid>
      <description>&lt;p&gt;I just returned from a four day trip to Tunisia with &lt;a href=&#34;http://www.euri.com/&#34;&gt;Euricom&lt;/a&gt;. Next to indulging on the sun, food and all-inclusive cocktails, getting to know each other in a less professional setting, we spent somewhere around half of our days - and this is a rather generous estimate - doing technical sessions and workshops.&lt;/p&gt;
&lt;p&gt;I gave a 90 minute long crash course on REST and ASP.NET Web API.&lt;/p&gt;
&lt;h3 id=&#34;content&#34;&gt;Content&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;REST:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Concepts&lt;/li&gt;
&lt;li&gt;Architectural values&lt;/li&gt;
&lt;li&gt;Left overs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;ASP.NET Web API&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Server/client&lt;/li&gt;
&lt;li&gt;Exception handling&lt;/li&gt;
&lt;li&gt;Content negotiation&lt;/li&gt;
&lt;li&gt;Message handlers&lt;/li&gt;
&lt;li&gt;IoC&lt;/li&gt;
&lt;li&gt;Testing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can find the &lt;a href=&#34;http://www.slideshare.net/jclaes/rest-and-aspnet-web-api-tunisia&#34;&gt;slides on SlideShare&lt;/a&gt;. The &lt;a href=&#34;https://github.com/JefClaes/aspnet-webapi-samples-tunisia&#34;&gt;code is hosted on GitHub&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Supporting the OPTIONS verb in ASP.NET Web API</title>
      <link>https://jefclaes.be/2012/09/supporting-options-verb-in-aspnet-web.html</link>
      <pubDate>Sun, 02 Sep 2012 18:27:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/09/supporting-options-verb-in-aspnet-web.html</guid>
      <description>&lt;p&gt;&lt;a href=&#34;http://www.asp.net/web-api&#34;&gt;ASP.NET Web API&lt;/a&gt; controllers support only
four HTTP verbs by convention: GET, PUT, POST and DELETE. The &lt;a href=&#34;http://annevankesteren.nl/2007/10/http-methods&#34;&gt;full list
of existing HTTP verbs&lt;/a&gt;
is more extensive though. One of those unsupported verbs which can be
particularly useful for API discovery and documentation is the &lt;a href=&#34;http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html&#34;&gt;OPTIONS
verb&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The OPTIONS method represents a request for information about the
communication options available on the request/response chain
identified by the Request-URI. This method allows the client to
determine the options and/or requirements associated with a resource,
or the capabilities of a server, without implying a resource action or
initiating a resource retrieval.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If we wanted to implement controller support for the OPTIONS verb, we
could manually map an action to the verb by decorating it with an
AcceptVerbs attribute, and making the action return a response with a
relevant Access-Control-Allow-Methods header.&lt;/p&gt;
&lt;p&gt;For a values controller, with a GET and DELETE action, it could look
like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ValuesController&lt;/span&gt; : ApiController
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; IEnumerable&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&amp;gt; Get()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;[] { &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;value1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;value2&amp;#34;&lt;/span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }                 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Delete(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; id) { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;    [AcceptVerbs(&amp;#34;OPTIONS&amp;#34;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; HttpResponseMessage Options()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; resp = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; HttpResponseMessage(HttpStatusCode.OK);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        resp.Headers.Add(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Access-Control-Allow-Origin&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        resp.Headers.Add(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Access-Control-Allow-Methods&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;GET,DELETE&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; resp;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If we now make an OPTIONS request to http://localhost:53314/api/values..&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;OPTIONS http://localhost:53314/api/values HTTP/1.1
User-Agent: Fiddler
Host: localhost:53314
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;..we receive following response.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Sun, 02 Sep 2012 13:46:21 GMT
X-AspNet-Version: 4.0.30319
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,DELETE
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Content-Length: 0
Connection: Close
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;While this works, it&amp;rsquo;s not a great solution. We don&amp;rsquo;t want to maintain
the list of supported verbs manually, and we certainly don&amp;rsquo;t want to
repeat this for each controller.&lt;/p&gt;
&lt;p&gt;ASP.NET Web API provides a nice way to have a more high level solution:
&lt;a href=&#34;http://www.asp.net/web-api/overview/working-with-http/http-message-handlers&#34;&gt;HTTP message handlers&lt;/a&gt;. These basically behave as HTTP intermediaries, meaning we can intercept each &lt;code&gt;OPTIONS&lt;/code&gt; request early, and bypass the whole request chain. Another useful component we can make good use of is the default
&lt;a href=&#34;http://blogs.msdn.com/b/yaohuang1/archive/2012/05/21/asp-net-web-api-generating-a-web-api-help-page-using-apiexplorer.aspx&#34;&gt;ApiExplorer&lt;/a&gt;;
this abstraction allows us to obtain metadata of our API&amp;rsquo;s stucture.&lt;/p&gt;
&lt;p&gt;To create a new HTTP message handler, I inherited from the
&lt;code&gt;DelegatingHandler&lt;/code&gt; class, and overwrote the &lt;code&gt;SendAsync&lt;/code&gt; method. Here we&amp;rsquo;ll
intercept the request when the verb equals &lt;code&gt;OPTIONS&lt;/code&gt;. An instance of the
Api explorer can be resolved through the global configuration. I grab
the requested controller from the request route data, and use that to
search the Api explorer&amp;rsquo;s &lt;code&gt;ApiDescriptions&lt;/code&gt; collection for its associated
actions, and its associated verbs. Once I get the outcome of this
lookup, and at least one verb is supported (*), I&amp;rsquo;ll return an OK
response with the relevant headers, and thus short circuit the
request.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;OptionsHttpMessageHandler&lt;/span&gt; : DelegatingHandler
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; Task&amp;lt;HttpResponseMessage&amp;gt; SendAsync(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        HttpRequestMessage request, CancellationToken cancellationToken)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (request.Method == HttpMethod.Options)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; apiExplorer = GlobalConfiguration.Configuration.Services.GetApiExplorer();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; controllerRequested = request.GetRouteData().Values[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;controller&amp;#34;&lt;/span&gt;] &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;;              
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; supportedMethods = apiExplorer.ApiDescriptions
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .Where(d =&amp;gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; controller = d.ActionDescriptor.ControllerDescriptor.ControllerName;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.Equals(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        controller, controllerRequested, StringComparison.OrdinalIgnoreCase);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .Select(d =&amp;gt; d.HttpMethod.Method)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .Distinct();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (!supportedMethods.Any())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Task.Factory.StartNew(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    () =&amp;gt; request.CreateResponse(HttpStatusCode.NotFound));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Task.Factory.StartNew(() =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; resp = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; HttpResponseMessage(HttpStatusCode.OK);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                resp.Headers.Add(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Access-Control-Allow-Origin&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                resp.Headers.Add(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Access-Control-Allow-Methods&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.Join(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;,&amp;#34;&lt;/span&gt;, supportedMethods));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; resp;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;base&lt;/span&gt;.SendAsync(request, cancellationToken);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Register this HTTP message handler by adding it to the configuration.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GlobalConfiguration.Configuration.MessageHandlers.Add(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; OptionsHttpMessageHandler());
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This second solution still yields the same result, but is far more
scalable.&lt;/p&gt;
&lt;p&gt;(*) When a resource can&amp;rsquo;t be read nor manipulated, it must not exist right?&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Is serialization really that expensive?</title>
      <link>https://jefclaes.be/2012/08/is-serialization-really-that-expensive.html</link>
      <pubDate>Wed, 22 Aug 2012 13:19:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/08/is-serialization-really-that-expensive.html</guid>
      <description>&lt;p&gt;While wading through an exotic codebase, I stumbled upon a static class
named Convert. This class contained somewhere around 2700
(non-generated) lines of code, where each method manually converted some
object to a simple textual representation. These methods were then used
to convert requests and reponses to and from a remote third party
service before logging them to the database for auditing reasons.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Convert&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; PaymentRequest(PaymentRequest req)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; sb = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; StringBuilder();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        sb.Append(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Reference: &amp;#34;&lt;/span&gt; + req.Reference + &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; - &amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        sb.Append(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;NumberOfLicenses: &amp;#34;&lt;/span&gt; + req.NumberOfLicenses + &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; - &amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        sb.Append(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;PricePerLicense: &amp;#34;&lt;/span&gt; + req.PricePerLicense + &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; - &amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        sb.Append(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CardNumber: &amp;#34;&lt;/span&gt; + req.CardNumber + &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; - &amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        sb.Append(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Address: &amp;#34;&lt;/span&gt; + req.Address);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; sb.ToString();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;My first thoughts were something along of the lines of &amp;ldquo;What the.. this
is insanely stupid code.&amp;rdquo; This must be a PITA to maintain and be
extremely error-prone. Looking at the solution now, it looks simple
enough to move that to some infrastructure and have the conversion done
by something more generic. &lt;a href=&#34;http://james.newtonking.com/projects/json-net.aspx&#34;&gt;Serializing to JSON&lt;/a&gt; comes to mind; interpretable by man ánd machine.&lt;/p&gt;
&lt;p&gt;Trying not to jump to conclusions, I looked for one of the remaining
team members, and asked why they made that decision. &amp;ldquo;Well&amp;rdquo;, he said,
&amp;ldquo;Those remote service calls are expensive as is; it&amp;rsquo;s a slow connection,
we have to encrypt everything going over the wire, and we can&amp;rsquo;t make
them asynchronously. We optimized where we could. Including logging.&amp;rdquo;&lt;br&gt;
I asked if they found serialization to be so expensive that it could
warrant all the monkey code. He said yes, but that he couldn&amp;rsquo;t vouch for
the decision since &lt;em&gt;they never measured&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Later that day, I took five minutes to see how the two really compare. I
have &lt;a href=&#34;http://stackoverflow.com/questions/1047218/benchmarking-small-code-samples-in-c-can-this-implementation-be-improved&#34;&gt;this code snippet&lt;/a&gt;
lying around if I quickly want to profile something.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Profile(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; description, &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; iterations, Action func)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// clean up&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    GC.Collect();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    GC.WaitForPendingFinalizers();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    GC.Collect();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// warm up &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    func();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; watch = Stopwatch.StartNew();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; i = &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; i &amp;lt; iterations; i++)    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        func();    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    watch.Stop();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Console.Write(description);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Console.WriteLine(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Time Elapsed {0} ms&amp;#34;&lt;/span&gt;, watch.ElapsedMilliseconds);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I picked an average sized object graph and ran the benchmark.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; req = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; PaymentRequest()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Reference = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ABC123&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    NumberOfLicenses = &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    PricePerLicense = &lt;span style=&#34;color:#ae81ff&#34;&gt;15.99&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    CardNumber = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;123456&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Address = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Sunset Boulevard&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Profile(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Serializing a request.&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, () =&amp;gt;       Newtonsoft.Json.JsonConvert.SerializeObject(req));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Profile(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Doing it manually.&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, () =&amp;gt; Convert.PaymentRequest(req));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This yielded following results.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Serializing a request. Time Elapsed 0 ms
Doing it manually. Time Elapsed 0 ms
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Neglectable.&lt;/p&gt;
&lt;p&gt;Turning up the number of iterations to 100 produces following results.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Serializing a request. Time Elapsed 9 ms
Doing it manually. Time Elapsed 1 ms
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This time around, we see a huge relative difference; doing it manually
is 9 times as fast. The absolute difference is still neglectable
though.&lt;/p&gt;
&lt;p&gt;As it turns out, for this specific scenario, with &lt;a href=&#34;http://james.newtonking.com/projects/json-net.aspx&#34;&gt;this specific serialization library&lt;/a&gt;, the
overhead of serialization would be very tolerable. Other serialization
libraries might produce &lt;a href=&#34;https://lh3.googleusercontent.com/-bZNx64Vindc/UDS-q5630JI/AAAAAAAABYk/DeNUYA9ARMs/s611/jsonperformance.png&#34;&gt;less tolerable results&lt;/a&gt; though. It&amp;rsquo;s important to measure this stuff; I&amp;rsquo;m (re)learning almost daily that &lt;em&gt;assuming is a mistake&lt;/em&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Measurement is the first step that leads to control and eventually to
improvement. If you can&amp;rsquo;t measure something, you can&amp;rsquo;t understand it.
If you can&amp;rsquo;t understand it, you can&amp;rsquo;t control it. If you can&amp;rsquo;t control
it, you can&amp;rsquo;t improve it. - H. James Harrington&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    
    <item>
      <title>My learning resources distilled</title>
      <link>https://jefclaes.be/2012/08/my-learning-resources-distilled.html</link>
      <pubDate>Sun, 19 Aug 2012 16:10:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/08/my-learning-resources-distilled.html</guid>
      <description>&lt;p&gt;I have picked up a few new tools this summer (&lt;a href=&#34;http://www.mongodb.org/&#34;&gt;MongoDB&lt;/a&gt;, &lt;a href=&#34;http://nancyfx.org/&#34;&gt;NancyFx&lt;/a&gt; and &lt;a href=&#34;http://www.asp.net/web-api&#34;&gt;WebAPI&lt;/a&gt;), and it occurred to me that I&amp;rsquo;ve built certain habits these last few years in how I make use of all the learning resources out there.&lt;/p&gt;
&lt;p&gt;I tried to identify all of them, to then categorize them, to finally
order them according to in which phase of my study process I use them.&lt;/p&gt;
&lt;h3 id=&#34;the-written-and-spoken-word&#34;&gt;The written and spoken word&lt;/h3&gt;
&lt;p&gt;The first thing I look for online is documentation. It might be a
coincidence, but all the documentation I found for these three tools was
excellent. It seems obvious, now more than ever, that the early
adaptation of new tools can be proportional to the quality of their
documentation.&lt;/p&gt;
&lt;p&gt;When there is no documentation - studying a concept instead of a
technology, when the documentation is too dispersed, or when the quality
is too low, I might order a book. The problem with technical books
though, is that they are often too lengthy. I think the first publisher
that cuts down on the number of pages, while guarding quality, will be
pleasantly surprised by demand. I really like &lt;a href=&#34;http://openmymind.net/2011/3/28/The-Little-MongoDB-Book/&#34;&gt;the &amp;ldquo;Little book&amp;rdquo; format&lt;/a&gt; &lt;a href=&#34;http://openmymind.net/&#34;&gt;Karl Seguin&lt;/a&gt; has been experimenting with.&lt;/p&gt;
&lt;p&gt;When there is no documentation, and there are no books, I find myself
turning to the spoken word. In general, I prefer reading over watching
and listening because I can do that at my own pace, skip chapters, or
quickly skim back for a look-up.&lt;/p&gt;
&lt;p&gt;Although often on the slow side, the videocasts from Pluralsight are not
bad. If you don&amp;rsquo;t want to subscribe to one of the paid videocast
services, you can also watch recorded conference sessions instead.
Before I commuted by train, I also listened to relevant podcasts.&lt;/p&gt;
&lt;h3 id=&#34;getting-intimate&#34;&gt;Getting intimate&lt;/h3&gt;
&lt;p&gt;As I wrote earlier, &lt;a href=&#34;http://www.jefclaes.be/2012/03/learning-hacker-way.html&#34;&gt;I am a strong advocate of learning by doing&lt;/a&gt;. Find &lt;a href=&#34;http://www.jefclaes.be/2011/09/building-small-things.html&#34;&gt;something small&lt;/a&gt;, and
build it.&lt;/p&gt;
&lt;p&gt;When I&amp;rsquo;m using a new tool, I also tend to regularly peek at its
internals to improve my understanding of how the tool works under the
covers. It&amp;rsquo;s never a bad idea to get intimate with the tools you rely
on.&lt;/p&gt;
&lt;p&gt;This becomes extremely easy when the tool you are using is OSS and uses
a source control provider that makes it easy to browse or fork the
source - read GitHub. If the tool isn&amp;rsquo;t OSS, you can still decompile the
sources using one of the free decompilation options out there. If you
have a Resharper 6 license, you can even decompile straight from Visual
Studio.&lt;/p&gt;
&lt;h3 id=&#34;sipping-from-the-fire-hose&#34;&gt;Sipping from the fire hose&lt;/h3&gt;
&lt;p&gt;Once I start building something, I crank open the fire hose - Twitter
Search, and take a sip. Although trying to consume all the information
on a subject is hardly bearable, and feels as being waterboarded at
times, I think it&amp;rsquo;s a necessary evil. Until you have assembled your
personal digest, that is.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll do my best to keep up with the Twitter Search feed for a while, and
try to filter knowledgeable people to follow, blogs to subscribe to, and
repositories to watch. Once I have a qualitative list of subscriptions,
I&amp;rsquo;ll shut off the fire hose, and limit my consummation to my personal
high quality-to-noise digest. This digest will serve as one of the
biggest aids in continuously improving my knowledge of said tool.&lt;/p&gt;
&lt;h3 id=&#34;free-pop-quizzes&#34;&gt;Free pop quizzes&lt;/h3&gt;
&lt;p&gt;I always thought that if you really want to become good at something -
become an expert, you must have spent time in the trenches, knees deep
in shit. Experiences like this force you to broaden your understanding
of a technology.&lt;/p&gt;
&lt;p&gt;Next to problems you encounter producing things, you can also simulate
this experience by following &lt;a href=&#34;http://stackoverflow.com/&#34;&gt;Stackoverflow&lt;/a&gt;
questions and commit to help solving them. The less ambitious can also
wait a while, and just skim over the questions and their answers. The
same goes for mailing lists obviously.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I&amp;rsquo;m very curious to hear about the techniques you use to unravel all
the information out there.&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Finito</title>
      <link>https://jefclaes.be/2012/07/finito.html</link>
      <pubDate>Mon, 30 Jul 2012 22:23:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/07/finito.html</guid>
      <description>&lt;p&gt;With this last post, our trip to Italy has come to an end. We have spent
these last few days practicing several indispensable tourist activities:
testing the ice cold lake water, to wriggle between other sunbathers on
the packed beach right after, exuberant eating and drinking, reading
novels, and sauntering between prullaria shops.&lt;/p&gt;
&lt;p&gt;Fortuitously, one of our last evenings here was upgraded by fireworks
over an already moonlit Lake Garda. This outlying location gave the
fireworks show an extra notch. With each firework rocket, the pitch dark
beach was illuminated for a few seconds. With each bang, the sound
echoed over the mountains, making the water ripple to strand in the
pebble beach eventually.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-07-30-finito-Garda_0640.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-07-30-finito-Garda_0640.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Milano</title>
      <link>https://jefclaes.be/2012/07/milano.html</link>
      <pubDate>Fri, 27 Jul 2012 22:25:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/07/milano.html</guid>
      <description>&lt;p&gt;After &lt;a href=&#34;http://www.jefclaes.be/2012/07/the-floating-city.html&#34;&gt;Venice on Wednesday&lt;/a&gt;, we decided to stay in Torbole for a relaxing hike yesterday. As it turned out, the hiking trail that was described in the brochures as suitable for all and with a duration of 1h20, in reality took us 2h30 and sour calves to complete. The views of the lake&amp;rsquo;s valley and its school of windsurfers defying the wind were worth the sweat though. Arriving at the endpoint, and discovering that we had to wait over an hour for the bus to take us back, we stumbled upon one of the best hidden lake side terraces we&amp;rsquo;ve seen yet.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-07-27-milano-Garda_0478.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-07-27-milano-Garda_0478.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-07-27-milano-Garda_0491.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-07-27-milano-Garda_0491.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Since the days of our dolce vita are numbered, we made our last big trip
today: &lt;a href=&#34;http://en.wikipedia.org/wiki/Milan&#34;&gt;Milano&lt;/a&gt;. We parked our car
in the suburbs, where you pay only a quarter an hour and have a direct
metro-connection to the &lt;a href=&#34;http://en.wikipedia.org/wiki/Duomo&#34;&gt;Duomo&lt;/a&gt;.
While we&amp;rsquo;ve had it with churches in general, we couldn&amp;rsquo;t let this one
slip. The Milanese Duomo is the third biggest church in all of
Christendom and could easily host a Metallica concert. The entrance to
the church is free, but if you want to visit the rooftop, you pay 7€ on
foot (250 stairs) or 12€ if you want to take the elevator. Although the
panorama wasn&amp;rsquo;t as striking as the one we had seen yesterday, the
architecture and craftsmanship of the rooftop details are worth to see
up close. After that, we continued the &amp;lsquo;Old City&amp;rsquo; itinerary of our
travel guide, which includes the &lt;a href=&#34;http://en.wikipedia.org/wiki/Galleria_Vittorio_Emanuele_II&#34;&gt;Galleria Vittorio Emanuele
II&lt;/a&gt; and the
&lt;a href=&#34;http://en.wikipedia.org/wiki/La_Scala&#34;&gt;Teatro alla Scala&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-07-27-milano-Garda_0510.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-07-27-milano-Garda_0510.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-07-27-milano-Garda_0563.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-07-27-milano-Garda_0563.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>The Floating City</title>
      <link>https://jefclaes.be/2012/07/the-floating-city.html</link>
      <pubDate>Thu, 26 Jul 2012 00:38:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/07/the-floating-city.html</guid>
      <description>&lt;p&gt;Yesterday we cruised along the eastern coastline of &lt;a href=&#34;http://en.wikipedia.org/wiki/Lake_Garda&#34;&gt;Lake
Garda&lt;/a&gt;. Plan A was to visit
&lt;a href=&#34;http://en.wikipedia.org/wiki/Malcesine&#34;&gt;Malcesine&lt;/a&gt; and take the
cableway up to the top of &lt;a href=&#34;http://en.wikipedia.org/wiki/Monte_Baldo&#34;&gt;Monte
Baldo&lt;/a&gt;, but since the line at
the ticket center resembled one of a Justin Bieber concert, we skipped
the cableway. Maybe we&amp;rsquo;ll give it another try later this week, but then
earlier in the day. We continued our journey along the coast, passing
past several genuinely picturesque villages. We stopped in Garda for an
elaborate lake side lunch, before continuing to our last destination
that day, &lt;a href=&#34;http://en.wikipedia.org/wiki/Sirmione&#34;&gt;Sirmione&lt;/a&gt;. There we
visited the medieval castello Scaligero and after climbing the numerous
steps inside the castle, we rewarded ourselves with an oversized typical
Italian gelato. &lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-07-26-the-floating-city-Garda_0238.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-07-26-the-floating-city-Garda_0238.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Today we made a trip to &lt;a href=&#34;http://en.wikipedia.org/wiki/Venice&#34;&gt;Venice&lt;/a&gt;.
After a 2 hour drive, we parked our car at Venezia Mestre train station,
to enter the Floating City by train. We soon found ourselves lost in a
maze of fairy alleys and waterways, searching for the main tourist
attractions. First we headed for the Mercato Rialto, which is probably
the best market in the world, but we can’t confirm that since it was
already cleared out when we got there at 2PM. After having some
delicious fresh fruit at the foot of the &lt;a href=&#34;http://en.wikipedia.org/wiki/Rialto_Bridge&#34;&gt;ponte di
Rialto&lt;/a&gt;, we crossed the
famous bridge stacked with souvenir shops. Arriving at Piazza San Marco,
we took the time to visit the impressive &lt;a href=&#34;http://en.wikipedia.org/wiki/St_Mark%27s_Basilica&#34;&gt;basilica San
Marco&lt;/a&gt; and the
gigantesque &lt;a href=&#34;http://en.wikipedia.org/wiki/Doge%27s_Palace,_Venice&#34;&gt;Doge&amp;rsquo;s
palace&lt;/a&gt;. While
these classics were definitely worthwhile, you can&amp;rsquo;t miss out on
strolling around the less tourist neighborhoods to experience the
authentic Venice.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-07-26-the-floating-city-Garda_0341.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-07-26-the-floating-city-Garda_0341.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-07-26-the-floating-city-Garda_0347.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-07-26-the-floating-city-Garda_0347.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-07-26-the-floating-city-Garda_0356.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-07-26-the-floating-city-Garda_0356.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-07-26-the-floating-city-Garda_0422.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-07-26-the-floating-city-Garda_0422.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Ferrari red. Lamborghini yellow.</title>
      <link>https://jefclaes.be/2012/07/ferrari-red-lamborghini-yellow.html</link>
      <pubDate>Tue, 24 Jul 2012 00:56:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/07/ferrari-red-lamborghini-yellow.html</guid>
      <description>&lt;p&gt;After 14 hours and 34 minutes in the car, driving 1148km, over the German autobahn, swerving Austrian roads, and the Italian autostrade, defying overwhelming hail storms, roadwork and miles long tunnel congestions, we arrived at Torbole, Italy.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://en.wikipedia.org/wiki/Nago-Torbole&#34;&gt;Torbole&lt;/a&gt; is a small village,
nestled between the mountains, right at the edge of &lt;a href=&#34;http://en.wikipedia.org/wiki/Lake_Garda&#34;&gt;Lake
Garda&lt;/a&gt;. While the lakeside view
is astonishing, you have to pick the right time to truly experience it.
In the daytime, the village is overwhelmed by tourists; miles long rows
of cars queue to enter the village, pizzerias and ristorantes on every
corner, Germans galore. This doesn&amp;rsquo;t take away that this location is a
great launching point to visit other places in northern Italy though.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-07-24-ferrari-red-lamborghini-yellow-Garda_0002.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-07-24-ferrari-red-lamborghini-yellow-Garda_0002.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-07-24-ferrari-red-lamborghini-yellow-Garda_0010.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-07-24-ferrari-red-lamborghini-yellow-Garda_0010.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;After a lazy day yesterday, we drove two hours South today, to
Sant&amp;rsquo;Agata Bolognese and Maranello, to visit two legendary car
manufacturers: &lt;a href=&#34;http://www.lamborghini.com/en/heritage/museum/overview/&#34;&gt;Lamborghini&lt;/a&gt; and &lt;a href=&#34;http://museo.ferrari.com/&#34;&gt;Ferrari&lt;/a&gt;. While both museums only take around 40 minutes to visit, I definitely was more impressed by the Lamborghini museum. Compared to the Ferrari museum, the Lamborghini
museum seemed to exhibit far more (non-racing) eccentric and rare
models.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-07-24-ferrari-red-lamborghini-yellow-Garda_0065.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-07-24-ferrari-red-lamborghini-yellow-Garda_0065.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-07-24-ferrari-red-lamborghini-yellow-Garda_0083.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-07-24-ferrari-red-lamborghini-yellow-Garda_0083.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-07-24-ferrari-red-lamborghini-yellow-Garda_0145.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-07-24-ferrari-red-lamborghini-yellow-Garda_0145.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Since both museums failed to entertain us for longer than an hour, we
visited &lt;a href=&#34;http://en.wikipedia.org/wiki/Verona&#34;&gt;Verona&lt;/a&gt; on our way back.
While we didn&amp;rsquo;t enter any tourist attractions, we enjoyed strolling
through the old town, blending into the mass, only halting on a Roman
square to pay way too much for an iced cappuccino which was served
lukewarm.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-07-24-ferrari-red-lamborghini-yellow-Garda_0171.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-07-24-ferrari-red-lamborghini-yellow-Garda_0171.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.youtube.com/watch?v=4aXIFFaWNjM&#34;&gt;Arrivederci&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Should I unit- or integration test my ASP.NET Web API services?</title>
      <link>https://jefclaes.be/2012/07/should-i-unit-or-integration-test-my.html</link>
      <pubDate>Sun, 15 Jul 2012 22:37:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/07/should-i-unit-or-integration-test-my.html</guid>
      <description>&lt;p&gt;Over the last two weeks, preparing for a talk, I have been doing some
research on &lt;a href=&#34;http://www.asp.net/web-api&#34;&gt;ASP.NET Web API&lt;/a&gt;. After working
my way through the API, and the implementation of certain features, I
looked at testing.&lt;/p&gt;
&lt;p&gt;Similar to ASP.NET MVC, Web API allows you to create relatively small
building blocks, which can replace parts of, or be added to an existing
default global setup. This makes it possible for us to test each
component in isolation:
&lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.web.http.apicontroller(v=vs.108).aspx&#34;&gt;controllers&lt;/a&gt;,
&lt;a href=&#34;http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver&#34;&gt;dependency
resolvers&lt;/a&gt;,
filters, serialization, &lt;a href=&#34;http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters&#34;&gt;type
formatters&lt;/a&gt;,
&lt;a href=&#34;http://www.asp.net/web-api/overview/working-with-http/http-message-handlers&#34;&gt;messagehandlers&lt;/a&gt;
and routing.&lt;/p&gt;
&lt;p&gt;Testing in isolation helps a great deal to keep the magnitude of things
to stuff in your head limited, and when you break something, you are
able to quickly pinpoint the origin of the error. What unit testing
fails to prove however, is the &lt;em&gt;correctness of your code when all the
little pieces are put together and configured&lt;/em&gt;. And let it be that this
is extremely important when you&amp;rsquo;re exposing an API.&lt;/p&gt;
&lt;p&gt;Looking at Web API, I would probably test most infrastructure in
isolation - filters, type formatters, messagehandlers and serialization,
because these tests will help pinpoint errors in components which will
affect a large amount of other code. I wouldn&amp;rsquo;t test controllers and
routing in isolation though.&lt;/p&gt;
&lt;p&gt;I would test controllers and routing from a client&amp;rsquo;s perspective;
meaning I&amp;rsquo;ll send a request to and endpoint on the server, I&amp;rsquo;ll go
through the infrastructure, and I&amp;rsquo;ll assert the replied response. This
would exclude false positives or false negatives which can originate
when you unit test controllers and have to fake a bunch of
infrastructure just to get it working, while you do include &lt;em&gt;testing the
effect the real infrastructure has&lt;/em&gt; on your incoming requests or
outgoing responses.&lt;/p&gt;
&lt;p&gt;An obvious counterargument might be starting and stopping a webserver in
your tests, and the associated performance hit. This isn&amp;rsquo;t something to
worry about with Web API though; HttpServer is just another
HttpMessageHandler, which makes it possible to consume it using an
&lt;a href=&#34;http://code.msdn.microsoft.com/Introduction-to-HttpClient-4a2d9cee&#34;&gt;HttpClient&lt;/a&gt;
in-memory.&lt;/p&gt;
&lt;p&gt;So let me show you some code I wrote trying out these thoughts. The
first thing I did was exposing the hosting server&amp;rsquo;s configuration to my
tests. This could be as simple as this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ServerSetup&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; HttpSelfHostConfiguration GetConfiguration(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; baseAdress)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; config = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; HttpSelfHostConfiguration(baseAdress);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; kernel = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; StandardKernel();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        kernel.Bind&amp;lt;IResumeStore&amp;gt;().To&amp;lt;ResumeStore&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        config.Routes.MapHttpRoute(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;DefaultApi&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;api/{controller}/{id}&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; { id = RouteParameter.Optional });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        config.MessageHandlers.Add(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; MethodOverrideHandler());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        config.DependencyResolver = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; NinjectDependencyResolver(kernel);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; config;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now in my test I can grab this configuration, and just overwrite the
dependencies and the error detail policy. I can initialize an HttpClient
by passing in an HttpServer instance which uses the modified
configuration.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; HttpClient _client;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[TestInitialize]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; kernel = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; StandardKernel();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    kernel.Bind&amp;lt;IResumeStore&amp;gt;().ToConstant(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Mock&amp;lt;IResumeStore&amp;gt;().Object);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; config = ServerSetup.GetConfiguration(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://test&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;                       
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    config.DependencyResolver = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; NinjectDependencyResolver(kernel);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    _client = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; HttpClient(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; HttpServer(config));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[TestMethod]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Post_Returns_HttpStatus_Code_Created()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{         
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; result = _client.PostAsync&amp;lt;Resume&amp;gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://test/api/resume&amp;#34;&lt;/span&gt;, 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Resume(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Jef&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Claes&amp;#34;&lt;/span&gt;), 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; JsonMediaTypeFormatter()).Result;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    result.EnsureSuccessStatusCode();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Assert.AreEqual(HttpStatusCode.Created, result.StatusCode);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now I&amp;rsquo;m consuming my API almost exactly as a client would; my request
goes through the routing, infrastructure and the controller.
Infrastructure is still tested under isolation so finding problems there
is easy, but I now have the advantage of testing routing, the effect of
my real infrastructure and the logic in my controller actions in one
simple integration test. Remember, we are testing a delivery mechanism,
not an application; Web API controllers should be skinny as well.&lt;/p&gt;
&lt;p&gt;One drawback I stumbled upon is discoverability of controller
dependencies, but surprisingly that didn&amp;rsquo;t bother me much. I can still
see an overview of all my dependencies in the controller&amp;rsquo;s constructor,
it&amp;rsquo;s not a disaster to not have intellisense.&lt;/p&gt;
&lt;p&gt;In general, I think this pragmatic approach to testing Web API
implementations gets as much value as possible from automated testing
with writing as little test code as possible, and without adding too
much complexity.&lt;/p&gt;
&lt;p&gt;What do you think about this approach to testing Web API solutions?&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>HtmlHelper to generate a top-level menu for areas</title>
      <link>https://jefclaes.be/2012/07/htmlhelper-to-generate-top-level-menu.html</link>
      <pubDate>Sun, 08 Jul 2012 19:10:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/07/htmlhelper-to-generate-top-level-menu.html</guid>
      <description>&lt;p&gt;Last week, we had to set up a new ASP.NET MVC web application, using a
somewhat customized &lt;a href=&#34;http://twitter.github.com/bootstrap/&#34;&gt;Twitter Bootstrap&lt;/a&gt; build. Because the application has multiple functional contexts, we divided it in multiple parts using areas. Since these areas were a one-to-one mapping with the top-level menu items, we tried abstracting the creation of the menu
items, ánd the management of setting the active item, into an
HtmlHelper.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s say, for this example, that we have six areas: Images, Maps, Play,
Search, Video and Blog, and we want to render a list item for each one
of them.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;nav-collapse collapse&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;ul&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;nav&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        // Add list items         
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;ul&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first solution we tried, assumed we needed an extreme
low-maintenance solution, for which we would write some infrastructure
once, and then be able to just create new areas without having to think
about updating the top-level menu.&lt;/p&gt;
&lt;p&gt;This solution reflected over all the types looking for classes which
inherit from the AreaRegistration class. Once you get a list of all the
area names, you can iterate over them and create a list item for each
one of them, using an instance of UrlHelper to resolve the associated
url. You have to impose some routing convention to make the url lookup
robust though; in this example, I assume the default route is
sufficient. To be able to mark the active area with a css class, you can
get the active areaname from the viewcontext, and use that to compare to
the iterand value.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;TopMenuExtensions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; IEnumerable&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&amp;gt; _areaNames;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; MvcHtmlString RenderTopMenuItems(&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt; HtmlHelper helper)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; areaNames = GetAreaNames();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; currentArea = helper.ViewContext.RouteData.DataTokens[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;area&amp;#34;&lt;/span&gt;] &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; html = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; StringBuilder();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; areaName &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; areaNames)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; urlHelper = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; UrlHelper(helper.ViewContext.RequestContext);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; url = urlHelper.Action(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.Empty, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.Empty, &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; { area = areaName });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// or similar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// var url = urlHelper.RouteUrl(areaName + &amp;#34;_default&amp;#34;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            html.AppendLine(areaName.Equals(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                currentArea, StringComparison.OrdinalIgnoreCase) ? 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;lt;li class=&amp;#39;active&amp;#39;&amp;gt;&amp;#34;&lt;/span&gt; : &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;lt;li&amp;gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            html.AppendLine(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.Format(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;lt;a href=&amp;#39;{0}&amp;#39;&amp;gt;{1}&amp;lt;/a&amp;gt;&amp;#34;&lt;/span&gt;, url, areaName));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            html.AppendLine(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;lt;/li&amp;gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; MvcHtmlString(html.ToString());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; IEnumerable&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&amp;gt; GetAreaNames()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (_areaNames == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            _areaNames = Assembly
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .GetExecutingAssembly()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .GetTypes()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .Where(t =&amp;gt; t.IsClass &amp;amp;&amp;amp; &lt;span style=&#34;color:#66d9ef&#34;&gt;typeof&lt;/span&gt;(AreaRegistration).IsAssignableFrom(t))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .Select(a =&amp;gt; (AreaRegistration)Activator.CreateInstance(a))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .Select(r =&amp;gt; r.AreaName);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; _areaNames;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we can add following line to our _Layout file, and be done with
it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@Html.RenderTopMenuItems()  
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While this works, we stumbled upon an annoyance pretty quickly: we
wanted to change the order of the menu items, but couldn&amp;rsquo;t. We took a
step back, and momentarily considered decorating the arearegistrations
with an attribute, but since the added value is so small compared to the
extra complexity introduced, we decided just to throw the
overengineering out.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; MvcHtmlString RenderTopMenuItems(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt; HtmlHelper helper, IEnumerable&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&amp;gt; areaNames)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; currentArea = helper.ViewContext.RouteData.DataTokens[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;area&amp;#34;&lt;/span&gt;] &lt;span style=&#34;color:#66d9ef&#34;&gt;as&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; html = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; StringBuilder();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; areaName &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; areaNames)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; urlHelper = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; UrlHelper(helper.ViewContext.RequestContext);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; url = urlHelper.Action(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.Empty, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.Empty, &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; { area = areaName });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (url == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; NullReferenceException(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.Format(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Couldn&amp;#39;t find an url for the area {0}.&amp;#34;&lt;/span&gt;, areaName));                
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        html.AppendLine(areaName.Equals(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            currentArea, StringComparison.OrdinalIgnoreCase) ? 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;lt;li class=&amp;#39;active&amp;#39;&amp;gt;&amp;#34;&lt;/span&gt; : &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;lt;li&amp;gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        html.AppendLine(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.Format(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;lt;a href=&amp;#39;{0}&amp;#39;&amp;gt;{1}&amp;lt;/a&amp;gt;&amp;#34;&lt;/span&gt;, url, areaName));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        html.AppendLine(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;lt;/li&amp;gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; MvcHtmlString(html.ToString());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}  
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The top-level menu items can now be rendered like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@Html.RenderTopMenuItems(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; [] { &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Search&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Images&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Blog&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Maps&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Play&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Video&amp;#34;&lt;/span&gt; } )
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the result looks like this.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-07-08-htmlhelper-to-generate-a-top-level-menu-for-areas-TwitterBootstrapMenu.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-07-08-htmlhelper-to-generate-a-top-level-menu-for-areas-TwitterBootstrapMenu.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;While you can go at this problem in a lot of different ways, I think
this is one of the most robust and most compact ways I have been able to
write this so far. How have you solved this in the past?&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>On crime and document stores</title>
      <link>https://jefclaes.be/2012/07/on-crime-and-document-stores.html</link>
      <pubDate>Sun, 01 Jul 2012 16:04:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/07/on-crime-and-document-stores.html</guid>
      <description>&lt;p&gt;Having worked with several storage paradigms over these last few months - from flatfiles, to  NoSQL, to the big enterprisey relational databases -, I have spent plenty of time trying to make sense of all the options
out there. It wasn&amp;rsquo;t until I watched one of the last episodes of &lt;a href=&#34;http://en.wikipedia.org/wiki/The_Wire&#34;&gt;The
Wire&lt;/a&gt; season 3 that I had an
epiphany regarding modeling data in document stores. Yes, I know, I tend
to take those things home with me.&lt;/p&gt;
&lt;p&gt;Somewhere half way through that episode, you see a detective going
through one of those old school, gray and clumsy file cabinets, looking
for a dossier on one of the recent murders. Once he finds the dossier,
he takes it out of the drawer, scribbles down contact information of an
eyeball witness, puts it back in the drawer, and closes the drawer again
with a loud stomp.&lt;/p&gt;
&lt;p&gt;And that file cabinet actually isn&amp;rsquo;t very different from a MongoDB
collection; it stores and categorizes documents of the same type, and
the trade-offs you have to consider when modeling dossiers, or
documents, are basically the same.&lt;/p&gt;
&lt;p&gt;Let me work the homicide department angle a little further..&lt;/p&gt;
&lt;p&gt;A few months later, the murder is still not solved, and one of the
detectives, being out of work, starts working the case again. He walks
over to that same file cabinet, searches the file and goes through the
data one more time. Short on leads, he decides to interrogate the
witness again. So he takes the file, steps in his black Buick, and
drives over to the address scribbled down next to the name of the
witness. When he arrives, after a grueling car ride through morning rush
hour, he finds himself standing in front of a vacant house. Son of a&amp;hellip;
He drives over to city hall, waits in line for 24 minutes, gets the new
address, and heads over there. When he gets back to the office, empty
handed, and several hours later, he is determined to prevent this from
happening again. He suggests the other detectives either check and
update their dossiers, or documents, every time somebody moves, or that
they just write down a reference to the person in the dossier, and look
up the data in the file cabinets at city hall. Since going through all
the files every time somebody moves is not feasible, he convinces his
chief to enforce the second option. Over time, people get a hang of it,
and are content to be relieved of stale data in the dossiers. However,
the more they introduce this system in other scenarios, the more they
get frustrated doing the manual look-ups. They now first have to fetch
the document in the file cabinet, and then go through five more
cabinets, just to collect all the bits of the file.&lt;/p&gt;
&lt;p&gt;To make matters worse, since it&amp;rsquo;s often hard to find something in the
dossier, chain of command has introduced templates for each of the
documents. Now each document has a fixed schema, a list of fields, of
which each one is in a fixed position on the document, and some of them
are even required. When you want to add a new file, they should be
signed off by your superior first. Sigh.&lt;/p&gt;
&lt;p&gt;Getting a taste after work, the detectives are discussing the new
system. &amp;lsquo;It&amp;rsquo;s great that we now have a single source of truth, are rid
of stale data, and don&amp;rsquo;t have to manually update everything when
something changes. But damn, all the extra paperwork, all the fuss over
formats and the going back and forth between file cabinets is getting
old quickly.&amp;rsquo; &amp;lsquo;However, I&amp;rsquo;m happy we could at least keep our OT slips
and expense notes simple; just one document, which we can fill in and
update as we please.&amp;rsquo; They collegially gulp down their drinks, and
signal the bartender to bring another round.&lt;/p&gt;
&lt;p&gt;In this short story, you witnessed the detectives totally ruining their
document store. By normalizing their documents and putting constraints
on the formats, they no longer reap the benefits of using a document
store. Now, they would be far better of with a relational solution.&lt;/p&gt;
&lt;p&gt;I hope these analogies made some sense, and maybe made you think about,
or even challenge the SQL dogma. What it all comes down to, is having
enough knowledge to be able to pick the right tool for the job. Each
paradigm has its merits, and as with any other decision in our field,
trade-offs have to be considered. The way you can or want to model your
data isn&amp;rsquo;t the only consideration to make though. While for some it is
scalability and performance that makes NoSQL the obvious choice, for me
it is the simplicity that does it. You don&amp;rsquo;t have to be an IT pro to
install a server instance locally, nor to migrate your application to
the cloud (MongoDB, for example, creates its collections on the fly).
The way you talk to the database also becomes easier; the mismatch
between your code and storage can become a lot smaller, while you also
rid yourself of some of the SQL foo. This doesn&amp;rsquo;t mean that you don&amp;rsquo;t
have to be considerate about how you query your data though; you still
need common sense, but there is a lot less black magic you need to
master.&lt;/p&gt;
&lt;p&gt;NoSQL solutions seem to put the developer first; I see NoSQL, and
particularly the document store flavor, not as a silver bullet, but as a
great new asset to my toolbox.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Persisting model state when using PRG</title>
      <link>https://jefclaes.be/2012/06/persisting-model-state-when-using-prg.html</link>
      <pubDate>Sun, 17 Jun 2012 16:48:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/06/persisting-model-state-when-using-prg.html</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been working on an ASP.NET MVC application in which we frequently
apply the &lt;a href=&#34;http://en.wikipedia.org/wiki/Post/Redirect/Get&#34;&gt;Post/Redirect/Get pattern&lt;/a&gt;. One of the direct consequences of applying this pattern is that you often want to persist the model state across redirects, so that you don&amp;rsquo;t lose validation errors, or the values of input fields.&lt;/p&gt;
&lt;p&gt;To persist the model state across redirects, we can put
&lt;a href=&#34;http://msdn.microsoft.com/en-us/library/dd394711.aspx&#34;&gt;TempData&lt;/a&gt; to
work. The sole purpose of &lt;code&gt;TempData&lt;/code&gt; is exactly this; persisting state
until the next request.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; ActionResult Index()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ViewData.Model = ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (TempData.ContainsKey(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ModelState&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ModelState.Merge((ModelStateDictionary)TempData[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ModelState&amp;#34;&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; View();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[HttpPost]&lt;/span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; ActionResult Update(AddModel inputModel)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (ModelState.IsValid)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    TempData[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ModelState&amp;#34;&lt;/span&gt;] = ModelState;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; RedirectToAction(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Index&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So this works, but I found it to be a bit too cumbersome. And so did
&lt;a href=&#34;https://twitter.com/#!/davybrion&#34;&gt;Davy Brion&lt;/a&gt;, he introduced a clean
abstraction into the project, smoothing out some of the friction: making
use of action filter attributes, we were able to eliminate duplication
across controllers, leaving behind an AOP-ish taste.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;SetTempDataModelStateAttribute&lt;/code&gt; stores the model state in the
&lt;code&gt;TempData&lt;/code&gt; dictionary.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SetTempDataModelStateAttribute&lt;/span&gt; : ActionFilterAttribute
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; OnActionExecuted(ActionExecutedContext filterContext)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;base&lt;/span&gt;.OnActionExecuted(filterContext);         
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        filterContext.Controller.TempData[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ModelState&amp;#34;&lt;/span&gt;] = 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            filterContext.Controller.ViewData.ModelState;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;While the &lt;code&gt;RestoreModelStateFromTempDataAttribute&lt;/code&gt; restores it by pulling
it out of &lt;code&gt;TempData&lt;/code&gt; again, when it exists.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;RestoreModelStateFromTempDataAttribute&lt;/span&gt; : ActionFilterAttribute
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; OnActionExecuting(ActionExecutingContext filterContext)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;base&lt;/span&gt;.OnActionExecuting(filterContext);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (filterContext.Controller.TempData.ContainsKey(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ModelState&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            filterContext.Controller.ViewData.ModelState.Merge(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (ModelStateDictionary)filterContext.Controller.TempData[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ModelState&amp;#34;&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So when we apply these attributes to the example at the beginning of
this post, we end up with something like this.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[RestoreModelStateFromTempData]
public ActionResult Index()
{
    ViewData.Model = ...    

    return View();
}

[HttpPost]   
[SetTempDataModelState]     
public ActionResult Update(AddModel inputModel)
{
    if (ModelState.IsValid)
        ...
    
    return RedirectToAction(&amp;#34;Index&amp;#34;);
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Very clean. I&amp;rsquo;m interested to hear how you handle these concerns when
using the PRG pattern.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Making my first NancyFx test pass</title>
      <link>https://jefclaes.be/2012/06/making-my-first-nancyfx-test-pass.html</link>
      <pubDate>Mon, 11 Jun 2012 16:47:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/06/making-my-first-nancyfx-test-pass.html</guid>
      <description>&lt;p&gt;Like I already said last week, I have been dabbling a bit with &lt;a href=&#34;http://nancyfx.org/&#34;&gt;NancyFx&lt;/a&gt; lately.&lt;/p&gt;
&lt;p&gt;This week I took a serious look at testing Nancy modules and Razor
views. Due to Nancy&amp;rsquo;s defaults and conventions, it takes a little while
to set up Nancy in a test context. Then again, Nancy&amp;rsquo;s granularity makes
it simple enough to set up a solid test infrastructure by replacing some
of its building blocks.&lt;/p&gt;
&lt;p&gt;Like always, I had to go through several iterations to get it right.&lt;/p&gt;
&lt;h3 id=&#34;a-first-attempt&#34;&gt;A first attempt&lt;/h3&gt;
&lt;p&gt;The first test I wrote looked something like this. This test simply
asserts whether a GET request to the root of my application returns a
&lt;code&gt;200 OK&lt;/code&gt; status code.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[TestMethod]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; root_should_return_response_ok()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; browser = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Browser(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; DefaultNancyBootstrapper());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; response = browser.Get(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;Assert.AreEqual failed. Expected:&amp;lt;OK&amp;gt;. Actual:&amp;lt;NotFound&amp;gt;.&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&#34;telling-nancy-which-modules-to-use&#34;&gt;Telling Nancy which modules to use&lt;/h3&gt;
&lt;p&gt;I figured out I had to tell Nancy which modules to load. You can do this
by using the configurable bootstrapper, which gives you an API to
configure parts of Nancy yourself.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; bootstrapper = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ConfigurableBootstrapper(with =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    with.Module&amp;lt;RootModule&amp;gt;();               
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; browser = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Browser(bootstrapper);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Running this test, I no longer got a NotFound result, but an exception.
Making progress.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Test method RootModuleTests.root_should_return_response_ok threw exception: 
System.Exception: ConfigurableBootstrapper Exception ---&amp;gt; 
                    Nancy.RequestExecutionException: Oh noes! ---&amp;gt; 
                    Nancy.ViewEngines.ViewNotFoundException: Unable to locate view &amp;#39;HomeView&amp;#39;
Currently available view engine extensions: sshtml,html,htm
Locations inspected: HomeView,views/HomeView,views/HomeView,/HomeView,views/Root/HomeView,Root/HomeView
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;where-is-the-view-engine&#34;&gt;Where is the view engine?&lt;/h3&gt;
&lt;p&gt;On inspecting the exception, I noticed that the cshtml view engine
extension was missing from the list.&lt;/p&gt;
&lt;p&gt;To add the view engine, you can just add a reference to the
&lt;code&gt;Nancy.ViewEngines.Razor&lt;/code&gt; assembly. Nancy will pick up the new engine
automatically.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Test method RootModuleTests.root_should_return_response_ok threw exception: 
System.Exception: ConfigurableBootstrapper Exception ---&amp;gt; 
                    Nancy.RequestExecutionException: Oh noes! ---&amp;gt; 
                    Nancy.ViewEngines.ViewNotFoundException: Unable to locate view &amp;#39;HomeView&amp;#39;
Currently available view engine extensions: sshtml,html,htm,cshtml,vbhtml
Locations inspected: HomeView,views/HomeView,views/HomeView,/HomeView,views/Root/HomeView,Root/HomeView
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;locating-the-views&#34;&gt;Locating the views&lt;/h3&gt;
&lt;p&gt;This time around we get a slightly different exception; the razor view
engine extension is available, but Nancy is still having trouble finding
the views - which is normal. Nancy is running in a different context
now, so the default rootpathprovider will return the wrong path.
Implementing another one is children&amp;rsquo;s play.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;TestRootPathProvider&lt;/span&gt; : IRootPathProvider
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; GetRootPath()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;C:\MyProject\&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I discovered that you don&amp;rsquo;t even need to use the configurable
bootstrapper to override the IRoothPathProvider; Nancy seems to pick up
the new implementation by herself.&lt;/p&gt;
&lt;p&gt;The hardcoded path will work on your machine, but not on the build
server. In my second iteration, I made the implementation smarter by
traversing my way through parent directories looking for my views folder - starting from my tests out folder all the way up to my web application
folder.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;TestRootPathProvider&lt;/span&gt; : IRootPathProvider
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; _cachedRootPath;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; GetRootPath()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (!&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.IsNullOrEmpty(_cachedRootPath))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; _cachedRootPath;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; currentDirectory = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; DirectoryInfo(Environment.CurrentDirectory);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; rootPathFound = &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; (!rootPathFound)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; directoriesContainingViewFolder = currentDirectory.GetDirectories(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Views&amp;#34;&lt;/span&gt;, SearchOption.AllDirectories);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (directoriesContainingViewFolder.Any())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                _cachedRootPath = directoriesContainingViewFolder.First().FullName;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                rootPathFound = &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            currentDirectory = currentDirectory.Parent;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; _cachedRootPath;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;Result: Passed&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;I was happy to find out that this technique works for the MSTest runner,
&lt;a href=&#34;http://www.ncrunch.net/&#34;&gt;NCrunch&lt;/a&gt; and &lt;a href=&#34;https://appharbor.com/&#34;&gt;Appharbor&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There is one more way you can go at this though, which works and maybe
even is the &amp;lsquo;recommended&amp;rsquo; technique, but also is &lt;a href=&#34;http://stackoverflow.com/questions/3738819/do-mstest-deployment-items-only-work-when-present-in-the-project-test-settings-f&#34;&gt;a lot more cumbersome&lt;/a&gt;: use the &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.deploymentitemattribute(v=vs.80).aspx&#34;&gt;DeploymentItem&lt;/a&gt; attribute to copy the views folder to your tests out folder.&lt;/p&gt;
&lt;h3 id=&#34;to-recapitulate&#34;&gt;To recapitulate&lt;/h3&gt;
&lt;p&gt;I hope this post documented some useful techniques to get started
testing Nancy&amp;rsquo;s modules and views:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use the configurable bootstrapper to add your modules&lt;/li&gt;
&lt;li&gt;Reference the correct view engine&lt;/li&gt;
&lt;li&gt;Implement a rootpathprovider telling Nancy where it can find her views&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Only a few days ago, &lt;a href=&#34;https://twitter.com/#!/thecodejunkie&#34;&gt;@thecodejunkie&lt;/a&gt; made a &lt;a href=&#34;https://github.com/NancyFx/Nancy/issues/633&#34;&gt;ticket on GitHub&lt;/a&gt; addressing some of these issues. I&amp;rsquo;m pretty confident we can smooth out these rough edges to make Nancy tests also walk the super-duper-happy-path.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Book review: The Art of Agile Development</title>
      <link>https://jefclaes.be/2012/06/book-review-art-of-agile-development.html</link>
      <pubDate>Sun, 10 Jun 2012 19:42:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/06/book-review-art-of-agile-development.html</guid>
      <description>&lt;p&gt;While I have - obviously - read the &lt;a href=&#34;http://agilemanifesto.org/&#34;&gt;Agile Manifesto&lt;/a&gt; before, and regularly click through to articles on agile, I had never read an extensive work on it. Browsing for a good book, I was advised by a peer to get &lt;a href=&#34;http://www.amazon.com/gp/product/0596527675/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0596527675&#34;&gt;The Art of Agile Development&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I wholeheartedly believe in the Agile Manifesto, but somewhere along the way Agile - with a capital A - got somewhat of a bad rep. The authors of this book, &lt;a href=&#34;http://jamesshore.com/&#34;&gt;James Shore&lt;/a&gt; and Shane Warden, already predicted this five years ago. Throughout the book, I never had the feeling they were connected to the Agile mob, but just genuinely care about working software.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I fully expect the big consulting companies to start offering
Certified Agile Processes and Certified Agile Consultants - for
astronomical fees, of course - any day now. &lt;strong&gt;Please don&amp;rsquo;t get sucked
into that mess.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The book consists of three parts: getting started, practicing XP and
mastering agility. Notice the title of the second part, this is a book
on agile development using the &lt;a href=&#34;http://en.wikipedia.org/wiki/Extreme_programming&#34;&gt;Extreme Programming&lt;/a&gt; methodology. This should be mentioned in the title.&lt;/p&gt;
&lt;p&gt;The second part is also the dominant chunk of the book - 271 pages to be precise -, in which 37 agile development practices are covered. These
practices are bundled into five categories: thinking, collaborating,
releasing, planning and developing. Each practice follows the same
recipe: breakdown, questions, results, contraindications, alternatives
and further reading. These recipes go into detail, making this book
suitable as a reference. As a result, it often also reads as reference
material; I found it hard at times to stay attentive. The material is a
bit tedious, sometimes a bit repetitive, and while some of the real
world experiences are very interesting, the made up stories often read
as a children&amp;rsquo;s book. Nonetheless, this doesn&amp;rsquo;t make the information in
this book any less valuable. The authors have lived it through and
through, and possess a very healthy and pragmatic vision on agile
software development.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Ultimately what matters is success, however you define it. The
practices, principles, and values are merely guides along the way.
 Start by following the practices rigorously. Learn what the the
principles mean. Break the rules, experiment, see what works, and
learn some more. Share your insights and passion, and learn even more.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I rate this book 4/5. You can &lt;a href=&#34;http://www.amazon.com/gp/product/0596527675/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0596527675&#34;&gt;get it on
Amazon&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>The &#39;everyone should learn to code&#39; dilemma</title>
      <link>https://jefclaes.be/2012/06/everyone-should-learn-to-code-dilemma.html</link>
      <pubDate>Sun, 03 Jun 2012 16:40:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/06/everyone-should-learn-to-code-dilemma.html</guid>
      <description>&lt;p&gt;Back when I was working on software for fire departments, we started
thinking about reworking a critical piece of our solution: deployment
plans. In a fire department domain, deployment plans help to make a
suggestion to the dispatcher about which units should be dispatched to a
location when an incident is called in. The suggested composition of
units depends on a wide range of variables: availability, response time,
ranks, type of incident, required tools, &amp;hellip; , even politics.
Originally, people high enough in rank could compose these plans using a
decision tree-like UI. However, as it turned out, this UI was
insufficient; not all variables and conditions were available. Since
this was no custom built tool, we had to work around it by composing
incomprehensible decision trees or by tricking the underlying services.
When talking about how we could do better, we hit a wall pretty soon. We
thought about building our own - but more extensive - UI, and damn, even
designing a DSL crossed our minds.&lt;/p&gt;
&lt;p&gt;Along the process, I heard that &lt;a href=&#34;http://mikehadlow.blogspot.co.uk/2012/05/configuration-complexity-clock.html&#34;&gt;Configuration Complexity
Clock&lt;/a&gt;
ticking, and I couldn&amp;rsquo;t stop myself from thinking that if everyone knew
how to code - just some boolean logic and control flow would suffice -,
we wouldn&amp;rsquo;t have gotten into this mess. It seemed impossible to build
something that would be intuitive, and still fulfill all the
requirements; some things just seem to be best expressed in code.&lt;/p&gt;
&lt;p&gt;I empathize with the &lt;a href=&#34;http://sachagreif.com/please-learn-to-code/&#34;&gt;proponents of teaching everyone how to
code&lt;/a&gt;. On the other hand,
I&amp;rsquo;ve been watching this movement from a safe distance; there are two
sides to the same coin.&lt;/p&gt;
&lt;p&gt;Just a few weeks ago, a peer shared one of those horror stories which
originate when non-professional developers take matters into their own
hands. The IT department of this big company was looking for a piece of
software which could standardize the way employees make hardware and
support requests. Shopping around, they found the existing products
couldn&amp;rsquo;t satisfy their needs, or they would take a considerable cut out
of their yearly budget. Eventually, a system administrator who knew just
enough about programming to be dangerous stepped up, and rolled his own
tool. For over two years, all was good with the world. Maybe the
solution wasn&amp;rsquo;t very pretty, and a bit on the slow side, but overall -
and most importantly - it got the job done. Now, the original developer
has decided he can&amp;rsquo;t be bothered maintaining his brainchild any longer.
The peer who told me this story, was also the guy chosen to take over
maintenance and feature requests. They assured him that it wouldn&amp;rsquo;t be
too much trouble; just a little feature here and there, and maybe the
exceptional bug. What he found however, were the things nightmares are
made of; a - classic - ASP.NET web application with just one web page,
written in VB.NET, containing over 20k LOC, with updatepanels nested
five levels deep.&lt;/p&gt;
&lt;p&gt;And this is the perfect example of how we have to be very careful with
the &amp;rsquo;everyone should learn to code&amp;rsquo; meme. &lt;strong&gt;Slinging code is easy, but
writing good code is hard&lt;/strong&gt;, and takes a lot of practice. &lt;a href=&#34;http://online.wsj.com/article/SB10001424053111903480904576512250915629460.html&#34;&gt;Software
might be eating up the
world&lt;/a&gt;,
but maybe it&amp;rsquo;s for the best we don&amp;rsquo;t turn it into a monstrous glutton.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>The open plan fallacy testimonials</title>
      <link>https://jefclaes.be/2012/05/open-plan-fallacy-testimonials.html</link>
      <pubDate>Sun, 27 May 2012 15:36:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/05/open-plan-fallacy-testimonials.html</guid>
      <description>&lt;p&gt;I wrote an article titled &amp;lsquo;&lt;a href=&#34;http://www.jefclaes.be/2012/05/open-plan-fallacy.html&#34;&gt;The open plan
fallacy&lt;/a&gt;&amp;rsquo; just
two weeks ago. Earlier this week &lt;a href=&#34;http://www.nytimes.com/2012/05/20/science/when-buzz-at-your-cubicle-is-too-loud-for-work.html?_r=3&amp;amp;pagewanted=all&#34;&gt;a similar
article&lt;/a&gt;
was published by the New York Times. The content of that article wasn&amp;rsquo;t
particularly extraordinary, but the comments were. I waded through all
of them on my daily commute, and it&amp;rsquo;s really hard to find one in favor
of open plan offices - people seem to be enraged.&lt;/p&gt;
&lt;p&gt;I handpicked some of the most interesting ones.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Research by Emberson et.al. (Psychological Science, 2010) demonstrate
both the impairment in performance for people forced to listen to half
a phone conversation and the neurological impossibility of &amp;ldquo;tuning
out&amp;rdquo; these overheard conversations. The office experience has been
described as trying to drive a car full of people all talking on their
cell phones.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;It&amp;rsquo;s preferable to have to make the effort to collaborate than the
effort to focus on one&amp;rsquo;s work amidst a distracting open workplace. My
profession, architecture, does require a high degree of collaboration,
but also a need for intense, individual concentration working on
complicated 3D computer models and details.. and long hours being in
&amp;ldquo;the zone&amp;rdquo;. My firm provides private offices for all of its staff and
a variety of collaborative and recreational environments..
particularly the latter, recognizing that just by hanging out together
for part of the day, individuals from different project teams and
pursuits &amp;ldquo;cross-pollinate&amp;rdquo;, come up with imaginative ideas, influence
and inspire eachother.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Cubicles were invented as a way to shove more people into a smaller
space and save money for corporations. The entire meme about &amp;ldquo;improved
workplace communications&amp;rdquo; was invented by consultants as a
smokescreen. Period. End of story. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;For example, someone whose job requires intense concentration (e.g.
computer programmer) needs absolute silence. Programmers who do not
get this silence are likely to make mistakes.&amp;rdquo;&lt;br&gt;
I&amp;rsquo;ve been around a lot of programmers, among lots of other kinds of
workers, and I&amp;rsquo;d say that 90% of the developers I saw were in a large
room with others all around them. It&amp;rsquo;s actually one of the least
likely jobs to provide someone with an office, despite the fact that
your diagnosis about what the job requires is absolutely right, in my
opinion.&lt;br&gt;
All it takes is a few months in the world of corporations to
understand that Dilbert is really a documentary.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;I currently work in an open plan office and absolutely hate it. Not
having an office with a door that others need to knock on before
disturbing me has led to non-stop disturbances all day long. Not to
mention having to listen to nonstop chatter of those around me. It is
an incredibly inefficient - and I may add, unprofessional - way to
work. Any money saved on rent is surely made up for in lost
productivity.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;I&amp;rsquo;ve noticed that the person who decides on the open cube layout
usually sits in an office.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Having participated in the design of office environments, where we
used low cubicle walls or even no walls to support certain kinds of
collaborative work, with the full involvement of the employees in that
design, it was always distressing to see the &amp;lsquo;open office&amp;rsquo; faddishly
embraced by management everywhere, regardless of actual practices
required for the work. Consultancies, as usual, led the way in yet
another blind embrace of &amp;lsquo;innovation&amp;rsquo;.&lt;br&gt;
Why would individual &amp;rsquo;entrepreneurs&amp;rsquo; - to take one example from this
story - want or need to be able to see and hear each other whilst
working? Are the activities in which they are engaged intimately
linked, are the tasks often (and necessarily) performed conjointly, is
their own working division of labour a concerted one? What do these
entrepreneurs themselves think about such matters? (Well, as the story
makes plain, they have very clear answers, voting with their
headphones!) Anyway, these are the kinds of very practical questions
about work activities and worker needs that should drive office
design.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In my article, I advocated isolating teams instead of individuals, but
most commenters seem to be heavy supporters of private offices -
including walls and a door. I never experienced that in a professional
environment, so I couldn&amp;rsquo;t say if that would work for software
development. Can you? Collaboration and communication between developers
is a necessity. Fostering that just seems hard when everyone is in a
separate place - definitely for young teams. While comparing office
layouts, I wondered how my proposed solution would scale; how many
people can you put in one team before you encounter the same undesired
open plan side-effects?&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Painless database logging with mongoDB</title>
      <link>https://jefclaes.be/2012/05/painless-database-logging-with-mongodb.html</link>
      <pubDate>Sun, 20 May 2012 17:18:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/05/painless-database-logging-with-mongodb.html</guid>
      <description>&lt;p&gt;While browsing the source code of the &lt;a href=&#34;https://github.com/CaptainCodeman/elmah-mongodb&#34;&gt;ELMAH mongoDB
provider&lt;/a&gt;, I learned
about a special type of collections: capped collections.&lt;/p&gt;
&lt;p&gt;From the &lt;a href=&#34;http://www.mongodb.org/display/DOCS/Capped+Collections&#34;&gt;mongoDB documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Capped collections are fixed sized collections that have a very high
performance auto-FIFO age-out feature (age out is based on insertion
order). In addition, capped collections automatically, with high
performance, maintain insertion order for the documents in the
collection; this is very powerful for certain use cases such as
logging.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is such a killer feature. Logging to the database can be extremely
useful, but also rather expensive. Using this feature, you can turn on
database logging without too many worries.&lt;/p&gt;
&lt;p&gt;Insertion into a capped collection is ridiculously fast. To get an idea
of how fast it really is, I did some measuring on my own humble machine.
I managed to insert 10.000 small documents in &lt;em&gt;less than 3.7 seconds&lt;/em&gt;.
The headaches of tweaking buffer sizes and rolling asynchronous
appenders seem to be miles away.&lt;/p&gt;
&lt;p&gt;Something which religiously gets ignored until shit hits the fan, is log
table maintenance. With a capped collection there is no need to set up a
database job that periodically cleans the logging table. You just set a
fixed size, and you&amp;rsquo;re done. No more middle-of-the-night support calls
when the logging table is eating up all the disk space.&lt;/p&gt;
&lt;p&gt;Creating a capped collection with the C# driver can look like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; server = MongoServer.Create(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mongodb://localhost/&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; db = server.GetDatabase(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;PlayGround&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; options = CollectionOptions
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .SetCapped(&lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .SetMaxSize(&lt;span style=&#34;color:#ae81ff&#34;&gt;5000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    .SetMaxDocuments(&lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (!db.CollectionExists(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Log&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    db.CreateCollection(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Log&amp;#34;&lt;/span&gt;, options);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now that&amp;rsquo;s easy sailing.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>The open plan fallacy</title>
      <link>https://jefclaes.be/2012/05/open-plan-fallacy.html</link>
      <pubDate>Sun, 13 May 2012 16:20:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/05/open-plan-fallacy.html</guid>
      <description>&lt;p&gt;I haven&amp;rsquo;t worked in a whole lot of places, somewhere around four, but
every single one of them used an &lt;a href=&#34;http://en.wikipedia.org/wiki/Open_plan&#34;&gt;open
plan&lt;/a&gt; to structure their
workplace. From what I hear from others, it&amp;rsquo;s the standard.&lt;/p&gt;
&lt;p&gt;There are a few things to say about the advantages of an open office
layout. They should stimulate communication, create more opportunities
for observing and learning from others and be more cost-effective. I&amp;rsquo;m
afraid it&amp;rsquo;s the latter which is the biggest driver though.&lt;/p&gt;
&lt;p&gt;In reality open plans really aren&amp;rsquo;t all that great. The noise alone has
proven to reduce productivity by &lt;em&gt;one third&lt;/em&gt;. When I look around, I see
plenty of signs that people have a hard time getting their job done:
programmers buying $500 noise-cancelling headphones in an attempt to
keep the environmental noise out, project managers camping in free
meeting rooms trying to focus on their number wizardry or even whole
teams occupying a meeting room days before a release.&lt;/p&gt;
&lt;p&gt;What bothers me the most is overhearing other teams, those distractions
amount to nothing at all. What&amp;rsquo;s the value of me overhearing a
discussion on some obscure Sharepoint problem? None. What are the
benefits of listening to your team&amp;rsquo;s Friday after lunch bullshitting?
Nothing. Team dynamics differ, that&amp;rsquo;s normal, but they shouldn&amp;rsquo;t disturb
others.&lt;/p&gt;
&lt;p&gt;The extreme alternative would be private offices, but I&amp;rsquo;m pretty
confident that&amp;rsquo;s far from perfect as well.&lt;/p&gt;
&lt;p&gt;What I suggest, is installing each team in their own fully isolated
area, free from distractions caused by other teams. This would still do
right to all the advantages of an open plan, while taking away some of
its biggest bottlenecks. By installing each team in their own cocoon,
you create an environment where overhearing conversations on the next
feature is an added value, where you can quickly short-circuit
discussions on an architectural decision or where you might even
concentrate on a problem for 45 minutes straight. The only advantage
which is partially gone is cost-effectiveness; there needs to be some
flexible infrastructure in place, that makes it easy to swiftly adapt
the environment when team compositions change.&lt;/p&gt;
&lt;p&gt;Instead of always focusing on that short term budget win, we need to
start paying attention to the big picture again: offices should enable
teams, not sabotage them.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Is there anybody who genuinely loves open plan offices? If not, what
alternative would you prefer?&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Why I will always love RSS</title>
      <link>https://jefclaes.be/2012/05/why-i-will-always-love-rss.html</link>
      <pubDate>Sun, 06 May 2012 16:50:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/05/why-i-will-always-love-rss.html</guid>
      <description>&lt;p&gt;There has been a lot of noise in the tech community earlier this year
about how RSS is supposedly having one foot in the grave. If that would
be even remotely true, I hope it dies with its boots on. The herald
would be browsers and social networking sites killing or hiding support
for RSS. While that may be true, their motives shouldn&amp;rsquo;t rig our
opinions.&lt;/p&gt;
&lt;p&gt;RSS has never worked out for the regular consumer, not directly anyways.
So I get why browsers are dropping support for it, I am not even
disappointed. Most popular social networks have enough traction by now
so that they can safely start fencing their gardens with the purpose of
bringing more money in. Also reasonable.&lt;/p&gt;
&lt;p&gt;What startles me is when peers start advertising the death of RSS. The
explanations I hear are somewhere along the lines of &amp;ldquo;Why use RSS? I
count on the people I follow on Twitter to share links to good
information&amp;rdquo;, or similarly &amp;ldquo;I just check Hacker News a few times a day
to read up on the latest news&amp;rdquo;. I strongly believe the contemporary
fetish of liking and sharing cheapens the way we consume our
information. Don&amp;rsquo;t get me wrong, I do see value in community driven
content, but there&amp;rsquo;s also a lot of dirt and sensationalism. Some days it
feels like I&amp;rsquo;m reading the front page of a cheap tabloid.&lt;/p&gt;
&lt;p&gt;I used to subscribe to a bunch of feeds, but today I&amp;rsquo;m pickier; I
subscribe to authors who share things I care about and who inspire me in
some way. By subscribing to their feed, I&amp;rsquo;m not missing a single update.
This forces me to absorb it all, even though most of their content
doesn&amp;rsquo;t go viral. This liberates me from feeling the urge to be
connected all the friggin&amp;rsquo; time, plus more importantly, there is a gold
mine of wisdom to be found in the non-controversial content out there.&lt;/p&gt;
&lt;p&gt;I love RSS. It just works, and enables me to learn so much, without
having to be connected constantly or having to rely on others to tell me
what to consume.&lt;/p&gt;
&lt;p&gt;Subscribe to my RSS feed &lt;a href=&#34;http://feed.jefclaes.be/jefclaes&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>My InfoQ article on HTML5 offline web applications</title>
      <link>https://jefclaes.be/2012/05/my-infoq-article-on-html5-offline-web.html</link>
      <pubDate>Wed, 02 May 2012 20:09:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/05/my-infoq-article-on-html5-offline-web.html</guid>
      <description>&lt;p&gt;After writing &lt;a href=&#34;http://www.jefclaes.be/2012/04/visualizing-offline-application-cache.html&#34;&gt;a&lt;/a&gt; &lt;a href=&#34;http://www.jefclaes.be/2012/03/html5-offline-web-applications-as.html&#34;&gt;few&lt;/a&gt; &lt;a href=&#34;http://www.jefclaes.be/2012/03/how-web-application-can-download-and.html&#34;&gt;things&lt;/a&gt; on HTML5 offline web applications earlier this year, I got contacted by &lt;a href=&#34;http://www.infoq.com/&#34;&gt;InfoQ&lt;/a&gt; to write an in-detail article on the subject for them. I hesitated at first, because I was afraid that it would feel too much like work, taking the fun out of my writing. Turns out it wasn&amp;rsquo;t like that at all. The guys at infoQ were really relaxed to work with, asking interesting questions and giving useful feedback, without forcing me into a certain direction. A pleasant experience.&lt;/p&gt;
&lt;p&gt;You can &lt;a href=&#34;http://www.infoq.com/articles/Offline-Web-Apps&#34;&gt;find the article
here&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Some Servicelocator pattern stinks</title>
      <link>https://jefclaes.be/2012/04/some-servicelocator-pattern-stinks.html</link>
      <pubDate>Tue, 17 Apr 2012 20:33:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/04/some-servicelocator-pattern-stinks.html</guid>
      <description>&lt;p&gt;I have been working on a somewhat legacy codebase which makes use of the
&lt;a href=&#34;http://martinfowler.com/articles/injection.html#UsingAServiceLocator&#34;&gt;Servicelocator
pattern&lt;/a&gt;.
Although I always thought of &lt;a href=&#34;http://martinfowler.com/articles/injection.html#FormsOfDependencyInjection&#34;&gt;Dependecy
Injection&lt;/a&gt;
to be the superior pattern, I was pleased to find some &lt;a href=&#34;http://martinfowler.com/articles/injection.html#InversionOfControl&#34;&gt;Inversion of
Control&lt;/a&gt;
implementation in there. Working with the codebase, I discovered first
hand how easily, when used without caution and discipline, the
Servicelocator pattern can introduce code rot.&lt;/p&gt;
&lt;p&gt;I will walk you through some of the issues I have with the
Servicelocator pattern, mostly looking at it from a test perspective.
It&amp;rsquo;s interesting how you can often quickly discover friction in a
codebase by just looking at, or writing, tests.&lt;/p&gt;
&lt;p&gt;The first thing that rubs me the wrong way is that by using the
Servicelocator pattern, you make each class dependant on the
servicelocator, degrading the purity of the models. Although this is a
conceptual consideration, it considerably affects development.&lt;/p&gt;
&lt;p&gt;What I really like about Dependency Injection is that you can look at
the constructor (or properties) from a class and instantly know its
dependencies. The Servicelocator pattern makes it too easy to hide
them.&lt;/p&gt;
&lt;p&gt;To demonstrate some of the beef I have with the Servicelocator pattern,
I wrote a FireStation class which has one public method Alert. I chose
an example which is not the de facto OrderService or ShoppingBasket
implementation, but which still is small enough to grasp easily.&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s have a look at this FireStation class. I know it&amp;rsquo;s a
ridiculously naïve implementation, but good enough as an example.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;FireStation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Alert(Incident incident)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        SendPagerMessage();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        SendEmail();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (incident.Priority == IncidentPriority.High)            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ActivateSiren();                        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; SendPagerMessage()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ServiceLocator.Current.GetInstance&amp;lt;IPagingTerminal&amp;gt;().SendMessage();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; SendEmail()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ServiceLocator.Current.GetInstance&amp;lt;IMailServer&amp;gt;().SendMailMessage();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; ActivateSiren()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ServiceLocator.Current.GetInstance&amp;lt;IImmoticaServer&amp;gt;().ActivateSiren();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There is one public Alert method, which takes an Incident instance, and
uses three alarmation channels to alert firemen: paging, email and a
siren.&lt;/p&gt;
&lt;p&gt;So, let&amp;rsquo;s imagine I wanted to test whether the siren is activated when
there is a high priority incident. I would just start writing the test,
to ultimately find out I have no idea what to assert.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[TestMethod()]&lt;/span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Alert_activates_the_siren_when_the_priority_is_high()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; fireStation = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; FireStation();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    fireStation.Alert(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Incident(IncidentPriority.High));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Assert.Inconclusive(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;How can I verify the siren is activated?&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Looking at the collapsed method definitions, I still don&amp;rsquo;t know. There
is no constructor, so the dependencies aren&amp;rsquo;t resolved in there. Nothing
left to do but inspect the Alert method content, and look at the
ActiviateSiren method implementation. That&amp;rsquo;s where I eventually find out
I need to mock the IImmoticaServer interface to assert the
interaction.&lt;/p&gt;
&lt;p&gt;So I do that, by creating the mock, setting up the container and setting
it as the provider for my servicelocator.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[TestMethod()]&lt;/span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Alert_activates_the_siren_when_the_priority_is_high()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; immoticaServer = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Mock&amp;lt;IImmoticaServer&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; kernel = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; StandardKernel();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    kernel.Bind&amp;lt;IImmoticaServer&amp;gt;().ToConstant(immoticaServer.Object);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ServiceLocator.SetLocatorProvider(() =&amp;gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; NinjectServiceLocator(kernel));    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; FireStation().Alert(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Incident(IncidentPriority.High));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    immoticaServer.Verify(i =&amp;gt; i.ActivateSiren(), Times.Once());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now I&amp;rsquo;m polluting my test with responsibilities it shouldn&amp;rsquo;t really care
about. I could probably move that into some infrastructure or the test
setup, but still, I&amp;rsquo;m writing code that could be easily averted.&lt;/p&gt;
&lt;p&gt;Anyways, I should now be able to verify the interaction with the
IImotticaServer implementation. Boom, red test. You probably figured
this one out already, but if I hadn&amp;rsquo;t expanded the private methods, you
would have had no idea that I needed two extra stubs to make the test
pass; one for the IPagingTerminal dependency and one for the IMailServer
dependency.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;kernel.Bind&amp;lt;IPagingTerminal&amp;gt;().ToConstant(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Mock&amp;lt;IPagingTerminal&amp;gt;().Object);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;kernel.Bind&amp;lt;IMailServer&amp;gt;().ToConstant(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Mock&amp;lt;IMailServer&amp;gt;().Object);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After binding these two dependencies the test finally turns up green.&lt;/p&gt;
&lt;p&gt;This development experience was horrible. The Servicelocator pattern
fails at making it easy for me to discover dependencies, leading to an
interrupted test flow. Another harmful side-effect is that it also
becomes harder for me to read code and understand the high level
interactions between objects, without getting knees deep into the
implementation details.&lt;/p&gt;
&lt;p&gt;By hiding your dependencies, you also promote ignorance to a problematic
amount of dependencies. I discovered three in this example, but as this
class grows, more and more of them will be buried inside the method
implementations.&lt;/p&gt;
&lt;p&gt;To make it easier to avoid and spot these smells earlier on, without
dropping the Servicelocator pattern as a whole, you could move service
resolution to the constructor. This isn&amp;rsquo;t a completely safe refactoring
though. It&amp;rsquo;s possible that some instantiations are expensive, and should
be implemented to be lazy initialized.&lt;/p&gt;
&lt;p&gt;There is one more annoyance I would like to spout in this post. The
Servicelocator pattern doesn&amp;rsquo;t encourage good OO. I&amp;rsquo;m not an OO purist,
but seeing dozens of static classes resolving their dependencies through
a servicelocator sends shivers down my spine. I would rather pick an
Inversion of Control technique which basically makes it impossible to do
this.&lt;/p&gt;
&lt;p&gt;This post turned out to be longer than I expected it to be, and I even
left some annoyances uncovered. I hope I succeeded in explaining my beef
with the Servicelocator pattern. I trust that the general consensus will
soon dictate that this pattern easily leads to marginal code, and that
it actually is an anti-pattern which should be avoided if possible.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Visualizing the offline application cache update progress</title>
      <link>https://jefclaes.be/2012/04/visualizing-offline-application-cache.html</link>
      <pubDate>Wed, 11 Apr 2012 16:27:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/04/visualizing-offline-application-cache.html</guid>
      <description>&lt;p&gt;I wrote about using the HTML5 application cache &lt;a href=&#34;http://jclaes.blogspot.com/2012/03/html5-offline-web-applications-as.html&#34;&gt;earlier&lt;/a&gt;, mostly focusing on generating and serving the manifest file using
ASP.NET MVC. I also bitched about how &lt;a href=&#34;http://jclaes.blogspot.com/2012/03/how-web-application-can-download-and.html&#34;&gt;not one browser I know of gives an indication of the application cache update progress&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Today I wanted to write something about how you can visualize the
application cache update progress yourself.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;applicationCache&lt;/code&gt; API has several useful and rather straightforward
events we can handle to inform the user of the update progress.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;window.&lt;span style=&#34;color:#a6e22e&#34;&gt;applicationCache&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;onchecking&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;updateCacheStatus&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Checking for a new version of the application.&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;window.&lt;span style=&#34;color:#a6e22e&#34;&gt;applicationCache&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ondownloading&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;updateCacheStatus&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Downloading a new offline version of the application&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;window.&lt;span style=&#34;color:#a6e22e&#34;&gt;applicationCache&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;oncached&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;updateCacheStatus&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;The application is available offline.&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;window.&lt;span style=&#34;color:#a6e22e&#34;&gt;applicationCache&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;onerror&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;updateCacheStatus&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Something went wrong while updating the offline version 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;                        of the application. It will not be available offline.&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;window.&lt;span style=&#34;color:#a6e22e&#34;&gt;applicationCache&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;onupdateready&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    window.&lt;span style=&#34;color:#a6e22e&#34;&gt;applicationCache&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;swapCache&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;updateCacheStatus&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;The application was updated. Refresh for the changes to take place.&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;window.&lt;span style=&#34;color:#a6e22e&#34;&gt;applicationCache&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;onnoupdate&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;updateCacheStatus&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;The application is also available offline.&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;window.&lt;span style=&#34;color:#a6e22e&#34;&gt;applicationCache&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;onobsolete&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;updateCacheStatus&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;The application can not be updated, no manifest file was found.&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;One event that is particularly helpful is the &lt;code&gt;progress&lt;/code&gt; event. This event
fires every time a resource is downloaded and contains three useful
attributes we can use to display the download progress:
&lt;code&gt;lengthComputable&lt;/code&gt;, &lt;code&gt;loaded&lt;/code&gt; and &lt;code&gt;total&lt;/code&gt;. These attributes should be fairly
self-descriptive, but here is the relevant snippet of &lt;a href=&#34;http://www.w3.org/TR/2011/WD-html5-20110525/offline.html&#34;&gt;the W3C specificiations&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For each cache host associated with an application cache in cache
group, queue a post-load task to fire an event with the name progress,
which does not bubble, which is cancelable, and which uses the
ProgressEvent interface, at the ApplicationCache singleton of the
cache host. The lengthComputable attribute must be set to true, the
total attribute must be set to the number of files in file list, and
the loaded attribute must be set to the number of number of files in
file list that have been either downloaded or skipped so far. The
default action of these events must be, if the user agent shows
caching progress, the display of some sort of user interface
indicating to the user that a file is being downloaded in preparation
for updating the application. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To have a text that updates the percentage of downloaded resources on
every download, I came up with this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;window.&lt;span style=&#34;color:#a6e22e&#34;&gt;applicationCache&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;onprogress&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;) {               
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Downloading offline resources.. &amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;lengthComputable&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;updateCacheStatus&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; Math.&lt;span style=&#34;color:#a6e22e&#34;&gt;round&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;loaded&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;total&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;%&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;updateCacheStatus&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;message&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These attributes seem to be implemented in WebKit browsers, but not in
Firefox. Firefox will fall back to the static message &amp;lsquo;Downloading
offline resources..&amp;rsquo;. Internet Explorer doesn&amp;rsquo;t support the offline
application cache as a whole.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m sure more creative souls have it in them to build a really elegant
and visually pleasing progress indication using this technique. I&amp;rsquo;m
curious to hear (or &lt;strong&gt;see&lt;/strong&gt;!) how you would represent the update
process.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Check for local file browsing with JavaScript</title>
      <link>https://jefclaes.be/2012/04/check-for-local-file-browsing-with.html</link>
      <pubDate>Mon, 02 Apr 2012 15:34:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/04/check-for-local-file-browsing-with.html</guid>
      <description>&lt;p&gt;Because I do most of my research while commuting by train, I often pull entire websites offline using &lt;a href=&#34;http://www.httrack.com/&#34;&gt;httrack&lt;/a&gt;. While browsing the [jQuery Mobile documentation](&lt;a href=&#34;http://jquerymobile.com/demos/1.1.0-rc.1/&#34;&gt;http://jquerymobile.com/demos/1.1.0-rc.1/&lt;/a&gt; locally this morning, I stumbled upon following gem.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-04-02-check-for-local-file-browsing-with-javascript-jQueryMobileLocal.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-04-02-check-for-local-file-browsing-with-javascript-jQueryMobileLocal.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I was curious to see how they determine whether a page is browsed
locally or not. Looking into the source, I was a bit dissapointed to
find nothing but plain common sense. The trick is comparing the protocol
of the current location with known local protocols.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ( &lt;span style=&#34;color:#a6e22e&#34;&gt;location&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;protocol&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;substr&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;)  &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;file&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;location&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;protocol&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;substr&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;11&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;*-extension&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;location&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;protocol&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;substr&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;)  &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;widget&amp;#39;&lt;/span&gt; ) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Disable AJAX support etc
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you would want to use that check in multiple locations in your
codebase, you might want to extend the &lt;a href=&#34;https://developer.mozilla.org/en/DOM/window.location&#34;&gt;location object&lt;/a&gt; with an &lt;code&gt;isLocal&lt;/code&gt; function.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;window.&lt;span style=&#34;color:#a6e22e&#34;&gt;location&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;constructor&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;prototype&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;isLocal&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() { 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;protocol&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;substr&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;)  &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;file&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;protocol&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;substr&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;11&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;*-extension&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;protocol&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;substr&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;)  &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;widget&amp;#39;&lt;/span&gt;; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The function could be used like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (window.&lt;span style=&#34;color:#a6e22e&#34;&gt;location&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;isLocal&lt;/span&gt;()) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Disable AJAX support etc
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>Add images to a GitHub readme</title>
      <link>https://jefclaes.be/2012/04/add-images-to-github-readme.html</link>
      <pubDate>Sun, 01 Apr 2012 19:32:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/04/add-images-to-github-readme.html</guid>
      <description>&lt;p&gt;Today I wanted to add some screenshots to a GitHub readme for the sake
of documenting. While this wasn&amp;rsquo;t particularly hard, I do had to iterate
a few times before I got it right.&lt;/p&gt;
&lt;h3 id=&#34;hosting-the-images&#34;&gt;Hosting the images&lt;/h3&gt;
&lt;p&gt;You could simply add the images to your repository and reference them
using the raw url&amp;rsquo;s, but this isn&amp;rsquo;t very efficient. Using this method,
every request needs to go through GitHub&amp;rsquo;s application layer. It&amp;rsquo;s far
better to make use of &lt;a href=&#34;http://pages.github.com/&#34;&gt;GitHub Pages&lt;/a&gt;, a
feature purely designed to publish web content. I also like how you&amp;rsquo;re
not polluting the repository this way.&lt;/p&gt;
&lt;h3 id=&#34;referencing-the-images&#34;&gt;Referencing the images&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;m using the - oh so beautiful and simple - &lt;a href=&#34;http://daringfireball.net/projects/markdown/syntax&#34;&gt;markdown format&lt;/a&gt; for most of my readme&amp;rsquo;s. The syntax for embedding images looks like this.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;[My image](username.github.com/repository/img/image.jpg)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;I hope this post fills in the void I stumbled upon when googling for
useful pointers earlier today.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>How a web application can download and store over 2GB without you even knowing it</title>
      <link>https://jefclaes.be/2012/03/how-web-application-can-download-and.html</link>
      <pubDate>Sun, 25 Mar 2012 13:11:00 +0200</pubDate>
      <guid>https://jefclaes.be/2012/03/how-web-application-can-download-and.html</guid>
      <description>&lt;p&gt;I have been experimenting with the &lt;a href=&#34;http://www.w3.org/TR/html5/offline.html&#34;&gt;HTML5 offline application
cache&lt;/a&gt; some more over the last
few days, doing boundary tests in an attempt to learn more about browser
behaviour in edge cases.&lt;/p&gt;
&lt;p&gt;One of these experiments was testing the cache quota.&lt;/p&gt;
&lt;p&gt;Two weeks ago, I blogged about &lt;a href=&#34;http://jclaes.blogspot.com/2012/03/html5-offline-web-applications-as.html&#34;&gt;generating and serving an offline
application manifest using ASP.NET MVC&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I reused that code to add hundreds of 7MB PDF files to the cache.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; ActionResult Manifest()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{     
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; cacheResources = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; List&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; n = &lt;span style=&#34;color:#ae81ff&#34;&gt;300&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;// Play with this number&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; i = &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; i &amp;lt; n; i++)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        cacheResources.Add(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Content/&amp;#34;&lt;/span&gt; + Url.Content(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;book.pdf?&amp;#34;&lt;/span&gt; + i));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; manifestResult = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ManifestResult(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        NetworkResources = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;[] { &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        CacheResources = cacheResources
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; manifestResult;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I initially tried adding 1000 PDF files to the cache, but this threw an
error: &lt;code&gt;Chrome failed to commit the new cache to the storage, because the quota would be exceeded.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;After lowering the number of files several times, I hit the sweet spot.
I could add 300 PDF files to the cache without breaking it.&lt;/p&gt;
&lt;p&gt;Looking into &lt;code&gt;chrome://appcache-internals/&lt;/code&gt;, I can see the size of the
cache being a whopping &lt;strong&gt;2.2GB&lt;/strong&gt; now for one single web application.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-03-25-how-a-web-application-can-download-and-store-over-2gb-without-you-even-knowing-it-appcache-internals.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-03-25-how-a-web-application-can-download-and-store-over-2gb-without-you-even-knowing-it-appcache-internals.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As a user, I had no idea that the website I&amp;rsquo;m browsing is downloading a
suspicious amount of data in the background. Chrome (17.0.963.83), nor
any other desktop browser that I know of, warns me. I would expect the
browser to ask for my permission when a website wants to download and
store such an excessive amount of data on my machine.&lt;/p&gt;
&lt;p&gt;Something else I noticed, is that other sites now fail to commit
anything to the application cache due to the browser-wide quota being
exceeded. I&amp;rsquo;m pretty sure this &amp;lsquo;first browsed, first reserved&amp;rsquo; approach
will be a source of frustration in the future.&lt;br&gt;
To handle this scenario we could use the applicationCache API to listen
for quota errors, and inform the user to browse to
&lt;code&gt;chrome://appcache-internals/&lt;/code&gt; and remove other caches in favor of the
new one. This feels sketchy though; shouldn&amp;rsquo;t the browser intervene in a
more elegant way here?&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-03-25-how-a-web-application-can-download-and-store-over-2gb-without-you-even-knowing-it-exceedquote.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-03-25-how-a-web-application-can-download-and-store-over-2gb-without-you-even-knowing-it-exceedquote.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What are your thoughts? What would you want your browser to do in
these scenarios?&lt;/strong&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Sent from my phone</title>
      <link>https://jefclaes.be/2012/03/sent-from-my-phone.html</link>
      <pubDate>Sat, 17 Mar 2012 19:46:00 +0100</pubDate>
      <guid>https://jefclaes.be/2012/03/sent-from-my-phone.html</guid>
      <description>&lt;p&gt;According to &lt;a href=&#34;http://37signals.com/svn/posts/2500-lets-be-honest-sent-from-my&#34;&gt;Matt from
37signals&lt;/a&gt;
the line &amp;ldquo;Sent from my iPhone&amp;rdquo; at the bottom of an email means this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let’s be honest. “Sent from my iPhone” really means “I’m not going to
bother to proofread and correct this because it would take me an extra
30 seconds.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I agree. I too use this line as an excuse to write a terse message and
omit proper salutations.&lt;/p&gt;
&lt;p&gt;However, I also think these four simple words greatly helped the viral
growth of the mobile phone. Having early adopters brag about how they&amp;rsquo;re
sending emails from their fancy new phone must have been an invaluable
form of word-of-mouth advertising.&lt;/p&gt;
&lt;p&gt;I think it&amp;rsquo;s safe to say that those four words first are a marketing
technique and then a convenient way of letting your correspondents know
that there might be a typo in your message. If not, the default line
wouldn&amp;rsquo;t include the brand name.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m turning this thing into a rambling though. What I really wanted to
share is a snippet of the &lt;em&gt;much recommended&lt;/em&gt; book &lt;a href=&#34;http://www.amazon.com/gp/product/0307887898/ref=as_li_tf_tl?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0307887898%22&#34;&gt;The Lean
Startup&lt;/a&gt;,
where &lt;a href=&#34;http://www.startuplessonslearned.com/&#34;&gt;Eric Ries&lt;/a&gt; shares a story
on how Hotmail used a similar technique in 1996 to fuel their viral
engine of growth.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;But everything changed when they made one small tweak to the product.
They added to the bottom of every e-mail the message &amp;ldquo;P.S. Get your
free e-mail at Hotmail&amp;rdquo; along with a clickable link.&lt;br&gt;
Within weeks, that small product change produced massive results.
Within six months, Bhatia and Smith had signed up more than 1 million
new customers. Five weeks later, they hit the 2 million mark. Eighteen
months after launching the service, with 12 million subscribers, they
sold the company to Microsoft for $400 million.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I find it incredibly intriguing how a few words can have such an impact.
Maybe you do too.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>HTML5 Offline Web applications as an afterthought in ASP.NET MVC</title>
      <link>https://jefclaes.be/2012/03/html5-offline-web-applications-as.html</link>
      <pubDate>Wed, 14 Mar 2012 15:39:00 +0100</pubDate>
      <guid>https://jefclaes.be/2012/03/html5-offline-web-applications-as.html</guid>
      <description>&lt;p&gt;Recently I prototyped a mobile web application using ASP.NET MVC,
&lt;a href=&#34;http://jquerymobile.com/&#34;&gt;jQuery Mobile&lt;/a&gt; and some HTML5 features. One
of the key goals was to find out how far you can push a web
&amp;lsquo;application&amp;rsquo; until the browser starts getting in the way. Working
disconnected is one of these things that appear to be a major
showstopper at first.&lt;/p&gt;
&lt;p&gt;However - to my surprise honestly - the &lt;a href=&#34;http://dev.w3.org/html5/spec/offline.html&#34;&gt;HTML5 Offline Web applications
API&lt;/a&gt; seems to be &lt;a href=&#34;http://caniuse.com/#search=offline&#34;&gt;widely
implemented&lt;/a&gt; across modern browsers
already. &lt;a href=&#34;https://picasaweb.google.com/lh/photo/lVnWvGLepGsFhIc2Z4SKdcdrvCRMWyke7-RbgGXMEiI?feat=directlink&#34;&gt;Not of all of them
though&lt;/a&gt;.
Looking into the specifics, the API itself is fairly straightforward. At
his core, you will find the manifest file, which dictates which files
should be cached by the browser. The API provides other useful events
and methods for inspecting the status of the cache and swapping the
cache for a newer version, but they are out of scope today. A useful
resource to read up on the full API can be found
&lt;a href=&#34;http://dev.opera.com/articles/view/offline-applications-html5-appcache/&#34;&gt;here&lt;/a&gt;,
and a working example implementation can be found
&lt;a href=&#34;http://html5demos.com/offlineapp&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;the-manifest-file&#34;&gt;The manifest file&lt;/h3&gt;
&lt;p&gt;Back to the manifest file. A manifest file could look like this.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-03-14-html5-offline-web-applications-as-an-afterthought-in-asp-net-mvc-ManifestFile.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-03-14-html5-offline-web-applications-as-an-afterthought-in-asp-net-mvc-ManifestFile.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The first line in the file should say &lt;code&gt;CACHE MANIFEST&lt;/code&gt;. If you want to
write comments, you should prefix the lines with a number sign.&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;CACHE&lt;/code&gt; section you declare which files should be cached. An
important and interesting note is that these files will be served from
the cache, even if you&amp;rsquo;re online.&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;NETWORK&lt;/code&gt; section you declare which files the browser should try to
download from the server, regardless of whether the user is online or
offline.&lt;/p&gt;
&lt;p&gt;In the last section, the &lt;code&gt;FALLBACK&lt;/code&gt; section, you can define fallback
resources to be used when the user is offline.&lt;/p&gt;
&lt;h3 id=&#34;serving-and-generating-the-manifest-file&#34;&gt;Serving and generating the manifest file&lt;/h3&gt;
&lt;p&gt;Now that we got all this theory out of the way, let&amp;rsquo;s look at generating
and serving the manifest file using ASP.NET MVC.&lt;/p&gt;
&lt;p&gt;I started by adding a ResourcesController with one action named
Manifest.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ResourcesController&lt;/span&gt; : Controller
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{             
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; ActionResult Manifest() { }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This action should serve a text file, using a specific cache-manifest
MIME type. To accommodate this I created a new action result, which
inherits from the &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.web.mvc.fileresult.aspx&#34;&gt;FileResult&lt;/a&gt; class, and overwrites the content type.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ManifestResult&lt;/span&gt; : FileResult
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; ManifestResult(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; version)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        : &lt;span style=&#34;color:#66d9ef&#34;&gt;base&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;text/cache-manifest&amp;#34;&lt;/span&gt;) { }    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I also made this same class (for the sake of example) responsible for
formatting and writing the manifest file to the output stream. That&amp;rsquo;s
why I added a few extra properties to the manifest result, one for each
section and one for versioning. Versioning the file comes in handy when
you want to expire the cache, because it only expires when the manifest
file changes.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ManifestResult&lt;/span&gt; : FileResult
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; ManifestResult(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; version)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        : &lt;span style=&#34;color:#66d9ef&#34;&gt;base&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;text/cache-manifest&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        CacheResources = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; List&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        NetworkResources = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; List&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        FallbackResources = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Version = version;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; Version { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; IEnumerable&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&amp;gt; CacheResources { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; IEnumerable&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&amp;gt; NetworkResources { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }       
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Dictionary&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&amp;gt; FallbackResources { &lt;span style=&#34;color:#66d9ef&#34;&gt;get&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt;; }        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;To write the file to the output stream, I had to &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; the &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;`&lt;/span&gt;WriteFile&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;method.  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;```&lt;/span&gt;csharp
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; WriteFile(HttpResponseBase response)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    WriteManifestHeader(response);            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    WriteCacheResources(response);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    WriteNetwork(response);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    WriteFallback(response);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; WriteManifestHeader(HttpResponseBase response)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    response.Output.WriteLine(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CACHE MANIFEST&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    response.Output.WriteLine(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;#V&amp;#34;&lt;/span&gt; + Version ?? &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.Empty);            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; WriteCacheResources(HttpResponseBase response)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    response.Output.WriteLine(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CACHE:&amp;#34;&lt;/span&gt;);           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; cacheResource &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; CacheResources)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        response.Output.WriteLine(cacheResource);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; WriteNetwork(HttpResponseBase response)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    response.Output.WriteLine();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    response.Output.WriteLine(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;NETWORK:&amp;#34;&lt;/span&gt;);            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; networkResource &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; NetworkResources)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        response.Output.WriteLine(networkResource);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; WriteFallback(HttpResponseBase response)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    response.Output.WriteLine();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    response.Output.WriteLine(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;FALLBACK:&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; fallbackResource &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; FallbackResources)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        response.Output.WriteLine(fallbackResource.Key + &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt; + fallbackResource.Value);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the &lt;code&gt;CACHE&lt;/code&gt; section I wanted to include all my static resources,
meaning the contents of the Scripts and Content folder. To do this in a
simple and low-maintenance fashion I introduced the
&lt;code&gt;GetRelativePathsToRoot&lt;/code&gt; method. This method takes the path of a virtual
folder, recursively scans its content and returns a list of relative
paths for each file.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; IEnumerable&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&amp;gt; GetRelativePathsToRoot(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; virtualPath)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; physicalPath = Server.MapPath(virtualPath);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; absolutePaths = Directory.GetFiles(physicalPath, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;*.*&amp;#34;&lt;/span&gt;,   SearchOption.AllDirectories);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; absolutePaths.Select(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        x =&amp;gt; Url.Content(virtualPath + x.Replace(physicalPath, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For the Content folder, the result could look something like this.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-03-14-html5-offline-web-applications-as-an-afterthought-in-asp-net-mvc-ContentFolder.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-03-14-html5-offline-web-applications-as-an-afterthought-in-asp-net-mvc-ContentFolder.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To add pages to the &lt;code&gt;CACHE&lt;/code&gt; section, I used the Url.Action method.&lt;/p&gt;
&lt;p&gt;For the &lt;code&gt;NETWORK&lt;/code&gt; resources, I added an asterisk, which basically means
that the cache shouldn&amp;rsquo;t be used when the user is online. I didn&amp;rsquo;t
specify any fallback resources in this example.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; ActionResult Manifest()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; pages = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; List&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    pages.Add(Url.Action(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SomeAction&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ControllerName&amp;#34;&lt;/span&gt;));    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; scriptsPaths = GetRelativePathsToRoot(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;~/Scripts/&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; contentPaths = GetRelativePathsToRoot(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;~/Content/&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; cacheResources = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; List&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    cacheResources.AddRange(pages);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    cacheResources.AddRange(contentPaths);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    cacheResources.AddRange(scriptsPaths);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; manifestResult = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ManifestResult(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        NetworkResources = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;[] { &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        CacheResources = cacheResources
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; manifestResult;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;setting-up-a-route-and-including-the-manifest&#34;&gt;Setting up a route and including the manifest&lt;/h3&gt;
&lt;p&gt;Now that we are able to generate and serve a manifest file, we should
set up a specific route for the manifest file; some browsers aren&amp;rsquo;t very
forgiving and expect it to have a specific name and location:
/cache.manifest.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;routes.MapRoute(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;cache.manifest&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;cache.manifest&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; { controller = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Resources&amp;#34;&lt;/span&gt;, action = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Manifest&amp;#34;&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The last step I had to take was include a reference to the manifest file
in the html element.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;html&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;manifest&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;@Url.RouteUrl(&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;cache&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;manifest&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#34;)&amp;#34;)&lt;/span&gt;/&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;poor-mans-testing&#34;&gt;Poor man&amp;rsquo;s testing&lt;/h3&gt;
&lt;p&gt;To verify if all of this works, you can look at the console of the
Chrome developer tools. You should see something like this.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-03-14-html5-offline-web-applications-as-an-afterthought-in-asp-net-mvc-ManifestDownloading.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-03-14-html5-offline-web-applications-as-an-afterthought-in-asp-net-mvc-ManifestDownloading.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That console logging has proven to be extremely useful when debugging
the manifest file.&lt;/p&gt;
&lt;p&gt;You could also just browse to the manifest file to inspect its content.
Don&amp;rsquo;t mind this screenshot too much, obviously there&amp;rsquo;s plenty of
cleaning up to do in my Scripts folder.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-03-14-html5-offline-web-applications-as-an-afterthought-in-asp-net-mvc-BrowsetoManifestFile.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-03-14-html5-offline-web-applications-as-an-afterthought-in-asp-net-mvc-BrowsetoManifestFile.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;summary&#34;&gt;Summary&lt;/h3&gt;
&lt;p&gt;In this post I showed you a technique I came up with to take advantage
of ASP.NET MVC to easily generate, maintain and serve an HTML5 Offline
Webappliction manifest file:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a controller and action that can serve the file&lt;/li&gt;
&lt;li&gt;Create a new action result, which returns the correct MIME type and formats the file&lt;/li&gt;
&lt;li&gt;Set up a specific route&lt;/li&gt;
&lt;li&gt;Include a reference to the manifest in the html tag&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Remember, this is a proof of concept, it&amp;rsquo;s not perfect. I look forward
to any feedback you might have!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Learning: the Hacker Way</title>
      <link>https://jefclaes.be/2012/03/learning-the-hacker-way/</link>
      <pubDate>Sun, 11 Mar 2012 11:08:00 +0100</pubDate>
      <guid>https://jefclaes.be/2012/03/learning-the-hacker-way/</guid>
      <description>&lt;p&gt;I have had a fair amount of discussions on continuous learning and
knowledge sharing the past few days. It became rather obvious that a lot
of us have developed their own techniques, but also that maybe most of
us are still in search of more efficient techniques. Having gone through
several phases myself, I would like to share my current way of learning:
the Hacker Way.&lt;/p&gt;
&lt;p&gt;Here are some snippets taken from a &lt;a href=&#34;http://seo-hacker.com/hacker/&#34;&gt;recent
letter&lt;/a&gt; from Mark Zuckerberg addressed to
the Facebook shareholders.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hacking is an inherently hands-on and active discipline. Instead of
debating for days whether a new idea is possible or what the best way
to build something is, hackers would rather just prototype something
and see what works. There&amp;rsquo;s a hacker mantra that you&amp;rsquo;ll hear a lot
around Facebook offices: Code wins arguments.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I like to believe learning should be a hands-on activity as well.
Basically, stop consuming, start producing. Don&amp;rsquo;t get me wrong, I do
think there is value in reading blog posts (I might be slightly biased
on this one), reading books and watching videos, but I find that this
value is marginal compared to what you gain by actually doing it.&lt;/p&gt;
&lt;p&gt;I remember I wanted to step up my JavaScript game two years ago, and
&lt;a href=&#34;http://www.jefclaes.be/2010/02/book-review-object-oriented-javascript.html&#34;&gt;ordered a
book&lt;/a&gt;.
A few months after finishing the book, I finally had the chance to
implement something in JavaScript, but I couldn&amp;rsquo;t. I remembered some
syntax, and most concepts, but I couldn&amp;rsquo;t do it. Eventually I really
learned JavaScript by doing it on the job, having to constantly fall
back on the book and Stackoverflow, making costly mistakes along the
way.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s not a terrible idea to pick up a new technology on the job, but it
very much depends on the environment. If you&amp;rsquo;re in the consultancy
business, there often is no room to pick up a brand new technology on
the job. Customers expect you to know what you&amp;rsquo;re doing.&lt;br&gt;
Imagine you really want to get into mobile development, and you were
able to get in the race for a new mobile project. Getting interviewed by
the customer, you have to admit that you haven&amp;rsquo;t built something for
mobile yet, but you did read a book and you find mobile development
really interesting. It&amp;rsquo;s really hard to sell that. If you are able to
show something you made, and talk about things that work and things that
don&amp;rsquo;t work in the real world, the customer can get a far better feel if
you would be a good fit for the project.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Hacker Way is an approach to building that involves continuous
improvement and iteration. Hackers believe that something can always
be better, and that nothing is ever complete. &lt;/p&gt;
&lt;p&gt;Hacker culture is also extremely open and meritocratic. Hackers
believe that the best idea and implementation should always win - not
the person who is best at lobbying for an idea or the person who
manages the most people. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is where it becomes interesting and where you can really make the
difference as a company.&lt;/p&gt;
&lt;p&gt;Depending on various parameters, you often don&amp;rsquo;t have the room to
experiment on the day job, but if you&amp;rsquo;re building something by yourself
or in a small team without these constraints, you can &lt;a href=&#34;http://www.youtube.com/watch?v=QckCBwdeCJU&#34;&gt;get
wild&lt;/a&gt;: experiment, innovate
and fail often. Not only do you build experience faster, but you also
(maybe indirectly) challenge existing practices and build a deeper
understanding of the used methodologies and technologies. Also, having
the freedom to innovate, aspiring to get closer to the Silver Bullet,
can bring yourself, the company and the industry to the next level.&lt;/p&gt;
&lt;p&gt;This is just the first step of the cycle though. The next step should be
to get these little projects and acquired experiences out there. Share
them with your peers and the community, educate those who want to listen
and ask for feedback from those who care, hopefully fueling the
inspiration of others.&lt;/p&gt;
&lt;p&gt;A welcome side-effect might be that the results could be used to extend
your personal and your company&amp;rsquo;s portfolio. This can help you prove that
you can do more than just talk the walk, talk is cheap after all.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I want to know from you what the flaws are in my way of thinking. Is
the described technique naive, too idealistic or unrealistic? Which technique has proven to work best for you?&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>ASP.NET MVC4 bundling in ASP.NET MVC3</title>
      <link>https://jefclaes.be/2012/02/aspnet-mvc4-bundling-in-aspnet-mvc3.html</link>
      <pubDate>Sat, 25 Feb 2012 20:26:00 +0100</pubDate>
      <guid>https://jefclaes.be/2012/02/aspnet-mvc4-bundling-in-aspnet-mvc3.html</guid>
      <description>&lt;p&gt;One of the new wildly evangelized features of &lt;a href=&#34;http://www.asp.net/mvc/mvc4&#34;&gt;ASP.NET MVC4&lt;/a&gt; is the &lt;a href=&#34;http://weblogs.asp.net/scottgu/archive/2011/11/27/new-bundling-and-minification-support-asp-net-4-5-series.aspx&#34;&gt;built-in support for bundling and minification&lt;/a&gt; of scripts and stylesheets.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t see any reason why this new feature wouldn&amp;rsquo;t work for ASP.NET
MVC3 though. If you open the packages config of an ASP.NET MVC4 beta
project, you will find that bundling support lives in the
&lt;code&gt;Microsoft.Web.Optimization&lt;/code&gt; package.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;id=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Microsoft.Web.Optimization&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;version=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1.0.0-beta&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So we should just be able to install &lt;a href=&#34;http://nuget.org/packages/Microsoft.Web.Optimization/0.1&#34;&gt;this package&lt;/a&gt; for
an ASP.NET MVC3 project. To install the package, run following command. Pay attention to the &lt;code&gt;-Pre&lt;/code&gt; switch.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;PM&amp;gt; Install-Package Microsoft.Web.Optimization -Pre
Attempting to resolve dependency &amp;#39;Microsoft.Web.Infrastructure (= 1.0.0)&amp;#39;.
Successfully installed &amp;#39;Microsoft.Web.Infrastructure 1.0.0.0&amp;#39;.
Successfully installed &amp;#39;Microsoft.Web.Optimization 1.0.0-beta&amp;#39;.
Successfully added &amp;#39;Microsoft.Web.Infrastructure 1.0.0.0&amp;#39; to Optimization.
Successfully added &amp;#39;Microsoft.Web.Optimization 1.0.0-beta&amp;#39; to Optimization.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Adding bundles happens when the application starts, together with
registering areas, adding global filters and registering routes.&lt;/p&gt;
&lt;p&gt;The quickest way to enable bundling is by enabling the default
bundles.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BundleTable.Bundles.EnableDefaultBundles();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This method will add two bundles to the bundle table: one bundle for the
stylesheets in the Content folder and one bundle for the scripts in the
Scripts folder. The default bundles try to take core scripts into
account when ordering the scripts in the bundle. For example, jQuery
will be included before any of its plug-ins are included.&lt;/p&gt;
&lt;p&gt;To reference these bundles you can add following snippet to your view or
layout file.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;href&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl(&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;~/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Content&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;css&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#34;)&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;rel&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;type&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;text/css&amp;#34;&lt;/span&gt; /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl(&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;~/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Scripts&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;js&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#34;)&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;script&lt;/span&gt;&amp;gt;    
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you start your application now, and inspect the HTML, you will find
two versioned links to a minified version of your CSS and JavaScript.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-02-25-asp-net-mvc4-bundling-in-asp-net-mvc3-minifiedhead.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-02-25-asp-net-mvc4-bundling-in-asp-net-mvc3-minifiedhead.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-02-25-asp-net-mvc4-bundling-in-asp-net-mvc3-minifiedJS.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-02-25-asp-net-mvc4-bundling-in-asp-net-mvc3-minifiedJS.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re trying this on a new project, you will probably have no
problems. However, if you&amp;rsquo;re trying this on an existing project, chances
are that some things are not included how they should be.&lt;/p&gt;
&lt;p&gt;To troubleshoot what&amp;rsquo;s going wrong, you can inspect the results of the
&lt;code&gt;GetRegisteredBundles&lt;/code&gt; method.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; registeredBundles = BundleTable.Bundles.GetRegisteredBundles();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you need more fine-grained control, you can remove the default bundles again and add your own bundles to the bundle table.&lt;/p&gt;
&lt;p&gt;For example, this is how you can add a jQuery bundle.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; jQueryBundle = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Bundle(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;~/Scripts/jquery&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; JsMinify());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;jQueryBundle.AddDirectory(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;~/Scripts&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;jquery*.js&amp;#34;&lt;/span&gt;, searchSubdirectories: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;, throwIfNotExist: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BundleTable.Bundles.Add(jQueryBundle);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl(&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;~/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Scripts&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;jQuery&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#34;)&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;script&lt;/span&gt;&amp;gt;  
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When you instantiate a new bundle, specify the relative path of the
bundle and pick a bundle transformation. You can add a directory to the
bundle, filtered by a search pattern. You can also tell the algorithm to
search in the subdirectories or to throw an exception when the directory
doesn&amp;rsquo;t exist.&lt;/p&gt;
&lt;p&gt;If you don&amp;rsquo;t want to add a whole directory to the bundle, but just one
or more files, you can use the &lt;code&gt;AddFile&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;For example, this is a separate bundle for modernizr.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; modernizrBundle = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Bundle(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;~/Scripts/modernizr&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; JsMinify());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;modernizrBundle.AddFile(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;~/Scripts/modernizr-1.7.js&amp;#34;&lt;/span&gt;, throwIfNotExist: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BundleTable.Bundles.Add(modernizrBundle);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s relatively easy to take advantage of bundling in ASP.NET MVC3.
Install the NuGet package, set up the bundle table, include the
references in your view or layout page and you&amp;rsquo;re done.&lt;/p&gt;
&lt;p&gt;There are some more interesting things you can do using bundling. I just
started experimenting with it, so I wouldn&amp;rsquo;t be surprised if I will be
writing a few more things on bundling in the coming weeks.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>There&#39;s no place for monogamy in technology</title>
      <link>https://jefclaes.be/2012/02/theres-no-place-for-monogamy-in.html</link>
      <pubDate>Mon, 20 Feb 2012 08:43:00 +0100</pubDate>
      <guid>https://jefclaes.be/2012/02/theres-no-place-for-monogamy-in.html</guid>
      <description>&lt;p&gt;In this post I would like to share some of my thoughts on a &lt;a href=&#34;http://prog21.dadgum.com/128.html&#34;&gt;recent post
by James Hague&lt;/a&gt; titled &amp;lsquo;Don&amp;rsquo;t Fall in
Love With Your Technology&amp;rsquo;. If you haven&amp;rsquo;t read that post yet, please
do, it&amp;rsquo;s so short that me summarizing it here would be silly.&lt;/p&gt;
&lt;p&gt;I think there is nothing wrong with falling in love with your technology
per se. If you want to have a fair relationship with your technology,
you have to invest in her. Don&amp;rsquo;t have a superficial relationship, take
her home with you, spend some cosy Sunday afternoons together. Get to
know her inside out. Know when it&amp;rsquo;s fun to be with her, but also more
importantly when it&amp;rsquo;s not.&lt;/p&gt;
&lt;p&gt;The problem with falling in love with your technology is that a lot of
us fall blindly in love. Please don&amp;rsquo;t. Be unfaithful, do - at least -
look at other technologies. Take them out on a crazy Friday night date.
In the meanwhile you might discover that that new technology does a few
things better than the current one and that she&amp;rsquo;s a lot more fun.&lt;/p&gt;
&lt;p&gt;I guarantee that what now seems like the love of your life, will one day
be nothing more than a long forgotten memory which might bring a smirk
on your face on remembering her, but there will be no regret in leaving
her.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Book review: Working with NHibernate 3.0</title>
      <link>https://jefclaes.be/2012/02/book-review-working-with-nhibernate-30.html</link>
      <pubDate>Wed, 08 Feb 2012 20:21:00 +0100</pubDate>
      <guid>https://jefclaes.be/2012/02/book-review-working-with-nhibernate-30.html</guid>
      <description>&lt;p&gt;It&amp;rsquo;s been a while since I wrote my last book review, mostly because I&amp;rsquo;m
still trying to figure out when it adds value to write one. For this one
it was pretty obvious, there are far too little reviews out there.&lt;/p&gt;
&lt;p&gt;Being new to NHibernate, and NHibernate being known as having a steep
learning curve, I thought it would be a good idea to do some reading.
Searching for books on NHibernate 3.0 on Amazon only yielded three
results: &lt;a href=&#34;http://www.amazon.com/gp/product/1849516022/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=1849516022&#34;&gt;NHibernate 3 beginner&amp;rsquo;s
guide&lt;/a&gt;,
&lt;a href=&#34;http://www.amazon.com/gp/product/184951304X/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=184951304X&#34;&gt;NHibernate 3.0
cookbook&lt;/a&gt;
and &lt;a href=&#34;http://www.amazon.com/gp/product/1118112571/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=1118112571&#34;&gt;working with NHibernate
3.0&lt;/a&gt;.
None of these books have a decent amount of reviews, so I had to pick
judging by the cover and summary. I chose the last one.&lt;/p&gt;
&lt;p&gt;The book &lt;a href=&#34;http://the%20book%20working%20with%20nhibernate%203.0%20by%20benjamin%20delcamp%20perkins%20contains%20six%20chapters%2C%20covered%20over%20213%20pages./&#34;&gt;Working with NHibernate
3.0&lt;/a&gt;
by &lt;a href=&#34;http://thebestcsharpprogrammerintheworld.com/&#34;&gt;Benjamin Delcamp
Perkins&lt;/a&gt; contains six
chapters, covered over 213 pages.&lt;/p&gt;
&lt;p&gt;The first chapter very briefly explains what an ORM is, and then starts
looking at configuring NHibernate. This means setting up the session
factory and its configuration, creating entities and mapping them to the
database (using XML and code), but also configuring log4net
(NHibernate&amp;rsquo;s logging framework), serializing startup and interceptors
and events. These last two subjects felt a little misplaced in this
chapter though.&lt;/p&gt;
&lt;p&gt;In the first chapter the foundation for the Guitar store example
application is laid. This example application is written in WPF, which
bothered me a bit. Not because I dislike WPF, but because when I&amp;rsquo;m
reading a book on a data access technology I really don&amp;rsquo;t want it to be
littered with fragments of XAML and code-behind. To make matters worse,
the author suggests using a console application to test your queries. I
think it would have been far more valuable to use real unit tests to
prove the queries are correct, &lt;a href=&#34;https://github.com/davybrion/NHibernateWorkshop/tree/master/NHibernateWorkshop&#34;&gt;more like
this&lt;/a&gt;.
Another complaint about the example application that I read in another
review is that there are no scripts available to set up the database,
which might be discouraging if you want to follow along.&lt;/p&gt;
&lt;p&gt;Chapter two, three and four cover the various NHibernate query API&amp;rsquo;s:
HQL (Hibernate Query Language), ICriteria and LINQ. Every chapter
implements the same or at least similar queries. Concepts covered in
these chapters are simple queries, complex queries, detached queries,
futures and aggregates. I think these chapters succeed in giving a good
overview of the ways you can use NHibernate to query data. Also the tips
on how to use futures, various fetch modes, the stateless session and
aggregates to improve performance will prove useful in the future.&lt;/p&gt;
&lt;p&gt;The fifth chapter covers managing state and saving data. In this
chapter, the author explains the various ways you can handle database
concurrency, listing the advantages and disadvantages of each option.
NHibernate caching is also explained, looking at first and second-level
caching. Further in this chapter, you can find an example of a custom
data type implementation. Finally we arrive at saving data with
NHibernate. Next to the standard way of saving data, the author explains
the use of Evict, Merge and Persist.&lt;/p&gt;
&lt;p&gt;The last chapter, covering only 9 pages, shows how you should set up
NHibernate in an MVC3 application.&lt;/p&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Although this book doesn&amp;rsquo;t do a great job showing you how to use
NHibernate in the real world, it does do a decent job giving you a basic
overview of NHibernate&amp;rsquo;s capabilities. Reading this book when you&amp;rsquo;re new
to NHibernate will save you from a few costly common NHibernate
pitfalls. I don&amp;rsquo;t think I will be able to use this book for reference,
but it should be easier now - knowing the correct terminology - to
search in the NHibernate documentation online.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;My rating: 3/5.&lt;/strong&gt; &lt;em&gt;Do you advise other books on NHibernate?&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Testing DI bootstrappers</title>
      <link>https://jefclaes.be/2012/02/testing-di-bootstrappers.html</link>
      <pubDate>Mon, 06 Feb 2012 08:59:00 +0100</pubDate>
      <guid>https://jefclaes.be/2012/02/testing-di-bootstrappers.html</guid>
      <description>&lt;p&gt;While your &lt;a href=&#34;http://martinfowler.com/articles/injection.html&#34;&gt;Dependency Injection&lt;/a&gt;
bootstrappers - being responsible for gluing your application together -
are a vital part of your application, they are seldom put under test. I
don&amp;rsquo;t see any reason why they shouldn&amp;rsquo;t be though. The cost of these
tests is negligible, definitely if you compare it to the cost of the
often catastrophical outcome of bugs in your bootstrappers.&lt;/p&gt;
&lt;p&gt;I encourage you to take a look at the commit history of your DI
bootstrappers; I bet they change a lot. Wouldn&amp;rsquo;t it be nice to have a
set of tests that proves that the dependency container still behaves
like you expect it to at runtime? Next to proving correctness, I think
writing these tests also helps you discover various behaviours of your
DI container, which is a valuable investment in itself.&lt;/p&gt;
&lt;p&gt;Let me show you a few tests that I wrote to put my &lt;a href=&#34;https://jefclaes.be/2011/10/ninjecting-mvc3.html&#34;&gt;ASP.NET MVC
Ninject&lt;/a&gt;
bootstrapper under test.&lt;/p&gt;
&lt;p&gt;I started by opening up the Ninject bootstrapper, making the
&lt;code&gt;CreateKernel&lt;/code&gt; method public.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; IKernel CreateKernel()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; kernel = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; StandardKernel();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    kernel.Bind&amp;lt;IEntryService&amp;gt;().To&amp;lt;EntryService&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; kernel;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the test class, I used the &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.testinitializeattribute(v=vs.80).aspx&#34;&gt;TestInitialize attribute&lt;/a&gt;
to initialize a new instance of the kernel before every test. I&amp;rsquo;m not
sure this is really necessary, but I want to avoid that my tests
experience side-effects of a previous test.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[TestInitialize]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Setup()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{         
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    _kernel = NinjectMVC3.CreateKernel();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}        
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Needless to say, the first test should prove that an implementation of
the &lt;code&gt;IEntryService&lt;/code&gt; interface can be resolved. The behaviour I observed
while playing with this case, is that Ninject throws a
&lt;code&gt;Ninject.ActivationException&lt;/code&gt; when the implementation can&amp;rsquo;t be resolved.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Ninject.ActivationException: Error activating IEntryService  
   No matching bindings are available, and the type is not
   self-bindable.  
   Activation path:  
       Request for IEntryService  
   
Suggestions:  

1.  Ensure that you have defined a binding for IEntryService. 
2.  If the binding was defined in a module, ensure that the module has
     been loaded into the kernel.
3.  Ensure you have not accidentally created more than one kernel.
4.  If you are using constructor arguments, ensure that the parameter
     name matches the constructors parameter name.
5.  If you are using automatic module loading, ensure the search path
     and filters are correct.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So to test whether an implementation can be resolved, I just make sure
no exceptions are thrown on resolving the dependency.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[TestMethod]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Test_IEntryService_Can_Be_Resolved()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    AssertDoesNotThrowWhenResolved&amp;lt;IEntryService&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;AssertDoesNotThrowWhenResolved&lt;/code&gt; method is a helper method which tries
to resolve a dependency of T and asserts that no exceptions are thrown
while doing so. The assertion is borrowed from
&lt;a href=&#34;http://xunit.codeplex.com/&#34;&gt;Xunit&lt;/a&gt; (&lt;a href=&#34;http://nuget.org/packages/xunit&#34;&gt;package available on
Nuget&lt;/a&gt;).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; AssertDoesNotThrowWhenResolved&amp;lt;T&amp;gt;() 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Xunit.Assert.DoesNotThrow(() =&amp;gt; _kernel.Get&amp;lt;T&amp;gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A second useful test is testing the lifetime of the resolved
implementation. For most of my dependencies, I expect a new instance
every time they are resolved. This test looks like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[TestMethod]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Test_IEntryService_Is_New_Instance()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    AssertNewInstanceIsResolved&amp;lt;IEntryService&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;AssertNewInstanceIsResolved&lt;/code&gt; method is another helper method which
resolves two instances of T and asserts they are not the same.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; AssertNewInstanceIsResolved&amp;lt;T&amp;gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; instance = _kernel.Get&amp;lt;T&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; secondInstance = _kernel.Get&amp;lt;T&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Assert.AreNotSame(instance, secondInstance);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}  
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it. While these tests are very cheap to write, they do provide
great value. I can imagine testing more complex bindings, like
contextual bindings, taking a bit more time to set up, but the value of
these tests increases proportionally.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do you put your DI bootstrappers under test?&lt;/strong&gt; If you don&amp;rsquo;t, why not?&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>A solar storm anecdote</title>
      <link>https://jefclaes.be/2012/02/a-solar-storm-anecdote/</link>
      <pubDate>Wed, 01 Feb 2012 08:43:00 +0100</pubDate>
      <guid>https://jefclaes.be/2012/02/a-solar-storm-anecdote/</guid>
      <description>&lt;p&gt;Last week, several news channels reported on the strongest &lt;a href=&#34;http://en.wikipedia.org/wiki/Solar_flare&#34;&gt;solar
storm&lt;/a&gt; since 2005. &lt;a href=&#34;http://www.bbc.co.uk/news/science-environment-16701407&#34;&gt;This news
item&lt;/a&gt; reminded
me of a peculiar support ticket we received one gray Monday morning a
few years ago, when I was still writing software for fire departments.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# Ticket 7238  
Subject: **AVL broken**  
Status: New  
Description  
06:22 Vehicles stay mostly stationary on the map, even when we are  
positive they are en route.  
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Fire departments that have to cover a large area - and are wealthy
enough - often use &lt;a href=&#34;http://en.wikipedia.org/wiki/Automatic_vehicle_location&#34;&gt;AVL (Automatic Vehicle
Location)&lt;/a&gt; to
track their vehicles and visualize them on a map. This is extremely
valuable, because you always want to dispatch the vehicles with the
smallest response time to a high priority intervention. Also being able
to advise drivers of possible blockages and toxic gas clouds can save
lives. To be able to track a vehicle, an AVL module is installed into
each vehicle&amp;rsquo;s cockpit. This module uses GPS to determine the location
and sends the location data over GPRS to a central server.&lt;/p&gt;
&lt;p&gt;On our end, we had a third party service listening for those location
packets and translating them into a more understandable format. This
service, not being mission critical, wasn&amp;rsquo;t being monitored, so we had
to look into the logs to see what was going on. Scrolling through
megabytes of debug logs, we couldn&amp;rsquo;t find anything suspicious.&lt;/p&gt;
&lt;p&gt;While I was investigating this, a co-worker had come in and was reading
through his mails while sipping on his morning coffee. After reading
support ticket 7238, he nonchalantly said he knew what was going on with
AVL and he would take over from there.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# Ticket 7238  
Subject: AVL broken  
Status: Pending  
Description  
**08:45 I heard on the radio that there is a solar storm going on at  
the moment, which affects sattelites. The AVL module might have  
a hard time getting a GPS fix. This issue should solve itself over  
time. We will keep an eye on this issue.**  
---------------------------------------------------------------------------------  
06:22 Vehicles stay mostly stationary on the map, even when we are  
positive they are en route.  
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A few days passed and although the solar storm was over, we were still
seeing signifcant packet loss. After spending a few hours working the
ticket, in which we restarted the service, monitored network traffic on
the machine and conctacted the telephony provider, we were getting a bit
desperate. We were discussing other potential paths to investigate, when
one of our more seasoned co-workers asked &amp;ldquo;You guys did try restarting
the server, right?&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Good enough, after restarting the server, we were seeing no more packet
loss and the vehicles started moving on the map again.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-02-01-a-solar-storm-anecdote-PokerFace.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-02-01-a-solar-storm-anecdote-PokerFace.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# Ticket 7238  
Subject: AVL broken  
**Status: Resolved**  
Description  
**15:47 The solar storm must be over. The vehicle locations are  
being updated in a timely fashion again.**  
--------------------------------------------------------------------------------  
08:45 I heard on the radio that there is a solar storm going on at  
the moment, which affects sattelites. The AVL module might have  
a hard time getting a GPS fix. This issue should solve itself over  
time. We will keep an eye on this issue.  
--------------------------------------------------------------------------------  
06:22 Vehicles stay mostly stationary on the map, even when we are  
positive they are en route.  
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Until today, we never talked about ticket 7238 again.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>How Wikipedia uses HTML5 to save bandwidth</title>
      <link>https://jefclaes.be/2012/01/how-wikipedia-uses-html5-to-save.html</link>
      <pubDate>Thu, 19 Jan 2012 20:56:00 +0100</pubDate>
      <guid>https://jefclaes.be/2012/01/how-wikipedia-uses-html5-to-save.html</guid>
      <description>&lt;p&gt;Something I hadn&amp;rsquo;t noticed until recently is that Wikipedia tries to use
the browser&amp;rsquo;s native &lt;a href=&#34;http://www.w3.org/TR/SVG/&#34;&gt;SVG&lt;/a&gt; support to render
certain images. For example, if you search for &lt;a href=&#34;http://upload.wikimedia.org/wikipedia/commons/9/92/Flag_of_Belgium_%28civil%29.svg&#34;&gt;a high resolution image
of your country&amp;rsquo;s
flag&lt;/a&gt;,
you will probably end up viewing an SVG. Wikipedia also offers downloads
to the image rendered as a PNG though.&lt;/p&gt;
&lt;p&gt;Next to being able to scale to an arbitrary size without suffering data
loss, the SVG data format allows images to be far more compact.
Basically, SVG is just XML, which also means it can be easily compressed
to make its size even smaller. For example, this is the (uncompressed)
SVG for the flag of the &lt;a href=&#34;http://en.wikipedia.org/wiki/Belgium&#34;&gt;Kingdom of
Belgium&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;svg&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;xmlns&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://www.w3.org/2000/svg&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;width&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;450&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;height&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;300&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;rect&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;width&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;450&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;height&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;300&amp;#34;&lt;/span&gt;/&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;rect&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;150&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;width&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;150&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;height&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;300&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fill&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;#FAE042&amp;#34;&lt;/span&gt;/&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;rect&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;300&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;width&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;150&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;height&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;300&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fill&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;#ED2939&amp;#34;&lt;/span&gt;/&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;svg&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This svg node only weighs as much as 224 bytes, while the image rendered
as a high resolution PNG weighs 13.402 bytes. Stuff like that makes a
significant difference when you&amp;rsquo;re &lt;a href=&#34;http://stats.wikimedia.org/EN/TablesPageViewsMonthlyCombined.htm&#34;&gt;serving millions of page views on a
daily
basis&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The first time I touched SVG was a few years ago when I was still
working on fire department projects. We were working with a third party
that used SVG to draw maps in the browser. Being already in the
post-Google Maps era, I thought it was terrible I had to download
&lt;a href=&#34;http://www.adobe.com/svg/viewer/install/&#34;&gt;Adobe&amp;rsquo;s SVG viewer&lt;/a&gt;. While
the Google Maps technology already works great, there are still things
SVG can do better and cleaner, especially for more specialized GIS
applications. There is an interesting paper on that subject
&lt;a href=&#34;http://svgopen.org/2008/papers/82-Web_Mapping_and_WebGIS_do_we_actually_need_to_use_SVG/&#34;&gt;here&lt;/a&gt;,
it&amp;rsquo;s a bit outdated though.&lt;/p&gt;
&lt;p&gt;I can only applaud making the browser more capable, and losing &lt;em&gt;yet
another plug-in&lt;/em&gt;. I&amp;rsquo;m curious to see how other applications will start
taking advantage of the opportunities native SVG support &lt;strong&gt;across all
modern browsers&lt;/strong&gt; (even Internet Explorer) presents.&lt;/p&gt;
&lt;p&gt;Have you already built things using SVG? Or even considered it?&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Autocorrecting unknown actions using the Levenshtein distance</title>
      <link>https://jefclaes.be/2012/01/autocorrecting-unknown-actions-using.html</link>
      <pubDate>Sun, 15 Jan 2012 16:04:00 +0100</pubDate>
      <guid>https://jefclaes.be/2012/01/autocorrecting-unknown-actions-using.html</guid>
      <description>&lt;p&gt;This weekend I prototyped an idea I had earlier this week:
autocorrecting unknown actions in ASP.NET MVC.&lt;/p&gt;
&lt;h3 id=&#34;handling-unknown-actions&#34;&gt;Handling unknown actions&lt;/h3&gt;
&lt;p&gt;To give you an example, let&amp;rsquo;s say I have a Home controller with an
action named Kitten on it. If there is an incoming route for the Home
controller with Kitty (instead of Kitten) as the action name, the
controller will not be able to invoke any action method and instead will
call the &lt;code&gt;HandleUnknownAction&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;Here is the snippet from the ASP.NET MVC source.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; ExecuteCore() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    PossiblyLoadTempData();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; actionName = RouteData.GetRequiredString(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;action&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (!ActionInvoker.InvokeAction(ControllerContext, actionName)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            HandleUnknownAction(actionName);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;finally&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        PossiblySaveTempData();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;HandleUnknownAction&lt;/code&gt; is virtual, meaning we can override it in our
derived controller. The base implementation of the &lt;code&gt;HandleUnknownAction&lt;/code&gt;
method does nothing more than throwing a &lt;code&gt;404 HttpException&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;virtual&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; HandleUnknownAction(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; actionName) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; HttpException(&lt;span style=&#34;color:#ae81ff&#34;&gt;404&lt;/span&gt;, String.Format(CultureInfo.CurrentCulture,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        MvcResources.Controller_UnknownAction, actionName, GetType().FullName));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So let&amp;rsquo;s override the &lt;code&gt;HandleUnknownAction&lt;/code&gt; method and try to autocorrect
the unknown action name. To be safe, we will only attempt to autocorrect
the action name when it&amp;rsquo;s a GET HTTP request.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; HandleUnknownAction(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; actionName)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (!HttpContext.Request.HttpMethod.Equals(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;, StringComparison.OrdinalIgnoreCase))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Throw404HttpException(actionName);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    TryToRedirectToAnActionNearby(actionName);           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;listing-all-actions&#34;&gt;Listing all actions&lt;/h3&gt;
&lt;p&gt;First we need a list of all available action names. I reflect on the
methods of the current controller and select the methods which are
public, can be invoked and are an instance method. Also the method
should return an &lt;code&gt;ActionResult&lt;/code&gt;, not be decorated with the &lt;code&gt;HttpPost&lt;/code&gt;
attribute and not have a special name. I&amp;rsquo;m pretty sure I&amp;rsquo;m missing a few
things here, but there seems to be no generic way to extract this
metadata from a controller. Places where these type of things are used
in the framework seem to be internal or non-public.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; IEnumerable&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&amp;gt; GetAllHttpGetActionNames()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; GetType()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .GetMethods(BindingFlags.InvokeMethod | 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        BindingFlags.Public | 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        BindingFlags.Instance)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .Where(m =&amp;gt; m.ReturnType == &lt;span style=&#34;color:#66d9ef&#34;&gt;typeof&lt;/span&gt;(ActionResult) &amp;amp;&amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        !m.IsSpecialName &amp;amp;&amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        !m.GetCustomAttributes(&lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            .Contains(&lt;span style=&#34;color:#66d9ef&#34;&gt;typeof&lt;/span&gt;(HttpPostAttribute)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .Select(m =&amp;gt; m.Name)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .Distinct();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once we have all these action names, we want to see how distant they are
from the unknown action name we are trying to autocorrect here. To
calculate this we can use the Levenshtein distance algorithm.&lt;/p&gt;
&lt;h3 id=&#34;the-levenshtein-distance&#34;&gt;The Levenshtein distance&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&#34;http://en.wikipedia.org/wiki/Levenshtein_distance&#34;&gt;Levenshtein
distance&lt;/a&gt; is defined
by Wikipedia like this.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In information theory and computer science, the Levenshtein distance
is a string metric for measuring the amount of difference between two
sequences. The Levenshtein distance between two strings is defined as
the minimum number of edits needed to transform one string into the
other, with the allowable edit operations being insertion, deletion,
or substitution of a single character. It is named after Vladimir
Levenshtein, who considered this distance in 1965.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;An implementation of this algorithm in C# could look like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; CalculateDistance(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; str1, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; str2) 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; matrix = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;[str1.Length + &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, str2.Length + &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; i = &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; i &amp;lt;= str1.Length; i++)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        matrix[i, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] = i;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; j = &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; j &amp;lt;= str2.Length; j++)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        matrix[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, j] = j;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; i = &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;; i &amp;lt;= str1.Length; i++)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; j = &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;; j &amp;lt;= str2.Length; j++)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; cost = str1[i - &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;] == str2[j - &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;] ? &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; : &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            matrix[i, j] = (&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt;[]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                matrix[i - &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, j] + &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, matrix[i, j - &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;] + &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, matrix[i - &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, j - &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;] + cost
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }).Min();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ((i &amp;gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) &amp;amp;&amp;amp; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (j &amp;gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) &amp;amp;&amp;amp; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (str1[i - &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;] == str2[j - &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;]) &amp;amp;&amp;amp;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (str1[i - &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;] == str2[j - &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;]))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                matrix[i, j] = Math.Min(matrix[i, j], matrix[i - &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, j - &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;] + cost);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; matrix[str1.Length, str2.Length];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}        
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is a direct port from the &lt;a href=&#34;http://en.wikipedia.org/wiki/Levenshtein_distance#Computing_Levenshtein_distance&#34;&gt;pseudocode found on Wikipedia&lt;/a&gt;. These tests might, probably a lot more than the implementation, help you understand what the Levenshtein algorithm calculates.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[TestMethod()]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Test_CalculateDistance_With_Two_Empty_String()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Assert.AreEqual(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, Levenshtein.CalculateDistance(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.Empty, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.Empty));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[TestMethod()]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Test_CalculateDistance_With_Empty_First_String()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{         
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Assert.AreEqual(&lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;, Levenshtein.CalculateDistance(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.Empty, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kitten&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[TestMethod()]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Test_CalculateDistance_With_Empty_Second_String()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Assert.AreEqual(&lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;, Levenshtein.CalculateDistance(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kitten&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.Empty));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[TestMethod()]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Test_CalculateDistance_With_Missing_Characters()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Assert.AreEqual(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, Levenshtein.CalculateDistance(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kitten&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kitt&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[TestMethod()]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Test_CalculateDistance_With_Wrong_Characters()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Assert.AreEqual(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, Levenshtein.CalculateDistance(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kitten&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kittyn&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[TestMethod()]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Test_CalculateDistance_With_Too_Much_Characters()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Assert.AreEqual(&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, Levenshtein.CalculateDistance(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kitten&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kittenkitty&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[TestMethod()]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Test_CalculateDistance_With_Equal_Strings()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{          
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Assert.AreEqual(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, Levenshtein.CalculateDistance(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kitten&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kitten&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now that we have implemented the Levenshtein distance algorithm, we can
calculate the distances between the unknown action name and all the
available action names.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Dictionary&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&amp;gt; CalculateLevenshteinDistance(IEnumerable&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&amp;gt; actionList, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; actionName)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; actionList
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .Select(a =&amp;gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                Action = a.ToLower(),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                Distance = Levenshtein.CalculateDistance(a.ToLower(), actionName.ToLower())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            })                    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            .ToDictionary(k =&amp;gt; k.Action, v =&amp;gt; v.Distance);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For the unknown action name &amp;lsquo;Kitty&amp;rsquo;, when the action names &amp;lsquo;Kitten&amp;rsquo;,
&amp;lsquo;Index&amp;rsquo; and &amp;lsquo;Dog&amp;rsquo; are available, this method would return a dictionary
that looks like this.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;#39;kitten&amp;#39; : 2
&amp;#39;index&amp;#39; : 6
&amp;#39;dog&amp;#39; : 6
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;putting-it-all-together&#34;&gt;Putting it all together&lt;/h3&gt;
&lt;p&gt;Now we have this dictionary, we want to filter on a certain distance
threshold. I picked three, given that when a word is three characters
off, the chance of it being a typo is rather small.&lt;/p&gt;
&lt;p&gt;If the dictionary still contains some items after filtering, we want to take the action with the shortest distance, this action is the nearest to the unknown action. Only thing left to do is change the action in the &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.web.mvc.controller.routedata(v=vs.90).aspx&#34;&gt;RouteData&lt;/a&gt; and execute a &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.web.mvc.redirectresult.aspx&#34;&gt;RedirectResult&lt;/a&gt;. The easiest way to generate a url to redirect to, is to use the controller&amp;rsquo;s UrlHelper to let it generate the url based on the RouteData.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; TryToRedirectToAnActionNearby(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; actionName)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; httpGetActionNames = GetAllHttpGetActionNames();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (!httpGetActionNames.Any())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Throw404HttpException(actionName);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; actionDistanceMap = CalculateLevenshteinDistance(httpGetActionNames, actionName)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                .Where(i =&amp;gt; i.Value &amp;lt;= &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (!actionDistanceMap.Any())
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Throw404HttpException(actionName);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; shortestDistance = actionDistanceMap.Select(v =&amp;gt; v.Value).Min();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; nearestAction = actionDistanceMap.Where(i =&amp;gt; i.Value == shortestDistance).First().Key;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ControllerContext.RouteData.Values[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;action&amp;#34;&lt;/span&gt;] = nearestAction;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; RedirectResult(Url.RouteUrl(RouteData.Values), permanent: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        .ExecuteResult(ControllerContext);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;the-outcome&#34;&gt;The outcome&lt;/h3&gt;
&lt;p&gt;Now when I, the user, type http://somesite/someController/kitty, I will
be redirected to http://somesite/someController/kitten without me even
noticing.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2012-01-15-autocorrecting-unknown-actions-using-the-levenshtein-distance-LevenshteinDistanceRedirect.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2012-01-15-autocorrecting-unknown-actions-using-the-levenshtein-distance-LevenshteinDistanceRedirect.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;feedback&#34;&gt;Feedback&lt;/h3&gt;
&lt;p&gt;This implementation definitely is &lt;strong&gt;not production ready&lt;/strong&gt;. It&amp;rsquo;s a
prototype, not even under test. I wonder if this  is even something you
would want to do. Or is this &lt;strong&gt;breaking the Web&lt;/strong&gt; in one way or the
other? Would it bother search engines?&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>2011 Annual Review</title>
      <link>https://jefclaes.be/2011/12/2011-annual-review.html</link>
      <pubDate>Mon, 26 Dec 2011 21:35:00 +0100</pubDate>
      <guid>https://jefclaes.be/2011/12/2011-annual-review.html</guid>
      <description>&lt;p&gt;Since the end of the year is approaching, I would like to look back on
2011 and take a peek at 2012. Unlike the years before, I&amp;rsquo;m hardly
setting any goals this year. Interests change so quickly, and new
opportunities present themselves so regularly, I feel like it might be
ignorant to set these things in stone.&lt;/p&gt;
&lt;h3 id=&#34;my-career&#34;&gt;My career&lt;/h3&gt;
&lt;p&gt;The year started out interesting, working on a brand new product for
fire departments at Ferranti Computer Systems. Although my role in this
project should have been fairly satisfying, I still felt like my
position back then failed to fill a certain void. That&amp;rsquo;s why I decided
to take the leap into &lt;a href=&#34;https://jefclaes.be/2011/08/high-hopes.html&#34;&gt;the Great
Unknown&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In September, I started working for &lt;a href=&#34;http://www.euri.com/&#34;&gt;Euricom&lt;/a&gt; as a
consultant. So far, I haven&amp;rsquo;t regretted making that decision at all, I
ended up in a group of intelligent, progressive and enjoyable people.&lt;/p&gt;
&lt;h3 id=&#34;blog&#34;&gt;Blog&lt;/h3&gt;
&lt;p&gt;This year I managed to write 69 posts (70 including this one), which is
a bit more than the year before.&lt;/p&gt;
&lt;p&gt;Plenty of posts have gotten &lt;a href=&#34;https://jefclaes.be/2011/12/2011s-most-read-posts.html&#34;&gt;decent
attention&lt;/a&gt;
this year, making the traffic tripple compared to 2010. And no matter
how other bloggers claim you shouldn&amp;rsquo;t care about your blog statistics,
this does mean a bunch to me.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-12-26-2011-annual-review-BlogTraffic.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-12-26-2011-annual-review-BlogTraffic.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The main topics I wrote about this year were mostly web related (HTML5,
JavaScript and ASP.NET MVC). I even wrote some opinionated posts this
year, which I found harder, but also more rewarding.&lt;/p&gt;
&lt;p&gt;Last year, I set a goal to get better at MVC and to at least look at
WebMatrix. I spent a large part of the year building things in ASP.NET
MVC at the day job, so that goal was easily achieved. I built &lt;a href=&#34;https://jefclaes.be/2011/09/real-developer-knows-when-to-pull-plug.html&#34;&gt;one small
thing&lt;/a&gt;
in
&lt;a href=&#34;https://jefclaes.be/2011/05/my-thoughts-on-webmatrix.html&#34;&gt;WebMatrix&lt;/a&gt;,
which was enough to give me a feel of what WebMatrix is all about.&lt;/p&gt;
&lt;p&gt;My guess is that I will cover similar topics next year. My faith in the
web has only grown stronger. I think the rise and rise of the browser
and JavaScript provides us with unseen opportunities, but also with an
enormous amount of challenges. I am really eager to start looking more
into &lt;em&gt;serious&lt;/em&gt; JavaScript development.&lt;/p&gt;
&lt;h3 id=&#34;community&#34;&gt;Community&lt;/h3&gt;
&lt;p&gt;I think I did fairly well this year. I attended several local community
meetings and got to to know a lot of nice people in the process.&lt;/p&gt;
&lt;p&gt;The highlight probably was &lt;a href=&#34;https://jefclaes.be/2011/04/video-slides-and-source-from-my.html&#34;&gt;my own talk on WebSockets at HTML5
Webcamps&lt;/a&gt;.
I really enjoyed that experience. I do not aspire to be a speaker
though, but should I have interesting things to talk about, I probably
won&amp;rsquo;t reject invitations.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not sure if I will be doing a lot of community events in 2012. I
often don&amp;rsquo;t seem to get out of them what I hoped for. Also, Euricom
regularly organizes meetups to talk about all things software
development. These will already consume plenty of time.&lt;/p&gt;
&lt;h3 id=&#34;travelling&#34;&gt;Travelling&lt;/h3&gt;
&lt;p&gt;This year my girlfriend and I did &lt;a href=&#34;http://www.jefclaes.be/2011/09/once-upon-time-in-west.html&#34;&gt;a three-week roadtrip along the West
Coast&lt;/a&gt;.
This trip was by far the best time of our lives. We are determined to
undertake similar projects in the future again.&lt;/p&gt;
&lt;p&gt;Next to that, we revisited the Czech Republic, taking plenty of time to
&lt;a href=&#34;http://www.jefclaes.be/2011/04/prague-impressions.html&#34;&gt;visit
Prague&lt;/a&gt; this
time.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re not sure what 2012 will bring. Right now, we are looking into
something more nearby, Italy.&lt;/p&gt;
&lt;h3 id=&#34;sporthealth&#34;&gt;Sport/Health&lt;/h3&gt;
&lt;p&gt;Last year I picked up boxing, but I had to give that up due to
scheduling conflicts. I have been working a tweaked &lt;a href=&#34;http://en.wikipedia.org/wiki/P90X&#34;&gt;P90X
routine&lt;/a&gt; twice a week instead, which
is very much recommended.&lt;/p&gt;
&lt;p&gt;I reasonably succeeded in achieving my running ambitions. Altogether, I
ran somewhere around 800 kilometers (= 500 miles) this year. This
summer, I probably was in the best shape of my life, running 15 km
pretty (= 9 miles) comfortably. Although the graph below suggests that
I&amp;rsquo;m slacking, it&amp;rsquo;s only partially true. I have been doing shorter (and
higher paced) runs lately, increasing the intensity. Running is probably
one of the sports that give me the most energy in return, so I intend to
stay at it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-12-26-2011-annual-review-nikeplus.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-12-26-2011-annual-review-nikeplus.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;2011 has been an eventful year for me. In 2012, I hope to be able to
keep doing the things I love, surrounded by the people I love. Trying to
live life as much as I can.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I wish you and your family the best for 2012. That the new year may bring you health, love and plenty of hacking.&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>2011&#39;s most read posts</title>
      <link>https://jefclaes.be/2011/12/2011s-most-read-posts.html</link>
      <pubDate>Sat, 17 Dec 2011 19:33:00 +0100</pubDate>
      <guid>https://jefclaes.be/2011/12/2011s-most-read-posts.html</guid>
      <description>&lt;p&gt;I compiled a list of most popular posts that were published on this blog
in 2011. Unlike &lt;a href=&#34;https://jefclaes.be/2010/12/top-5-popular-posts-of-2010.html&#34;&gt;last
year&lt;/a&gt;,
and &lt;a href=&#34;https://jefclaes.be/2009/12/high-5-five-most-popular-blog-posts-of.html&#34;&gt;the year before
that&lt;/a&gt;,
this year it&amp;rsquo;s not a strict top five list. While analyzing the
statistics, I found out that a few topics -covered over multiple posts -
were popular this year.&lt;/p&gt;
&lt;p&gt;Preparing for &lt;a href=&#34;https://jefclaes.be/2011/04/video-slides-and-source-from-my.html&#34;&gt;my HTML5 Webcamps session on
WebSockets&lt;/a&gt;,
I wrote a few posts on the Microsoft WebSockets prototype. I published
&lt;a href=&#34;https://jefclaes.be/2011/01/html5-installing-microsoft-websockets.html&#34;&gt;a step-by-step guide on how to get the prototype
working&lt;/a&gt;
on your machine. A little later I also published two posts covering the
internals of the
&lt;a href=&#34;https://jefclaes.be/2011/01/html5-websockets-prototype-with.html&#34;&gt;client&lt;/a&gt;
and
&lt;a href=&#34;https://jefclaes.be/2011/01/html5-rebuilding-websockets-server.html&#34;&gt;server&lt;/a&gt;
WebSockets prototype. I&amp;rsquo;m not surprised search drove a lot of traffic to
these posts. Microsoft hardly tried to make it easy to play with the
prototype: no tutorials, no source, nothing. Now the specification is
stable, and WCF 4.5 has WebSockets support out of the box, I suspect MS
will make greater evangelizing efforts. Or maybe, they will wait &lt;a href=&#34;https://jefclaes.be/2011/03/how-will-ie9-maintain-momentum.html&#34;&gt;until
one of their browsers support
it&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In &lt;a href=&#34;https://jefclaes.be/2011/09/building-small-things.html&#34;&gt;this post&lt;/a&gt; I
rambled on how liberating it can be to build something small on your own
now and then, just to keep your sanity and escape from software in the
real world. This post got picked up by Hacker News, making it the second
entry in this list.&lt;/p&gt;
&lt;p&gt;In one of those sporadic academic moments, I had a look at one of the
&lt;a href=&#34;https://jefclaes.be/2011/04/anonymous-type-equality.html&#34;&gt;quirks in anonymous type
equality&lt;/a&gt;.
I also looked at the reason &lt;a href=&#34;https://jefclaes.be/2011/04/anonymous-type-equality-follow-up.html&#34;&gt;why anonymous types can be compared in the
first
place&lt;/a&gt;,
being reference types after all.&lt;/p&gt;
&lt;p&gt;To wrap up this link collection, I would like to &lt;strong&gt;thank you for reading&lt;/strong&gt;. I hope to see you contribute to this little outlet of mine for another year.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>When should you take performance into consideration?</title>
      <link>https://jefclaes.be/2011/11/when-should-you-take-performance-into.html</link>
      <pubDate>Sun, 27 Nov 2011 17:55:00 +0100</pubDate>
      <guid>https://jefclaes.be/2011/11/when-should-you-take-performance-into.html</guid>
      <description>&lt;p&gt;Before publishing &lt;a href=&#34;https://jefclaes.be/2011/11/rewriting-if.html&#34;&gt;my previous post on rewriting an
if&lt;/a&gt;, I knew some
people would hate it, because the refactored construct is less
performant.&lt;/p&gt;
&lt;p&gt;Although I think performance is important, relevant performance
improvements are, apart from in tight loops, hardly ever to find in
language constructs. To put it more bluntly, they are a waste of time.
When translating your thoughts into code, you should aim to make your
intentions as clear as possible for the person who comes after you.
Don&amp;rsquo;t obfuscate your code for an negligible performance improvement.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not advocating readability and pretty code are an end goal,
performance and quality still are. But look for optimizations where it
counts: optimizations which, after measuring, prove to be make a
significant impact on the overall performance of your system. These are
most likely to be found in I/O operations, architectures and algorithms.
Not in language constructs.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Rewriting an if</title>
      <link>https://jefclaes.be/2011/11/rewriting-if.html</link>
      <pubDate>Thu, 24 Nov 2011 21:12:00 +0100</pubDate>
      <guid>https://jefclaes.be/2011/11/rewriting-if.html</guid>
      <description>&lt;p&gt;Yesterday I came across an if statement that looked something like
this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (arg == &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt; ||
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    arg == &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt; ||
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    arg == &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;c&amp;#34;&lt;/span&gt; ||
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    arg == &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt; ||
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    arg == &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;e&amp;#34;&lt;/span&gt;) 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Console.WriteLine(&lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;An alternative way of writing this could look like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; [] { &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;c&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;e&amp;#34;&lt;/span&gt; }.Contains(arg))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Console.WriteLine(&lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I can&amp;rsquo;t remember in which Github repository I spotted this technique,
but I&amp;rsquo;m sure it was written in something other than C#. I think it
works for C# as well though. The language hardly gets in the way,
although it would be nice to be able to drop the new.&lt;/p&gt;
&lt;p&gt;This is one of these trivial things I tend to geek about. The condition
fits on one line now, making the eyes do less work. Also adding a
variable is less work; you don&amp;rsquo;t have to enter and indent accordingly. I
think it&amp;rsquo;s a win in readability, size and maintenance.&lt;/p&gt;
&lt;p&gt;But then I stop and wonder: how do you feel about this construct?&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Blame no one but yourself</title>
      <link>https://jefclaes.be/2011/11/blame-no-one-but-yourself.html</link>
      <pubDate>Wed, 23 Nov 2011 21:24:00 +0100</pubDate>
      <guid>https://jefclaes.be/2011/11/blame-no-one-but-yourself.html</guid>
      <description>&lt;p&gt;Blame no one but yourself. This is one of the few quotes I remember
months after reading &lt;a href=&#34;https://jefclaes.be/2011/04/its-not-how-good-you-are-its-how-good.html&#34;&gt;this book&lt;/a&gt;. Although it&amp;rsquo;s a harsh statement, there definitely is some truth to it.&lt;/p&gt;
&lt;p&gt;Once I started observing my own behavior when faced with failure, I
caught myself regularly blaming others for failures to which I am - at
least - an accomplice.&lt;/p&gt;
&lt;p&gt;Think about it. You might be guilty of this too.&lt;/p&gt;
&lt;p&gt;Frustrated with management because you missed &lt;em&gt;their&lt;/em&gt; too tight
deadline? Did you tell your project manager that taking that &amp;lsquo;one small&amp;rsquo;
task in between would get you behind on schedule? Dissapointed by your
team mate because he messed up the task you asked him to do? Are you
sure you gave him all the information and provided enough feedback?
Tired of doing the same repetitive task over and over? Why haven&amp;rsquo;t you
automated it yet? Not happy with a certain implementation? Did you speak
up and propose alternative solutions?&lt;/p&gt;
&lt;p&gt;So next time you blame someone else, ask yourself: Did I try everything
within my reach to make this work or did I unconsciously sabotage this
myself?&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Daydreaming about jQuery Mobile and the WebAPI</title>
      <link>https://jefclaes.be/2011/11/blame-no-one-but-yourself.html</link>
      <pubDate>Sun, 20 Nov 2011 17:24:00 +0100</pubDate>
      <guid>https://jefclaes.be/2011/11/blame-no-one-but-yourself.html</guid>
      <description>&lt;p&gt;I recently blogged about &lt;a href=&#34;https://jefclaes.be/2011/11/programming-for-future-of-mobile.html&#34;&gt;programming for the future of
mobile&lt;/a&gt;
with &lt;a href=&#34;http://jquerymobile.com/&#34;&gt;jQuery Mobile&lt;/a&gt; and the
&lt;a href=&#34;https://wiki.mozilla.org/WebAPI&#34;&gt;WebAPI&lt;/a&gt;. You probably heard that
jQuery Mobile 1.0 was released earlier this week. Although it will take
a while before we will see some actual results from the WebAPI
initiative, that shouldn&amp;rsquo;t keep us from letting our minds play with
things that might be possible one day using the WebAPI.&lt;/p&gt;
&lt;p&gt;The thoughts in this post were provoked by an interesting comment
&lt;a href=&#34;http://www.kristofclaes.be/&#34;&gt;Kristof Claes&lt;/a&gt; left on my previous post.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One thing I don&amp;rsquo;t like about jQuery Mobile is that it has this iPhony
(pun not intended) look to it.&lt;/p&gt;
&lt;p&gt;I have a WP7 device and for some reason I don&amp;rsquo;t want applications to
look like I&amp;rsquo;m using an iPhone. I can imagine the average iPhone user
wouldn&amp;rsquo;t be happy when jQuery Mobile used a Metro-like skin.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And I agree, it does look iPhony. Although there already is a
themeroller for jQuery mobile, it&amp;rsquo;s limited to changing the color
scheme. Like Kristof said, the contrast between the Metro UI and the
jQuery Mobile UI is enormous.&lt;/p&gt;
&lt;p&gt;Platform specific themes might help to close that gap. I really think
this makes sense for mobile, because - compared to desktops - most
mobile operating systems do leverage a signifantly different feel. Also,
the browser is full screen on most mobile devices, saving space, but
also losing the native OS context.&lt;/p&gt;
&lt;p&gt;I have been thinking a bit about how this could be implemented. So
follow along, and let me know if these ramblings seem feasible.&lt;/p&gt;
&lt;p&gt;Serving themes based on the operating system should be doable. A naïve
implementation, which only supports Metro, could be as simple as this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;UserAgent&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Contains&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Windows Phone OS 7.5&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;jQueryMobile.Metro.css&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;jQueryMobile.Default.css&amp;#34;&lt;/span&gt;;            
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On my Windows Phone, I can configure the background- and the accent
color for the Metro UI. And this is where it gets interesting. Using the
&lt;a href=&#34;https://wiki.mozilla.org/WebAPI/SettingsAPI&#34;&gt;SettingsAPI&lt;/a&gt;, defined in
the WebAPI standards, we might be able to find out those values in our
webapplication. Meaning we could make the mobile UI &amp;rsquo;experience&amp;rsquo;
completely transparant.&lt;/p&gt;
&lt;p&gt;The proposed Settings API standard looks like this.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;interface SettingsManager
{
    // List of known settings.
    const DOMString FOOBAR = &amp;#34;foobar&amp;#34;;
 

    // Setters. SettingsRequest.result is always null.
    SettingsRequest set(DOMString name, DOMString value);
    SettingsRequest set(DOMString name, long value);
    SettingsRequest set(DOMString name, long long value);
    SettingsRequest set(DOMString name, float value);

    // Getters. SettingsRequest.result will be of the requested type if the success event is sent.
    SettingsRequest getString(DOMString name);
    SettingsRequest getInt(DOMString name);
    SettingsRequest getLong(DOMString name);
    SettingsRequest getFloat(DOMString name);
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So, dynamically modifying the css to comply to the Metro color sheme
could be this easy.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;backgroundColorRequest&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;settingsManager&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;getString&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;metro-backgroundColor&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;backgroundColorRequest&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;onSuccess&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.main&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;css&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;background-color&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;result&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;accentColorRequest&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;settingsManager&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;getString&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;metro-accentColor&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;accentColorRequest&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;onSuccess&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.tile&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;css&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;background-color&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;result&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Is it just me, or does the WebAPI have some sick potential?&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Programming for the future of mobile</title>
      <link>https://jefclaes.be/2011/11/programming-for-future-of-mobile.html</link>
      <pubDate>Wed, 09 Nov 2011 22:27:00 +0100</pubDate>
      <guid>https://jefclaes.be/2011/11/programming-for-future-of-mobile.html</guid>
      <description>&lt;p&gt;I have been working on something small on the side lately. I hardly have
anything to show for it though, most of it is still being shaped in my
head.&lt;/p&gt;
&lt;p&gt;Anyhow, a very important part of the front-end is built using &lt;a href=&#34;http://jquerymobile.com/&#34;&gt;jQuery
mobile&lt;/a&gt;. Although the framework hasn&amp;rsquo;t been
released - release candidates are available though -, it&amp;rsquo;s something you
should start looking into today. Why? Because the browser is the future
of mobile applications. With the
&lt;a href=&#34;http://blogs.adobe.com/conversations/2011/11/flash-focus.html&#34;&gt;Flash&lt;/a&gt;
and &lt;a href=&#34;http://www.theverge.com/2011/11/9/2548975/microsoft-may-halt-development-work-on-silverlight-after-next-release&#34;&gt;Silverlight
bombs&lt;/a&gt;
that were dropped today, I am even more confident that that future might
be nearer than we think.&lt;/p&gt;
&lt;p&gt;Built upon the jQuery and jQuery UI foundation, jQuery mobile aims to
make mobile web applications seriously cross-platform and cross-device,
while optimizing for touchfriendliness. From what I&amp;rsquo;ve seen so far, the
jQuery team has (once again) succeeded at making the web just work.&lt;/p&gt;
&lt;p&gt;To start using jQuery mobile, you just have to add one extra script file
and one stylesheet on top of the existing jQuery infrastructure. Once
that is done, the framework will already do most of the heavy lifting
for you. Depending on your needs, you might want to enrich some elements
explicitly in a nice semantic fashion.&lt;/p&gt;
&lt;p&gt;For example, this is how you would get some collapsible panel action
going.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data-role&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;collapsible&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data-theme&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;c&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data-content-theme&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;c&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data-collapsed&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;@dataCollapsed&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;entriesList&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;h3&lt;/span&gt;&amp;gt;@entryGroup.Date.ToString(&amp;#34;dd/MM/yyyy&amp;#34;)&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;h3&lt;/span&gt;&amp;gt;                
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;ul&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data-role&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;listview&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data-inset&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data-theme&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;d&amp;#34;&lt;/span&gt;&amp;gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        @foreach (var entry in entryGroup.Entries)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                @entry.CreatedOn.ToString(&amp;#34;HH:mm&amp;#34;) @entry.Description                     
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;li&lt;/span&gt;&amp;gt;         
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;ul&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt;&amp;gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To give you an idea, this would result in something that looks like
this. Clean, right?&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-11-09-programming-for-the-future-of-mobile-jQueryMobile.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-11-09-programming-for-the-future-of-mobile-jQueryMobile.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now that these problems are out of the way soon, the only barrier left
for mobile web applications is that the browser has no actual hooks in
the device itself. But this last barrier can&amp;rsquo;t hold forever&amp;hellip; Mozilla
initiated a very interesting project not so long ago. They started
defining standards for a set of APIs that should give you direct access
to the device: a camera API, telephony and messaging API, accelerometer
API.. Find everything about the WebAPI initiative
&lt;a href=&#34;https://wiki.mozilla.org/WebAPI&#34;&gt;here&lt;/a&gt;. Subscribe to the &lt;a href=&#34;https://lists.mozilla.org/listinfo/dev-webapi&#34;&gt;mailing
list&lt;/a&gt;, participate and
help pushing the web forward.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m fairly optimistic about the future of mobile web applications. It&amp;rsquo;s
impossible to put a timeframe on it, &lt;strong&gt;but eventually WWW, the Web Will
Win.&lt;/strong&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>The gift of legacy</title>
      <link>https://jefclaes.be/2011/10/gift-of-legacy.html</link>
      <pubDate>Sun, 30 Oct 2011 13:36:00 +0100</pubDate>
      <guid>https://jefclaes.be/2011/10/gift-of-legacy.html</guid>
      <description>&lt;p&gt;Just after graduating, I hated legacy with the heat of a thousand suns.
I felt unfortunate, having to work on old code, built using outdated
technologies, while software is all about making new and shiny things.
&lt;em&gt;Right, guys?&lt;/em&gt; Those naïve expectations of a rookie got crumbled very
soon. Legacy is a constant in our industry. You can try to ignore it as
long as possible, but it&amp;rsquo;s impossible to keep that up forever. Over the years, I have come to accept that. I even have been fully
embracing it lately.&lt;/p&gt;
&lt;p&gt;Legacy is an opportunity to learn from the past. To learn from the
costly mistakes our predecessors made, so you can avoid them in the
present. Often legacy also helps me fully comprehend the motivation
behind more modern architectures and software practices. Finding
yourself all alone in thousands of lines of code, where the smallest
change can impact an unknown amount of long forgotten scenarios, makes
it perfectly clear why we test our code, and why it should be a crime
not to.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a shame that there often isn&amp;rsquo;t a whole lot of glory in maintaining
old software. Although, I do think some programmers should be awarded a
medal of honor after serving multiple months in the trenches. There is,
however, a lot of space to make small refactorings, improving the code
quality and in the meanwhile giving you the small wins you need to keep
going.&lt;/p&gt;
&lt;p&gt;All legacy isn&amp;rsquo;t bad per se though. Once in a while you discover &lt;a href=&#34;http://www.youtube.com/watch?v=zphUt_tp898#t=01m22s&#34;&gt;a ruby
in the dust&lt;/a&gt;; a
creative solution or a small but interesting trick, which you might be
able to apply later on.&lt;/p&gt;
&lt;p&gt;Legacy is a gift, learn to embrace it.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Book review: The Art of Unit Testing</title>
      <link>https://jefclaes.be/2011/10/book-review-art-of-unit-testing.html</link>
      <pubDate>Thu, 06 Oct 2011 21:08:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/10/book-review-art-of-unit-testing.html</guid>
      <description>&lt;p&gt;I think &lt;a href=&#34;http://www.amazon.com/gp/product/1933988274/ref=as_li_tf_tl?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399377&amp;amp;creativeASIN=1933988274&#34;&gt;The Art of Unit
Testing&lt;/a&gt;
targets a broad audience. Beginners will find every part of the book
useful, where intermediates might be more interested in the final two
parts.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://osherove.com/blog/&#34;&gt;Roy Osherove&lt;/a&gt; starts this book by laying a
solid foundation of the unit testing concept. Why is testing important?
What defines a good unit test, and how does a unit test differ from an
integration test? In the second part of the book, he demonstrates the
use of two core unit testing techniques: stubs and mocks. After showing
you how these techniques work, he shows off various isolation frameworks
which can help you creating stubs and mocks at runtime (fakes), greatly
reducing the effort of writing these objects.&lt;/p&gt;
&lt;p&gt;If you have some experience with unit testing, you might not be
impressed with the content of the book so far. If you&amp;rsquo;re somewhat like
me, and have been writing tests for some while, but often find yourself
wondering if your tests will still be considered solid six months from
now, you will find the content of part three very useful. In this part,
Roy talks about organizing your tests and how to strive for satisfying
the three pillars of good tests: trustworthiness, maintainability and
readability.&lt;/p&gt;
&lt;p&gt;The final part wasn&amp;rsquo;t something I expected to find in this book. In this
chapter it&amp;rsquo;s very clear that the author has been an agent of change
himself for a long time. Next to sharing successful strategies on how to
usher testing into the organization, he answers a bunch of hard
questions you will be asked when you&amp;rsquo;re on your own quest to bring
change.&lt;/p&gt;
&lt;p&gt;As I said before, there&amp;rsquo;s something in the book for everyone. While
there are a lot of topics discussed, the book counts less than 300
pages. It&amp;rsquo;s well written at large, sometimes a bit sloppy, but in
general a smooth read. All of the concepts are explained using examples
written in C#, where the problems are small enough to keep it simple,
yet comprehensive enough to make it a plausible scenario.&lt;/p&gt;
&lt;p&gt;If you want to start out with unit testing, are looking for confirmation
on how you&amp;rsquo;re doing or want to refine some techniques, &lt;a href=&#34;http://www.amazon.com/gp/product/1933988274/ref=as_li_tf_tl?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;linkCode=as2&amp;amp;camp=217145&amp;amp;creative=399377&amp;amp;creativeASIN=1933988274&#34;&gt;this
book&lt;/a&gt;
might be the one to get.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>A real developer knows when to pull the plug</title>
      <link>https://jefclaes.be/2011/09/a-real-developer-knows-when-to-pull-the-plug/</link>
      <pubDate>Thu, 29 Sep 2011 20:38:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/09/a-real-developer-knows-when-to-pull-the-plug/</guid>
      <description>&lt;p&gt;My mini-website &lt;a href=&#34;#&#34;&gt;arealdeveloper.com&lt;/a&gt; will no
longer be available online after tomorrow.&lt;/p&gt;
&lt;p&gt;I slapped it together over a weekend, trying out WebMatrix, which turned
out to be the &lt;a href=&#34;https://jefclaes.be/2011/05/my-thoughts-on-webmatrix.html&#34;&gt;perfect companion&lt;/a&gt;
for &lt;a href=&#34;https://jefclaes.be/2011/09/building-small-things.html&#34;&gt;building small things&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A pleasant surprise was &lt;a href=&#34;https://jefclaes.be/2011/05/arealdevelopercom-mentioned-on-channel9.html&#34;&gt;the mention of &amp;lsquo;A Real Developer&amp;rsquo; by the guys at Channel9&lt;/a&gt;. This made the traffic go through the roof for a few days.&lt;/p&gt;
&lt;p&gt;A few months later the site was a ghosttown. But I don&amp;rsquo;t mind, had to happen. It never had the ambition to deliver real value. I was more than happy to deliver five minutes of entertainment.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-29-a-real-developer-knows-when-to-pull-the-plug-ARealDeveloperAnalytics.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-29-a-real-developer-knows-when-to-pull-the-plug-ARealDeveloperAnalytics.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To have a memento, I &lt;a href=&#34;https://github.com/JefClaes/ARealDeveloper&#34;&gt;uploaded the source to GitHub&lt;/a&gt;. Remember, it&amp;rsquo;s far from clever or impressive. However, I do think it can serve as a nice introduction-by-example to WebMatrix.&lt;/p&gt;
&lt;p&gt;I committed the latest database as well, so now you can read all the
quotes (even the bad ones), and start your own t-shirt business ;).&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Comfortably numb</title>
      <link>https://jefclaes.be/2011/09/comfortably-numb.html</link>
      <pubDate>Wed, 21 Sep 2011 20:51:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/09/comfortably-numb.html</guid>
      <description>&lt;p&gt;Something that can bother me tremendously is being surrounded by people
who are in a constant state of being &lt;a href=&#34;http://www.youtube.com/watch?v=0wtiNzci1Wc&#34;&gt;comfortably numb&lt;/a&gt;. People who don&amp;rsquo;t
welcome change, try to scare away new concepts and are just too much at
home in their comfort zone. Some are perfectly happy filling their days
keeping up appearances of being busy. They don&amp;rsquo;t care about
self-improvement, but only care about augmenting their paychecks by
accumulating as much legacy baggage as possible, with the sole intention
of being perceived as an irreplaceable asset to the company, whilst not
having to leave their comfort zone. These people also have the tendency
to shy away from responsibility and commitment. They are satisfied with
doing just enough to not draw any attention to themselves.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s really tempting to just go along, and follow. After all, it&amp;rsquo;s in
human nature to strive for comfort: the path of the least resistance. If
you are reading this blog, you probably already belong to the group of
people who care about their craft, and are aiming for something more
than the status quo. I applaud you. For you, this post only serves as a
reminder that you should constantly evaluate your current position and
be honest with yourself: Am I still moving forward?&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Building small things</title>
      <link>https://jefclaes.be/2011/09/building-small-things.html</link>
      <pubDate>Sun, 18 Sep 2011 16:35:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/09/building-small-things.html</guid>
      <description>&lt;p&gt;Due to the nature of things we build in our day to day job, writing
software can wear out even the most fit of us.&lt;/p&gt;
&lt;p&gt;Most software jobs make you constantly deal with complexity. The amount
of things which can lead to a complex software project are immense. A
poor first design, and failure to redesign. External dependencies, which
seem to behave different every time around. Or just the complexity of
the problems itself.&lt;br&gt;
You are almost always working in a team, which can be exhausting as
well. If the team doesn&amp;rsquo;t share your passion and you have a hard time
getting your ideas across, you will get frustrated, real soon. Add some
coroporate politics to the mix and you&amp;rsquo;ll be on your way to Paranoia.&lt;/p&gt;
&lt;p&gt;It feels like I&amp;rsquo;m turning this into a rant, but I&amp;rsquo;ll stop right here,
you get where I&amp;rsquo;m going at. Building software in the real world can be
hard. Very hard.&lt;/p&gt;
&lt;p&gt;I like to think building something small on your own once in a while can
be extremely liberating. It can help you keep your sanity and not lose
your passion towards software. You pick what to build. Something small.
Something new. Something built with your favorite tools, on your
favorite platform. Something that can be shipped. Something which takes
only you and your machine.&lt;/p&gt;
&lt;p&gt;Having problems finding something meaningful to make? Look around you,
the most trivial problem can lead to a satisfying little sideproject.
Look for things that bother you, and try making them bother you less.
Listen to others, maybe you can help solve their problems. Who cares if
it already exists in one way or the other? Look for something that looks
fun. And just build it.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Once upon a time in the West</title>
      <link>https://jefclaes.be/2011/09/once-upon-time-in-west.html</link>
      <pubDate>Sat, 17 Sep 2011 11:15:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/09/once-upon-time-in-west.html</guid>
      <description>&lt;p&gt;The girlfriend and I returned from our &lt;a href=&#34;https://jefclaes.be/2011/08/west-coast-road-trip-schedule.html&#34;&gt;West Coast
roadtrip&lt;/a&gt; yesterday morning.&lt;/p&gt;
&lt;p&gt;We found this trip to be an unforgettable experience, which made us even
more hungry for future travels.&lt;/p&gt;
&lt;p&gt;This blog will return to business as usual, with mainly technical
content and opinions.&lt;/p&gt;
&lt;p&gt;Here is an overview of our posts exploring the West Coast:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://jefclaes.be/2011/08/if-youre-going-to-san-francisco.html&#34;&gt;If you&amp;rsquo;re going to San Francisco&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://jefclaes.be/2011/09/yosemite-skyscrapers.html&#34;&gt;Yosemite skyscrapers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://jefclaes.be/2011/09/yesterday-evening-we-spent-night-in.html&#34;&gt;Sands of Nevada&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://jefclaes.be/2011/09/rusty-rocks.html&#34;&gt;Rusty Rocks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.jefclaes.be/2011/09/from-glen-to-grand.html&#34;&gt;From Glen to Grand&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://jefclaes.be/2011/09/edge-of-eternity.html&#34;&gt;Edge of eternity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://jefclaes.be/2011/09/fear-and-loathing-in-las-vegas.html&#34;&gt;Fear and loathing in Las Vegas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://jefclaes.be/2011/09/city-of-fallen-angels.html&#34;&gt;City of fallen angels&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-17-once-upon-a-time-in-the-west-Yosemite_0210.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-17-once-upon-a-time-in-the-west-Yosemite_0210.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.youtube.com/watch?v=NSRGCtZ9_Uc&#34;&gt;Once upon a time in the
West..&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>City of fallen angels</title>
      <link>https://jefclaes.be/2011/09/city-of-fallen-angels.html</link>
      <pubDate>Tue, 13 Sep 2011 05:45:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/09/city-of-fallen-angels.html</guid>
      <description>&lt;p&gt;After seeing the celebrities at Madame Tussaud&amp;rsquo;s in &lt;a href=&#34;https://jefclaes.be/2011/09/fear-and-loathing-in-las-vegas.html&#34;&gt;Las Vegas&lt;/a&gt;,
we went for the real deal.&lt;/p&gt;
&lt;p&gt;Turns out Hollywood is a lot less glamourous than we expected. The Walk
of Fame isn&amp;rsquo;t a lot different from any other gray sidewalk, paved with
long-forgotten stars. The famous Hollywood sign isn&amp;rsquo;t even lit a night,
making the contrast with Beverly Hills at the other side of town even
bigger. &lt;/p&gt;
&lt;p&gt;Maybe there&amp;rsquo;s another side to Hollywood that we haven&amp;rsquo;t seen, since we
only stayed for two days, one of which at the &lt;a href=&#34;http://www.universalstudioshollywood.com/&#34;&gt;Universal Studios&lt;/a&gt;. Here we took a sneak peek behind the scenes of movies like The Fast and the Furious, Jaws and Jurassic Park. We also drove through &lt;a href=&#34;http://en.wikipedia.org/wiki/Wisteria_Lane&#34;&gt;Wisteria Lane&lt;/a&gt; and other generic-built shooting sets.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-13-city-of-fallen-angels-LosAngeles_0005.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-13-city-of-fallen-angels-LosAngeles_0005.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-13-city-of-fallen-angels-LosAngeles_0205.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-13-city-of-fallen-angels-LosAngeles_0205.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-13-city-of-fallen-angels-LosAngeles_0138.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-13-city-of-fallen-angels-LosAngeles_0138.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-13-city-of-fallen-angels-LosAngeles_0072.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-13-city-of-fallen-angels-LosAngeles_0072.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-13-city-of-fallen-angels-LosAngeles_0048.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-13-city-of-fallen-angels-LosAngeles_0048.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This will probably be our last post from the US. We will spend our last
few days driving the coast line back to the Bay Area, to depart there on
Thursday.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Fear and loathing in Las Vegas</title>
      <link>https://jefclaes.be/2011/09/fear-and-loathing-in-las-vegas.html</link>
      <pubDate>Sun, 11 Sep 2011 02:49:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/09/fear-and-loathing-in-las-vegas.html</guid>
      <description>&lt;p&gt;Driving back into the desert after &lt;a href=&#34;http://www.youtube.com/watch?v=5GHczEmd11E&#34;&gt;our breakfast&lt;/a&gt;, with Las Vegas in the rear-view mirror, we secretly feel a little relieved to be heading back to the real world. The cocktail of fake pyramids, indoor jungles, Paris landmarks, castles and volcanoes became a little nauseating. With hotels and casinoes resembling labyrinths, designed to get people trapped inside, it feels liberating to drive through the wide open landscape again.&lt;/p&gt;
&lt;p&gt;Some of the things we enjoyed the most were the late nights walking the
Strip, watching free shows, standing on top of the
&lt;a href=&#34;http://en.wikipedia.org/wiki/Stratosphere_Las_Vegas&#34;&gt;Stratosphere&lt;/a&gt; and
posing with the wax celebs at Madame Tussaud&amp;rsquo;s. &lt;/p&gt;
&lt;p&gt;Although we had a great time, Vegas probably only shows its full
potential when you&amp;rsquo;re a highroller.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-11-fear-and-loathing-in-las-vegas-LasVegas_0371.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-11-fear-and-loathing-in-las-vegas-LasVegas_0371.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-11-fear-and-loathing-in-las-vegas-LasVegas_0107.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-11-fear-and-loathing-in-las-vegas-LasVegas_0107.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-11-fear-and-loathing-in-las-vegas-LasVegas_0313.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-11-fear-and-loathing-in-las-vegas-LasVegas_0313.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-11-fear-and-loathing-in-las-vegas-LasVegas_0360.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-11-fear-and-loathing-in-las-vegas-LasVegas_0360.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-11-fear-and-loathing-in-las-vegas-LasVegas_0290.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-11-fear-and-loathing-in-las-vegas-LasVegas_0290.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-11-fear-and-loathing-in-las-vegas-LasVegas_0231.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-11-fear-and-loathing-in-las-vegas-LasVegas_0231.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Edge of eternity</title>
      <link>https://jefclaes.be/2011/09/edge-of-eternity.html</link>
      <pubDate>Wed, 07 Sep 2011 06:40:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/09/edge-of-eternity.html</guid>
      <description>&lt;p&gt;We all know the Grand Canyon as one of &lt;a href=&#34;http://en.wikipedia.org/wiki/Wonders_of_the_World#Seven_Natural_Wonders_of_the_World&#34;&gt;the seven natural wonders of the world&lt;/a&gt;, today I learned why. As one of the locals described: &amp;lsquo;Pretty amazing for
a big hole in the ground&amp;rsquo;. &lt;/p&gt;
&lt;p&gt;Being the closest to the south entrance, we visited the South Rim of the
canyon. A trip to the visitor center taught us there were no easy hikes
(except for the going down part), so we didn&amp;rsquo;t attempt at one. A hike
down the canyon and back up is a two day endeavor. A shuttle bus took us
along the scenic route, dropping us off at three viewpoints. Standing on
the edge, stunned by the view, we were accompanied by some &lt;a href=&#34;http://en.wikipedia.org/wiki/California_Condor&#34;&gt;California
Condors&lt;/a&gt; circling above
us. However, their view must have been more impressive, being able to
stare down right into the 4000 feet (1200m) deep canyon. &lt;/p&gt;
&lt;p&gt;After visiting the park, we went to see the &lt;a href=&#34;http://en.wikipedia.org/wiki/Grand_Canyon:_The_Hidden_Secrets&#34;&gt;National Geographic Grand
Canyon movie&lt;/a&gt; at the IMAX. This film revealed parts of the inner canyon, following in the footsteps of &lt;a href=&#34;http://en.wikipedia.org/wiki/John_Wesley_Powell&#34;&gt;John Wesley Powell&lt;/a&gt;. The show is a cheap alternative to an expensive helicopter flight through the canyon.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-07-edge-of-eternity-GrandCanyon_0020.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-07-edge-of-eternity-GrandCanyon_0020.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-07-edge-of-eternity-GrandCanyon_0066.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-07-edge-of-eternity-GrandCanyon_0066.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-07-edge-of-eternity-GrandCanyon_0114.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-07-edge-of-eternity-GrandCanyon_0114.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Tomorrow morning we will return to the more civilized (?) man-made
world: Las Vegas.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>From Glen to Grand</title>
      <link>https://jefclaes.be/2011/09/from-glen-to-grand.html</link>
      <pubDate>Tue, 06 Sep 2011 07:14:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/09/from-glen-to-grand.html</guid>
      <description>&lt;p&gt;Yesterday, we drove from Saint-George to Page, Arizona. The &lt;a href=&#34;http://en.wikipedia.org/wiki/Pipe_Spring_National_Monument&#34;&gt;Pipe Springs National Monument&lt;/a&gt; happened to be on our way, so we made a stop. Turned out there wasn&amp;rsquo;t much to see. A 30-minute ranger-led tour made it worthwhile though. During the tour through the Winsor Castle, she told us about the Mormons who used to live there. The Fort manager, also head of their Mormon church, married 58 women, resulting in plenty of children to work the Fort.&lt;/p&gt;
&lt;p&gt;Arriving at Page, we hiked the Horseshoe Bend trail, which ended in one
of the most amazing views we&amp;rsquo;ve seen so far. To cool off, we took a swim
in &lt;a href=&#34;http://en.wikipedia.org/wiki/Lake_powell&#34;&gt;Lake Powell&lt;/a&gt;, the
reservoir above the &lt;a href=&#34;http://en.wikipedia.org/wiki/Glen_Canyon_Dam&#34;&gt;Glen Canyon Dam&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-06-from-glen-to-grand-LakePowell_0049.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-06-from-glen-to-grand-LakePowell_0049.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-06-from-glen-to-grand-LakePowell_0120.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-06-from-glen-to-grand-LakePowell_0120.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-06-from-glen-to-grand-LakePowell_0144.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-06-from-glen-to-grand-LakePowell_0144.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Today we took a guided tour through &lt;a href=&#34;http://en.wikipedia.org/wiki/Antelope_Canyon&#34;&gt;Antelope Canyon&lt;/a&gt;, which resulted in some interesting pictures. &lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-06-from-glen-to-grand-LakePowell_0173.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-06-from-glen-to-grand-LakePowell_0173.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-06-from-glen-to-grand-LakePowell_0216.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-06-from-glen-to-grand-LakePowell_0216.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;At the moment we&amp;rsquo;re in Flagstaff, which will be our launching point to
the Grand Canyon tomorrow.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Rusty rocks</title>
      <link>https://jefclaes.be/2011/09/rusty-rocks.html</link>
      <pubDate>Sun, 04 Sep 2011 07:23:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/09/rusty-rocks.html</guid>
      <description>&lt;p&gt;We started the day with a short drive to &lt;a href=&#34;http://en.wikipedia.org/wiki/Zion_National_Park&#34;&gt;Zion National Park&lt;/a&gt;. On our way we came across some colossal rock formations, layered with different shades of red. Since the park is almost entirely car free, we took the shuttle bus along the scenic route. We got off at different stops, to take short hikes to the park&amp;rsquo;s natural treasures. The Emerald Pools were first up,
followed by the Weeping Rock and a riverside walk to the Narrows, which
are architected by the &lt;a href=&#34;http://en.wikipedia.org/wiki/Virgin_River&#34;&gt;Virgin river&lt;/a&gt;. Wading in the river gave us some much needed refreshment after a long day of hiking.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-04-rusty-rocks-Zion_0096.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-04-rusty-rocks-Zion_0096.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-04-rusty-rocks-Zion_0176.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-04-rusty-rocks-Zion_0176.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-04-rusty-rocks-Zion_0106.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-04-rusty-rocks-Zion_0106.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-04-rusty-rocks-Zion_0214.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-04-rusty-rocks-Zion_0214.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Our next destination is &lt;a href=&#34;http://en.wikipedia.org/wiki/Lake_Powell&#34;&gt;Lake Powell&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Sands of Nevada</title>
      <link>https://jefclaes.be/2011/09/yesterday-evening-we-spent-night-in.html</link>
      <pubDate>Sat, 03 Sep 2011 06:29:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/09/yesterday-evening-we-spent-night-in.html</guid>
      <description>&lt;p&gt;Yesterday evening we spent the night in a town called
&lt;a href=&#34;http://en.wikipedia.org/wiki/Tonopah,_Nevada&#34;&gt;Tonopah&lt;/a&gt;, which is
literally in the middle of nowhere. Today we continued our trip to
&lt;a href=&#34;http://en.wikipedia.org/wiki/Zion_National_Park&#34;&gt;Zion&lt;/a&gt; (Utah), driving
hundreds of miles through the Nevada desert, getting sunburned on the
way. There was not a soul in sight, except for cattle crossing the road,
who seemed to be waiting for us to pass to say hello. &lt;/p&gt;
&lt;p&gt;We just arrived at &lt;a href=&#34;http://en.wikipedia.org/wiki/St._George,_Utah&#34;&gt;St.
George&lt;/a&gt;, which is a
launching point to Zion National Park.&lt;/p&gt;
&lt;p&gt;So, not much to report today. Anyway, here are a few random pictures of
our drive through the Nevada desert.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-03-sands-of-nevada-Zion_0044.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-03-sands-of-nevada-Zion_0044.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-03-sands-of-nevada-Zion_0010.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-03-sands-of-nevada-Zion_0010.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-03-sands-of-nevada-Zion_0051.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-03-sands-of-nevada-Zion_0051.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-03-sands-of-nevada-Zion_0064.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-03-sands-of-nevada-Zion_0064.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.youtube.com/watch?v=R8pFzU93SzI&#34;&gt;Sands of Nevada&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Yosemite skyscrapers</title>
      <link>https://jefclaes.be/2011/09/yosemite-skyscrapers.html</link>
      <pubDate>Fri, 02 Sep 2011 07:10:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/09/yosemite-skyscrapers.html</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-02-yosemite-skyscrapers-Yosemite_0166.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-02-yosemite-skyscrapers-Yosemite_0166.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;These skyscrapers are, other than the enormous mountains, the redwood
&lt;a href=&#34;http://en.wikipedia.org/wiki/Sequoia_sempervirens&#34;&gt;sequoia&lt;/a&gt; on top of
them. Some of these trees are the same height as a thirty story
building, which is higher than the Statue Of Liberty. It&amp;rsquo;s almost
impossible to capture these giants on camera. &lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-02-yosemite-skyscrapers-Yosemite_0058.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-02-yosemite-skyscrapers-Yosemite_0058.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;After a short hike between the sequoia, we drove off to &lt;a href=&#34;http://en.wikipedia.org/wiki/Yosemite_Valley&#34;&gt;Yosemite Valley&lt;/a&gt; to discover the Yosemity Falls. Although the falls must be more impressive in Winter, they were still worth visiting. &lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-02-yosemite-skyscrapers-Yosemite_0093.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-02-yosemite-skyscrapers-Yosemite_0093.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Today we drove through Yosemite National Park once again, this time on
our way to cross the border to Nevada. On the route, we came across
breathtaking swirling roads. &lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-02-yosemite-skyscrapers-Yosemite_0204.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-02-yosemite-skyscrapers-Yosemite_0204.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Just before crossing the border to Nevada, we stopped at two &lt;a href=&#34;http://en.wikipedia.org/wiki/Mono_Lake&#34;&gt;Mono
Lake&lt;/a&gt; vista points.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-09-02-yosemite-skyscrapers-Yosemite_0231.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-09-02-yosemite-skyscrapers-Yosemite_0231.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Tomorrow, we are continuing our trip to &lt;a href=&#34;http://en.wikipedia.org/wiki/Zion_National_Park&#34;&gt;Zion&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>If you&#39;re going to San Francisco</title>
      <link>https://jefclaes.be/2011/08/if-youre-going-to-san-francisco.html</link>
      <pubDate>Wed, 31 Aug 2011 09:30:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/08/if-youre-going-to-san-francisco.html</guid>
      <description>&lt;p&gt;While I&amp;rsquo;m writing this, the girlfriend and I are on our way from San
Francisco to &lt;a href=&#34;http://en.wikipedia.org/wiki/Yosemite_National_Park&#34;&gt;Yosemite National Park&lt;/a&gt;. We have spent two full days visiting &amp;lsquo;Fog City&amp;rsquo;. During these two intensive days we were able to see everything we aimed for, maybe more.&lt;/p&gt;
&lt;h3 id=&#34;financial-district&#34;&gt;Financial District&lt;/h3&gt;
&lt;p&gt;This part of town is definitely worth a visit. The multiplicity of
skyscrapers merging into the San Francisco fog, is an impressive view.
When the fog has gone, the shadows the buildings cast on each other are
just as amazing.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-08-31-if-youre-going-to-san-francisco-SanFrancisco_0060.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-08-31-if-youre-going-to-san-francisco-SanFrancisco_0060.png&#34;&gt;&lt;/a&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-08-31-if-youre-going-to-san-francisco-SanFrancisco_0035.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-08-31-if-youre-going-to-san-francisco-SanFrancisco_0035.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;pier-39&#34;&gt;Pier 39&lt;/h3&gt;
&lt;p&gt;While obviously &lt;a href=&#34;http://en.wikipedia.org/wiki/Pier_39&#34;&gt;a tourist trap&lt;/a&gt;,
I found strolling through the shops and restaurants on the pier to be
surprisingly amusing.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-08-31-if-youre-going-to-san-francisco-SanFrancisco_0258.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-08-31-if-youre-going-to-san-francisco-SanFrancisco_0258.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;alcatraz-island&#34;&gt;Alcatraz Island&lt;/h3&gt;
&lt;p&gt;One of the main attractions of San Francisco, and a must see. If you
plan on taking a tour on &lt;a href=&#34;http://en.wikipedia.org/wiki/Alcatraz_Island&#34;&gt;the island&lt;/a&gt;, you must make reservations a few days ahead. We failed to do that, and ended up taking a cruise around Alcatraz Island. I feel like we missed out, but the boat tour was definitely good value for money too.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-08-31-if-youre-going-to-san-francisco-SanFrancisco_0127.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-08-31-if-youre-going-to-san-francisco-SanFrancisco_0127.png&#34;&gt;&lt;/a&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-08-31-if-youre-going-to-san-francisco-SanFrancisco_0169.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-08-31-if-youre-going-to-san-francisco-SanFrancisco_0169.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;ss-jeremiah-obrien&#34;&gt;SS Jeremiah O&amp;rsquo;Brien&lt;/h3&gt;
&lt;p&gt;Not so far from Pier 39, you can find a very nicely preserved World War
II liberty ship. If you have been on one of those ships before, it might
not be worth the 10 bucks.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-08-31-if-youre-going-to-san-francisco-SanFrancisco_0518.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-08-31-if-youre-going-to-san-francisco-SanFrancisco_0518.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;lombard-street&#34;&gt;Lombard Street&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;http://en.wikipedia.org/wiki/Lombard_Street_(San_Francisco)&#34;&gt;Thé most famous street in San Francisco&lt;/a&gt;, but kind of overrated. Save yourself the steep hill climb, and try finding a view from a few blocks away.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-08-31-if-youre-going-to-san-francisco-SanFrancisco_0340.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-08-31-if-youre-going-to-san-francisco-SanFrancisco_0340.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;chinatown&#34;&gt;Chinatown&lt;/h3&gt;
&lt;p&gt;Always a charming neighbourhood to window shop small boutiques for
Chinese kitsch.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-08-31-if-youre-going-to-san-francisco-SanFrancisco_0365.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-08-31-if-youre-going-to-san-francisco-SanFrancisco_0365.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;golden-gate-bridge&#34;&gt;Golden Gate Bridge&lt;/h3&gt;
&lt;p&gt;An &lt;a href=&#34;http://en.wikipedia.org/wiki/Golden_Gate_Bridge&#34;&gt;amazing piece of architecture&lt;/a&gt;. Can you imagine building that in the thirties? We drove there by bike, very recommended. Not for the faint of heart though.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-08-31-if-youre-going-to-san-francisco-SanFrancisco_0632.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-08-31-if-youre-going-to-san-francisco-SanFrancisco_0632.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;palace-of-fine-arts&#34;&gt;Palace of Fine Arts&lt;/h3&gt;
&lt;p&gt;On your way to the Golden Gate Bridge, you should drop by the &lt;a href=&#34;http://en.wikipedia.org/wiki/Palace_of_Fine_Arts&#34;&gt;Palace of
Fine Arts&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-08-31-if-youre-going-to-san-francisco-SanFrancisco_0579.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-08-31-if-youre-going-to-san-francisco-SanFrancisco_0579.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;trivia&#34;&gt;Trivia&lt;/h3&gt;
&lt;p&gt;If Anonymous isn&amp;rsquo;t hacking the Sony network, they are
&lt;a href=&#34;http://www.pcmag.com/article2/0,2817,2391160,00.asp&#34;&gt;protesting&lt;/a&gt; in the
streets of San Francisco.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-08-31-if-youre-going-to-san-francisco-SanFrancisco_0380.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-08-31-if-youre-going-to-san-francisco-SanFrancisco_0380.png&#34;&gt;&lt;/a&gt;&lt;br&gt;
I hope this post might have given you some ideas on locations to visit
&lt;a href=&#34;http://www.youtube.com/watch?v=bch1_Ep5M1s&#34;&gt;when you&amp;rsquo;re going to San Francisco&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>High Hopes</title>
      <link>https://jefclaes.be/2011/08/high-hopes.html</link>
      <pubDate>Mon, 08 Aug 2011 20:30:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/08/high-hopes.html</guid>
      <description>&lt;p&gt;Last week, I resigned from my job at &lt;a href=&#34;http://www.ferranti.be/&#34;&gt;Ferranti Computer
Systems&lt;/a&gt;. Three years ago, days after receiving my Graduate Diploma in Applied Computer Science, I had my first real-world working experience at Ferranti Computer Systems.&lt;/p&gt;
&lt;p&gt;The first project I was assigned to, was a project for the Antwerp fire
department. Along with two other graduates and four seniors, I was
thrown in at the deep end. I always had solid grades in school, and was
fairly confident that I grasped the material I was taught. Was I
misguided (!): it only took me a few days to realize that &lt;strong&gt;I knew
nothing about building software&lt;/strong&gt;. It immediately became clear that I
had to start learning and probably would need to keep at it forever, if
I ever wanted to get remotely good at this.&lt;/p&gt;
&lt;p&gt;The Antwerp fire department project turned out to be an immense and
complex project, which I have worked on throughout my whole career at
Ferranti. Not always that intense though, in the meanwhile I have had a
few smaller, more shippable projects and a very similar project for fire
department Ghent.&lt;/p&gt;
&lt;p&gt;Today, we are a few months into building a promising product for fire
departments, which has the potential to be big (in Belgium). Although my role in this project was fun and fairly satisfying, I still felt like it was time for me to move on.&lt;/p&gt;
&lt;p&gt;Many might think I&amp;rsquo;m a fool for throwing away a career where I was
actually helping to save lives, building software. There are some
frustrations that come along with building software for the public
safety sector though. Firstly, how perverted it might sound, this sector has a lot less money to spend on innovation compared to other, commercial sectors. This often leads to solutions which are not perfect, built to meet very tight deadlines.  Secondly, making progress is hard. Firefighters want to extinguish fires, save people&amp;hellip; Most of them don&amp;rsquo;t really care about software, making the adaptation and integration process painful. Although, I like to believe that this will change in the future. Our solution has been able to reduce station start-up times by 50%. It&amp;rsquo;s impossible to ignore those numbers.&lt;/p&gt;
&lt;p&gt;This isn&amp;rsquo;t the real reason I quit my job though. Every sector has its
own problems. The real motivation for me to change jobs was that &lt;strong&gt;I
felt stuck&lt;/strong&gt;. I have been working with the same team, on the same
problem, mostly using the same technology stack, at the same desk, on
the same chair for more than three years. This is not what I want, not
yet. I want to solve other problems, meet new people, learn from others,
try out new technologies and change chairs.&lt;/p&gt;
&lt;p&gt;In September, I will start working for &lt;a href=&#34;http://www.euri.com/&#34;&gt;Euricom&lt;/a&gt;
as a consultant, which should give me more opportunities to experience
new things.&lt;/p&gt;
&lt;p&gt;Will this job be able to give me personal satisfaction? I really don&amp;rsquo;t
know. Will I regret this decision? Probably not, I&amp;rsquo;d rather make the
wrong decision than do nothing.&lt;/p&gt;
&lt;p&gt;Anyway, I have &lt;a href=&#34;http://www.youtube.com/watch?v=Bqvcmud3LFQ&#34;&gt;high hopes&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Merge sorting in JavaScript</title>
      <link>https://jefclaes.be/2011/07/merge-sorting-in-javascript_1458.html</link>
      <pubDate>Tue, 26 Jul 2011 19:00:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/07/merge-sorting-in-javascript_1458.html</guid>
      <description>&lt;p&gt;The latest addition to my [data structures and algorithms in
JavaScript](&lt;a href=&#34;https://github.com/JefClaes&#34;&gt;https://github.com/JefClaes&lt;/a&gt; Data-structures-and-algorithms-in-JavaScript)
is the merge sort algorithm.&lt;/p&gt;
&lt;p&gt;There are four main steps in the merge sort algorithm (from
&lt;a href=&#34;http://en.wikipedia.org/wiki/Merge_sort&#34;&gt;Wikipedia&lt;/a&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If the list is of length 0 or 1, then it is already sorted.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Otherwise:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Divide the unsorted list into two sublists of about half the size.&lt;/li&gt;
&lt;li&gt;Sort each sublist recursively by re-applying the merge sort.&lt;/li&gt;
&lt;li&gt;Merge the two sublists back into one sorted list.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I found it a lot easier to understand the algorithm by just looking at
this diagram (also from &lt;a href=&#34;http://en.wikipedia.org/wiki/Merge_sort&#34;&gt;Wikipedia&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-07-26-merge-sorting-in-javascript-MergeSort.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-07-26-merge-sorting-in-javascript-MergeSort.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I added a public &lt;code&gt;mergeSort&lt;/code&gt; function to the &lt;code&gt;sortArray&lt;/code&gt; object, which I
showed in the &lt;a href=&#34;https://jefclaes.be/2011/07/simple-sorting-in-javascript.html&#34;&gt;first post&lt;/a&gt; in these series.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;mergeSort&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {                                       
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;internalMergeSort&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;onSort&lt;/span&gt;);                
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};     
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This function calls the &lt;code&gt;internalMergeSort&lt;/code&gt; function passing in the
internal elements array and the onSort callback.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;internalMergeSort&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;onSort&lt;/span&gt;){            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;){                               
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }                           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Calculate the middle of the elements
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;middle&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Math.&lt;span style=&#34;color:#a6e22e&#34;&gt;floor&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;);           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Divide 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;leftRange&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;slice&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;middle&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;rightRange&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;slice&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;middle&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;);           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Conquer                                                           
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mergingResult&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;merge&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;internalMergeSort&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;leftRange&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;onSort&lt;/span&gt;), 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              &lt;span style=&#34;color:#a6e22e&#34;&gt;internalMergeSort&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;rightRange&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;onSort&lt;/span&gt;));                                   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;onSort&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;mergingResult&lt;/span&gt;);           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mergingResult&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The function recursively divides the elements in two parts, sorting them
and finally merging them back together.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;merge&lt;/code&gt; function is implemented like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;merge&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;left&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;right&lt;/span&gt;){                      
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [];           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;left&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;right&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;) {                
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;left&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;right&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;]) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;left&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;shift&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;right&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;shift&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }                                              
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;left&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;) {                
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;left&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;shift&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;right&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;) {            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;right&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;shift&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};  
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I peeked at &lt;a href=&#34;http://css.dzone.com/news/friday-algorithms-javascript?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed%3A+zones%2Fcss+(CSS+Zone)&#34;&gt;this implementation&lt;/a&gt;,
which is very similar to mine and which helped me write the first while
loop more elegantly.&lt;/p&gt;
&lt;p&gt;Testing sorting algorithms is pretty easy. So far, I have only defined
one &lt;a href=&#34;http://docs.jquery.com/Qunit&#34;&gt;QUnit&lt;/a&gt; test for this algorithm.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;test&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;MergeSort sorts.&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sortArray&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;algorithms&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;sortArray&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;sortArray&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;sortArray&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;130&lt;/span&gt;); 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;actual&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sortArray&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;mergeSort&lt;/span&gt;();                               
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;expected&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;12&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;17&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;25&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;50&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;60&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;90&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;130&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;deepEqual&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;actual&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;expected&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});  
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A small remark here is that you should &lt;a href=&#34;https://github.com/jquery/qunit/issues/27&#34;&gt;use deepEqual&lt;/a&gt; instead of &lt;code&gt;equal&lt;/code&gt; for array assertions. We want to compare the contents of the array, not
their references.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>My js data structures and algorithms now on GitHub</title>
      <link>https://jefclaes.be/2011/07/my-js-data-structures-and-algorithms.html</link>
      <pubDate>Sat, 23 Jul 2011 15:30:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/07/my-js-data-structures-and-algorithms.html</guid>
      <description>&lt;p&gt;If you have been reading my blog lately, you know that I&amp;rsquo;m implementing
some data structures and algorithms in JavaScript. So far, I have
blogged about &lt;a href=&#34;https://jefclaes.be/2011/07/simple-sorting-in-javascript.html&#34;&gt;simple sorting algorithms&lt;/a&gt;, &lt;a href=&#34;https://jefclaes.be/2011/07/stacks-and-queues-in-javascript.html&#34;&gt;the stack data structure and the queue data structure&lt;/a&gt;. This week I have also implemented a doubly linked list. I started writing a post about that last implementation, but I didn&amp;rsquo;t like where it was going, so instead of writing about it, I have pushed everything to a public Git repository.&lt;/p&gt;
&lt;p&gt;You can &lt;a href=&#34;https://github.com/JefClaes/Data-structures-and-algorithms-in-JavaScript&#34;&gt;find the public repository here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I structured the repository like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Scripts&lt;/code&gt;: The JavaScript files which contain the various algorithms and data structures.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Implementations&lt;/code&gt;: HTML pages used to demonstrate the usage of some of these algorithms and data structures.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Tests&lt;/code&gt;: QUnit tests.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Feel free to watch or fork this project. I will still be writing about
most implemenations, but probably not all of them.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Overoptimizing my JavaScript stack implementation for fun</title>
      <link>https://jefclaes.be/2011/07/overoptimizing-my-javascript-stack.html</link>
      <pubDate>Mon, 18 Jul 2011 21:00:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/07/overoptimizing-my-javascript-stack.html</guid>
      <description>&lt;p&gt;&lt;a href=&#34;http://davybrion.com/blog/&#34;&gt;Davy Brion&lt;/a&gt; made a comment on &lt;a href=&#34;https://jefclaes.be/2011/07/stacks-and-queues-in-javascript.html&#34;&gt;my
JavaScript stack/queue implementation&lt;/a&gt; on Twitter last night: Any reason why you don&amp;rsquo;t immediately set elements to [] at declaration in your stack/queue example?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;element&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;typeof&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;undefined&amp;#39;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [];   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }                            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;element&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Yes, I made an overoptimization, and a bad one. In this implementation,
you save a few bytes in memory if you initialize the stack, but don&amp;rsquo;t
push elements. This might have made some sense 15 years ago, but today a
few bytes are very negligible compared to the cost of evaluating the
elements reference on every push call.&lt;/p&gt;
&lt;p&gt;Anyway, thinking about this driving home, I thought of another
optimization, which meets both arguments and is far more &lt;em&gt;fun&lt;/em&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;element&lt;/span&gt;) {                        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [];   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;element&lt;/span&gt;);                            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;element&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//Rewriting self. Overoptimization ftw!
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;element&lt;/span&gt;);                                   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }                                                 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first time the push function is executed, the elements array is
initialized. In the same function, the function rewrites itself to no
longer initialize the elements array. So the second time the push
function is called, it will no longer initalize the array, but only push
a new item to the existing elements array.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dynamilicious!&lt;/strong&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Stacks and queues in JavaScript</title>
      <link>https://jefclaes.be/2011/07/stacks-and-queues-in-javascript.html</link>
      <pubDate>Tue, 12 Jul 2011 21:00:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/07/stacks-and-queues-in-javascript.html</guid>
      <description>&lt;p&gt;The second assignment in my &amp;lsquo;implementing data structures and algorithms
in JavaScript&amp;rsquo; quest consists of two popular data structures: the &lt;a href=&#34;http://en.wikipedia.org/wiki/Stack_(data_structure)&#34;&gt;stack&lt;/a&gt; and the &lt;a href=&#34;http://en.wikipedia.org/wiki/Queue_(data_structure)&#34;&gt;queue&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;the-stack&#34;&gt;The stack&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;A stack is a last in, first out (LIFO) abstract data type and data
structure. A stack can have any abstract data type as an element, but
is characterized by only three fundamental operations: push, pop and
stack top.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Implementing this turned out to be pretty easy. A &lt;a href=&#34;https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array&#34;&gt;native JavaScript
array&lt;/a&gt; already exposes methods to
&lt;a href=&#34;https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/push&#34;&gt;push&lt;/a&gt; and &lt;a href=&#34;https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/pop&#34;&gt;pop&lt;/a&gt; elements. In the &lt;code&gt;dataStructures&lt;/code&gt; namespace, I defined a stack object. The
&lt;code&gt;stack&lt;/code&gt; object contains a private array which is initialized as soon as
the first element is pushed into the stack. The public &lt;code&gt;push&lt;/code&gt; and &lt;code&gt;pop&lt;/code&gt;
functions expose the corresponding functions of the private array. The
&lt;code&gt;stackTop&lt;/code&gt; function returns the last element added to the stack, but
doesn&amp;rsquo;t remove it from the internal array.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;dataStructures&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;stack&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {                  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;element&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;typeof&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;undefined&amp;#39;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [];   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }                            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;element&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;pop&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;pop&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;stackTop&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;element&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Although a native array contains most stack operations, the stack object
we made is still pretty useful. We end up with a clean encapsulated
stack which only exposes the core stack operations.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;someStack&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;dataStructures&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;stack&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;someStack&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;someStack&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;someStack&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;stackTopResult&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;someStack&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;stackTop&lt;/span&gt;();                         
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;stackTopResults&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;html&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;stackTopResult&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;popResult&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;popResult&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;someStack&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;pop&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;popResult&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;someStack&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;pop&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;popResult&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;someStack&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;pop&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;the-queue&#34;&gt;The queue&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;A queue is a particular kind of collection in which the entities in
the collection are kept in order and the principal (or only)
operations on the collection are the addition of entities to the rear
terminal position and removal of entities from the front terminal
position. This makes the queue a First-In-First-Out (FIFO) data
structure. In a FIFO data structure, the first element added to the
queue will be the first one to be removed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As with the stack, the native array object already contains a few
functions which help us implement a queue. The terminology doesn&amp;rsquo;t
completely match though. &lt;code&gt;Enqueue&lt;/code&gt; maps with &lt;code&gt;pop&lt;/code&gt; and &lt;code&gt;dequeue&lt;/code&gt; maps with &lt;a href=&#34;https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/shift&#34;&gt;shift&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I added the &lt;code&gt;queue&lt;/code&gt; object to the &lt;code&gt;dataStructures&lt;/code&gt; namespace. The queue also holds a private array of elements. The &lt;code&gt;enqueue&lt;/code&gt; function pushes a new element on the queue, and the dequeue function removes the first element from the queue. The &lt;code&gt;peek&lt;/code&gt; function returns the first element in the array, but does not remove it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;queue&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;enqueue&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;element&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;typeof&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;undefined&amp;#39;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [];   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;element&lt;/span&gt;);                       
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;dequeue&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;shift&lt;/span&gt;();                                   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;peek&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;];                  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The queue can be used like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;someQueue&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;enqueue&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;someQueue&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;enqueue&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;someQueue&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;enqueue&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;);               
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;queuePeekResult&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;someQueue&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;peek&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;queuePeekResults&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;html&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;queuePeekResult&lt;/span&gt;); 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;dequeueResult&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;                   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;dequeueResult&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;someQueue&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;dequeue&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;dequeueResult&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;someQueue&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;dequeue&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;dequeueResult&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;someQueue&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;dequeue&lt;/span&gt;(); 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Find &lt;strong&gt;the final result
&lt;a href=&#34;http://dl.dropbox.com/u/19698383/Blog/JavaScriptAlgorithmsDataStructs/Implementations/StackQueues.html&#34;&gt;here&lt;/a&gt;&lt;/strong&gt;.
Also check out the previous post on &lt;a href=&#34;https://www.jefcles.be/2011/07/simple-sorting-in-javascript.html&#34;&gt;simple sorting in
JavaScript&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Simple sorting in JavaScript</title>
      <link>https://jefclaes.be/2011/07/simple-sorting-in-javascript.html</link>
      <pubDate>Thu, 07 Jul 2011 21:30:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/07/simple-sorting-in-javascript.html</guid>
      <description>&lt;p&gt;About three years ago I graduated and got my degree in Applied Computer
Science. Although it says Computer Science, we hardly ever focused on
data structures and algorithms. Obviously, I now see that as a
shortcoming. So I plan to make up for that by reading up on some of the
basics. While at it, I might be blogging on some of the topics.&lt;/p&gt;
&lt;p&gt;I am going to start by implementing some of the simple sorting
algorithms in JavaScript.&lt;/p&gt;
&lt;p&gt;Find the final result
&lt;a href=&#34;http://dl.dropbox.com/u/19698383/Blog/JavaScriptAlgorithmsDataStructs/Implementations/SimpleSorting.html&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;bubble-sort&#34;&gt;Bubble sort&lt;/h3&gt;
&lt;p&gt;The first sorting algorithm I&amp;rsquo;m going to implement is probably also the
easiest, and slowest in most scenario&amp;rsquo;s: &lt;a href=&#34;http://en.wikipedia.org/wiki/Bubblesort&#34;&gt;Bubble
sort&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Bubble sort is a simple sorting algorithm that works by repeatedly
stepping through the list to be sorted, comparing each pair of
adjacent items and swapping them if they are in the wrong order. The
pass through the list is repeated until no swaps are needed, which
indicates that the list is sorted.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let&amp;rsquo;s start by defining a namespace.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;algorithms&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; { };
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We could extend the native array object, but to keep things simple,
let&amp;rsquo;s create our own sortArray object.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;algorithms&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {         
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;sortArray&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;sortArray&lt;/code&gt; object contains a private array of elements. To add
elements to that array, we will expose a &lt;code&gt;push&lt;/code&gt; function on our &lt;code&gt;sortArray&lt;/code&gt; object.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;algorithms&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;sortArray&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [];                                                                      
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;val&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;val&lt;/span&gt;);                    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };                                       
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So far, we can do something like this.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sortArr&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;algorithms&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;sortArray&lt;/span&gt;();               
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sortArr&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;80&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sortArr&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sortArr&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt;(...);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we have to add a public &lt;code&gt;sort&lt;/code&gt; function. Before we do that we need to
define a private &lt;code&gt;swap&lt;/code&gt; function, which can swap elements.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;swap&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;one&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;two&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;tmp&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;one&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;one&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;two&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;two&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;tmp&lt;/span&gt;;                    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;bubbleSort&lt;/code&gt; function will take a callback argument which will be
called every &lt;code&gt;sort&lt;/code&gt; iteration.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;bubbleSort&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;callback&lt;/span&gt;) {   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;callback&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//Loop over all the elements
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt;){                
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;inn&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;inn&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;inn&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;//Are they out of order?
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;inn&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;inn&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;]){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;swap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;inn&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;inn&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;);                                
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            } 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;callback&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }                    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That should be it. Now let&amp;rsquo;s try to &lt;code&gt;push&lt;/code&gt; some elements in the array,
define a callback and call the &lt;code&gt;bubbleSort&lt;/code&gt; function. In the callback
function I&amp;rsquo;m using the &lt;a href=&#34;http://code.google.com/intl/nl-BE/apis/chart/&#34;&gt;Google Charts API&lt;/a&gt; to visualize the sorting process.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;(document).&lt;span style=&#34;color:#a6e22e&#34;&gt;ready&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {             
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ...                                 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;results&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;#results&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;drawElements&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;) {                            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;chd&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;                    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;chd&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;].&lt;span style=&#34;color:#a6e22e&#34;&gt;toString&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;,&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//Remove that last &amp;#34;,&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;chd&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;chd&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;substring&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;chd&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;);                        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//Build the Google Charts url
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;chartUrlBase&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://chart.apis.google.com/chart?chxt=y&amp;amp;chbh=a&amp;amp;chs=300x225&amp;amp;cht=bvg&amp;amp;chco=A2C180,3D7930&amp;amp;chtt=Sorting&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;chartUrlComplete&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;chartUrlBase&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;amp;chd=t:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;chd&lt;/span&gt;;                                   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;#results&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;append&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;lt;img src=&amp;#39;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;chartUrlComplete&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#39;/&amp;gt;&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;append&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;lt;br/&amp;gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }                              
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;sortArr&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;bubbleSort&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;drawElements&lt;/span&gt;);                               
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;selection-sort&#34;&gt;Selection sort&lt;/h3&gt;
&lt;p&gt;The second algorithm is &lt;a href=&#34;http://en.wikipedia.org/wiki/Selection_sort&#34;&gt;Selection sort&lt;/a&gt;. I found this one the easiest to understand so far: find the mimimum value, swap it with the value in the first position, advance one position and repeat.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Selection sort is a sorting algorithm, specifically an in-place
comparison sort. It has O(n2) time complexity, making it inefficient
on large lists, and generally performs worse than the similar
insertion sort. Selection sort is noted for its simplicity, and also
has performance advantages over more complicated algorithms in certain
situations, particularly where auxiliary memory is limited.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let&amp;rsquo;s start by giving the BubbleSort callback function another place. We
will make this a public function on our &lt;code&gt;sortArray&lt;/code&gt;. I will name it &lt;code&gt;onSort&lt;/code&gt; and set it to an empty function by default.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;onSort&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;() {};      
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once that is done we can define our public &lt;code&gt;selectionSort&lt;/code&gt; function. This
function calls the &lt;code&gt;onSort&lt;/code&gt; function every sort iteration.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;selectionSort&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;onSort&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;min&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;inn&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;inn&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;inn&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;//If minium greater =&amp;gt; new minimum
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;inn&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;min&lt;/span&gt;]) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;min&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;inn&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }                            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;swap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;min&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;onSort&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;insertion-sort&#34;&gt;Insertion sort&lt;/h3&gt;
&lt;p&gt;The last simple sorting algorithm I&amp;rsquo;m going to implement in this post is
&lt;a href=&#34;http://en.wikipedia.org/wiki/Insertion_sort&#34;&gt;Insertion sort&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Insertion sort is a simple sorting algorithm: a comparison sort in
which the sorted array (or list) is built one entry at a time.&lt;/p&gt;
&lt;p&gt;Every repetition of insertion sort removes an element from the input
data, inserting it into the correct position in the already-sorted
list, until no input elements remain. The choice of which element to
remove from the input is arbitrary, and can be made using almost any
choice algorithm.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The &lt;code&gt;insertionSort&lt;/code&gt; is just another public function on our &lt;code&gt;sortArray&lt;/code&gt;
object.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;insertionSort&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;onSort&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;) {               
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;temp&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;inn&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;;            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//Until one is smaller
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;inn&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;inn&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;temp&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;inn&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;inn&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;inn&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;inn&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;temp&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;onSort&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;elements&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can &lt;strong&gt;find the final result &lt;a href=&#34;http://dl.dropbox.com/u/19698383/Blog/JavaScriptAlgorithmsDataStructs/Implementations/SimpleSorting.html&#34;&gt;here&lt;/a&gt;&lt;/strong&gt;. If you have any remarks on these implementations, please let me know!&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-07-07-simple-sorting-in-javascript-SortResult.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-07-07-simple-sorting-in-javascript-SortResult.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Should we get this tool?</title>
      <link>https://jefclaes.be/2011/06/should-we-get-this-tool.html</link>
      <pubDate>Wed, 15 Jun 2011 21:45:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/06/should-we-get-this-tool.html</guid>
      <description>&lt;p&gt;This is a decision that often needs to be made by middle management. For
managers the most natural way to make this call is by evaluating the
&lt;a href=&#34;http://nl.wikipedia.org/wiki/Return_on_investment&#34;&gt;return on investment&lt;/a&gt;. To calculate the ROI, you need to compare the gain of an investment
relative to the amount of investment. And this is exactly where things
get hard, if not impossible. Measuring developer productivity is one of
the unsolvable problems in our industry.&lt;/p&gt;
&lt;p&gt;If a developer wants something which he feels will improve his
productivity, not a lot of questions should be asked. The investment is
probably ridiculously little, compared to the risk of depressing one of
your codemonkeys. Developer happinness is at least as important as
developer productivity. Happy developers tend to get passionate about
their profession, and therefor ship better software as a result. And
that&amp;rsquo;s what we are all after, right?&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-06-15-should-we-get-this-tool-sad-monkey.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-06-15-should-we-get-this-tool-sad-monkey.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I also find that peers saying something along the lines of &amp;ldquo;What&amp;rsquo;s wrong
with notepad?&amp;rdquo; are foolish. If you are most productive and happy using
notepad, that&amp;rsquo;s perfectly fine, but don&amp;rsquo;t go belittling people who enjoy
using more rich and intelligent editors.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Book review: More Joel on Software</title>
      <link>https://jefclaes.be/2011/06/book-review-more-joel-on-software.html</link>
      <pubDate>Tue, 07 Jun 2011 19:00:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/06/book-review-more-joel-on-software.html</guid>
      <description>&lt;p&gt;I was lucky to pick up a copy of &lt;a href=&#34;http://www.amazon.com/gp/product/1430209879/ref=as_li_tf_tl?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;linkCode=as2&amp;amp;camp=217153&amp;amp;creative=399353&amp;amp;creativeASIN=1430209879&#34;&gt;More Joel on
Software&lt;/a&gt; for only 5 euros at a &lt;a href=&#34;http://www.boekenfestijn.com/&#34;&gt;bookfest&lt;/a&gt; last week. Turns out the book ships pretty cheap on &lt;a href=&#34;http://www.amazon.com/gp/product/1430209879/ref=as_li_tf_tl?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;linkCode=as2&amp;amp;camp=217153&amp;amp;creative=399353&amp;amp;creativeASIN=1430209879&#34;&gt;Amazon&lt;/a&gt; as well.&lt;/p&gt;
&lt;p&gt;More Joel on Software was written by &lt;a href=&#34;http://en.wikipedia.org/wiki/Joel_Spolsky&#34;&gt;Joel Spolsky&lt;/a&gt;, already a legend for launching &lt;a href=&#34;http://stackexchange.com/&#34;&gt;The Stack Exchange Network&lt;/a&gt; with &lt;a href=&#34;http://www.codinghorror.com/blog/&#34;&gt;Jeff Atwood&lt;/a&gt;. Although it&amp;rsquo;s hard to not know him, I admittedly hadn&amp;rsquo;t read a lot of his material so far. Starting my professional career in late 2008, the Spolsky writing high days were mostly over.&lt;/p&gt;
&lt;p&gt;More Joel on Software is the second
&lt;a href=&#34;http://en.wikipedia.org/wiki/Blook&#34;&gt;blook&lt;/a&gt; which bundles the best of
the digital content of the &lt;a href=&#34;http://www.joelonsoftware.com/&#34;&gt;Joel on Software
blog&lt;/a&gt; into a dead tree. Although you can
find every part of the book on &lt;a href=&#34;http://www.joelonsoftware.com/&#34;&gt;Spolsky&amp;rsquo;s
blog&lt;/a&gt;, it was well worth the money. I
love how he has, next to amusing anecdotes, a very opinionated view on
our industry which really challenges you to broaden your thinking. His
writing is also extremely enjoyable, I think he must be one of the best
writers in our field.&lt;/p&gt;
&lt;p&gt;Here is, for your convenience, the content of the book with links to the
original articles online. Might be useful if you are the owner of one of
those &lt;a href=&#34;http://en.wikipedia.org/wiki/Amazon_Kindle&#34;&gt;reading devices&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Part 1 - Managing People&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/items/2006/06/16.html&#34;&gt;My First BillG
Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/articles/FindingGreatDevelopers.html&#34;&gt;Finding Great
Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/articles/FieldGuidetoDevelopers.html&#34;&gt;A Field Guide to
Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/items/2006/08/07.html&#34;&gt;Three Management Methods
(Introduction)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/items/2006/08/08.html&#34;&gt;The Command and Control Management
Method&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/items/2006/08/09.html&#34;&gt;The Econ 101 Management
Method&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/items/2006/08/10.html&#34;&gt;The Identity Management
Method&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Part 2 - Advice to Potential Programmers&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/articles/ThePerilsofJavaSchools.html&#34;&gt;The Perils of
JavaSchools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Talk at Yale
(&lt;a href=&#34;http://www.joelonsoftware.com/items/2007/12/03.html&#34;&gt;1&lt;/a&gt;,
&lt;a href=&#34;http://www.joelonsoftware.com/items/2007/12/04.html&#34;&gt;2&lt;/a&gt;,
&lt;a href=&#34;http://www.joelonsoftware.com/items/2007/12/05.html&#34;&gt;3&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/articles/CollegeAdvice.html&#34;&gt;Advice for Computer Science College
Students&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Part 3 - The Impact of Design&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/items/2007/06/12.html&#34;&gt;Font Smoothing, Anti-Aliasing, and Subpixel
Rendering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/items/2007/06/07.html&#34;&gt;A Game of
Inches&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/items/2007/01/21.html&#34;&gt;The Big
Picture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/items/2006/11/21.html&#34;&gt;Choices =
Headaches&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/articles/NotJustUsability.html&#34;&gt;It&amp;rsquo;s Not Just
Usability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/articles/BuildingCommunitieswithSo.html&#34;&gt;Building Communities with
Software&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Part 4 - Managing Large Projects&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/items/2008/03/17.html&#34;&gt;Martian
Headsets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/items/2008/02/19.html&#34;&gt;Why Are the Microsoft Office File Formats So Complicated? (And Some
Workarounds)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/items/2007/12/06.html&#34;&gt;Where There&amp;rsquo;s Muck, There&amp;rsquo;s
Brass&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Part 5 - Programming Advice&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/items/2007/10/26.html&#34;&gt;Evidence-Based
Scheduling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/items/2007/09/18.html&#34;&gt;Strategy Letter
VI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/items/2006/08/01.html&#34;&gt;Can Your Programming Language Do
This?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/articles/Wrong.html&#34;&gt;Making Wrong Code Look
Wrong&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Part 6 - Starting a Software Business&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/articles/BusinessofSoftware.html&#34;&gt;Forward to Eric Sink on the Business of
Software&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/articles/HighNotes.html&#34;&gt;Forward to Micro-ISV: From Vision to
Reality&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/articles/HighNotes.html&#34;&gt;Hitting the High
Notes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Part 7 - Running a Software Business&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/articles/BionicOffice.html&#34;&gt;Bionic
Office&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/articles/fog0000000026.html&#34;&gt;Up the Tata Without a
Tutu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/items/2006/12/09.html&#34;&gt;Simplicity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/articles/fog0000000348.html&#34;&gt;Rub a Dub
Dub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/articles/BetaTest.html&#34;&gt;Top Twelve Tips for Running a Beta
Test&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/articles/customerservice.html&#34;&gt;Seven Steps to Remarkable Customer
Service&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Part 8 - Releasing Software&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/articles/PickingShipDate.html&#34;&gt;Picking a Ship
Date&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/articles/CamelsandRubberDuckies.html&#34;&gt;Camels and Rubber
Duckies&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Part 9 - Revising Software&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/items/2008/01/22.html&#34;&gt;Five Whys&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.joelonsoftware.com/articles/SetYourPriorities.html&#34;&gt;Set Your
Priorities&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Checking for anonymous types</title>
      <link>https://jefclaes.be/2011/05/checking-for-anonymous-types.html</link>
      <pubDate>Sat, 21 May 2011 18:00:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/05/checking-for-anonymous-types.html</guid>
      <description>&lt;p&gt;Because I blogged about anonymous types &lt;a href=&#34;https://jefclaes.be/2011/04/anonymous-type-equality-follow-up.html&#34;&gt;last
month&lt;/a&gt;, I thought following method would also make an interesting post.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; IsAnonymousType(Type type) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Debug.Assert(type != &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Type should not be null&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// HACK: The only way to detect anonymous types right now.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Attribute.IsDefined(type, &lt;span style=&#34;color:#66d9ef&#34;&gt;typeof&lt;/span&gt;(CompilerGeneratedAttribute), &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;amp;&amp;amp; type.IsGenericType 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;amp;&amp;amp; type.Name.Contains(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;AnonymousType&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;amp;&amp;amp; (type.Name.StartsWith(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;lt;&amp;gt;&amp;#34;&lt;/span&gt;, StringComparison.OrdinalIgnoreCase) ||
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                type.Name.StartsWith(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;VB$&amp;#34;&lt;/span&gt;, StringComparison.OrdinalIgnoreCase))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;amp;&amp;amp; (type.Attributes &amp;amp; TypeAttributes.NotPublic) == TypeAttributes.NotPublic;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For a type to be anonymous:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It should be marked with the &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.compilergeneratedattribute.aspx&#34;&gt;CompilerGenerated&lt;/a&gt; attribute&lt;/li&gt;
&lt;li&gt;It should be a generic type&lt;/li&gt;
&lt;li&gt;Its name should contain &amp;ldquo;AnonymousType&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Its name should start with &amp;ldquo;&amp;lt;&amp;gt;&amp;rdquo; or &amp;ldquo;VB$&amp;rdquo;&lt;/li&gt;
&lt;li&gt;It shouldn&amp;rsquo;t be publicly accessible&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A little fun fact is that the VB and C# compiler generate different
type names. The C# compiler makes the type name start with &amp;ldquo;&amp;lt;&amp;gt;&amp;rdquo;
and the VB compiler uses &amp;ldquo;VB$&amp;rdquo;. Both smart safeguards, because the
compiler doesn&amp;rsquo;t allow us to use &amp;ldquo;&amp;lt;&amp;gt;&amp;rdquo; or &amp;ldquo;$&amp;rdquo; while defining type
names. I find the C# way a tad more elegant though.&lt;/p&gt;
&lt;p&gt;I stumbled upon this beauty while browsing the [ASP.NET MVC source] (&lt;a href=&#34;http://aspnet.codeplex.com/&#34;&gt;http://aspnet.codeplex.com/&lt;/a&gt;) (System.Web.Helpers.ObjectVisitor).
Because there is no direct way to detect anonymous types yet, I&amp;rsquo;m pretty
sure this is the best implementation out there.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>My thoughts on WebMatrix</title>
      <link>https://jefclaes.be/2011/05/my-thoughts-on-webmatrix/</link>
      <pubDate>Mon, 09 May 2011 21:15:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/05/my-thoughts-on-webmatrix/</guid>
      <description>&lt;p&gt;After building &lt;a href=&#34;https://jefclaes.be/2011/04/arealdevelopercom.html&#34;&gt;arealdeveloper.com&lt;/a&gt;, I felt like I had to do a follow-up post sharing my experiences with &lt;a href=&#34;http://www.asp.net/webmatrix&#34;&gt;WebMatrix&lt;/a&gt;. While doing some research, I came across &lt;a href=&#34;http://blog.wekeroad.com/microsoft/someone-hit-their-head&#34;&gt;this post&lt;/a&gt; by Rob Connery. And frankly, I think it&amp;rsquo;s almost impossible for me to add something to his findings.&lt;/p&gt;
&lt;h3 id=&#34;in-a-nutshell&#34;&gt;In a nutshell&lt;/h3&gt;
&lt;p&gt;For those who are here for the &amp;ldquo;tl;dr&amp;rdquo;, here are my thoughts on WebMatrix..&lt;/p&gt;
&lt;p&gt;WebMatrix is the perfect framework to start with ASP.NET development
(wish I had). For people who are already familiar with ASP.NET,
WebMatrix will hardly have any learning curve. They should also have a
look at it though, because it&amp;rsquo;s a lot of &lt;strong&gt;fun&lt;/strong&gt; ánd it is a great
framework to &lt;strong&gt;get things done&lt;/strong&gt;. Every developer has been asked - at
least once - to slap together a site for a distant acquaintance, where
the site consists of mostly static pages, with a dynamic
List&amp;lt;Something&amp;gt; pulled out of a database. I see WebMatrix as a
perfect &lt;strong&gt;gluing framework&lt;/strong&gt; to swiftly ship these types of projects.
While you &lt;strong&gt;could&lt;/strong&gt; probably also build something more enterprisey, I
don&amp;rsquo;t think you should.&lt;/p&gt;
&lt;h3 id=&#34;see-for-yourself&#34;&gt;See for yourself&lt;/h3&gt;
&lt;p&gt;I have &lt;a href=&#34;https://github.com/JefClaes/real-dev&#34;&gt;uploaded the source of
arealdeveloper.com&lt;/a&gt;.
Download WebMatrix using the &lt;a href=&#34;http://www.microsoft.com/web/downloads/platform.aspx&#34;&gt;WebPlatform
Installer&lt;/a&gt; and see
for yourself.&lt;/p&gt;
&lt;p&gt;You might notice that the project is called arealprogrammer. That was
the name of the project before I bought the wrong domain name.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>arealdeveloper.com mentioned on Channel9</title>
      <link>https://jefclaes.be/2011/05/arealdevelopercom-mentioned-on-channel9.html</link>
      <pubDate>Mon, 02 May 2011 21:30:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/05/arealdevelopercom-mentioned-on-channel9.html</guid>
      <description>&lt;p&gt;While nosing around in the &lt;a href=&#34;#&#34;&gt;arealdeveloper.com&lt;/a&gt; analytics, I saw a
bunch of traffic coming from &lt;a href=&#34;http://channel9.msdn.com/&#34;&gt;Channel9&lt;/a&gt;.
Clicking through, I found out &lt;a href=&#34;#&#34;&gt;A Real Developer&lt;/a&gt; was mentioned in &lt;a href=&#34;http://channel9.msdn.com/Shows/This+Week+On+Channel+9/TWC9-HouseBuilder-Solver-Dev-Labs-Project-Windows-Shell-Extensions&#34;&gt;this video&lt;/a&gt;
(02:01). That&amp;rsquo;s a Channel9 front-page video!&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s so awesome, I think it&amp;rsquo;s great people find it a fun project.&lt;/p&gt;
&lt;p&gt;I have been listening to your feedback, and this Sunday I implemented some of your requests:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Easier linking&lt;/li&gt;
&lt;li&gt;Sharing&lt;/li&gt;
&lt;li&gt;A feed&lt;/li&gt;
&lt;li&gt;Voting&lt;/li&gt;
&lt;li&gt;Comments&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I try to keep everything as simple as possible, that&amp;rsquo;s why I implemented
most of these features using two popular free plug-ins: &lt;a href=&#34;http://www.addthis.com/&#34;&gt;AddThis&lt;/a&gt; and &lt;a href=&#34;http://disqus.com/&#34;&gt;Disqus&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Oh, and by the way, for Americans, they did pretty well pronouncing my
last name ;)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>arealdeveloper.com</title>
      <link>https://jefclaes.be/2011/04/arealdevelopercom.html</link>
      <pubDate>Tue, 26 Apr 2011 20:00:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/04/arealdevelopercom.html</guid>
      <description>&lt;p&gt;&lt;a href=&#34;#&#34;&gt;A Real Developer&lt;/a&gt; is a side-project I built
over the weekend poking around with &lt;a href=&#34;http://www.asp.net/webmatrix&#34;&gt;WebMatrix&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-04-26-arealdeveloper-com-arealdevss.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-04-26-arealdeveloper-com-arealdevss.PNG&#34;&gt;&lt;/a&gt;&lt;br&gt;
It got a little out of hand. After publishing, I showed it to a few
popular tweeps, and they were kind enough to mention it. 24 hours after
the launch it has gotten over 3.5k unique visitors, 39k page views (see
what I did there?) and over 240 submissions. Being mentioned by &lt;a href=&#34;http://twitter.com/#!/shanselman&#34;&gt;Scott
Hanselman&lt;/a&gt; and &lt;a href=&#34;http://twitter.com/#!/reybango&#34;&gt;Rey
Bango&lt;/a&gt; helps.&lt;/p&gt;
&lt;p&gt;I kind of felt like a mini - Mark Zuckerberg constantly refreshing the
page and reading new quotes hours afer the launch.&lt;/p&gt;
&lt;p&gt;I was somewhat surprised by how original and creative our community is.
Some of my favorite quotes so far..&lt;/p&gt;
&lt;p&gt;A real developer has changed live code in production at least once,
begrudgingly. (by
&lt;a href=&#34;http://twitter.com/#!/jasonfamularo&#34;&gt;@jasonfamularo&lt;/a&gt;)&lt;br&gt;
A real developer has code on his t-shirt. (by
&lt;a href=&#34;http://twitter.com/#!/stevenmilne&#34;&gt;@stevenmilne&lt;/a&gt;)&lt;br&gt;
A real developer knows family is more important than computers. (by
&lt;a href=&#34;http://twitter.com/#!/shanselman&#34;&gt;@shanselman&lt;/a&gt;)&lt;br&gt;
A real developer tries to write as little code as possible. (by
&lt;a href=&#34;http://twitter.com/#!/marknijhof&#34;&gt;@marknijhof&lt;/a&gt;)&lt;br&gt;
A real developer works in the dark, but communicates with those in the
light. (by &lt;a href=&#34;http://twitter.com/#!/atcrawford&#34;&gt;@atcrawford&lt;/a&gt;)&lt;br&gt;
A real developer understands code is nearly the same as an organic
life-form that evolves. (by
&lt;a href=&#34;http://twitter.com/#!/stefandidak&#34;&gt;@stefandidak&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;And so much more of them are awesome.&lt;/p&gt;
&lt;h3 id=&#34;the-future&#34;&gt;The future&lt;/h3&gt;
&lt;p&gt;I enjoyed the experience so far. I&amp;rsquo;m well aware that this buzz will end
soon, but I&amp;rsquo;m going to try to maintain momentum as long as possible.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s why I am eager to hear your suggestions and feedback.&lt;/p&gt;
&lt;p&gt;Requests received so far:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make it possible to up- or downvote quotes.&lt;/li&gt;
&lt;li&gt;Make a smart algorithm based on those votes.&lt;/li&gt;
&lt;li&gt;Make it easier to link to quotes.&lt;/li&gt;
&lt;li&gt;Twitter authentication.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I might open source this little project (it&amp;rsquo;s only 50 lines of code) and
I might do a few blog posts on the making of in the next weeks.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Prague impressions</title>
      <link>https://jefclaes.be/2011/04/prague-impressions.html</link>
      <pubDate>Sun, 24 Apr 2011 15:45:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/04/prague-impressions.html</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/2010/04/trip-report-czech-republic.html&#34;&gt;Last
year&lt;/a&gt;
my girlfriend and I already made a trip to the Czech Republic, but we
felt like we had spent to little time visiting Prague. We made up for
that by making a follow-up trip last week.&lt;/p&gt;
&lt;p&gt;Find some of our most memorable impressions captured on picture
below..&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-04-24-prague-impressions-Praag_166.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-04-24-prague-impressions-Praag_166.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;http://en.wikipedia.org/wiki/Lennon_Wall&#34;&gt;The Lennon Wall&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-04-24-prague-impressions-Praag_179.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-04-24-prague-impressions-Praag_179.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;http://en.wikipedia.org/wiki/Love_padlocks&#34;&gt;Love padlocks&lt;/a&gt; near the
Lennon Wall.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-04-24-prague-impressions-Praag_220.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-04-24-prague-impressions-Praag_220.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
Hiking route in the &lt;a href=&#34;http://en.wikipedia.org/wiki/New_Town,_Prague&#34;&gt;New Town
district&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-04-24-prague-impressions-Praag_229.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-04-24-prague-impressions-Praag_229.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
The &lt;a href=&#34;http://en.wikipedia.org/wiki/Charles_Bridge&#34;&gt;Charles bridge&lt;/a&gt; from a
distance.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-04-24-prague-impressions-Praag_243.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-04-24-prague-impressions-Praag_243.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;http://en.wikipedia.org/wiki/Prague_Astronomical_Clock&#34;&gt;The astronomical
clock&lt;/a&gt; of
Prague.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-04-24-prague-impressions-Praag_245.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-04-24-prague-impressions-Praag_245.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
Hand painting Easter eggs like a boss.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-04-24-prague-impressions-Praag_247.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-04-24-prague-impressions-Praag_247.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
More fairylike Easter festivities.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-04-24-prague-impressions-Praag_350.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-04-24-prague-impressions-Praag_350.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
Close-up of a butterfly, shot in the Prague Fata Morgana.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-04-24-prague-impressions-Praag_395.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-04-24-prague-impressions-Praag_395.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
Night at the &lt;a href=&#34;http://en.wikipedia.org/wiki/National_Technical_Museum_(Prague)&#34;&gt;National Technical
Museum&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-04-24-prague-impressions-Praag_462.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-04-24-prague-impressions-Praag_462.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
Prague by night.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-04-24-prague-impressions-Praag_136.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-04-24-prague-impressions-Praag_136.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
Oh, iPads are for taking pictures.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Anonymous type equality follow-up: Equals()</title>
      <link>https://jefclaes.be/2011/04/anonymous-type-equality-follow-up.html</link>
      <pubDate>Sun, 24 Apr 2011 12:30:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/04/anonymous-type-equality-follow-up.html</guid>
      <description>&lt;p&gt;After publishing &lt;a href=&#34;https://jefclaes.be/2011/04/anonymous-type-equality.html&#34;&gt;yesterday&amp;rsquo;s post on anonymous type
equality&lt;/a&gt;,
I received an interesting comment. The comment stated that
even if the sequence of the property assignment were the same, the
equality comparison would still return false, because the types
generated by the C# compiler are reference types, making their
references being tested for equality and not their data.&lt;/p&gt;
&lt;p&gt;This is very true, unless the &lt;code&gt;Equals()&lt;/code&gt; method is overridden. And this is exactly what the compiler does for us when we define anonymous types.&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2011-04-24-anonymous-type-equality-follow-up-equals-anonymoustypeequals.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-04-24-anonymous-type-equality-follow-up-equals-anonymoustypeequals.PNG&#34;&gt;&lt;/a&gt;&lt;br&gt;
In the &lt;code&gt;Equals()&lt;/code&gt; method the equality of each property is evaluated by
using a &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/ms132123.aspx&#34;&gt;generic EqualityComparer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That explains this behaviour.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; a = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; { x = &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, y = &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; b = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; { y = &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, x = &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; c = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; { x = &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, y = &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Console.WriteLine(a.Equals(b)); &lt;span style=&#34;color:#75715e&#34;&gt;//False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Console.WriteLine(a.Equals(c)); &lt;span style=&#34;color:#75715e&#34;&gt;//True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>Anonymous type equality</title>
      <link>https://jefclaes.be/2011/04/anonymous-type-equality/</link>
      <pubDate>Sat, 23 Apr 2011 15:15:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/04/anonymous-type-equality/</guid>
      <description>&lt;p&gt;Let&amp;rsquo;s say you instantiate two variables (a and b) using &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/bb397696.aspx&#34;&gt;anonymous
types&lt;/a&gt;. They both
have the same two properties (x and y) with equal values.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; a = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; { x = &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, y = &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; b = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; { y = &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, x = &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Do you think they are equal?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Console.WriteLine(a.Equals(b)); &lt;span style=&#34;color:#75715e&#34;&gt;//Prints false :O&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;They are not. Not something I expected!&lt;/p&gt;
&lt;p&gt;If we look at the IL the C# compiler produced, it starts making sense
though.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-04-23-anonymous-type-equality-AnonymousTypeEquality.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-04-23-anonymous-type-equality-AnonymousTypeEquality.PNG&#34;&gt;&lt;/a&gt;&lt;br&gt;
There are two different types generated, although the properties we
assigned are the same. What differs is &lt;strong&gt;the sequence of the property
assignment&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This is defined in chapter &lt;em&gt;7.6.10.6 Anonymous object creation
expressions&lt;/em&gt; of the C# 4.0 specifications.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Within the same program, two anonymous object initializers that
specify a sequence of properties of the same names and compile-time
types in the same order will produce instances of the same anonymous
type.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;When defining anonymous types, the sequence of the property assignment
matters. If the sequence of the property assignment differs, different
types are defined by the C# compiler.&lt;/p&gt;
&lt;p&gt;Also read &lt;a href=&#34;https://jefclaes.be/2011/04/anonymous-type-equality-follow-up.html&#34;&gt;the
follow-up&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Using C# keywords as variables</title>
      <link>https://jefclaes.be/2011/04/using-c-keywords-as-variables.html</link>
      <pubDate>Mon, 11 Apr 2011 19:00:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/04/using-c-keywords-as-variables.html</guid>
      <description>&lt;p&gt;Hold it, don&amp;rsquo;t shoot me. I know this would be an awful practice, but it
is an interesting C# compiler quirk nonetheless.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Keywords are predefined reserved identifiers that have special
meanings to the compiler. They cannot be used as identifiers in your
program unless they include @ as a prefix. For example, @if is a legal
identifier but if is not because it is a keyword.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Main(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;[] args) {           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; @if = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;oh my..&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Console.WriteLine(@if);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========
&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    
    <item>
      <title>It&#39;s not how good you are, it&#39;s how good you want to be</title>
      <link>https://jefclaes.be/2011/04/its-not-how-good-you-are-its-how-good.html</link>
      <pubDate>Sun, 10 Apr 2011 20:30:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/04/its-not-how-good-you-are-its-how-good.html</guid>
      <description>&lt;p&gt;This Christmas, my girlfriend and I got this little book called &lt;a href=&#34;http://www.amazon.com/gp/product/0714843377/ref=as_li_tf_tl?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0714843377&#34;&gt;It&amp;rsquo;s
not how good you are, it&amp;rsquo;s how good you want to
be&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This book is mainly directed to (advertisement) designers, but since I
feel that designers and developers do have a few things in common, we
both like to create things, I also read it.&lt;/p&gt;
&lt;p&gt;The content of this book is a collection of &lt;a href=&#34;http://en.wikipedia.org/wiki/Paul_Arden&#34;&gt;Paul Ardens&lt;/a&gt; observations on business and life presented in a &lt;em&gt;very&lt;/em&gt; consumable format. As it turns out, although I am not part of the target audience, a good amount of his thoughts can be applied to software development as well.&lt;/p&gt;
&lt;p&gt;Find a few of these thought-provoking quotes below.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you are involved in something that goes wrong, never blame others.
Blame no one but yourself.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Give away everything you know, and more will come back to you.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Don&amp;rsquo;t look for the next opportunity. The one you have in hand is the
opportunity.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The person who doesn&amp;rsquo;t make mistakes is unlikely to make anything.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;If you get stuck, draw with a different pen.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Don&amp;rsquo;t be afraid to work with the best.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    
    <item>
      <title>Video, slides and source from my WebSockets talk</title>
      <link>https://jefclaes.be/2011/04/video-slides-and-source-from-my-websockets-talk/</link>
      <pubDate>Thu, 07 Apr 2011 21:30:00 +0200</pubDate>
      <guid>https://jefclaes.be/2011/04/video-slides-and-source-from-my-websockets-talk/</guid>
      <description>&lt;p&gt;Yesterday, I gave a talk on WebSockets at HTML5 WebCamps Belgium.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;WebSockets on Fire&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;While the WebSockets API specification is not stable yet, various
browser vendors have already implemented a prototype in their latest
browser versions. Microsoft released their WebSockets prototype in
December 2010. While there is no native implementation of WebSockets
in IE9 just yet, for now they are providing a solution which works
cross-browser, relying on a Silverlight client. Server-side a Windows
Communication Foundation server is made available, which implements
the latest version of the WebSockets protocol.&lt;/p&gt;
&lt;p&gt;In this session, Jef covers the WebSockets fundamentals, demonstrates
a proof of concept that could be used in various fire department web
applications and deep-dives into the code of this proof of concept.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I got &lt;a href=&#34;http://twitter.com/8x3h/statuses/55644413145268224&#34;&gt;a lot of&lt;/a&gt;
&lt;a href=&#34;http://twitter.com/shahways/statuses/55698964598624256&#34;&gt;positive&lt;/a&gt;
&lt;a href=&#34;http://twitter.com/b_d_m/statuses/55725260527505408&#34;&gt;feedback&lt;/a&gt; on
Twitter, which makes me a very happy panda!&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-04-07-video-slides-and-source-from-my-websockets-talk-HappyPanda.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-04-07-video-slides-and-source-from-my-websockets-talk-HappyPanda.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can already find the video of my session on &lt;a href=&#34;http://channel9.msdn.com/Blogs/liese/HTML5-Web-Camp-Belgium-WebSockts-on-Fire&#34;&gt;Channel9&lt;/a&gt;. The slides can be found on &lt;a href=&#34;http://www.slideshare.net/jclaes/websockets-on-fire&#34;&gt;SlideShare&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to play with the demo yourself, you can &lt;a href=&#34;#&#34;&gt;download the
source&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make sure your firewall allows incoming TCP traffic on port 4502&lt;/li&gt;
&lt;li&gt;Deploy the client access policy file to IIS&lt;/li&gt;
&lt;li&gt;Also host the Demo.WebSockets.WebClient in IIS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;More information on installing the WebSockets prototype &lt;a href=&#34;#&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Keeping WebSockets alive</title>
      <link>https://jefclaes.be/2011/03/keeping-websockets-alive.html</link>
      <pubDate>Sat, 12 Mar 2011 17:40:00 +0100</pubDate>
      <guid>https://jefclaes.be/2011/03/keeping-websockets-alive.html</guid>
      <description>&lt;p&gt;The problem with using stateful connections on an imperfect place as the
internet is that connections might drop. The server or an intermediary
can drop the connection due to an idle timeout. Even a temporary problem
at the server or a local network hiccup might kill your connection.&lt;/p&gt;
&lt;p&gt;If you aren&amp;rsquo;t prepared to handle these scenarios, you will not be able
to fully rely on &lt;a href=&#34;http://websocket.org/&#34;&gt;WebSockets&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;a-simple-solution&#34;&gt;A simple solution&lt;/h3&gt;
&lt;p&gt;The simplest solution is checking every few seconds whether the
WebSocket is still opened. This might suffice in a good amount of
scenarios, but a lot of other scenarios require more stable
connectivity.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;(document).&lt;span style=&#34;color:#a6e22e&#34;&gt;ready&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; () {        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;setInterval&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;openWebSocket&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;5000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;openWebSocket&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;websocket&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;readyState&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;undefined&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;websocket&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;readyState&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;keepalives&#34;&gt;Keepalives&lt;/h3&gt;
&lt;p&gt;As mentioned before, the server or an intermediate might drop the
connection when the connection becomes idle. To prevent this, you could
make your server send keepalive messages at predefined intervals.&lt;/p&gt;
&lt;p&gt;I implemented this in the &lt;a href=&#34;https://jefclaes.be/2011/01/html5-rebuilding-websockets-server.html&#34;&gt;HTML5 Labs WCF Server&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-cs&#34; data-lang=&#34;cs&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;                 ConcurrencyMode = ConcurrencyMode.Multiple)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CadSubscriptionService&lt;/span&gt; : WebSocketsService {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; KeepAliveBroadcaster _keepAliveBroadcaster;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; CadSubscriptionService() {           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (_keepAliveBroadcaster == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            _keepAliveBroadcaster = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; KeepAliveBroadcaster();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; OnOpen() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _keepAliveBroadcaster.AddService(&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;base&lt;/span&gt;.OnOpen();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; OnClose(&lt;span style=&#34;color:#66d9ef&#34;&gt;object&lt;/span&gt; sender, EventArgs e) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _keepAliveBroadcaster.RemoveService(&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;base&lt;/span&gt;.OnClose(sender, e);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }     
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;KeepAliveBroadcaster&lt;/code&gt; class maintains a list of connected sessions.
Using a &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.threading.timer.aspx&#34;&gt;Timer&lt;/a&gt; it sends a message to each client every 15 seconds. This should stop the connection from dropping due to an idle timeout.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-cs&#34; data-lang=&#34;cs&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;KeepAliveBroadcaster&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; List&amp;lt;WebSocketsService&amp;gt; _services;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Timer _timer;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; KeepAliveBroadcaster() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _timer = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Timer((o) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (_services == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;lock&lt;/span&gt; (_services) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (_services.Count &amp;gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#66d9ef&#34;&gt;foreach&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; service &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; _services) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        service.Send(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;staying alive!&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }, &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;15000&lt;/span&gt;);              
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; AddService(WebSocketsService service) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (_services == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            _services = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; List&amp;lt;WebSocketsService&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;lock&lt;/span&gt; (_services) {               
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            _services.Add(service);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; RemoveService(WebSocketsService service) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;lock&lt;/span&gt; (_services) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            _services.Remove(service);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;reopening-asap&#34;&gt;Reopening ASAP&lt;/h3&gt;
&lt;p&gt;Something you could also implement is reopening the connection as soon
as it closes.&lt;/p&gt;
&lt;p&gt;Retry opening the connection when the onclose event fires. Think about
limiting the number of retries, or you might end up with an infinite
loop.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;websocket&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;onclose&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;event&lt;/span&gt;) {            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;$&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;#status&amp;#39;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;html&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Socket closed&amp;#39;&lt;/span&gt;);    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;retryOpeningWebSocket&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;retryOpeningWebSocket&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;retries&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;) {            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;setTimeout&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;openWebSocket&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;);            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;retries&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;some-afterthought&#34;&gt;Some afterthought&lt;/h3&gt;
&lt;p&gt;Depending on what type of connectivity you require, these solutions
might not suffice. If you can&amp;rsquo;t afford to lose a single message, you
might want to think about implementing queues at the client and server
to overcome a gap of connection loss. Maybe you even want to implement
some sort of acknowledge messaging. Something for a future post maybe!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Why I still buy real books</title>
      <link>https://jefclaes.be/2011/02/why-i-still-buy-real-books.html</link>
      <pubDate>Tue, 01 Feb 2011 08:30:00 +0100</pubDate>
      <guid>https://jefclaes.be/2011/02/why-i-still-buy-real-books.html</guid>
      <description>&lt;p&gt;As a technology geek, it should be hard to keep ignoring the latest
generation of eReaders (read: &lt;a href=&#34;http://www.amazon.com/gp/product/B002FQJT3Q?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=B002FQJT3Q&#34;&gt;the
Kindle&lt;/a&gt;).
With &lt;a href=&#34;http://blogs.siliconvalley.com/gmsv/2010/01/amazon-updates-kindle-sales-figures-from-lots-to-millions.html&#34;&gt;over three million devices
sold&lt;/a&gt;,
the Kindle has proven that it adds value to people&amp;rsquo;s lives, and that
it&amp;rsquo;s a lot more than just a gadget.&lt;/p&gt;
&lt;p&gt;Some of the most obvious benefits&amp;hellip; You can carry a whole library in
your backpack. The price of an eBook often is substantially less than
the hardcover version. I am far from a Green, but I can&amp;rsquo;t neglect the
fact that no trees need to be chopped down to print an eBook. Reading a
1000+ page book in bed or next to the pool is the opposite of
convenient.&lt;/p&gt;
&lt;p&gt;Sufficient arguments to get a Kindle, but still, I just can&amp;rsquo;t. Like
serial killers &lt;a href=&#34;http://en.wikipedia.org/wiki/Dexter_(TV_series)#Series_outset&#34;&gt;collect trophies of their
victims&lt;/a&gt;,
I want to collect every book I have ever read. Unlike serial killers, I
want to exhibit every trophy. I catch myself regularly halting for a few
minutes when I pass by my bookcase. I love to have a look at the
bookspines and associate the title with the time and place I read the
book. Part of my love for paper books might also be caused by the global
perception that books equal wisdom.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-02-01-why-i-still-buy-real-books-dexterblood.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-02-01-why-i-still-buy-real-books-dexterblood.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Book review: The Art of Non-Conformity</title>
      <link>https://jefclaes.be/2011/01/book-review-art-of-non-conformity.html</link>
      <pubDate>Sat, 22 Jan 2011 14:00:00 +0100</pubDate>
      <guid>https://jefclaes.be/2011/01/book-review-art-of-non-conformity.html</guid>
      <description>&lt;p&gt;The book &lt;a href=&#34;http://www.amazon.com/gp/product/0399536108?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0399536108&#34;&gt;The Art of Non-Conformity: Set Your Own Rules, Live the Life
You Want, and Change the
World&lt;/a&gt;
was written by Chris Guillebeau.&lt;/p&gt;
&lt;p&gt;I learned about this book through Chris&amp;rsquo; blog. He hosts a &lt;a href=&#34;http://chrisguillebeau.com/3x5/&#34;&gt;very popular
blog&lt;/a&gt; where he writes on lifehacking,
entrepreneurship and his goal to travel to each country in the world.&lt;/p&gt;
&lt;p&gt;In this book Chris tries to show the reader that you don&amp;rsquo;t have the live
your life the way other people expect you to. As long as you are open to
new ideas, are dissatisfied with the status quo and are willing to work
hard, you should be able to live the life of your dreams.&lt;/p&gt;
&lt;p&gt;The first part of this book was an eye-opener for me. Once you find
something that you really enjoy doing, your passion, make a commitment
and be dedicated to use it to make a positive change. For yourself and
for the world. Don&amp;rsquo;t be afraid to be somehow different, a lot of great
things have been accomplished outside the status quo. If living the life
you want, takes it for you to be unconventional and nonconformist,
overcome your fear, and pursue it.&lt;/p&gt;
&lt;p&gt;In the second and last part of the book, Chris lost most of my interest.
In the second part he shares his personal experience with education,
building an army of followers and financing a noncomformist lifestyle.
The last part of this book is on building a legacy.&lt;/p&gt;
&lt;p&gt;Throughout the book Chris shares his personal stories and aneckdotes.
There are also dozens of stories about other people changing their lifes
for the better. I especially enjoyed the latter. In his personal stories
some of his achievements are repeated throughout the book, which
sometimes gives the impression he wrote the book to brag and to promote
the AONC brand. Another letdown of this book is that some of the advice
isn&amp;rsquo;t useful for most of us. &lt;a href=&#34;http://en.wikipedia.org/wiki/Frequent-flyer_program&#34;&gt;Frequent flyer
miles&lt;/a&gt; anyone?&lt;/p&gt;
&lt;p&gt;I enjoyed the first part of the book &lt;strong&gt;a lot&lt;/strong&gt;. Too bad the other parts
mostly failed in keeping me interested.&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;font-weight:bold;&#34;&gt;My rating: 3/5.&lt;/span&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Book review: Got Fight?</title>
      <link>https://jefclaes.be/2011/01/book-review-got-fight.html</link>
      <pubDate>Sat, 15 Jan 2011 18:00:00 +0100</pubDate>
      <guid>https://jefclaes.be/2011/01/book-review-got-fight.html</guid>
      <description>&lt;p&gt;I rarely review books with non-technical content here, but I just felt
like I had to with this one.&lt;/p&gt;
&lt;p&gt;The book &lt;a href=&#34;http://www.amazon.com/gp/product/0061721727?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0061721727&#34;&gt;Got
Fight?&lt;/a&gt;
was written by &lt;a href=&#34;http://en.wikipedia.org/wiki/Forrest_Griffin&#34;&gt;Forrest
Griffin&lt;/a&gt;, assisted by
Erich Krauss.&lt;/p&gt;
&lt;p&gt;Forrest Griffin is one of the toughest light-heavyweight mixed martial
artists competing in the &lt;a href=&#34;http://uk.ufc.com/&#34;&gt;UFC&lt;/a&gt;. If you are
unfamiliar with MMA and UFC, I encourage you to &lt;a href=&#34;http://www.youtube.com/watch?v=wsUW3x3GSWE&#34;&gt;watch one of the
Forrest Griffin tribute
videos&lt;/a&gt; on Youtube.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2011-01-15-book-review-got-fight-mma_e_griffin-jackson_580.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2011-01-15-book-review-got-fight-mma_e_griffin-jackson_580.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
This book touches several subjects. Forrest talks about the path he
followed to become a professional fighter and what made him who he is
today. Forrest also shares a bunch of advice on fighting and
non-fighting topics. The last part of the book contains a series of
how-to MMA techniques. All these topics are talked together in the form
of &lt;strong&gt;hilarious&lt;/strong&gt;, and sometimes offending (to some of you), ramblings.
After all, the main goal to read this book shouldn&amp;rsquo;t be to learn, but to
be entertained, and &lt;em&gt;maybe&lt;/em&gt; learn something along the way!&lt;/p&gt;
&lt;p&gt;Below you can find some quotes taken from the book, which will probably
tell you a lot more than my small summary above.&lt;/p&gt;
&lt;h3 id=&#34;forrest-on&#34;&gt;Forrest on..&lt;/h3&gt;
&lt;p&gt;.. sphincter control&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Back in the day, when I first met a chick, there was no way I would
let one rip. I would wait until at least the second or third date
before I introduced her to my Love Potion 109.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;.. advice for the fat and tremendously out-of-shape fighter&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Steroids, steroids, steroids. This magic elixir can replace all forms
of training and will add to your intimidating appearance.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;.. cheating&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When asked about the tactic after the fight, Tito said, &amp;lsquo;If you ain&amp;rsquo;t
cheating, you ain&amp;rsquo;t trying&amp;rsquo;. I would have to agree with him. I would
rather be known as a cheater than a loser. Seriously, I have this deep
hatred of losing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;.. fear&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A black eye will dissapear and a broken nose can be mended. Fear is a
good thing because it keeps you alive, but it becomes so great that it
hinders you from doing what you want, you need to confront it head-on.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;.. eating challenges&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I kept mumbling over and over, &amp;lsquo;Oh God, I made a mistake&amp;rsquo;, and
vociferously promised sweet baby Jesus I would never accept an eating
challenge again.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;.. being humble&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Although it can be depressing to admit to yourself that you will never
be the best, it is liberating at the same time. Instead of trying to
be better than everyone else, which is existentially arrogant, you can
focus on being the best that you can be.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;My rating: 4/5&lt;/strong&gt;. This is probably the funniest book I have ever
read.&lt;/p&gt;
&lt;p&gt;Photo credit: &lt;a href=&#34;http://sports.espn.go.com/&#34;&gt;ESPN&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Book review: Pro HTML5 Programming</title>
      <link>https://jefclaes.be/2011/01/book-review-pro-html5-programming.html</link>
      <pubDate>Thu, 06 Jan 2011 14:30:00 +0100</pubDate>
      <guid>https://jefclaes.be/2011/01/book-review-pro-html5-programming.html</guid>
      <description>&lt;p&gt;The &lt;a href=&#34;http://apress.com/&#34;&gt;Apress&lt;/a&gt; book &lt;a href=&#34;http://www.amazon.com/gp/product/1430227907?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=1430227907&#34;&gt;Pro HTML5
Programming&lt;/a&gt;
was written by three authors: &lt;a href=&#34;http://runlaketahoe.blogspot.com/&#34;&gt;Peter
Lubbers&lt;/a&gt;, Brian Albers and &lt;a href=&#34;http://www.franksalim.com/&#34;&gt;Frank
Salim&lt;/a&gt;. In this book the authors introduce
the reader to the most popular and useful features of HTML5.&lt;/p&gt;
&lt;p&gt;The book contains 11 concise chapters: An overview of HTML5, the Canvas
API, audio and video, the Geolocation API, the Communication API, the
WebSocket API, Forms, the Web Workers API, the Web Storage API, Offline
Web Applications and the future of HTML5.&lt;/p&gt;
&lt;p&gt;This book succeeds in breaking the myth that HTML5 will not be
applicable until 2022. The authors demonstrate this by accompanying all
theory with a ton of examples based on realistic scenarios. The examples
are not to complex, and most of the time, cut in well sized pieces,
which makes them easy to digest. The authors show you how to detect
whether a certain feature is supported by the hosting browser. They do
not provide information on fallback mechanismes though, which I think is
a good thing, because it would only break the tight scoping of the
book.&lt;/p&gt;
&lt;p&gt;Developers who are new to HTML and JavaScript should pick up
&lt;a href=&#34;http://www.amazon.com/gp/product/1590597273?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=1590597273&#34;&gt;other&lt;/a&gt;
&lt;a href=&#34;http://www.amazon.com/gp/product/0321430840?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0321430840&#34;&gt;books&lt;/a&gt;
first, some experience with client-side webdevelopement is adviced.&lt;/p&gt;
&lt;p&gt;I think this book is a good read and can serve as an excellent
introduction to HTML5. You should &lt;a href=&#34;http://www.amazon.com/gp/product/1430227907?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=1430227907&#34;&gt;get
it&lt;/a&gt;
before it&amp;rsquo;s obsolete ;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;My rating: 4/5.&lt;/strong&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Reviewing and renewing resolutions</title>
      <link>https://jefclaes.be/2010/12/reviewing-and-renewing-resolutions.html</link>
      <pubDate>Wed, 29 Dec 2010 20:17:00 +0100</pubDate>
      <guid>https://jefclaes.be/2010/12/reviewing-and-renewing-resolutions.html</guid>
      <description>&lt;h3 id=&#34;my-career&#34;&gt;My career&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;m still working on the same projects as I was last year: Firestation
Antwerp and Ghent. This year we did not build a lot of brand new things,
but we have added a decent amount of new functionalities. Next to that
there were a bunch of bugs to fix and technical debt to pay off. I
learned a lot from the mistakes we made and refactoring makes you really
think about what good and clean code should look like.&lt;/p&gt;
&lt;p&gt;In 2011 I will still be spending time on Firestation Antwerp and Ghent.
There is a hazy bright light on the horizon though, chances are there is
a new interesting challenge ahead.&lt;/p&gt;
&lt;p&gt;This year I had some fun side-challenges. I gave internal technical
sessions on ASP.NET 4 &amp;amp; ASP.NET AJAX, something I enjoyed doing more than I thought. I also passed the MCTS 70-536 exam, which I didn&amp;rsquo;t enjoy studying for that much. In 2011 I want to pass at least one MCTS ASP.NET exam, and give more technical sessions.&lt;/p&gt;
&lt;h3 id=&#34;blog&#34;&gt;Blog&lt;/h3&gt;
&lt;p&gt;I have written 62 posts this year. Not as much as I would have liked to. There are several reasons I didn&amp;rsquo;t produce more content. I have had a technology hiatus this summer, because I was just too busy with other life stuff. Next to that, I have been working on a side-project and have been studying for the MCTS 70-356 exam. A lot of excuses, but I plan to make up for it in 2011.&lt;/p&gt;
&lt;p&gt;I am pretty satisfied with the qualtiy I produced this year, although
there is a lot of room for improvement. I like to think a good metric
for quality is the number of visitors and retweets. I got double the
traffic compared to last year, which makes me feel a little warm
inside.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-12-29-reviewing-and-renewing-resolutions-blogtraffic.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-12-29-reviewing-and-renewing-resolutions-blogtraffic.PNG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This year I mainly blogged about Webforms (refactoring), ASP.NET AJAX,
the Bing API, TechEd, IE9 and HTML5. In 2011 I plan to continue to focus
on Microsoft and the web. I&amp;rsquo;m still an MVC and WebMatrix novice, which
needs to change next year.&lt;/p&gt;
&lt;h3 id=&#34;community&#34;&gt;Community&lt;/h3&gt;
&lt;p&gt;Last year I planned on being more active on StackOverflow, but I failed
miserably. I don&amp;rsquo;t think I will be making this a goal this year. I&amp;rsquo;m
just going to continue to go there for questions only.&lt;/p&gt;
&lt;p&gt;I also planned on going to a big event in 2010, which turned out to be
TechEd Europe. Seriously, I could hang around there an entire month.&lt;/p&gt;
&lt;p&gt;In being part of the Belgian .NET community I was less successful. I
have been talking a lot with other Belgian developers through blogs and
Twitter, but I should attend more real-life events. With the
DrinksWithDevs community &lt;a href=&#34;http://davybrion.com/blog/&#34;&gt;Davy Brion&lt;/a&gt; is
starting, I think I might be doing better this year.&lt;/p&gt;
&lt;h3 id=&#34;travelling&#34;&gt;Travelling&lt;/h3&gt;
&lt;p&gt;One of the goals I&amp;rsquo;m totally satisfied about.&lt;/p&gt;
&lt;p&gt;Next to citytripping in Belgium, I was lucky enough to travel abroad 5
times this year:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://jefclaes.be/2010/04/trip-report-czech-republic.html&#34;&gt;Czech Republic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://jefclaes.be/2010/07/tripping-in-holland-honey-who-shrunk.html&#34;&gt;Holland&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://jefclaes.be/2010/10/trip-report-denmark-part-2.html&#34;&gt;Denmark&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Spain&lt;/li&gt;
&lt;li&gt;Germany (TechEd)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are no plans for next year (yet), but I don&amp;rsquo;t think I will be able
to do much better.&lt;/p&gt;
&lt;h3 id=&#34;sporthealth&#34;&gt;Sport/Health&lt;/h3&gt;
&lt;p&gt;This is a new section in this year&amp;rsquo;s report. Sport has become more and
more important to me over the years. Next to going to the gym and
running, I picked up boxing this September.&lt;/p&gt;
&lt;p&gt;In the next year I want to focus more on conditioning and less on
strength. It&amp;rsquo;s hard to set a specific goal right now, because I haven&amp;rsquo;t
measured the speed and distance of my runs this year. For Christmas I
got the &lt;a href=&#34;http://www.amazon.com/gp/product/B002FEK400?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=B002FEK400&#34;&gt;Nike+ iPod gear&lt;/a&gt;, so that should help me to collect some data the following months.&lt;/p&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;This year had its ups and downs. Not a lot of exciting things happened
at work, but 2011 should change that. I am overall content with the
progress of my blog, although I think I should do better next year. I
should be very satisfied with the travelling I did this year, I have
spent more than a month abroad! I think I improved my health noticeably
this year, I hope I stay injury-free and can put enough effort in to
keep on improving my conditioning.&lt;/p&gt;
&lt;p&gt;All by all 2010 was a good year and I hope 2011 will be at least as
good. And to be honest, I don&amp;rsquo;t mind not being able to accomplish all
goals, because the love of my family and friends compensates a lot. That
was cheesy, right?&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>HTML5: Exception handling with the Geolocation API</title>
      <link>https://jefclaes.be/2010/12/html5-exception-handling-with.html</link>
      <pubDate>Sun, 26 Dec 2010 20:30:00 +0100</pubDate>
      <guid>https://jefclaes.be/2010/12/html5-exception-handling-with.html</guid>
      <description>&lt;p&gt;In &lt;a href=&#34;https://jefclaes.be/2010/12/html5-geolocation-api-is-scary-good.html&#34;&gt;my previous post&lt;/a&gt; on the &lt;a href=&#34;http://dev.w3.org/geo/api/spec-source.html&#34;&gt;Geolocation API&lt;/a&gt; I passed in a &lt;code&gt;PositionErrorCallback&lt;/code&gt; to the &lt;a href=&#34;http://dev.w3.org/geo/api/spec-source.html#geolocation_interface&#34;&gt;geolocation.getCurrentPosition()&lt;/a&gt; method. When I received this callback I displayed a generic message informing the user something went wrong. In real-world scenarios you probably want the message to be more specific. You might also want to call a specific fallback method depending on what went wrong.&lt;/p&gt;
&lt;p&gt;This is where the &lt;a href=&#34;http://dev.w3.org/geo/api/spec-source.html#position_error_interface&#34;&gt;PositionError&lt;/a&gt; argument of the &lt;code&gt;PositionErrorCallback&lt;/code&gt; comes in handy. This object has two properties: &lt;code&gt;code&lt;/code&gt; and &lt;code&gt;message&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The code property can return three codes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;PERMISSION_DENIED&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;POSITION_UNAVAILABLE&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TIMEOUT&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The message property returns a string describing what went wrong. Be
careful, this property is primarily intended for debugging!&lt;/p&gt;
&lt;h3 id=&#34;example&#34;&gt;Example&lt;/h3&gt;
&lt;p&gt;The codesnippet below only shows the part where I am handling the
&lt;code&gt;PositionErrorCallback&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;onError&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;error&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;content&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; document.&lt;span style=&#34;color:#a6e22e&#34;&gt;getElementById&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;);        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;switch&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;error&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;code&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Something went wrong: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;error&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;message&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;You denied permission to this page to retrieve a location.&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;The browser was unable to determine a location: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;error&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;message&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;message&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;The browser timed out before retrieving the location.&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;content&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;innerHTML&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;message&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>HTML5: The Geolocation API is scary (good)</title>
      <link>https://jefclaes.be/2010/12/html5-geolocation-api-is-scary-good.html</link>
      <pubDate>Sun, 19 Dec 2010 17:30:00 +0100</pubDate>
      <guid>https://jefclaes.be/2010/12/html5-geolocation-api-is-scary-good.html</guid>
      <description>&lt;p&gt;I read about the &lt;a href=&#34;http://dev.w3.org/geo/api/spec-source.html&#34;&gt;HTML5 Geolocation API&lt;/a&gt; in the &lt;a href=&#34;http://www.amazon.com/gp/product/1430227907?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=1430227907&#34;&gt;Pro HTML5 Programming&lt;/a&gt; book a while ago, and decided to play with it on this lazy Sunday.&lt;/p&gt;
&lt;p&gt;Using the Geolocation API to make a one-shot position request is very
straight-forward. Get a reference to the &lt;code&gt;navigator.geolocation&lt;/code&gt; object
and call the &lt;code&gt;getCurrentPosition()&lt;/code&gt; method, passing in at least a
&lt;code&gt;PositionCallback&lt;/code&gt;. In this example I&amp;rsquo;m also passing in a
&lt;code&gt;PositionErrorCallback&lt;/code&gt;. In the &lt;code&gt;PositionCallback&lt;/code&gt; you can examine the
properties of the &lt;code&gt;position&lt;/code&gt; object. Here I am only using the &lt;code&gt;latitude&lt;/code&gt; and &lt;code&gt;longitude&lt;/code&gt; properties.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;showLocation&lt;/span&gt;() {                       
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;navigator&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;geolocation&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;navigator&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;geolocation&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;getCurrentPosition&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;onSuccess&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;onError&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;content&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; document.&lt;span style=&#34;color:#a6e22e&#34;&gt;getElementById&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;);        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;content&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;innerHTML&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Geolocation is not supported by your browser!&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }                
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;onSuccess&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;position&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;content&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; document.&lt;span style=&#34;color:#a6e22e&#34;&gt;getElementById&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;);        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;content&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;innerHTML&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;position&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;coords&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;latitude&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;, &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;position&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;coords&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;longitude&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;onError&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;error&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;content&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; document.&lt;span style=&#34;color:#a6e22e&#34;&gt;getElementById&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;);        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;content&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;innerHTML&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Something went wrong..&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s really easy, right?&lt;/p&gt;
&lt;h3 id=&#34;the-scary-part&#34;&gt;The scary part&lt;/h3&gt;
&lt;p&gt;The privacy part isn&amp;rsquo;t that scary, because the specs state that browsers
must acquire permissions through a user interface. The scary part is,
that it really works and is very accurate even though I&amp;rsquo;m on a desktop
with no known hotspots nearby! After getting the results, I pasted them
in &lt;a href=&#34;http://maps.google.com/&#34;&gt;Google Maps&lt;/a&gt; and they were only a few
meters off. Why is it that while most geolocation services have been
failing over the years, it suddenly works this good?&lt;/p&gt;
&lt;p&gt;There is some documentation out there, but this documentation is very
simplistic and doesn&amp;rsquo;t touch the internals.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;http://www.amazon.com/gp/product/1430227907?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=1430227907&#34;&gt;Pro HTML5 Programming book&lt;/a&gt; lists which sources can be used.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A device can use any of the following sources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IP address&lt;/li&gt;
&lt;li&gt;Coordinate triangulation:
&lt;ul&gt;
&lt;li&gt;Global Positioning System (GPS)&lt;/li&gt;
&lt;li&gt;Wi-Fi with MAC addresses from RFID, Wi-Fi and Bluetooth&lt;/li&gt;
&lt;li&gt;GSM or CDMA cell phone IDs&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;User defined&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;http://www.mozilla.com/en-US/firefox/geolocation/&#34;&gt;FireFox&lt;/a&gt; lets the
Google Location Services assist them.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you consent, Firefox gathers information about nearby wireless
access points and your computer’s IP address. Then Firefox sends this
information to the default geolocation service provider, Google
Location Services, to get an estimate of your location. That location
estimate is then shared with the requesting website.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    
    <item>
      <title>HTML5 selectors and jQuery</title>
      <link>https://jefclaes.be/2010/12/html5-selectors-and-jquery.html</link>
      <pubDate>Sun, 12 Dec 2010 13:09:00 +0100</pubDate>
      <guid>https://jefclaes.be/2010/12/html5-selectors-and-jquery.html</guid>
      <description>&lt;p&gt;In &lt;a href=&#34;https://jefclaes.be/2010/11/html5-new-in-javascript-selector-api.html&#34;&gt;my first post on the HTML5 javascript Selector
API&lt;/a&gt;
I wondered how the new methods &lt;code&gt;querySelector()&lt;/code&gt; and &lt;code&gt;querySelectorAll()&lt;/code&gt;
would influence &lt;a href=&#34;http://jquery.com/&#34;&gt;jQuery&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At the time, I couldn&amp;rsquo;t find any information on the subject, but
yesterday I found out that jQuery has been taking advantage of these new
methods since version &lt;code&gt;1.4.3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;From the &lt;a href=&#34;http://blog.jquery.com/2010/10/16/jquery-143-released/&#34;&gt;release notes&lt;/a&gt;..&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The performance of nearly all the major traversal methods has been
drastically improved. .closest(), .filter() (and as a result, .is()),
and .find() have all been greatly improved.&lt;/p&gt;
&lt;p&gt;These improvements were largely the result of making greater use of
the browsers querySelectorAll and matchesSelector methods (should they
exist). The jQuery project petitioned the browsers to add the new
matchesSelector method (writing up a test suite, talking with vendors,
and filing bugs) and the whole community gets to reap the excellent
performance benefits now.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-12-12-html5-selectors-and-jquery-jqueryClosestResults.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-12-12-html5-selectors-and-jquery-jqueryClosestResults.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-12-12-html5-selectors-and-jquery-jQueryFilterResult.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-12-12-html5-selectors-and-jquery-jQueryFilterResult.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-12-12-html5-selectors-and-jquery-jqueryFindResults.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-12-12-html5-selectors-and-jquery-jqueryFindResults.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
The above performance results specifically look at three very common
cases in jQuery code: Using .closest() on a single DOM node, using
.filter() (or .is()) on a single DOM node, and using .find() rooted on
a DOM element (e.g. $(“#test”).find(“something”)).&lt;/p&gt;
&lt;p&gt;Note that the the browsers shown are those that actually support
querySelectorAll or matchesSelector – existing browsers that don’t
support those methods continue to have the same performance
characteristics.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Looks like it&amp;rsquo;s not a bad idea to keep an eye on the release notes..&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>HTML5: Drawing images to the canvas gotcha</title>
      <link>https://jefclaes.be/2010/12/html5-drawing-images-to-canvas-gotcha.html</link>
      <pubDate>Sun, 05 Dec 2010 19:55:00 +0100</pubDate>
      <guid>https://jefclaes.be/2010/12/html5-drawing-images-to-canvas-gotcha.html</guid>
      <description>&lt;p&gt;While I was playing with the &lt;a href=&#34;http://www.w3.org/TR/html5/the-canvas-element.html&#34;&gt;Canvas
API&lt;/a&gt; I came across a
weird issue: I was trying to draw an image to the canvas, but the image
failed to render very often.&lt;/p&gt;
&lt;p&gt;Have a look at the source. Do you spot the problem?&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;html&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;head&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;title&lt;/span&gt;&amp;gt;HTML5: Canvas&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;title&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;type&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt;&amp;gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            window.&lt;span style=&#34;color:#a6e22e&#34;&gt;addEventListener&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;load&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;draw&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;draw&lt;/span&gt;(){                            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;canvas&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; document.&lt;span style=&#34;color:#a6e22e&#34;&gt;getElementById&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;canvas&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;canvas&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;getContext&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;2d&amp;#39;&lt;/span&gt;);    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;img&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Image&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;img&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;logo.png&amp;#34;&lt;/span&gt;;                
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;drawImage&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;img&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;);                
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;script&lt;/span&gt;&amp;gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;head&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;canvas&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;canvas&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;height&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;500&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;width&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;500&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Looks like canvas isn&amp;#39;t supported in your browser! 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;canvas&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;html&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It wasn&amp;rsquo;t until I opened &lt;a href=&#34;http://getfirebug.com/&#34;&gt;Firebug&lt;/a&gt; and saw an
unhandled exception in the console that I discovered what was going
on.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;uncaught exception: \[Exception... &amp;#34;Component returned failure code:
0x80040111 (NS\_ERROR\_NOT\_AVAILABLE)
\[nsIDOMCanvasRenderingContext2D.drawImage\]&amp;#34; nsresult: &amp;#34;0x80040111
(NS\_ERROR\_NOT\_AVAILABLE)&amp;#34; location: &amp;#34;JS frame :: file:///....html
:: draw :: line 15&amp;#34; data: no\]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Browsers load images asynchronously while scripts are already being
interpreted and executed. If the image isn&amp;rsquo;t fully loaded the canvas
fails to render it. Turns out the &lt;em&gt;weird&lt;/em&gt; issue, is pretty logical.&lt;/p&gt;
&lt;p&gt;Luckily this isn&amp;rsquo;t hard to resolve. We just have to wait to start
drawing until we receive a callback from the image, notifying loading
has completed.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;window.&lt;span style=&#34;color:#a6e22e&#34;&gt;addEventListener&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;load&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;draw&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;draw&lt;/span&gt;(){                                    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;img&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Image&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;img&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;logo.png&amp;#34;&lt;/span&gt;;                
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;img&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;onload&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;canvas&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; document.&lt;span style=&#34;color:#a6e22e&#34;&gt;getElementById&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;canvas&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;canvas&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;getContext&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;2d&amp;#39;&lt;/span&gt;);    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;drawImage&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;img&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;);        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}                    
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Et voila!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>HTML5: More on selectors</title>
      <link>https://jefclaes.be/2010/12/html5-more-on-selectors.html</link>
      <pubDate>Sun, 05 Dec 2010 13:15:00 +0100</pubDate>
      <guid>https://jefclaes.be/2010/12/html5-more-on-selectors.html</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/2010/11/html5-new-in-javascript-selector-api.html&#34;&gt;Last weekend I blogged&lt;/a&gt; on new addittions to the javascript Selector API: &lt;code&gt;querySelector()&lt;/code&gt; and
&lt;code&gt;querySelectorAll()&lt;/code&gt;. These two new methods enable you to find elements by
matching against a group of selectors. I only scratched the surface in
the previous post, that&amp;rsquo;s why you can find a few more examples in this
post. These examples should demonstrate the power and ease of use of the
new Selector API features. It&amp;rsquo;s impossible to show you all of the
selectors usages in just one post, that&amp;rsquo;s why I strongly encourage you
to have a look at the &lt;a href=&#34;http://www.w3.org/TR/css3-selectors/&#34;&gt;W3C Selectors
specifications&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-12-05-html5-more-on-selectors-aspnethomepageplusdevtools.PNG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-12-05-html5-more-on-selectors-aspnethomepageplusdevtools.PNG&#34;&gt;&lt;/a&gt;&lt;br&gt;
I experimented on the &lt;a href=&#34;http://www.asp.net/&#34;&gt;asp.net homepage&lt;/a&gt; using the
&lt;a href=&#34;http://msdn.microsoft.com/en-us/ie/aa740478.aspx&#34;&gt;IE9 developer
tools&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;attribute-selectors&#34;&gt;Attribute selectors&lt;/h3&gt;
&lt;p&gt;Select all elements which have an attribute named &lt;em&gt;title&lt;/em&gt;.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;document.querySelectorAll(&amp;#39;[title]&amp;#39;);
[object] {
    length : 5,
    0 : http://www.asp.net/,
    1 : [object HTMLImageElement],
    2 : http://www.asp.net/get-started,
    3 : http://www.asp.net/downloads,
    4 : http://www.asp.net/rss/spotlight
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Select all elements where the &lt;em&gt;title&lt;/em&gt; attribute has the value set to
&lt;em&gt;Rss&lt;/em&gt;.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;document.querySelectorAll(&amp;#39;[title=Rss]&amp;#39;);
[object] {
    length : 1,
    0 : http://www.asp.net/rss/spotlight
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Select all elements where the &lt;em&gt;href&lt;/em&gt; attribute is set to
&lt;code&gt;http://umbraco.org/&lt;/code&gt; and where the &lt;em&gt;target&lt;/em&gt; attribute is set to
_blank.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;document.querySelectorAll(&amp;#39;[href=&amp;#34;http://umbraco.org/&amp;#34;][target=&amp;#34;_blank&amp;#34;]&amp;#39;);
[object] {
    length : 1,
    0 : http://umbraco.org/
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Select all elements where the &lt;em&gt;href&lt;/em&gt; attribute contains &lt;em&gt;umbraco&lt;/em&gt;.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;document.querySelectorAll(&amp;#39;[href*=&amp;#34;umbraco&amp;#34;]&amp;#39;);
[object] {
    length : 3,
    0 : [object HTMLLinkElement],
    1 : [object HTMLLinkElement],
    2 : http://umbraco.org/
}
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;class-selectors&#34;&gt;Class selectors&lt;/h3&gt;
&lt;p&gt;Find the first element where the &lt;em&gt;class&lt;/em&gt; is set to &lt;em&gt;.search_box&lt;/em&gt;.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;document.querySelector(&amp;#39;.search_box&amp;#39;)

[object HTMLInputElement] {
    jQuery1291484082884 : 1,
    align : &amp;#34;&amp;#34;,
    border : &amp;#34;&amp;#34;,
    hspace : 0,
    vspace : 0,
    accept : &amp;#34;&amp;#34;,
    alt : &amp;#34;&amp;#34;,
    checked : false,
    defaultChecked : false,
    defaultValue : &amp;#34;Search&amp;#34;
    ...
}
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;id-selectors&#34;&gt;Id selectors&lt;/h3&gt;
&lt;p&gt;Find the first element with the id &lt;em&gt;#WLSearchBoxInput&lt;/em&gt;.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;document.querySelector(&amp;#39;#WLSearchBoxInput&amp;#39;)

[object HTMLInputElement] {
    jQuery1291484082884 : 1,
    align : &amp;#34;&amp;#34;,
    border : &amp;#34;&amp;#34;,
    hspace : 0,
    vspace : 0,
    accept : &amp;#34;&amp;#34;,
    alt : &amp;#34;&amp;#34;,
    checked : false,
    defaultChecked : false,
    defaultValue : &amp;#34;Search&amp;#34;
    ...
}
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;pseudo-classes&#34;&gt;Pseudo classes&lt;/h3&gt;
&lt;p&gt;Select the first hyperlink that is being hovered over.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;document.querySelector(&amp;#39;a:hover&amp;#39;)

http://umbraco.org/ {
    charset : &amp;#34;&amp;#34;,
    coords : &amp;#34;&amp;#34;,
    hash : &amp;#34;&amp;#34;,
    host : &amp;#34;umbraco.org:80&amp;#34;,
    hostname : &amp;#34;umbraco.org&amp;#34;,
    href : &amp;#34;http://umbraco.org/&amp;#34;,
    hreflang : &amp;#34;&amp;#34;,
    name : &amp;#34;&amp;#34;,
    pathname : &amp;#34;&amp;#34;,
    port : &amp;#34;80&amp;#34;
    ...
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Select the third child element from the first element with the class
&lt;em&gt;.welcom_nav&lt;/em&gt;.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;document.querySelector(&amp;#39;.welcome_nav:nth-child(3)&amp;#39;)
    
    type : &amp;#34;&amp;#34;,
    compact : false,
    currentStyle : [object MSCurrentStyleCSSProperties],
    runtimeStyle : [object MSStyleCSSProperties],
    accessKey : &amp;#34;&amp;#34;,
    className : &amp;#34;welcome_nav&amp;#34;,
    contentEditable : &amp;#34;inherit&amp;#34;,
    dir : &amp;#34;&amp;#34;,
    disabled : false,
    id : &amp;#34;&amp;#34;
    ...
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As you can see searching for elements with native javascript has become
a lot easier. I tried to show some examples which can be applied to real
life scenarios. Examples based on more complex scenarios can be found in
the &lt;a href=&#34;http://www.w3.org/TR/css3-selectors/&#34;&gt;W3C Selectors
specifications&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>HTML5: New in the javascript Selector API</title>
      <link>https://jefclaes.be/2010/11/html5-new-in-javascript-selector-api.html</link>
      <pubDate>Mon, 29 Nov 2010 19:30:00 +0100</pubDate>
      <guid>https://jefclaes.be/2010/11/html5-new-in-javascript-selector-api.html</guid>
      <description>&lt;p&gt;Because I finally got the MCTS 70-536 certification out of the way, I
can start experimenting with some fun stuff again. One of the things on
the top of my list is HTML5. I started reading the book &lt;a href=&#34;http://www.amazon.com/gp/product/1430227907?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=1430227907&#34;&gt;Pro HTML5 Programming&lt;/a&gt;, so expect more posts on HTML5 in the near future.&lt;/p&gt;
&lt;p&gt;In this post I will show you two new methods in the javascript Selector
API which are extremely useful to find elements.&lt;/p&gt;
&lt;h3 id=&#34;specificiations&#34;&gt;Specificiations&lt;/h3&gt;
&lt;p&gt;Methods we can now use to find elements are
&lt;a href=&#34;https://developer.mozilla.org/en/document.getElementById&#34;&gt;getElementById()&lt;/a&gt;,
&lt;a href=&#34;https://developer.mozilla.org/en/DOM/document.getElementsByName&#34;&gt;getElementsByName()&lt;/a&gt;
and
&lt;a href=&#34;https://developer.mozilla.org/en/DOM/document.getElementsByTagName&#34;&gt;getElementsByTagName&lt;/a&gt;().
In HTML5 there are two new methods in the Selector API: querySelector()
and querySelectorAll(). These new methods find elements by matching
against a group of
&lt;a href=&#34;http://www.w3.org/TR/css3-selectors/#link&#34;&gt;selectors&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Their description as in the &lt;a href=&#34;http://www.w3.org/TR/selectors-api/&#34;&gt;W3C
specifications&lt;/a&gt; is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The querySelector() method on the NodeSelector interface must, when
invoked, return the first matching Element node within the node’s
subtrees. If there is no such node, the method must return null.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The querySelectorAll() method on the NodeSelector interface must, when
invoked, return a NodeList containing all of the matching Element
nodes within the node’s subtrees, in document order. If there are no
such nodes, the method must return an empty NodeList.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;throwing-out-some-feelers&#34;&gt;Throwing out some feelers&lt;/h3&gt;
&lt;p&gt;To play with these new methods I made a simple page which displays an
unordered list of methods in the Selector API. Existing methods have the
class &lt;strong&gt;exists&lt;/strong&gt; and new methods have the class &lt;strong&gt;new&lt;/strong&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;html&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;head&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;title&lt;/span&gt;&amp;gt;HTML5: Selector API&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;title&lt;/span&gt;&amp;gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;head&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;content&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;ul&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;methodslist&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;li&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;exists&amp;#34;&lt;/span&gt;&amp;gt;getElementById&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;li&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;exists&amp;#34;&lt;/span&gt;&amp;gt;getElementsByName&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;li&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;exists&amp;#34;&lt;/span&gt;&amp;gt;getElementsByTagName&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;li&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;new&amp;#34;&lt;/span&gt;&amp;gt;[NEW] querySelector&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;li&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;new&amp;#34;&lt;/span&gt;&amp;gt;[NEW] querySelectorAll&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;li&lt;/span&gt;&amp;gt;   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;ul&lt;/span&gt;&amp;gt;            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;html&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To select the first new method we can use the &lt;code&gt;querySelector()&lt;/code&gt; method
with the &lt;strong&gt;li.new&lt;/strong&gt; Selector. The first matching element is returned.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;selectFirstNewMethod&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;firstNewMethod&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; document.&lt;span style=&#34;color:#a6e22e&#34;&gt;querySelector&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;li.new&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;firstNewMethod&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;style&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;color&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Red&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To select all new methods we can use the &lt;code&gt;querySelectorAll()&lt;/code&gt; method with
the &lt;strong&gt;li.new&lt;/strong&gt; Selector. All matching elements are returned.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;selectAllNewMethods&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;allNewMethods&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; document.&lt;span style=&#34;color:#a6e22e&#34;&gt;querySelectorAll&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;li.new&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;allNewMethods&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;allNewMethods&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;].&lt;span style=&#34;color:#a6e22e&#34;&gt;style&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;color&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Blue&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To select all methods (existing and new) we can use the
&lt;code&gt;querySelectorAll()&lt;/code&gt; method with the &lt;strong&gt;li.exists, li.new&lt;/strong&gt; Selector.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;selectExistingAndNewMethods&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;existingAndNewMethods&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; document.&lt;span style=&#34;color:#a6e22e&#34;&gt;querySelectorAll&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;li.exists, li.new&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;existingAndNewMethods&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;existingAndNewMethods&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;].&lt;span style=&#34;color:#a6e22e&#34;&gt;style&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;color&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Yellow&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These examples just demonstrate the tip of the iceberg. Check out the
&lt;a href=&#34;http://www.w3.org/TR/css3-selectors/#link&#34;&gt;Selectors specifications&lt;/a&gt; to
see how they can be used to greatly improve the way of finding elements
in the DOM.&lt;/p&gt;
&lt;h3 id=&#34;the-html5-selector-api-and-jquery&#34;&gt;The HTML5 Selector API and jQuery?&lt;/h3&gt;
&lt;p&gt;I am far from a &lt;a href=&#34;http://jquery.com/&#34;&gt;jQuery&lt;/a&gt; or javascript expert, so I
wonder: how will these methods and selectors influence jQuery? Will they
be encapsulated into jQuery, because I can imagine that these natively
implemented methods will be a few times faster than &lt;a href=&#34;http://api.jquery.com/category/selectors/&#34;&gt;jQuery
Selectors&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edit:&lt;/strong&gt; querySelectorAll is being used by jQuery since version 1.4.3.
(&lt;a href=&#34;http://stackoverflow.com/questions/4038878/jquery-will-not-exist-in-future&#34;&gt;Source&lt;/a&gt;).&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Trip Report Denmark (Part 2)</title>
      <link>https://jefclaes.be/2010/10/trip-report-denmark-part-2.html</link>
      <pubDate>Thu, 14 Oct 2010 15:30:00 +0200</pubDate>
      <guid>https://jefclaes.be/2010/10/trip-report-denmark-part-2.html</guid>
      <description>&lt;p&gt;If you missed the first part of this trip report, you can find it
&lt;a href=&#34;https://jefclaes.be/2010/10/trip-report-denmark-part-1.html&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;funen&#34;&gt;Funen&lt;/h3&gt;
&lt;p&gt;After three days of Copenhagen we stayed at
&lt;a href=&#34;http://en.wikipedia.org/wiki/Funen&#34;&gt;Funen&lt;/a&gt; for two days. This is the
smallest of the three big islands of Denmark. Our motel was in a small
town called Faaborg.&lt;/p&gt;
&lt;p&gt;During these two days in Funen the most impressive attraction we went to
see was the &lt;a href=&#34;http://en.wikipedia.org/wiki/Egeskov_Castle&#34;&gt;Egeskov
Castle&lt;/a&gt;. This castle is
Europe&amp;rsquo;s best preserved Renaissance water castle. You can also walk
around in the big park surrounding the castle, or visit the five museums
on the Egeskov domain. The vintage automobile and motorcycle museums are
awesome!&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-14-trip-report-denmark-part-2-Faaborg_068.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-14-trip-report-denmark-part-2-Faaborg_068.JPG&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-14-trip-report-denmark-part-2-Faaborg_103.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-14-trip-report-denmark-part-2-Faaborg_103.JPG&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-14-trip-report-denmark-part-2-Faaborg_111.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-14-trip-report-denmark-part-2-Faaborg_111.JPG&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-14-trip-report-denmark-part-2-Faaborg_112.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-14-trip-report-denmark-part-2-Faaborg_112.JPG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;jutland&#34;&gt;Jutland&lt;/h3&gt;
&lt;p&gt;The last three days of our trip we stayed at the biggest island
(peninsula) of Denmark,
&lt;a href=&#34;http://en.wikipedia.org/wiki/Jutland&#34;&gt;Jutland&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here we visited the &lt;a href=&#34;http://en.wikipedia.org/wiki/Ribe&#34;&gt;oldest city of
Denmark&lt;/a&gt;, went hiking and strolled
the cleanest beaches in Europe. A perfect place to relax and find new
energy.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-14-trip-report-denmark-part-2-Blaavand_020.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-14-trip-report-denmark-part-2-Blaavand_020.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-14-trip-report-denmark-part-2-Blaavand_036.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-14-trip-report-denmark-part-2-Blaavand_036.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-14-trip-report-denmark-part-2-Blaavand_066.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-14-trip-report-denmark-part-2-Blaavand_066.JPG&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-14-trip-report-denmark-part-2-Blaavand_143.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-14-trip-report-denmark-part-2-Blaavand_143.JPG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;This trip was amazing. From Copenhagen to Jutland, this country has
surprised me hundreds of times. We got the best out of Denmark&amp;rsquo;s culture
and history in Copenhagen, and enjoyed the beauty of Denmark&amp;rsquo;s nature in
Funen and Jutland. Summarized Denmark has it all!&lt;/p&gt;
&lt;p&gt;One small drawback is that Denmark isn&amp;rsquo;t cheap. Everything is twice as
expensive compared to Belgium. Although with some good looking around
you can save a lot.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Trip Report Denmark (Part 1)</title>
      <link>https://jefclaes.be/2010/10/trip-report-denmark-part-1.html</link>
      <pubDate>Wed, 13 Oct 2010 20:30:00 +0200</pubDate>
      <guid>https://jefclaes.be/2010/10/trip-report-denmark-part-1.html</guid>
      <description>&lt;p&gt;Last month me and my
girlfriend went on a holiday
to &lt;a href=&#34;http://en.wikipedia.org/wiki/Denmark&#34;&gt;Denmark&lt;/a&gt; for a week. We had a
great time, visited a lot of places and took hundreds of pictures. In
this post you can find a trip report containing the best pictures and
tips on places to see.&lt;/p&gt;
&lt;h3 id=&#34;copenhagen&#34;&gt;Copenhagen&lt;/h3&gt;
&lt;p&gt;The first three days of this holiday we visited
&lt;a href=&#34;http://en.wikipedia.org/wiki/Copenhagen&#34;&gt;Copenhagen&lt;/a&gt;. These three days
were the most interesting, but also the most intensive days of the
holiday. There are so many places to visit in Copenhagen!&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-13-trip-report-denmark-part-1-Kopenhagen_157.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-13-trip-report-denmark-part-1-Kopenhagen_157.JPG&#34;&gt;&lt;/a&gt;&lt;br&gt;
If you are in Copenhagen to do some sightseeing I advice you to get
yourself a &lt;a href=&#34;http://www.visitcopenhagen.com/tourist/what_to_see_and_do/copenhagen_card/where_to_buy_copenhagen_card&#34;&gt;Copenhagen
card&lt;/a&gt;.
This card is valid for 72 hours and includes entrance fees for almost
all attractions and public transport. And it only costs 63€.&lt;/p&gt;
&lt;h3 id=&#34;ripleys-believe-it-or-not-museum&#34;&gt;Ripley&amp;rsquo;s believe it or not museum&lt;/h3&gt;
&lt;p&gt;Next to the &lt;a href=&#34;http://en.wikipedia.org/wiki/Ripley&#39;s_Believe_It_or_Not!#Television&#34;&gt;TV
show&lt;/a&gt;
hosted by &lt;a href=&#34;http://en.wikipedia.org/wiki/Dean_Cain&#34;&gt;Superman&lt;/a&gt;, there are
Ripley&amp;rsquo;s believe it or not museums spread over the world. Although this
museum isn&amp;rsquo;t a must-see, the bizarre items featured are definitely
entertaining.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-13-trip-report-denmark-part-1-Kopenhagen_057_2.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-13-trip-report-denmark-part-1-Kopenhagen_057_2.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;dansk-design-center&#34;&gt;Dansk Design Center&lt;/h3&gt;
&lt;p&gt;Although this is one of the museums my girlfriend had to drag me to, it
turned out to be not that bad. The UX people out there will find this
very interesting.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-13-trip-report-denmark-part-1-Kopenhagen_069_2.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-13-trip-report-denmark-part-1-Kopenhagen_069_2.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;christianborg&#34;&gt;Christianborg&lt;/h3&gt;
&lt;p&gt;This palace used to be the home of the Danish monarchy. Today
&lt;a href=&#34;http://en.wikipedia.org/wiki/Christiansborg_Palace&#34;&gt;Christianborg&lt;/a&gt; is
the seat of the parliament, the Prime Minister&amp;rsquo;s Office and the Supreme
Court.&lt;/p&gt;
&lt;p&gt;The palace is probably most known for it&amp;rsquo;s turbulent past. It had to be
rebuilt two times due to serious fires.&lt;/p&gt;
&lt;p&gt;A small part of the palace is open to the public. The inside of the
palace is even more impressive than the outside!&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-13-trip-report-denmark-part-1-Kopenhagen_098.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-13-trip-report-denmark-part-1-Kopenhagen_098.JPG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;tivoli&#34;&gt;Tivoli&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;http://en.wikipedia.org/wiki/Tivoli&#34;&gt;Tivoli&lt;/a&gt; is the second oldest
amusement park in the world. It was built over 150 years ago. Although
you can&amp;rsquo;t compare it to Disney World, this is a must-see. If you go
there, I advice you to go by night.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-13-trip-report-denmark-part-1-Kopenhagen_118.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-13-trip-report-denmark-part-1-Kopenhagen_118.JPG&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-13-trip-report-denmark-part-1-Kopenhagen_127.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-13-trip-report-denmark-part-1-Kopenhagen_127.JPG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;zoological-museum&#34;&gt;Zoological Museum&lt;/h3&gt;
&lt;p&gt;In this museum there is a permanent exhibition called From Pole To Pole.
There is also a semi-permanent Darwin exhibition.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-13-trip-report-denmark-part-1-Kopenhagen_159.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-13-trip-report-denmark-part-1-Kopenhagen_159.JPG&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-13-trip-report-denmark-part-1-Kopenhagen_164.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-13-trip-report-denmark-part-1-Kopenhagen_164.JPG&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-13-trip-report-denmark-part-1-Kopenhagen_173.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-13-trip-report-denmark-part-1-Kopenhagen_173.JPG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;copenhagen-zoo&#34;&gt;Copenhagen Zoo&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&#34;http://uk.zoo.dk/VisitZoo.aspx&#34;&gt;Copenhagen Zoo&lt;/a&gt; is definitely worth
a visit. The main reason we wanted to go there is because we wanted to
see a &lt;a href=&#34;http://en.wikipedia.org/wiki/Tasmanian_Devil&#34;&gt;Tasmanian Devil&lt;/a&gt;.
Copenhagen Zoo is the only zoo outside of Australia that has Tasmanian
Devils in captivity. It turned out it didn&amp;rsquo;t totally live up to &lt;a href=&#34;http://en.wikipedia.org/wiki/Tasmanian_Devil_(Looney_Tunes)&#34;&gt;our
expectation.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-13-trip-report-denmark-part-1-Kopenhagen_175.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-13-trip-report-denmark-part-1-Kopenhagen_175.JPG&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-13-trip-report-denmark-part-1-Kopenhagen_183.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-13-trip-report-denmark-part-1-Kopenhagen_183.JPG&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-13-trip-report-denmark-part-1-Kopenhagen_184.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-13-trip-report-denmark-part-1-Kopenhagen_184.JPG&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-13-trip-report-denmark-part-1-Kopenhagen_213.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-13-trip-report-denmark-part-1-Kopenhagen_213.JPG&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-13-trip-report-denmark-part-1-Kopenhagen_233.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-13-trip-report-denmark-part-1-Kopenhagen_233.JPG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The Tasmanian Devil guarding its
territory borders, is not that scary, right?&lt;/p&gt;
&lt;h3 id=&#34;christiania&#34;&gt;Christiania&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;http://en.wikipedia.org/wiki/Freetown_Christiania&#34;&gt;Christiania&lt;/a&gt; is a
special part of Copenhagen. This part of Copenhagen is a self-proclaimed
autonomous neighbourhood. In the seventies a group of hippies founded
this freetown. Although the government tried to turn the situation
around at first, in the late seventies Christiania was tolerated and
considered a social experiment.&lt;/p&gt;
&lt;p&gt;This probably was the weirdest experience of this trip. Soft drugs are
tolerated and publicly sold in Christiania, giving this freetown a very
special atmosphere. People from all around Copenhagen get together here
to smoke, socialize and &lt;span style=&#34;font-style:italic;&#34;&gt;chill&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Too bad taking pictures at Pusher Street isn&amp;rsquo;t allowed.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-13-trip-report-denmark-part-1-Kopenhagen_250_2.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-13-trip-report-denmark-part-1-Kopenhagen_250_2.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-13-trip-report-denmark-part-1-Kopenhagen_253_2.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-13-trip-report-denmark-part-1-Kopenhagen_253_2.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-13-trip-report-denmark-part-1-Kopenhagen_267_2.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-13-trip-report-denmark-part-1-Kopenhagen_267_2.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;rosenborg-castle&#34;&gt;Rosenborg castle&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;http://en.wikipedia.org/wiki/Rosenborg_Castle&#34;&gt;This castle&lt;/a&gt; used to be
a country summerhouse for the monarchy. Today it is a museum exhibiting
the Royal Collection and Crown Jewels.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-13-trip-report-denmark-part-1-Kopenhagen_345.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-13-trip-report-denmark-part-1-Kopenhagen_345.JPG&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-13-trip-report-denmark-part-1-Kopenhagen_333.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-13-trip-report-denmark-part-1-Kopenhagen_333.JPG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;nyhavn&#34;&gt;Nyhavn&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;http://en.wikipedia.org/wiki/Nyhavn&#34;&gt;Nyhaven&lt;/a&gt;, meaning new harbor, is
very popular among tourists. It is best known for its colorful buildings
and cozy restaurants.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-13-trip-report-denmark-part-1-Kopenhagen_378.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-13-trip-report-denmark-part-1-Kopenhagen_378.JPG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;architecture&#34;&gt;Architecture&lt;/h3&gt;
&lt;p&gt;For people with an architectural fetish there are tons of buildings
worth visiting. The ones that impressed me the most are the &lt;a href=&#34;http://en.wikipedia.org/wiki/Royal_Danish_Library&#34;&gt;Black
Diamond&lt;/a&gt; and the &lt;a href=&#34;http://en.wikipedia.org/wiki/Copenhagen_Opera_House&#34;&gt;new
Opera House&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-13-trip-report-denmark-part-1-Kopenhagen_403.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-13-trip-report-denmark-part-1-Kopenhagen_403.JPG&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-10-13-trip-report-denmark-part-1-Kopenhagen_384.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-10-13-trip-report-denmark-part-1-Kopenhagen_384.JPG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Things good to know about SQL State Server</title>
      <link>https://jefclaes.be/2010/09/things-good-to-know-about-sql-state.html</link>
      <pubDate>Thu, 23 Sep 2010 19:31:00 +0200</pubDate>
      <guid>https://jefclaes.be/2010/09/things-good-to-know-about-sql-state.html</guid>
      <description>&lt;p&gt;While installing a &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/ms178586.aspx&#34;&gt;SQL State
Server&lt;/a&gt; last
week, I came across a few things worth sharing about the installation
and use of SQL State Server.&lt;/p&gt;
&lt;h3 id=&#34;finding-a-good-tutorial&#34;&gt;Finding a good tutorial&lt;/h3&gt;
&lt;p&gt;There are lots of tutorials out there on how to install SQL State Server
but most of them are not great. To do a basic installation you only need
this MSDN documentation on how to &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/h6bb9cz9(VS.71).aspx&#34;&gt;run the Aspnet_regsql.exe
tool&lt;/a&gt; and
&lt;a href=&#34;http://msdn.microsoft.com/en-us/library/h6bb9cz9(VS.71).aspx&#34;&gt;edit your
web.config&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;all-the-objects-in-session-need-to-be-serializable&#34;&gt;All the objects in Session need to be serializable&lt;/h3&gt;
&lt;p&gt;If you try to store an object in Session which isn&amp;rsquo;t marked as
serializible an
&lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.web.httpexception.aspx&#34;&gt;HttpException&lt;/a&gt;
will get thrown with following message.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Unable to serialize the session state. In &amp;#39;StateServer&amp;#39; and
&amp;#39;SQLServer&amp;#39; mode, ASP.NET will serialize the session state objects,
and as a result non-serializable objects or MarshalByRef objects are
not permitted. The same restriction applies if similar serialization
is done by the custom session state store in &amp;#39;Custom&amp;#39; mode.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Marking your classes with the &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.serializableattribute.aspx&#34;&gt;Serializible
attribute&lt;/a&gt;
shouldn&amp;rsquo;t be a problem. Be careful when storing WebControls in Session
though, most of these aren&amp;rsquo;t marked as serializible!&lt;/p&gt;
&lt;p&gt;When you are using UpdatePanels this exception doesn&amp;rsquo;t fully propagate
to the front-end. The javascript error shown will have following
message.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Error: Sys.WebForms.PageRequestManagerServerErrorException: An unknown
error occurred while processing the request on the server. The status
code returned from the server was: 500
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;use-the-same-machinekey-on-multiple-servers&#34;&gt;Use the same machinekey on multiple servers&lt;/h3&gt;
&lt;p&gt;To make the SQL State Server work across servers hosting the same
application, you need to make sure the &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/w8h3skw9.aspx&#34;&gt;machineKey
element&lt;/a&gt; in the
machine.config is identical.&lt;/p&gt;
&lt;h3 id=&#34;redundancy-options-are-limited&#34;&gt;Redundancy options are limited&lt;/h3&gt;
&lt;p&gt;Looking at the &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/ms178586.aspx&#34;&gt;MSDN
documentation&lt;/a&gt;,
it looks like only &lt;a href=&#34;http://www.sql-server-performance.com/articles/clustering/clustering_intro_p1.aspx&#34;&gt;SQL Server
clustering&lt;/a&gt;
is supported. You can&amp;rsquo;t specify a Failover Partner, so &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/ms131373.aspx&#34;&gt;SQL Server
mirroring&lt;/a&gt; isn&amp;rsquo;t
supported.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In SQLServer mode, you can configure several computers running SQL
Server to work as a failover cluster, which is two or more identical
computers running SQL Server that store data for a single database. If
one computer running SQL Server fails, another server in the cluster
can take over and serve requests without session-data loss.&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    
    <item>
      <title>Tripping in Holland. Honey, who shrunk Holland?</title>
      <link>https://jefclaes.be/2010/07/tripping-in-holland-honey-who-shrunk.html</link>
      <pubDate>Wed, 21 Jul 2010 17:30:00 +0200</pubDate>
      <guid>https://jefclaes.be/2010/07/tripping-in-holland-honey-who-shrunk.html</guid>
      <description>&lt;p&gt;People who &lt;a href=&#34;http://twitter.com/JefClaes&#34;&gt;follow me on Twitter&lt;/a&gt; might
have seen my tweets about going on a weekend to Holland with some
friends. Next to excessive eating and drinking, we took the time to do
some sightseeing in &lt;a href=&#34;http://en.wikipedia.org/wiki/The_Hague&#34;&gt;The
Hague&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The sight which gave us the most interesting pictures is
&lt;a href=&#34;http://en.wikipedia.org/wiki/Madurodam&#34;&gt;Madurodam&lt;/a&gt;. Madurodam is a
miniature city featuring the most famous Dutch buildings and landmarks.
Hope you enjoy these pictures!&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-07-21-tripping-in-holland-honey-who-shrunk-holland-34883_410055137771_577672771_4647375_6866294_n.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-07-21-tripping-in-holland-honey-who-shrunk-holland-34883_410055137771_577672771_4647375_6866294_n.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-07-21-tripping-in-holland-honey-who-shrunk-holland-34883_410055132771_577672771_4647374_5158652_n.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-07-21-tripping-in-holland-honey-who-shrunk-holland-34883_410055132771_577672771_4647374_5158652_n.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-07-21-tripping-in-holland-honey-who-shrunk-holland-34659_410054942771_577672771_4647367_6651472_n.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-07-21-tripping-in-holland-honey-who-shrunk-holland-34659_410054942771_577672771_4647367_6651472_n.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-07-21-tripping-in-holland-honey-who-shrunk-holland-34659_410054927771_577672771_4647364_4170752_n.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-07-21-tripping-in-holland-honey-who-shrunk-holland-34659_410054927771_577672771_4647364_4170752_n.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-07-21-tripping-in-holland-honey-who-shrunk-holland-34659_410054922771_577672771_4647363_3191554_n.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-07-21-tripping-in-holland-honey-who-shrunk-holland-34659_410054922771_577672771_4647363_3191554_n.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-07-21-tripping-in-holland-honey-who-shrunk-holland-34883_410055167771_577672771_4647381_903821_n.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-07-21-tripping-in-holland-honey-who-shrunk-holland-34883_410055167771_577672771_4647381_903821_n.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-07-21-tripping-in-holland-honey-who-shrunk-holland-34883_410055157771_577672771_4647379_6670582_n.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-07-21-tripping-in-holland-honey-who-shrunk-holland-34883_410055157771_577672771_4647379_6670582_n.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-07-21-tripping-in-holland-honey-who-shrunk-holland-34883_410055152771_577672771_4647378_6311361_n.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-07-21-tripping-in-holland-honey-who-shrunk-holland-34883_410055152771_577672771_4647378_6311361_n.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-07-21-tripping-in-holland-honey-who-shrunk-holland-34883_410055147771_577672771_4647377_2312223_n.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-07-21-tripping-in-holland-honey-who-shrunk-holland-34883_410055147771_577672771_4647377_2312223_n.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-07-21-tripping-in-holland-honey-who-shrunk-holland-34883_410055142771_577672771_4647376_7398635_n.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-07-21-tripping-in-holland-honey-who-shrunk-holland-34883_410055142771_577672771_4647376_7398635_n.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-07-21-tripping-in-holland-honey-who-shrunk-holland-34883_410055172771_577672771_4647382_6254087_n.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-07-21-tripping-in-holland-honey-who-shrunk-holland-34883_410055172771_577672771_4647382_6254087_n.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Switching with non-constant cases in C#</title>
      <link>https://jefclaes.be/2010/07/switching-with-non-constant-cases-in-c.html</link>
      <pubDate>Wed, 14 Jul 2010 22:25:00 +0200</pubDate>
      <guid>https://jefclaes.be/2010/07/switching-with-non-constant-cases-in-c.html</guid>
      <description>&lt;p&gt;Last week I came across a scenario where I wanted to switch over
non-constants (aka variables), but while I was compiling I got &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/6weteh5e(VS.80).aspx&#34;&gt;Compiler
Error CS0150 (A constant value is
expected)&lt;/a&gt;.
This is one of those things I always forget. You can&amp;rsquo;t use variables in
your case statements because the C# compiler doesn&amp;rsquo;t allow you to. It&amp;rsquo;s
very logical though, the compiler forces you to use constants because
otherwise there is no way of knowing there are equal case statements.&lt;/p&gt;
&lt;h3 id=&#34;the-scenario&#34;&gt;The scenario&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s say I have an ASP.NET page where the user can input and submit a
value. On the server-side I want to match this value with a value from a
local resource file. Depending on the match I want to execute other
code.&lt;/p&gt;
&lt;p&gt;Remember I can&amp;rsquo;t use a switch because the values in the local resource
file are variable.&lt;/p&gt;
&lt;h3 id=&#34;option-one-using-conditional-statements&#34;&gt;Option one: Using conditional statements&lt;/h3&gt;
&lt;p&gt;As shown in the code snippet below you can use else-if statements to
search for a match.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (input == GetLocalResourceObject(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CaseOne&amp;#34;&lt;/span&gt;).ToString()) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.ltResult.Text = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Case one matched.&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (input == GetLocalResourceObject(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CaseTwo&amp;#34;&lt;/span&gt;).ToString()) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.ltResult.Text = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Case two matched.&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (input == GetLocalResourceObject(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CaseThree&amp;#34;&lt;/span&gt;).ToString()) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.ltResult.Text = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Case three matched.&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.ltResult.Text = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;No matching case found.&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This option has at least two disadvantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It allows equal conditions (cases) which might have horrible consequences.&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s ugly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;option-two-using-a-dictionary&#34;&gt;Option two: Using a dictionary&lt;/h3&gt;
&lt;p&gt;You can also use a generic dictionary where the pairs have a
string as the key and a delegate as the value. Because the code I&amp;rsquo;m
executing when a match is found is so compact I&amp;rsquo;m using the simplest
delegate of them all: an &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.action.aspx&#34;&gt;Action
delegate&lt;/a&gt;.
An Action delegate takes no parameters and does not return a value.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-cs&#34; data-lang=&#34;cs&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Dictionary&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, Action&amp;gt; mappings = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, Action&amp;gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      { GetLocalResourceObject(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CaseOne&amp;#34;&lt;/span&gt;).ToString(), () =&amp;gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.ltResult.Text = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Case one matched.&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      { GetLocalResourceObject(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CaseTwo&amp;#34;&lt;/span&gt;).ToString(), () =&amp;gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.ltResult.Text = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Case two matched.&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      { GetLocalResourceObject(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CaseThree&amp;#34;&lt;/span&gt;).ToString(), () =&amp;gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.ltResult.Text = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Case three matched.&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (mappings.ContainsKey(input)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      mappings[input]();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.ltResult.Text = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;No matching case found.&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I think this option is a lot better than the previous one:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This code is elegant, no spaghetti here.&lt;/li&gt;
&lt;li&gt;And better yet, having equal conditions (cases) is impossible. You can&amp;rsquo;t add duplicate keys to a dictionary. If you do, an &lt;code&gt;ArgumentException&lt;/code&gt; gets thrown at runtime.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-07-14-switching-with-non-constant-cases-in-c-argumentExc.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-07-14-switching-with-non-constant-cases-in-c-argumentExc.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Handling the AggregateException</title>
      <link>https://jefclaes.be/2010/05/handling-aggregateexception.html</link>
      <pubDate>Sun, 23 May 2010 13:10:00 +0200</pubDate>
      <guid>https://jefclaes.be/2010/05/handling-aggregateexception.html</guid>
      <description>&lt;p&gt;Last week I showed you how you can use the &lt;code&gt;AggregateException&lt;/code&gt; to apply
consistent exception handling in batch operations. You can find that
post
&lt;a href=&#34;https://jefclaes.be/2010/05/exception-handling-in-batch-operations.html&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://bartdesmet.net/blogs/bart/&#34;&gt;Bart De Smet&lt;/a&gt; read that post and
pointed out that I should check out the Handle method of the
AggregateException.&lt;/p&gt;
&lt;h3 id=&#34;the-handle-method&#34;&gt;The Handle method&lt;/h3&gt;
&lt;p&gt;As found in the &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.aggregateexception.handle.aspx&#34;&gt;MSDN
documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Description&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Invokes a handler on each Exception contained by this AggregateException.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Parameters&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;System.Func&amp;lt;Exception, Boolean&amp;gt; predicate  

The predicate to execute for each exception. The predicate accepts as an argument the Exception to be processed and returns a Boolean to indicate whether the exception was handled.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Remarks&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Each invocation of the predicate returns true or false to indicate whether the Exception was handled. After all invocations, if any exceptions went unhandled, all unhandled exceptions will be put into a new AggregateException which will be thrown. Otherwise, the Handle method simply returns. If any invocations of the predicate throws an exception, it will halt the processing of any more exceptions and immediately propagate the thrown exception as-is.
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;in-practice&#34;&gt;In practice&lt;/h3&gt;
&lt;p&gt;I refactored the example in &lt;a href=&#34;https://jefclaes.be/2010/05/exception-handling-in-batch-operations.html&#34;&gt;my previous
post&lt;/a&gt; to make use of the &lt;code&gt;Handle&lt;/code&gt; method.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Main(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;[] args)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ExecuteBatch();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (AggregateException aggEx)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            aggEx.Handle(HandleBatchExceptions);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Console.ReadLine();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;m passing a &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/bb549151.aspx&#34;&gt;Func&amp;lt;T, TResult&amp;gt;
delegate&lt;/a&gt; to the
&lt;code&gt;Handle&lt;/code&gt; method. In this delegate I decide whether I&amp;rsquo;m handling the
exception or not. If I handle the exception, I return true, else I
return false.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; HandleBatchExceptions(Exception exceptionToHandle)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (exceptionToHandle &lt;span style=&#34;color:#66d9ef&#34;&gt;is&lt;/span&gt; ArgumentNullException)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// I&amp;#39;m handling the ArgumentNullException.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Console.WriteLine(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Handling the ArgumentNullException.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// I handled this Exception&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      {   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// I&amp;#39;m only handling ArgumentNullExceptions.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Console.WriteLine(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.Formaxt(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;I&amp;#39;m not handling the {0}.&amp;#34;&lt;/span&gt;, exceptionToHandle.GetType()));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;//I didn&amp;#39;t handle this Exception, return false.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }          
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When we run this example a new &lt;code&gt;AggregateException&lt;/code&gt; is thrown with the
exceptions I didn&amp;rsquo;t handle.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-05-23-handling-the-aggregateexception-ConsoleOut.bmp&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-05-23-handling-the-aggregateexception-ConsoleOut.bmp&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2010-05-23-handling-the-aggregateexception-Rethrown.bmp&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-05-23-handling-the-aggregateexception-Rethrown.bmp&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Make use of the &lt;code&gt;Handle&lt;/code&gt; method to run over each &lt;code&gt;InnerException&lt;/code&gt; and decide which exception you want to handle or not. The exceptions you didn&amp;rsquo;t handle are automatically wrapped in a new &lt;code&gt;AggregateException&lt;/code&gt; which gets rethrown.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Exception handling in batch operations with the AggregateException</title>
      <link>https://jefclaes.be/2010/05/exception-handling-in-batch-operations.html</link>
      <pubDate>Sat, 15 May 2010 18:34:00 +0200</pubDate>
      <guid>https://jefclaes.be/2010/05/exception-handling-in-batch-operations.html</guid>
      <description>&lt;p&gt;Doing batch operations and elegantly handling exceptions is a problem
which every developer has faced before. In .NET 3.5 or older there is no
out-of-the-box solution to handle exceptions in these types of
scenarios, without being inconsistent to the normal flow of exception
handling. .NET 4 introduces the
&lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.aggregateexception.aspx&#34;&gt;AggregateException&lt;/a&gt;;
an exception representing multiple exceptions. The AggregateException
was introduced in the first place to be used with the &lt;a href=&#34;http://msdn.microsoft.com/en-us/concurrency/default.aspx&#34;&gt;parallel
framework&lt;/a&gt;,
but it can be used in other scenarios as well, such as batch
operations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Take a look at the following example..&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I have a single action which I want to peform in batch. This single
action might throw some exceptions.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; ExecuteSingleAction(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; i)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (i == &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;)            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ArgumentNullException(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;You forgot an argument.&amp;#34;&lt;/span&gt;);       
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (i == &lt;span style=&#34;color:#ae81ff&#34;&gt;18&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ArgumentException(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;This argument doesn&amp;#39;t make sense.&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Most of the exceptions the single action might throw shouldn&amp;rsquo;t break my
whole batch operation. While I&amp;rsquo;m executing the single actions I catch
the exceptions which shouldn&amp;rsquo;t break the batch operation and hold them
in a list of exceptions. The &lt;code&gt;AggregateException&lt;/code&gt; has a public constructor
taking an &lt;code&gt;IEnumerable&lt;/code&gt; of exceptions. If I catch some exceptions while
executing the single action I throw an &lt;code&gt;AggregateException&lt;/code&gt; passing in
that list of exceptions to its constructor.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; ExecuteBatch()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      List&amp;lt;Exception&amp;gt; exceptions = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; List&amp;lt;Exception&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; i = &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; i &amp;lt; &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;; i++)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  ExecuteSingleAction(i);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (ArgumentNullException nullRefEx)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  exceptions.Add(nullRefEx);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (ArgumentException argumentEx)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  exceptions.Add(argumentEx);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }             
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (exceptions.Count &amp;gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; AggregateException(exceptions);            
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the front-end I can catch the &lt;code&gt;AggregateException&lt;/code&gt;, run over its
&lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.aggregateexception.innerexceptions(v=VS.100).aspx&#34;&gt;InnerExceptions&lt;/a&gt;
and act based on the type of exception.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Main(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;[] args)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ExecuteBatch();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (AggregateException aggEx)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;foreach&lt;/span&gt;(Exception ex &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt; aggEx.InnerExceptions)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            {                  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  Console.WriteLine(ex.Message);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (ex &lt;span style=&#34;color:#66d9ef&#34;&gt;is&lt;/span&gt; ArgumentNullException)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#75715e&#34;&gt;//Do something&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (ex &lt;span style=&#34;color:#66d9ef&#34;&gt;is&lt;/span&gt; ArgumentException)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#75715e&#34;&gt;//Do something else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Console.ReadLine();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The result looks like this.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-05-15-exception-handling-in-batch-operations-with-the-aggregateexception-ResultAggregateException.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-05-15-exception-handling-in-batch-operations-with-the-aggregateexception-ResultAggregateException.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Can you imagine other scenarios where the &lt;code&gt;AggregateException&lt;/code&gt; might be
able to add some value?&lt;/p&gt;
&lt;p&gt;Related post: &lt;a href=&#34;https://jefclaes.be/2010/05/handling-aggregateexception.html&#34;&gt;Handling the AggregateException&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Trip Report Czech Republic</title>
      <link>https://jefclaes.be/2010/04/trip-report-czech-republic.html</link>
      <pubDate>Mon, 12 Apr 2010 20:16:00 +0200</pubDate>
      <guid>https://jefclaes.be/2010/04/trip-report-czech-republic.html</guid>
      <description>&lt;p&gt;Last week my girlfriend and I went on a short holiday to the city of
&lt;a href=&#34;http://en.wikipedia.org/wiki/Plze%C5%88&#34;&gt;Plzeň&lt;/a&gt; in the &lt;a href=&#34;http://en.wikipedia.org/wiki/Czech_Republic&#34;&gt;Czech
Republic&lt;/a&gt;. In this post you
can find a small trip report.&lt;/p&gt;
&lt;h3 id=&#34;roadtrippin&#34;&gt;Roadtrippin&#39;&lt;/h3&gt;
&lt;p&gt;Minutes after leaving home we discovered an unpleasant surprise; my Tom
Tom has no map of the Czech Republic. Good thing that people used to
print this stuff on paper. After consulting a paper map of Europe we did
have an idea which direction to follow.&lt;/p&gt;
&lt;p&gt;The route was easy enough though; straight ahead for 800km. Driving
through Germany was a blast. For those not from Europe; a big part
of the &lt;a href=&#34;http://en.wikipedia.org/wiki/Autobahn&#34;&gt;German autobahn&lt;/a&gt; has no
speedlimit.&lt;/p&gt;
&lt;h3 id=&#34;prague&#34;&gt;Prague&lt;/h3&gt;
&lt;p&gt;The highlight of our holiday was
&lt;a href=&#34;http://en.wikipedia.org/wiki/Prague&#34;&gt;Prague&lt;/a&gt;. A lot of the historic
architecture is still intact, making Prague an impressive city and
deservingly one of the most-visited cities in Europe.&lt;/p&gt;
&lt;p&gt;Some of the sights we visited were..&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;http://en.wikipedia.org/wiki/Charles_Bridge&#34;&gt;Charles Bridge&lt;/a&gt;. This
bridge is one of the most popular sights in Prague and has a &lt;a href=&#34;http://en.wikipedia.org/wiki/Charles_Bridge#History&#34;&gt;very rich
history&lt;/a&gt;. It&amp;rsquo;s over
600 (!) years old.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-04-12-trip-report-czech-republic-Pilsen_012.2.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-04-12-trip-report-czech-republic-Pilsen_012.2.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
The &lt;a href=&#34;http://en.wikipedia.org/wiki/Pet%C5%99%C3%ADn_Lookout_Tower&#34;&gt;Petřínská
rozhledna&lt;/a&gt;
on top of the &lt;a href=&#34;http://en.wikipedia.org/wiki/Pet%C5%99%C3%ADn&#34;&gt;Petřín&lt;/a&gt;
hill is a miniature version of the Eiffel Tower. On top of the Petřínská
rozhledna you have a great view of the Prague skyline.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-04-12-trip-report-czech-republic-Pilsen_024.2.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-04-12-trip-report-czech-republic-Pilsen_024.2.jpg&#34;&gt;&lt;/a&gt;&lt;br&gt;
The &lt;a href=&#34;http://en.wikipedia.org/wiki/Prague_Castle&#34;&gt;Prague Castle&lt;/a&gt; is one
of the biggest castles in the world. Today it still houses the Czech
government.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-04-12-trip-report-czech-republic-Pilsen_030.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-04-12-trip-report-czech-republic-Pilsen_030.JPG&#34;&gt;&lt;/a&gt;&lt;br&gt;
The &lt;a href=&#34;http://en.wikipedia.org/wiki/St._Vitus_Cathedral&#34;&gt;Saint Vitus&amp;rsquo;s
Cathedral&lt;/a&gt; next to the
Prague Castle is the biggest and most important church of the Czech
Republic.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-04-12-trip-report-czech-republic-Pilsen_037.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-04-12-trip-report-czech-republic-Pilsen_037.JPG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;plzeň&#34;&gt;Plzeň&lt;/h3&gt;
&lt;p&gt;Plzeň is known worldwide for &lt;a href=&#34;http://en.wikipedia.org/wiki/Pilsener&#34;&gt;Pilsener&lt;/a&gt; beer and its &lt;a href=&#34;http://en.wikipedia.org/wiki/%C5%A0koda_Auto&#34;&gt;Skoda&lt;/a&gt; factories.
Although industry made &lt;a href=&#34;http://en.wikipedia.org/wiki/Plze%C5%88&#34;&gt;Plzeň&lt;/a&gt;
one of the biggest cities of the Chzech Republic, the number of tourist
attractions is rather limited..&lt;/p&gt;
&lt;p&gt;We had some good laughs at the
&lt;a href=&#34;http://www.dinopark.cz/dinopark-plzen-english/&#34;&gt;Dinopark&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-04-12-trip-report-czech-republic-Pilsen_079.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-04-12-trip-report-czech-republic-Pilsen_079.JPG&#34;&gt;&lt;/a&gt;&lt;br&gt;
We also visited the famous &lt;a href=&#34;http://nl.wikipedia.org/wiki/Pilsner_Urquell&#34;&gt;Pilsner
Urquell&lt;/a&gt; museum and got a
bonus show! That evening the soccer match &lt;a href=&#34;http://en.wikipedia.org/wiki/FC_Viktoria_Plze%C5%88&#34;&gt;Viktoria
Plzen&lt;/a&gt; vs &lt;a href=&#34;http://en.wikipedia.org/wiki/Sparta_Prague&#34;&gt;Sparta
Prague&lt;/a&gt; took place. While we
were standing in front of the Pilsner Urquell museum 80 fully equipped
cops stormed a restaurant on the other side of the street to arrest some
hooligans. Sweet action!&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-04-12-trip-report-czech-republic-Pilsen_086.jpg&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-04-12-trip-report-czech-republic-Pilsen_086.jpg&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;final-thoughts&#34;&gt;Final thoughts&lt;/h3&gt;
&lt;p&gt;Although the Czech Republic does not have a good reputation, I think all
the problems this country used to have belong to the past. The people
were nice, the culture was rich and everything was pretty cheap compared
to most European countries. Definitely worth visiting!&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-04-12-trip-report-czech-republic-Pilsen_090.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-04-12-trip-report-czech-republic-Pilsen_090.JPG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Cannot Start Service from the command line or debugger. A Windows Service must first be installed (using installutil.exe)..</title>
      <link>https://jefclaes.be/2010/03/cannot-start-service-from-command-line.html</link>
      <pubDate>Sat, 13 Mar 2010 16:36:00 +0100</pubDate>
      <guid>https://jefclaes.be/2010/03/cannot-start-service-from-command-line.html</guid>
      <description>&lt;p&gt;When you create a new Windows Service project and try to debug it,
Visual Studio will show you a Windows Service Start Failure with the
message &lt;code&gt;Cannot Start Service from the command line or debugger. A Windows Service must first be installed (using installutil.exe) and then started with the Server Explorer, Windows Services Administrative tool or the NET START command.&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-03-13-cannot-start-service-from-the-command-line-or-debugger-a-windows-service-must-first-be-installed-using-installutil-exe-serviceError.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-03-13-cannot-start-service-from-the-command-line-or-debugger-a-windows-service-must-first-be-installed-using-installutil-exe-serviceError.JPG&#34;&gt;&lt;/a&gt;&lt;br&gt;
The trick my team and I use to workaround this problem, makes use of the
service &lt;code&gt;Debug&lt;/code&gt; flag. If the &lt;code&gt;Debug&lt;/code&gt; flag is on, we just start the service
by using our own public &lt;code&gt;Start&lt;/code&gt; method. When the &lt;code&gt;OnStart&lt;/code&gt; event is fired in
the service itself, we call the same public &lt;code&gt;Start&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;This goes in your service.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; OnStart(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;[] args)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Start();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Start()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//Start!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And this goes in &lt;code&gt;Program.cs&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;namespace&lt;/span&gt; UdpListener
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Program&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Main()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;#if&lt;/span&gt; (!DEBUG)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                ServiceBase[] ServicesToRun;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                ServicesToRun = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ServiceBase[] 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                { 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; UdpListener() 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                ServiceBase.Run(ServicesToRun);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;#else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                UdpListener listener = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; UdpListener();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                listener.Start();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;#endif&lt;/span&gt;           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can set the &lt;code&gt;Debug&lt;/code&gt; flag of your service in your service properties.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2010-03-13-cannot-start-service-from-the-command-line-or-debugger-a-windows-service-must-first-be-installed-using-installutil-exe-debug.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2010-03-13-cannot-start-service-from-the-command-line-or-debugger-a-windows-service-must-first-be-installed-using-installutil-exe-debug.JPG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The only problem with this solution is that you can&amp;rsquo;t debug your &lt;code&gt;OnStop&lt;/code&gt;
event but this hasn&amp;rsquo;t been an issue for us so far.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Book review: Object-Oriented JavaScript</title>
      <link>https://jefclaes.be/2010/02/book-review-object-oriented-javascript.html</link>
      <pubDate>Mon, 22 Feb 2010 19:47:00 +0100</pubDate>
      <guid>https://jefclaes.be/2010/02/book-review-object-oriented-javascript.html</guid>
      <description>&lt;p&gt;Although I&amp;rsquo;ve made my feet wet with various JavaScript frameworks, I am
not a JavaScript hero at all. This might be one of the disadvantages of
being a WebForms developer and having great toolkits at hand like the
&lt;a href=&#34;http://www.asp.net/(S(fu2l2uzphr2u3u45q2dnez55))/ajax/AjaxControlToolkit/Samples/&#34;&gt;AJAX Control
Toolkit&lt;/a&gt;
and Telerik RADControls.&lt;/p&gt;
&lt;p&gt;Because you really can&amp;rsquo;t call yourself a webdeveloper without having
some understanding of JavaScript I decided to order Object-Oriented
Javascript by &lt;a href=&#34;http://www.phpied.com/&#34;&gt;Stoyan Stefanov&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This book really handles the language itself. The first chapters handle
the basics: Types, loops, functions and objects. Although these concepts
and the syntax resemble C#, JavaScript is a total different beast.
After covering the basics, Stoyan goes deeper into OO JavaScript with
Prototype and Inheritance. Then he shows the Browser Environment and he
finishes the book with Coding and Design patterns.&lt;/p&gt;
&lt;p&gt;All these concepts are accompanied by a ton of easy-to-read examples.
After every chapter he also gives you some homework, because you learn
coding by coding. After finishing this book you can also use the
excellent Appendix for your reference.&lt;/p&gt;
&lt;p&gt;I thought this was a great and very complete book. Definitely one of the
best software books I&amp;rsquo;ve read in a while.&lt;/p&gt;
&lt;p&gt;Get the book
&lt;a href=&#34;http://www.amazon.com/gp/product/1847194141?ie=UTF8&amp;amp;tag=diofanedebyje-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=1847194141&#34;&gt;here&lt;/a&gt;
(Amazon).&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Webforms lessons learned the hard way (Part 2)</title>
      <link>https://jefclaes.be/2010/02/webforms-lessons-learned-hard-way-part_15.html</link>
      <pubDate>Mon, 15 Feb 2010 17:43:00 +0100</pubDate>
      <guid>https://jefclaes.be/2010/02/webforms-lessons-learned-hard-way-part_15.html</guid>
      <description>&lt;p&gt;If you missed part 1, you can find it
&lt;a href=&#34;https://jefclaes.be/2010/02/webforms-lessons-learned-hard-way-part.html&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;use-the-built-in-goodies&#34;&gt;Use the built-in goodies&lt;/h3&gt;
&lt;p&gt;ASP.NET Webforms has a lot of good stuff built into it. Do your homework
before you start building the next big Webforms thing! A perfect example
of this is ASP.NET Membership. ASP.NET provides an out-of-box membership
solution. I&amp;rsquo;ve seen people who were to lazy to do some research or
thought they could do better and ended up with a solution which put its
doors wide open to people with bad intentions.&lt;/p&gt;
&lt;p&gt;When a feature doesn&amp;rsquo;t exactly match your needs, try extending it. The
ASP.NET team are artists as it comes to writing solid extensible frameworks. I&amp;rsquo;d like to point to ASP.NET Membership again. You can write
your &lt;a href=&#34;http://www.asp.net/(S(ywiyuluxr3qb2dfva1z5lgeg))/learn/videos/video-189.aspx&#34;&gt;own provider&lt;/a&gt; which integrates with ASP.NET seamlessly.&lt;/p&gt;
&lt;h3 id=&#34;move-as-much-as-possible-away-from-your-page&#34;&gt;Move as much as possible away from your page&lt;/h3&gt;
&lt;p&gt;Separating the domain and persistence away from your presentation logic positively affects the quality of your page and code-behind in so many ways.&lt;/p&gt;
&lt;p&gt;One of the big drawbacks of Webforms is that testing your pages isn&amp;rsquo;t
easy. That&amp;rsquo;s why it&amp;rsquo;s important to keep the quantity of code in the
code-behind as low as possible. Code outside your presentation logic can
easily be covered using unittests.&lt;/p&gt;
&lt;p&gt;Dividing your web application in multiple layers also makes the code in
the page and page-behind easier to grasp (encapsulation etc..).&lt;/p&gt;
&lt;h3 id=&#34;let-others-do-it-for-you&#34;&gt;Let others do it for you&lt;/h3&gt;
&lt;p&gt;Because most of the ASP.NET Server controls are easy to extend, there a
lot of third party control vendors out there.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve only been using the &lt;a href=&#34;http://www.telerik.com/products/aspnet-ajax.aspx&#34;&gt;Telerik RadControls&lt;/a&gt; for a few months now, and using this control suite, made my life so much easier.1000$ might look like a big investment, but you can&amp;rsquo;t believe how many time it has saved me. Especially the &lt;a href=&#34;http://demos.telerik.com/aspnet-ajax/grid/examples/performance/linq/defaultcs.aspx&#34;&gt;RadGrid&lt;/a&gt;
control is a great time-saver. Binding a list of objects to a RadGrid,
and finding out sorting, paging,.. just works is awesome.&lt;/p&gt;
&lt;p&gt;What are some of your Webforms lessons learned the hard way?&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Webforms lessons learned the hard way (Part 1)</title>
      <link>https://jefclaes.be/2010/02/webforms-lessons-learned-hard-way-part.html</link>
      <pubDate>Sun, 14 Feb 2010 16:22:00 +0100</pubDate>
      <guid>https://jefclaes.be/2010/02/webforms-lessons-learned-hard-way-part.html</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been spending a lot of my days in Webforms the last two years. In
this post I want to share some best practices I&amp;rsquo;ve learned the hard way
over these years. A lot of MVC developers might think this post comes a
bit late (who still cares about Webforms?!), I do think (in the real
world) a lot of the ASP.NET developers are still using Webforms. This
post is directly targeting them.&lt;/p&gt;
&lt;h3 id=&#34;keep-your-pages-light&#34;&gt;Keep your pages light&lt;/h3&gt;
&lt;p&gt;There are a few things where you should pay attention to.&lt;/p&gt;
&lt;p&gt;Most of the times the
&lt;a href=&#34;http://msdn.microsoft.com/en-us/library/ms972976.aspx&#34;&gt;Viewstate&lt;/a&gt; is
the number one performance killer. Although most developers know storing
a lot of &lt;code&gt;ViewState&lt;/code&gt; on the page has issues, and that there are numerous
&lt;a href=&#34;http://www.eggheadcafe.com/articles/20040613.asp&#34;&gt;alternatives&lt;/a&gt;. Most
developers don&amp;rsquo;t take the time to think about the &lt;code&gt;Viewstate&lt;/code&gt;. I don&amp;rsquo;t
blame them. Persisting the &lt;code&gt;ViewState&lt;/code&gt; to another medium is not as easy as
it should be. The &lt;code&gt;Viewstate&lt;/code&gt; is enabled by default, disabling the
&lt;code&gt;Viewstate&lt;/code&gt; on each control is a hassle.. In ASP.NET 4 the
&lt;a href=&#34;#&#34;&gt;ViewStateMode&lt;/a&gt; will make it much easier though. Once the users start complaining about performance, you are too late. I really encourage you to start thinking about the Viewstate as early as possible. Only use it when you need to persist changes across &lt;code&gt;Postbacks&lt;/code&gt;. You will be surprised how little you really needs to persist.&lt;/p&gt;
&lt;p&gt;A &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/wtxbf3hh.aspx&#34;&gt;Masterpage&lt;/a&gt; is
great for applying a consistent style to your pages. But be careful with
what you put in the head tag of your Masterpage. Often you only need a
certain stylesheet or javascript library in a few pages. Avoid including
references to these stylesheets and javascript libraries in your Masterpage. Better is to put a &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.contentplaceholder.aspx&#34;&gt;ContentPlaceHolder&lt;/a&gt; in the head tag of your Masterpage and use that for your conditional
resources.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.asp.net/Ajax/Documentation/Live/overview/UpdatePanelOverview.aspx&#34;&gt;Updatepanels&lt;/a&gt; are great controls, but you should apply them wisely. Don&amp;rsquo;t blindly wrap your whole form in an &lt;code&gt;Updatepanel&lt;/code&gt;. Think about which part of your page really needs to be refreshed. The less HTML and &lt;code&gt;ViewState&lt;/code&gt; (!) coming back from the server the better.&lt;/p&gt;
&lt;p&gt;Use javascript. I think to many Webforms developers are uncomfortable
leaving their serverside habitat. Avoid a postback whenever you can.&lt;/p&gt;
&lt;h3 id=&#34;stay-away-from-the-designer&#34;&gt;Stay away from the designer&lt;/h3&gt;
&lt;p&gt;Creating pages using the designer doesn&amp;rsquo;t work on so many levels.&lt;/p&gt;
&lt;p&gt;The Design view doesn&amp;rsquo;t always give a correct representation of how the
page will look like when it&amp;rsquo;s rendered by the browser.&lt;/p&gt;
&lt;p&gt;Using drag-and-drop, databinding wizards.. does not end well. I have a
big problem with defining
&lt;a href=&#34;http://www.beansoftware.com/asp.net-tutorials/data-source-controls.aspx&#34;&gt;datasources&lt;/a&gt;
in the ASPX markup. In my opinion the ASPX markup should be as clean as
possible. It should serve as a view, and as a view only. Another
downside of defining your datasources in your ASPX markup is that your
application tends to be more fragile.&lt;/p&gt;
&lt;p&gt;Let me prove this by this example..&lt;/p&gt;
&lt;p&gt;In this example I&amp;rsquo;m binding a List of FireStationEvents to a GridView.
Notice the TypeName and SelectMethods are strings.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;form&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;id&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;form1&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;runat&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;server&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt;&amp;gt;           
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;asp:GridView&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ID&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gvEvents&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;runat&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;server&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DataSourceID&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;odsEvents&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;asp:GridView&lt;/span&gt;&amp;gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;asp:ObjectDataSource&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ID&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;odsEvents&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;runat&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;server&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;SelectMethod&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Load&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;TypeName&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;WFDemo.BusinessLogic.FireStationEvents&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;asp:ObjectDataSource&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;form&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A few weeks later I decide to change the methodname Load to LoadAll. I
rebuild my solution and all is good. I publish my site to production, and a few
hours later I get a critical bug report assigned to me. After looking
into it, I discover I forgot to change the &lt;code&gt;SelectMethod&lt;/code&gt; property of the
DataSource. Loading the page throws an unhandled Exception at runtime:
&lt;code&gt;ObjectDataSource &#39;odsEvents&#39; could not find a non-generic method &#39;Load&#39; that has no parameters.&lt;/code&gt; One small refactoring made the application fail
big time and I didn&amp;rsquo;t even have a clue.&lt;/p&gt;
&lt;p&gt;Stay posted for Part 2 tomorrow! What are some of your Webforms lessons
learned the hard way?&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Log4Net: log.Debug(String.Format()) versus log.DebugFormat()</title>
      <link>https://jefclaes.be/2010/01/log4net-logdebugstringformat-versus.html</link>
      <pubDate>Wed, 20 Jan 2010 20:30:00 +0100</pubDate>
      <guid>https://jefclaes.be/2010/01/log4net-logdebugstringformat-versus.html</guid>
      <description>&lt;p&gt;&lt;a href=&#34;http://logging.apache.org/log4net/index.html&#34;&gt;Log4net&lt;/a&gt; is one of the
most popular opensource logging frameworks available in the .NET world.
I&amp;rsquo;ve been using this framework for over a year now, and today I
discovered something new.&lt;/p&gt;
&lt;p&gt;I often use
&lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.string.format.aspx&#34;&gt;string.Format()&lt;/a&gt;
to format my log messages. Earlier this morning I made a typo formatting
my message and an Exception was thrown in the beginning of my method
which caused the application flow to break. You can avoid this by using
the
&lt;a href=&#34;http://logging.apache.org/log4net/release/sdk/log4net.ILog.DebugFormat_overloads.html&#34;&gt;DebugFormat()&lt;/a&gt;
method. If you mistype here, no exception will be thrown, but a &lt;code&gt;WARN&lt;/code&gt;
message will be logged.&lt;/p&gt;
&lt;h3 id=&#34;example-using-stringformat&#34;&gt;Example using &lt;code&gt;String.Format&lt;/code&gt;&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-cs&#34; data-lang=&#34;cs&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;log.Debug(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;.Format(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{0}{1}&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ABC_1&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As expected this throws a &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.formatexception.aspx&#34;&gt;System.FormatException&lt;/a&gt;: &lt;code&gt;Index (zero based) must be greater than or equal to zero and less than the size of the argument list.&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&#34;example-using-logdebugformat&#34;&gt;Example using &lt;code&gt;log.DebugFormat&lt;/code&gt;&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-cs&#34; data-lang=&#34;cs&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;log.DebugFormat(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{0}{1}&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ABC_1&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Using &lt;code&gt;DebugFormat()&lt;/code&gt; the logger logs a &lt;code&gt;WARN&lt;/code&gt; message, but it doesn&amp;rsquo;t break
the application flow.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;WARN StringFormat: Exception while rendering format [{0} {1}.]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So to avoid logging breaking your application, you should use the
&lt;code&gt;DebugFormat()&lt;/code&gt;, &lt;code&gt;WarningFormat()&lt;/code&gt;, &lt;code&gt;InfoFormat()&lt;/code&gt;, &lt;code&gt;ErrorFormat()&lt;/code&gt; methods
instead of &lt;code&gt;String.Format()&lt;/code&gt; to format your log message.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Looking back, moving forward (New years post)</title>
      <link>https://jefclaes.be/2009/12/looking-back-moving-forward-new-years-post/</link>
      <pubDate>Mon, 21 Dec 2009 18:57:00 +0100</pubDate>
      <guid>https://jefclaes.be/2009/12/looking-back-moving-forward-new-years-post/</guid>
      <description>&lt;p&gt;In this post I&amp;rsquo;m going to reflect on the year that&amp;rsquo;s almost finished and
the year to come.&lt;/p&gt;
&lt;p&gt;I came up with a few topics that are worth discussing in this post.&lt;/p&gt;
&lt;h3 id=&#34;my-career&#34;&gt;My career&lt;/h3&gt;
&lt;p&gt;I don&amp;rsquo;t think I ever mentioned where I work. The first of January I will
be working 18 months for &lt;a href=&#34;http://www.ferranti.be&#34;&gt;Ferranti&lt;/a&gt;. The only company I&amp;rsquo;ve worked for since I graduated.&lt;/p&gt;
&lt;p&gt;The first project I&amp;rsquo;ve ever worked on was a rather big one. &lt;a href=&#34;http://www.bloggen.be/brandweerantwerpen/&#34;&gt;Firestation
Antwerp&lt;/a&gt;. Last year we heard
that sales scored another firestation for us (&lt;a href=&#34;http://www.brandweergent.be/&#34;&gt;Firestation Ghent&lt;/a&gt;). So I&amp;rsquo;ve been working on these two projects since I started.&lt;/p&gt;
&lt;p&gt;Do these projects get boring? Well, not boring, exhausting maybe. These
projects are very complex (Dispatching, telecommunication, web applications,
GIS, ..) and the requirements are very high. Although these projects are
exhausting from time to time, I don&amp;rsquo;t think there are other projects
where I would&amp;rsquo;ve learned as much in such a small period of time. As a
developer I have touched and worked on lots of stuff: ASP.NET,
WindowsServices, WCF, WebServices, GIS, API&amp;rsquo;s, Telecommunication.. You
name it.&lt;/p&gt;
&lt;h3 id=&#34;blog&#34;&gt;Blog&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;ve been blogging since October 2008. When I just started out
the quality of the content was rather poor. Although I&amp;rsquo;m not totally
satisfied with the content I produced this year, I hope the quality has
improved noticeable. I saw the traffic increase significantly this year,
so I hope that&amp;rsquo;s a good sign.&lt;/p&gt;
&lt;p&gt;There are a few posts that scored pretty good out there. You can find
them &lt;a href=&#34;#&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;By blogging I&amp;rsquo;ve made lots of new friends. I enjoy reading through all
of your Tweets. &lt;a href=&#34;http://community.bartdesmet.net/blogs/bart/Default.aspx&#34;&gt;Bart De Smet&lt;/a&gt; in particular has been a very good mentor.&lt;/p&gt;
&lt;h3 id=&#34;community&#34;&gt;Community&lt;/h3&gt;
&lt;p&gt;I managed to go to two events this year:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TechDays Belgium&lt;/li&gt;
&lt;li&gt;Scott Guthrie in Belgium&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I hope I will get the opportunity to go to some big event next year. I
also plan on going to more &lt;a href=&#34;http://www.visug.be/&#34;&gt;VISUG&lt;/a&gt; sessions.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been neglecting the &lt;a href=&#34;http://forums.asp.net/&#34;&gt;ASP.NET forums&lt;/a&gt;
lately. In general I think the quality of the questions is rather poor
and there are plenty of good answerers. I&amp;rsquo;ve been a long time
&lt;a href=&#34;http://stackoverflow.com/&#34;&gt;StackOverflow&lt;/a&gt; lurker. Next year I&amp;rsquo;ll try to
contribute to that community.&lt;/p&gt;
&lt;h3 id=&#34;travelling&#34;&gt;Travelling&lt;/h3&gt;
&lt;p&gt;I managed to travel four times this year:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;France (Albi)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://jefclaes.be/2009/11/my-trip-to-madrid-in-ten-pictures.html&#34;&gt;Spain (Madrid)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Belgium (Ardennes)&lt;/li&gt;
&lt;li&gt;France (Normandie)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In 2010 I&amp;rsquo;ll try to go abroad at least three times.&lt;/p&gt;
&lt;h3 id=&#34;wrap-up&#34;&gt;Wrap up&lt;/h3&gt;
&lt;p&gt;In general, my year was pretty fun. I hope 2010 will be at least as good. Excited about hearing how you did this year and what you hope to achieve in 2010!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Response.RedirectPermanent in .NET 3.5 and older</title>
      <link>https://jefclaes.be/2009/12/response.redirectpermanent-in-.net-3.5-and-older/</link>
      <pubDate>Sat, 05 Dec 2009 17:50:00 +0100</pubDate>
      <guid>https://jefclaes.be/2009/12/response.redirectpermanent-in-.net-3.5-and-older/</guid>
      <description>&lt;p&gt;One of the new features in ASP.NET 4.0 is permanently redirecting to a
page using &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/system.web.httpresponse.redirectpermanent(VS.100).aspx&#34;&gt;Response.RedirectPermanent&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is common practice in Web applications to move pages and other
content around over time, which can lead to an accumulation of stale
links in search engines. In ASP.NET, developers have traditionally
handled requests to old URLs by using by using the Response.Redirect
method to forward a request to the new URL. However, the Redirect
method issues an HTTP 302 Found (temporary redirect) response, which
results in an extra HTTP round trip when users attempt to access the
old URLs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&#34;http://www.asp.net/LEARN/whitepapers/aspnet4/default.aspx#_TOC1_4&#34;&gt;Source&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can achieve this functionality in ASP.NET 3.5 and older by writing a
&lt;code&gt;301 Moved Permanently Status&lt;/code&gt; and
a ``Location Header&lt;code&gt;to the&lt;/code&gt;Response` stream. This can be found in the &lt;a href=&#34;http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html&#34;&gt;HTTP
specifications&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here is an example.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Response.Clear();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Response.Status = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;301 Moved Permanently&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Response.AddHeader(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Location&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;PageOne.aspx&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Response.End();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can verify the result by using  &lt;a href=&#34;http://www.fiddler2.com/fiddler2/&#34;&gt;Fiddler&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2009-12-05-response-redirectpermanent-in-net-3-5-and-older-fiddler.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2009-12-05-response-redirectpermanent-in-net-3-5-and-older-fiddler.JPG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Book review: Professional Refactoring in C# &amp; ASP.NET</title>
      <link>https://jefclaes.be/2009/11/book-review-professional-refactoring-in.html</link>
      <pubDate>Tue, 17 Nov 2009 19:37:00 +0100</pubDate>
      <guid>https://jefclaes.be/2009/11/book-review-professional-refactoring-in.html</guid>
      <description>&lt;p&gt;Three months ago I was looking up to refactoring a legacy ASP.NET
Webforms application. Although I was familiar with refactoring, I
ordered &amp;ldquo;Professional Refactoring in C# &amp;amp; ASP.NET&amp;rdquo; by Daniejel
Arsenovski to get deeper into refactoring.&lt;/p&gt;
&lt;h3 id=&#34;the-title&#34;&gt;The title&lt;/h3&gt;
&lt;p&gt;Although the title states &amp;ldquo;Professional&amp;rdquo;, I think this book should find
its main audience in coding novices. Another problem with the title is
the word ASP.NET in it. The book has one chapter covering ASP.NET, with
only 35 poor-quality pages in it.&lt;/p&gt;
&lt;p&gt;Now the title has some issues, but how was the content?&lt;/p&gt;
&lt;h3 id=&#34;the-content&#34;&gt;The content&lt;/h3&gt;
&lt;p&gt;Danijel identifies codes mells and shows refactoring techniques to solve
them. Too bad some of these examples are spreaded over multiple pages,
which makes them a tad sloppy and hard to read. Danijel stresses how
important Object Oriented design is. He proves this by transforming
procedural code into Object Oriented code, greatly improving the
readability. This book should help developers who are new to or come
from a non-OO background to apply the basic Object Oriented concepts.
Next to refactoring techniques, he also touches refactoring tools, unit
testing and design patterns.&lt;/p&gt;
&lt;p&gt;I think the beginning .NET developer might be able to significally start
improving his codebase by reading this book. For more experienced .NET
developers most of the topics handled in the book should be part of
their day-to-day skillset.&lt;/p&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;All by all I was a bit dissapointed by the book, it was an easy read,
had a few interesting tricks, but I expected it would go more into
depth.&lt;/p&gt;
&lt;p&gt;Something valuable I realised though.. &lt;strong&gt;is that refactoring isn&amp;rsquo;t something you learn
by reading a book, but you learn it by obeying the constant hunger for
improving your code.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you feel confident that you dig the basic concepts of writing quality
code, I would instead of buying this book, invest in a good book on
Object Oriented concepts or design patterns.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>My trip to Madrid in ten pictures</title>
      <link>https://jefclaes.be/2009/11/my-trip-to-madrid-in-ten-pictures.html</link>
      <pubDate>Mon, 09 Nov 2009 20:30:00 +0100</pubDate>
      <guid>https://jefclaes.be/2009/11/my-trip-to-madrid-in-ten-pictures.html</guid>
      <description>&lt;p&gt;Last week I went to Madrid with my family-in-law to visit my
girlfriend&amp;rsquo;s brother and cousin.&lt;/p&gt;
&lt;p&gt;Although our stay there was rather short (only four days), we visited
some of the most impressive places in Madrid:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;- &lt;a href=&#34;http://en.wikipedia.org/wiki/Estadio_Santiago_Bernab%C3%A9u&#34;&gt;Stadium Real
Madrid&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://en.wikipedia.org/wiki/Royal_Palace_of_Madrid&#34;&gt;The Royal
Palace&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://en.wikipedia.org/wiki/The_Prado&#34;&gt;Prado Museum&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://en.wikipedia.org/wiki/Museo_Nacional_Centro_de_Arte_Reina_Sof%C3%ADa&#34;&gt;Queen Sofia
Museum&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://en.wikipedia.org/wiki/Parque_del_Retiro&#34;&gt;Buen Retiro Park&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://en.wikipedia.org/wiki/Plaza_Mayor_of_Madrid&#34;&gt;Plaza Mayor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;stadium-real-madrid&#34;&gt;Stadium Real Madrid&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2009-11-09-my-trip-to-madrid-in-ten-pictures-Madrid_0227.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2009-11-09-my-trip-to-madrid-in-ten-pictures-Madrid_0227.JPG&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2009-11-09-my-trip-to-madrid-in-ten-pictures-Madrid_0242.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2009-11-09-my-trip-to-madrid-in-ten-pictures-Madrid_0242.JPG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Pay attention to the stitching &lt;em&gt;Jesus in first place&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&#34;royal-palace&#34;&gt;Royal Palace&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2009-11-09-my-trip-to-madrid-in-ten-pictures-Madrid_0178.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2009-11-09-my-trip-to-madrid-in-ten-pictures-Madrid_0178.JPG&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2009-11-09-my-trip-to-madrid-in-ten-pictures-Madrid_0163.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2009-11-09-my-trip-to-madrid-in-ten-pictures-Madrid_0163.JPG&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2009-11-09-my-trip-to-madrid-in-ten-pictures-Madrid_0186.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2009-11-09-my-trip-to-madrid-in-ten-pictures-Madrid_0186.JPG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;ruïnes-of-an-egyptian-temple&#34;&gt;Ruïnes of an Egyptian temple&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2009-11-09-my-trip-to-madrid-in-ten-pictures-Madrid_0026.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2009-11-09-my-trip-to-madrid-in-ten-pictures-Madrid_0026.JPG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;buen-retiro-park&#34;&gt;Buen Retiro Park&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2009-11-09-my-trip-to-madrid-in-ten-pictures-Interactieve_0435.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2009-11-09-my-trip-to-madrid-in-ten-pictures-Interactieve_0435.JPG&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2009-11-09-my-trip-to-madrid-in-ten-pictures-Interactieve_0429.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2009-11-09-my-trip-to-madrid-in-ten-pictures-Interactieve_0429.JPG&#34;&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href=&#34;https://jefclaes.be/post/images/2009-11-09-my-trip-to-madrid-in-ten-pictures-Interactieve_0415.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2009-11-09-my-trip-to-madrid-in-ten-pictures-Interactieve_0415.JPG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Older lady feeding the birds. I wonder what her trick is.. Four of us tried letting them eat out of our hands, but we all failed.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://jefclaes.be/post/images/2009-11-09-my-trip-to-madrid-in-ten-pictures-Interactieve_0408.JPG&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://jefclaes.be/post/images/thumbnails/2009-11-09-my-trip-to-madrid-in-ten-pictures-Interactieve_0408.JPG&#34;&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Why code reviews should be a team thing</title>
      <link>https://jefclaes.be/2009/08/why-codereviews-should-be-teamthing.html</link>
      <pubDate>Sun, 23 Aug 2009 19:22:00 +0200</pubDate>
      <guid>https://jefclaes.be/2009/08/why-codereviews-should-be-teamthing.html</guid>
      <description>&lt;p&gt;Often code reviews are done by one person, the technical lead of your
team.&lt;/p&gt;
&lt;p&gt;In my opinion it&amp;rsquo;s better to make each developer of your team do code
reviews.&lt;/p&gt;
&lt;h3 id=&#34;my-arguments&#34;&gt;My arguments&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Having all developers do code reviews leads to discussions about what coding standards should be used..&lt;/li&gt;
&lt;li&gt;Leading to well-documented standards.&lt;/li&gt;
&lt;li&gt;Each developer is forced to understand the workflow of an application which isn&amp;rsquo;t his, which expands his domain knowledge.&lt;/li&gt;
&lt;li&gt;Each developer learns from others and is given an opportunity to teach and discuss why someone chose a certain path.. There is always     something new to learn, even for seasoned developers. You might just pick up that latest trick doing whizbang Silverlight 3 stuff from that freshman that just started working this year.&lt;/li&gt;
&lt;li&gt;Multiple perspectives on a problem can only benefit the solution.&lt;/li&gt;
&lt;/ol&gt;
</description>
    </item>
    
    <item>
      <title>Stored Procedures: Make them or break them</title>
      <link>https://jefclaes.be/2009/01/stored-procedures-make-them-or-break.html</link>
      <pubDate>Sun, 15 Feb 2009 18:58:00 +0100</pubDate>
      <guid>https://jefclaes.be/2009/01/stored-procedures-make-them-or-break.html</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been thinking about the use of stored procedures lately.&lt;/p&gt;
&lt;p&gt;Some questions that popped up in my head: What are the
advantages/disadvantages? When and how should they be used? Will they
extinct with LINQ to SQL becoming more and more popular? Why should you
store your queries in your database, instead of in your code..&lt;/p&gt;
&lt;p&gt;I asked the opinion of a few ASP.NET/.NET professionals. Hope you find
this interesting!&lt;/p&gt;
&lt;h3 id=&#34;kris-van-der-mast-blog&#34;&gt;Kris Van Der Mast (&lt;a href=&#34;http://blog.krisvandermast.com/&#34;&gt;Blog&lt;/a&gt;)&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Since I&amp;rsquo;m a consultant I have to go with the specifications of my
clients. Most still use stored procedures though I see a shift
occurring. My current client allows us to use Linq To Sql for select
statements (generated by L2S) but for update, delete and insert
statements they require us to make sprocs since they put security on
it on a database level. My former client allowed us to use NHibernate
(winforms project) but for 3-4 special occasions we used sprocs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;syntaxc4-profile&#34;&gt;SyntaxC4 (&lt;a href=&#34;http://forums.asp.net/members/SyntaxC4.aspx&#34;&gt;Profile&lt;/a&gt;)&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;I do use Stored Procedures on a regular basis. I develop mostly in
DotNetNuke, which has an extensive use of stored procs. I have read
blogs, and forum posts that suggest that stored procedures shouldn&amp;rsquo;t
be used as they can be a performance bottleneck, but I believe they
are an excellent way of promoting SQL Abstraction. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;I do however try to preserve the number of stored procedures I write.
I normally create one stored procedure to handle both insert and
updates to the a particular table, one for deleting, and one to select
(sometimes i do multiple select statements within one stored proc if
it makes sense). &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;To work away from bottlenecks, i try to use subqueries in my stored
procedures instead of using a view to query against. unless of course
a view is more efficient.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;tatworth-profile&#34;&gt;TATWORTH (&lt;a href=&#34;http://forums.asp.net/members/TATWORTH.aspx&#34;&gt;Profile&lt;/a&gt;)&lt;/span&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;It is not much a case of would I use stored procedures as when would I
not use them! Occasionally for searching, dynamic TSQL needs to be
generated and for this I would use parameterized TSQL. Otherwise I use
stored procedures all the time. I do have stored procedures for
generating from the table definition stored procedures plus wrapper
code. This allows very rapid development of the data layer.&lt;/p&gt;
&lt;p&gt;The use of stored procedures (or the occasional parameterized TSQL) is
in my opinion one of a series of essential steps to produce robust
applications.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;tom-peeters-a-co-worker&#34;&gt;Tom Peeters (a co-worker)&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;I prefer to (read &lt;em&gt;always&lt;/em&gt;) use stored procedures when I’m developing
front end applications. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The ones who find creating stored procedures is intolerable overhead,
I want to give some advantages.. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;They are modular, I’d prefer to troubleshoot a stored procedure
than an embedded query buried within many lines of GUI code.&lt;/li&gt;
&lt;li&gt;They are tunable. Changes can be made to the stored procedures
&amp;ndash;in terms of join methods, differing tables, etc.&amp;ndash; that are
transparent to the front-end interface.&lt;/li&gt;
&lt;li&gt;Stored procedures abstract or separate server-side functions from
the client-side. It is much easier to code a GUI application to
call a procedure than to build a query through the GUI code.&lt;/li&gt;
&lt;li&gt;Stored procedures are usually written by database
developers/administrators. Persons holding these roles are usually
more experienced in writing efficient queries and SQL statements.
This frees the GUI application developers to utilize their skills
on the functional and graphical presentation pieces of the
application. If you have your people performing the tasks to which
they are best suited, then you will ultimately produce a better
overall application.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In short, queries are best handled via stored procedures. While the
initial development overhead is greater, you will more than make up
for the investment down the line.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Looks like a lot of people are still very fond of stored procedures. The
arguments make a lot of sense!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://jefclaes.be/about/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://jefclaes.be/about/</guid>
      <description>&lt;p&gt;Hello world&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
