﻿<?xml version="1.0" encoding="utf-8"?><rss version="2.0"><channel><title>Ayende @ Rahien</title><link>http://ayende.com/blog/</link><description>Ayende @ Rahien</description><copyright>Copyright (C) Ayende Rahien  2004 - 2012 (c) 2013</copyright><ttl>60</ttl><item><title>Querying your way to madness: the Facebook timeline</title><description>&lt;p&gt;Facebook certainly changed the way we are doing things. Sometimes, that ain’t always for the best, as can be seen from the way too much time humanity as a whole spend watching cat videos. &lt;/p&gt; &lt;p&gt;One of the ways that Facebook impacted our professional lives is that a lot of people look at that as a blue print of how they want their application to be. I am not going to touch on whatever that is a good thing or not, suffice to say that this is a well known model that is very easy for a lot of users to grasp.&lt;/p&gt; &lt;p&gt;It is also a pretty hard model to actually design and build. I recently had a call from a friend who was tasked with building a Facebook like timeline. Like most such tasks, we have the notion of social network, with people following other people. I assume that this isn’t actually YASNP (yet another social network project), but I didn’t check too deeply.&lt;/p&gt; &lt;p&gt;The question was how to actually build the timeline. The first thing that most people would try is something like this:&lt;/p&gt; &lt;blockquote&gt; &lt;div id="codeSnippetWrapper"&gt; &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; var user = session.Load&amp;lt;User&amp;gt;(userId);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; var timelineItems = &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;    session.Query&amp;lt;Items&amp;gt;()&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;       .Where(x=&amp;gt;x.Source.In(user.Following))&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;       .OrderByDescending(x=&amp;gt;x.PublishedAt)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;       .Take(30)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;       .ToList();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;Now, this &lt;em&gt;looks&lt;/em&gt; good, and it would work, as long as you have small number of users and no one follows a lot of people. And as long as you don’t have&amp;nbsp; a lot of items. And as long as you don’t have to do any additional work.&amp;nbsp; When any of those assumption is broken… well, welcome to unpleasantville, population: you.&lt;/p&gt;
&lt;p&gt;It &lt;em&gt;can’t&lt;/em&gt; work. And I don’t care what technology you are using for storage. You can’t create a good solution using queries for something like the timeline.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Nitpicker corner:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you have users that are following a LOT of people (and you will have those), you are likely to get into problems with the query.&lt;/li&gt;
&lt;li&gt;The more items you have, the slower this query becomes. Since you need to sort them all before you can return results. And you are likely to have a LOT of them.&lt;/li&gt;
&lt;li&gt;You can’t really shard this query nicely or easily.&lt;/li&gt;
&lt;li&gt;You can’t apply additional filtering in any meaningful way.&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;
&lt;p&gt;Let us consider the following scenario. Let us assume that I care for this Rohit person. But I really &lt;em&gt;don’t&lt;/em&gt; care for Farmville. &lt;/p&gt;
&lt;p&gt;&lt;img title="farmville-ribbon" border="1" alt="hide farmville ribbon" src="http://www.quickonlinetips.com/archives/wp-content/uploads/farmville-ribbon.png"&gt;&lt;/p&gt;
&lt;p&gt;And then:&lt;/p&gt;
&lt;p&gt;&lt;img title="hide-farmville" alt="hide farmville " src="http://www.quickonlinetips.com/archives/wp-content/uploads/hide-farmville.png" width="500" height="62"&gt;&lt;/p&gt;
&lt;p&gt;Now, try to imagine doing this sort of thing in a query. For fun, assume that I &lt;em&gt;do&lt;/em&gt; care for Farmville updates from &lt;em&gt;some&lt;/em&gt; people, but not from all. That is what I mean when I said that you want to do meaningful filtering.&lt;/p&gt;
&lt;p&gt;You can’t do this using queries. Not in any real way.&lt;/p&gt;
&lt;p&gt;Instead, you have to turn it around. You would do something like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; var user = session.Load&amp;lt;User&amp;gt;(userId);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; var timelineItmes = session.Query&amp;lt;TimeLineItems&amp;gt;() &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;       .Where(x=&amp;gt;x.ForUser == userId)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;       .OrderBy(x=&amp;gt;x.Date)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;       .ToList();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;Note how we structure this. There is a set of TimeLineItems objects, which store a bit of information about a set of items. Usually we would have one per user per day. Something like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;users/123/timeline/2013-03-12&lt;/li&gt;
&lt;li&gt;users/123/timeline/2013-03-13&lt;/li&gt;
&lt;li&gt;users/123/timeline/2013-03-14&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;That means that we get well scoped values, we only need to search on a single set of items (easily sharded, with a well known id, which means that we can also just load them by id, instead of querying for them).&lt;/p&gt;
&lt;p&gt;Of course, that means that you have to have something that &lt;em&gt;builds&lt;/em&gt; those timeline documents. That is usually an async process that run whenever you have a user that update something. It goes something like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; UpdateFollowers(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; itemId)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     var item = session.Include&amp;lt;Item&amp;gt;(x=&amp;gt;x.UserId)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;         .Load(itemId);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;     var user = session.Load&amp;lt;User&amp;gt;(item.UserId);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;     &lt;span style="color: #008000"&gt;// user.Followers list of documents with batches of followers&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;     &lt;span style="color: #008000"&gt;// we assume that we might have a LOT, so we use this techinque&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;     &lt;span style="color: #008000"&gt;// to avoid loading them all into memory at once&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;     &lt;span style="color: #008000"&gt;// http://ayende.com/blog/96257/document-based-modeling-auctions-bids&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt;(var followersDocId &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; user.Followers)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;     {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt;         NotifyFollowers(followersDocId, item);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum15"&gt;  15:&lt;/span&gt;     }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum16"&gt;  16:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum17"&gt;  17:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum18"&gt;  18:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; NotifyFollowers(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; followersDocId, Item item)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum19"&gt;  19:&lt;/span&gt; {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum20"&gt;  20:&lt;/span&gt;     var followers = session.Include&amp;lt;FollowersCollection&amp;gt;(x=&amp;gt;x.Followers)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum21"&gt;  21:&lt;/span&gt;         .Load(followersDocId);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum22"&gt;  22:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum23"&gt;  23:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt;(var follower &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; followers.Followers)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum24"&gt;  24:&lt;/span&gt;     {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum25"&gt;  25:&lt;/span&gt;         var user = session.Load&amp;lt;User&amp;gt;(follower);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum26"&gt;  26:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(user.IsMatch(item) == &lt;span style="color: #0000ff"&gt;false&lt;/span&gt;)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum27"&gt;  27:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;continue&lt;/span&gt;;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum28"&gt;  28:&lt;/span&gt;         AddToTimeLine(follower, item);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum29"&gt;  29:&lt;/span&gt;     }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum30"&gt;  30:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;As you can see, we are batching the operation, loading the followers and batched on their settings, decide whatever to let that item to be added to their timeline or not.&lt;/p&gt;
&lt;p&gt;Note that this has a lot of implications. Different people will see this show up in their timeline in different times (but usually very close to one another). Your memory usage is kept low, because you are only processing some of it at any given point in time. For users with a LOT of followers, and there will be some like those, you might want to build special code paths, but this should be fine even at its current stage.&lt;/p&gt;
&lt;p&gt;What about post factum operations? Let us say that I want to start following a new user? This require special treatment, you would have to read the latest timeline items from the new user to follow and start merging that with the existing timeline. Likewise when you need to delete someone. Or adding a new filter. &lt;/p&gt;
&lt;p&gt;It is a lot more work than just changing the query, sure. But you can get things done this way. And you cannot get anywhere with the query only approach.&lt;/p&gt;</description><link>http://ayende.com/blog/161537/querying-your-way-to-madness-the-facebook-timeline?key=81c5d40b-5061-4bc2-a0db-9700fa041be9</link><guid>http://ayende.com/blog/161537/querying-your-way-to-madness-the-facebook-timeline?key=81c5d40b-5061-4bc2-a0db-9700fa041be9</guid><pubDate>Mon, 22 Apr 2013 10:00:00 GMT</pubDate></item><item><title>What is making us slow (for the first time, after an idle period)?</title><description>&lt;p&gt;We recently covered this question in several iterations in the ravendb mailing list.&lt;/p&gt; &lt;p&gt;The actual content of the discussion wasn’t so interesting as the number of ways idle time can make you life… interesting. In order to avoid having issues with idle time, you need to:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Disable IIS unloading for inactive websites.&lt;/li&gt; &lt;li&gt;Disable RavenDB&amp;nbsp; unloading for inactive databases.&lt;/li&gt; &lt;li&gt;Make sure that the HD doesn’t spin down during inactivity.&lt;/li&gt; &lt;li&gt;You need to make sure that the system doesn’t got to idle / hibenration.&lt;/li&gt; &lt;li&gt;Check that the server hasn’t been paged.&lt;/li&gt; &lt;li&gt;Check that the CPU hasn’t moved to low power mode.&lt;/li&gt; &lt;li&gt;Check authentication timeouts.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;In the end, it was actually the last one that caused the problem. By default, Windows Auth token expire after 15 minutes, so you have to re-authenticate again, and that may make the first query after a while a little slower.&lt;/p&gt; &lt;p&gt;Just for fun, by default, &lt;em&gt;all of the above &lt;/em&gt;happen. And that is just when running on a physical machine. When running on VMs (or in the cloud), you need to do all of those checks for the VM and the host machines.&lt;/p&gt;</description><link>http://ayende.com/blog/161665/what-is-making-us-slow-for-the-first-time-after-an-idle-period?key=ef928c18-b2b1-4a85-9cc4-916b10c088df</link><guid>http://ayende.com/blog/161665/what-is-making-us-slow-for-the-first-time-after-an-idle-period?key=ef928c18-b2b1-4a85-9cc4-916b10c088df</guid><pubDate>Wed, 17 Apr 2013 10:00:00 GMT</pubDate></item><item><title>My Passover Project: Introducing Rattlesnake.CLR</title><description>&lt;p&gt;Okay, after spending quite a lot of time digging through the leveldb codebase, and with several years of working with RavenDB, I can say with confidence that the CLR make it extremely hard to build high performance server side systems using the CLR.&lt;/p&gt; &lt;p&gt;Mostly, the issues are related to GC and memory. In particular, not having any way to control memory allocation and/or the GC means that we can’t optimize those scenarios in any meaningful way. At the same time, I do &lt;em&gt;not&lt;/em&gt; want to go back to the unmanaged world. As mentioned ,I just came back from a very deep dive into a non trivial C++ codebase ,and while I consider that codebase a really good one, that ain’t to say it is a pleasure to always be thinking about all the stuff that the CLR just takes away.&lt;/p&gt; &lt;p&gt;Therefor, I decided that I’m going to be doing something about it. And Rattlesnake.CLR was born:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Implementing-LevelDB-in-managed-code-and_9F16/image_2.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/Implementing-LevelDB-in-managed-code-and_9F16/image_thumb.png" width="157" height="161"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;The major features of the Rattlesnake.CLR include explicit memory management &lt;em&gt;when&lt;/em&gt; required. Let us say that we know that we are going to be needing some amount of memory for a while, and then all of that can be thrown away. This is extremely common in scenarios such as a web request, pretty much all the memory that you generate during the processing web request can be safely free immediately. In RavenDB’s case, the memory we consume during indexing can be free immediately when we stop indexing. Right now this is a painful process of making sure that we allocate within the same gen0 and hoping that it won’t be too expensive, or that we won’t get a complete halt of the entire server while it is releasing memory. It also make it &lt;em&gt;really&lt;/em&gt; hard to do things like limit the amount of memory your code uses.&lt;/p&gt; &lt;p&gt;Another requirement that I have is that Rattlesnake.CLR should be able to execute existing .NET assemblies without any additional steps. Since I don’t fancy doing ports of stuff that already exists.&lt;/p&gt; &lt;p&gt;In order to handle this scenario with the given constraints, we have:&lt;/p&gt; &lt;blockquote&gt; &lt;div id="codeSnippetWrapper"&gt; &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; var heap = Heap.Create(HeapOptions.None, &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;     1024 * 1024,&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     512 * 1024 * 1024);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;using&lt;/span&gt;(MemoryAllocations.AllocateFrom(heap))&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt; {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;    var sb = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; StringBuilder();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;    &lt;span style="color: #0000ff"&gt;for&lt;/span&gt;(var i = 0; i &amp;lt; 100; i ++ )&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;          sb.AppendLine(i);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;    Console.WriteLine(sb.ToString());&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt; heap.Destroy(); &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;All the code within the using statement is allocated in our own heap. In line 13, we are destroying all of that memory in one fell swoop.&lt;/p&gt;
&lt;p&gt;There are a few notes about this that we probably should address:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;By default, memory allocated by this form is not subject to any form of GC. The idea is that this whole heap is getting released immediately.&lt;/li&gt;
&lt;li&gt;Note that last two parameters for the Heap.Create. The first is the initial size of the heap, and the second is&amp;nbsp; the max size. We now have a real way to actually limit the amount of memory a piece of code will use. This is really important on server applications where avoiding paging is critical.&lt;/li&gt;
&lt;li&gt;For that matter, we can now figure out how much memory a particular piece of code uses, and allocate our resources accordingly.&lt;/li&gt;
&lt;li&gt;You can use multiple heaps at the same time, although only one can be installed as the default allocation at a given point in time.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;There is the explicit heap.GarbageCollect() method that will do GC only on that heap, and which you can schedule at your own convenience.&amp;nbsp; You can have two heaps, and allocate from one while you are GCing from the other. And yes ,that means that GCs using this methods will &lt;em&gt;not&lt;/em&gt; stop the process!&lt;/p&gt;
&lt;p&gt;Memory allocated on the heap is obviously only valid as long as the heap is valid. That means that once the heap is destroyed, you can’t access any of the objects that were created there. This has implications for things like cache. We provide MemoryAllocations.AllocateOnGlobalHeap&amp;lt;T&amp;gt;(args) method to force you to use the global heap, instead, if you want this memory to be always available and subject to GC.&lt;/p&gt;
&lt;p&gt;This is early days yet, but we already see some really interesting performance improvements!&lt;/p&gt;
&lt;p&gt;How does this work?&lt;/p&gt;
&lt;p&gt;While an early experiment with Rattlensake.CLR was based on the Mono runtime. I quickly decided that I wanted to keep using the MS CLR. Now, it order to handle this I had to do some unnatural things (to say the least), but I think that I even managed to make this a supported option. Essentially, we are using the CLR Hosting API for this. In particular:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ICLRGCManager&lt;/li&gt;
&lt;li&gt;IHostMalloc&lt;/li&gt;
&lt;li&gt;IHostMemoryManager &lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;You can use Rattlesnake.CLR like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;.\Rattlesnake.exe Raven.Server.exe&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Just for fun, we also allowed to place limits on the default heap, so you can be sure that you aren’t allocating too much there.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;.\Rattlesnake.exe Raven.Server.exe --max-default-heap-size=256MB&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;We are still running some tests, but this is looking really good. &lt;/p&gt;</description><link>http://ayende.com/blog/161889/my-passover-project-introducing-rattlesnake-clr?key=d79d601a-c67a-4d80-a182-117b2e343aac</link><guid>http://ayende.com/blog/161889/my-passover-project-introducing-rattlesnake-clr?key=d79d601a-c67a-4d80-a182-117b2e343aac</guid><pubDate>Mon, 01 Apr 2013 10:00:00 GMT</pubDate></item><item><title>Hibernating Rhinos Practices: A Sample Project</title><description>&lt;p&gt;I have previously stated that one of the things that I am looking for in a candidate is the actual candidate code. Now, I won’t accept “this is a project that I did for a client / employee”, and while it is nice to be pointed at a URL from the last project the candidate took part of, it is not a really good way to evaluate someone’s abilities.&lt;/p&gt; &lt;p&gt;Ideally, I would like to have someone that has an OSS portfolio that we can look at, but that isn’t always relevant. Instead, I decided to sent potential candidates the following:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;Hi,&lt;/p&gt; &lt;p&gt;I would like to give you a small project, and see how you handle that.&lt;/p&gt; &lt;p&gt;The task at hand is to build a website for Webinars questions. We run bi-weekly webinars for our users, and we want to do the following:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Show the users a list of our webinars (The data is here: &lt;a title="http://www.youtube.com/user/hibernatingrhinos" href="http://www.youtube.com/user/hibernatingrhinos"&gt;http://www.youtube.com/user/hibernatingrhinos&lt;/a&gt;)  &lt;li&gt;Show a list of the next few scheduled webinar (in the user’s own time zone)  &lt;li&gt;Allow the users to submit questions, comment on questions and vote on questions for the next webinar.  &lt;li&gt;Allow the admin to mark specific questions as answered in a specific webinar (after it was uploaded to YouTube).  &lt;li&gt;Manage Spam for questions &amp;amp; comments.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;The project should be written in C#, beyond that, feel free to use whatever technologies that you are most comfortable with.&lt;/p&gt; &lt;p&gt;Things that we will be looking at:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Code quality  &lt;li&gt;Architecture  &lt;li&gt;Ease of modification  &lt;li&gt;Efficiency of implementation  &lt;li&gt;Ease of setup &amp;amp; deployment&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Please send us the link to a Git repository containing the project, as well as any instructions that might be necessary.&lt;/p&gt; &lt;p&gt;Thanks in advance,&lt;/p&gt; &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Oren Eini&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;This post will go live about two weeks after I started sending this to candidates, so I am not sure yet what the response would be.&lt;/p&gt;</description><link>http://ayende.com/blog/161026/hibernating-rhinos-practices-a-sample-project?key=36b548de-576b-479b-9eeb-9547a76aa1a3</link><guid>http://ayende.com/blog/161026/hibernating-rhinos-practices-a-sample-project?key=36b548de-576b-479b-9eeb-9547a76aa1a3</guid><pubDate>Fri, 22 Feb 2013 10:00:00 GMT</pubDate></item><item><title>Software architecture with nail guns</title><description>&lt;p&gt;As you probably know, I get called quite a lot to customers to “assist” in failing or problematic software projects. Maybe the performance isn’t nearly what it should be, maybe it is so very hard to make changes, maybe it is… one of the thousand and one things that can go wrong, and usually does.&lt;/p&gt; &lt;p&gt;Internally, I divide those projects into two broad categories: The stupid and the nail guns.&lt;/p&gt; &lt;p&gt;I rarely get called to projects that fall under the stupid category. When it happens, it is usually because someone new came in, looked at the codebase and called for help. I &lt;em&gt;love&lt;/em&gt; working with stupid code bases. They are easy to understand, if hard to work with, and it is pretty obvious what is wrong. And the team is usually very receptive about getting advice on how to fix it.&lt;/p&gt; &lt;p&gt;But I usually am called for nail gun projects, and those are so much more complex…&lt;/p&gt; &lt;p&gt;But before I can talk about them, I need to explain first what I meant when I say “nail gun projects”. Consider an interesting fact. &lt;em&gt;Absolutely no one &lt;/em&gt;will publish an article saying “we did nothing special, we had nothing out of the ordinary, and we shipped roughly on time, roughly on budget and with about the expected feature set. The client was reasonably happy.” And even if someone would post that, no one would read it.&lt;/p&gt; &lt;p&gt;Think about your life, as an example. You wake up, walk the dogs, take kids to school, go to work, come back from work, fall asleep reading this sentence, watch some TV, eat along the way, sleep. Rinse, repeat. &lt;/p&gt; &lt;p&gt;Now, let us go and look at the paper. At the time of this writing, those were the top stories at CNN:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://edition.cnn.com/2013/01/26/world/africa/egypt-unrest/index.html?hpt=hp_t2"&gt;Egypt deploys troops to quell clashes&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://edition.cnn.com/2013/01/26/world/meast/iraq-protests/index.html?hpt=hp_t3"&gt;Iraq unrest: 4 soldiers killed, 4 abducted&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://edition.cnn.com/2013/01/26/world/africa/mali-unrest/index.html?hpt=hp_t3"&gt;Malian troops reach rebel stronghold&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://edition.cnn.com/video/?hpt=hp_t3#/video/world/2013/01/26/lister-syria-prison-attack.cnni"&gt;Syrian rebels attack prison&lt;/a&gt; &lt;/li&gt; &lt;li&gt;&lt;a href="http://edition.cnn.com/2013/01/26/world/americas/venezuela-prison-riot/index.html?hpt=hp_t3"&gt;Dozens killed in Venezuela prison riot&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://edition.cnn.com/2013/01/26/world/antarctica-plane/index.html?hpt=hp_t3"&gt;3 feared dead in Antarctic plane crash&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://edition.cnn.com/2013/01/25/showbiz/band-fraud-accusations/index.html?hpt=hp_t3"&gt;Musician held for fake loan applications&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Hopefully, there is a big disconnect between your life and those sort of news.&lt;/p&gt; &lt;p&gt;Now, let us think about the sort of posts, articles and books that you have been reading. You won’t find any book called: "Delivering OK projects”&lt;/p&gt; &lt;p&gt;And most of the literature about software projects is on one of two ends: We did something incredibly hard, and we did it well or we did something (obvious, usually) and we failed really badly. People who read those books tend to look at those books (either kind) and almost blindly adopt the suggested practices. Usually without looking at that section called “When it is appropriate to do what we do”.&lt;/p&gt; &lt;p&gt;Probably the best example is the waterfall methodology, originated in the 1970&amp;nbsp; paper "&lt;a href="http://leadinganswers.typepad.com/leading_answers/files/original_waterfall_paper_winston_royce.pdf"&gt;Managing the Development of Large Software Systems&lt;/a&gt;" from Winston W. Royce.&lt;/p&gt; &lt;p&gt;From the paper:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;…the implementation described above is &lt;strong&gt;risky and invites failure&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;As you can imagine, no one actually listened, and the rest is history. &lt;/p&gt; &lt;p&gt;How about those nail guns again? &lt;/p&gt; &lt;p&gt;Well, imagine that you are a contractor, and here are you tools of the trade:&lt;/p&gt; &lt;p&gt;&lt;img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBhISEBIUERITFBIWFRcQGBgQExMUGBYTFRQXGhYYFRMcHCYgGhsjGRUVHy8gJigpLSwsFh4xNzAqNSYrLikBCQoKDgwOGg4PGTMkHyQ1NDIpNTU1LDUxNSwvLCwsKTItNi80Kik1Lyw0KSw0LSwsLCs1LywsNCwwLDQsLCw1L//AABEIAKsBJgMBIgACEQEDEQH/xAAcAAEAAgMBAQEAAAAAAAAAAAAABgcEBQgDAgH/xABBEAACAQIDBQUFBQYEBwEAAAAAAQIDEQQhMQUGEkFRBxNhcYEiMmKRoSNScrHBFEJDgtHwM1ST4RYkc5KisvEV/8QAGgEBAAIDAQAAAAAAAAAAAAAAAAQFAQMGAv/EACoRAQACAQMACgEFAAAAAAAAAAABAgMEESEFEiIxQVGBkaHwcRMjwdHh/9oADAMBAAIRAxEAPwC8QAAAIjtneKXeuCuqa9m65yWt/ACRYvatOHO76R/Vmgx+8VR+61FeGvzZqZ4m+jNTtKpWk+GDUYvWS1Wt+fla30A2Vfa1Rv2p1P8Auf8AU1mK2/GF+OtwfinJt+UVdv5W8Txp4TgVk5O+bcne78uRrNsbGjWX3ZpWjK30fVAZT31p8pVZeSSXzcr/AEPuHaIo6RxH+vFfTgZAK+zu6m4V6lWnldOMVKMs82rO9vr1sS3Z2C2XNUlCtTk5rNYipiKLi1bWSq8PPkno9QN3R7Vbawr/AOtTl+dM2NLtapr3o175axoy+qcbmPT7O8LKzVCvKOnFhMVCstNftIxdsuV9UJ9m2A/zOIot/wCahGOf4pQin6MDaYPtPjVrUadKDn3lSNNucVTtxNLK05X1fTQnxAN3+y2OHxFKssT3kYS7xLukrtLK0uN87PTkT8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfM6iirtpLxdiLba3vnGs6OHgpOLtKUldJ80ldadb+hpttYrGRp99Uj3lPm6eTh+KHJeKbAndbGw4G+8ila1007N6Febbx8FPi92CeV7XZHaG061epw0lKTf3c0l4nvtfYtVVoxxOmVRSvk480380BIdlbOli4ynTuksr5Wk/XVnrW2BWgtOLw92V/J6+jZ74Xe1U6UaeHhFKKs5STzfhBfm/ka/F704mV138o3X7kacWvJ8N/qBg4qLWTTT6NW+hjcZssLvDPhUMRGOJp/EowqrxjNWTfnr1MHaypR4ZUKjmpvhjTaarKSV2nDnZfvXt49cWtFY3lmImZ2hi16MZxakrrpz810fiab/hbG1YSlhVVq0lLhupJ5rVcPFna+trEhobPk/8AFVtHwp39JPn+X67PDXptODcWucciky9M46X2rG8ef9LGnR9prvadpQGbx2EXtwr0ne/FKnONmtPasZ2E7S8bwtftPFfJqcYS6dV+RdexdrRr01mu8StOPR9UujPnH7s4Ss71sNRm9bypwcvSVrlzjyVyVi9Z3iVfas0nqyjvZn31SlUxFZpKb4IKMVFNRb4ptLX2nZP4WTU8sNho04RhTiowilGMYqySWiSPU9vIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACtdjUHOvUu/a45N3yz4ncsDDYSPd8LSaas08001mrdCHbzbIlRxHfQT7ub4m1+7N6p+Defm2SjYWM46dnqgINidqPZkq+HjST9pVKVRq32NRNqMurjKMo35pI0+ztn4rH10pTdpXbc72UV4clovUmW88FicTGjTipygk5Nq6i82s/5jd7B2CsOm2+Ko1Zvkl0QERqbhYxXUalFx0VpTTa8nG31NVjN1sdTT+xlLLWDjP/AMU7/QtoAUROdWDtOnKL6NNfRmdsiXeYqLf8Om2l41HZu/go/UuHGbPpVVarTjNfEk7eT5ehqZ7m4dcTpQ7uo7e1eUrpcmm9CHrsV8uC1MffLfp71pki1u5oeBNaXZ5unB6XTNyt26y507fil+XD+pgYvBSi7VItPk/6PmcDm0eo0/ayVmI++i8pmpedqywe7nTkpQbUlpKJIdk72J2jXtGWnGvdfn938vI0qjJae0vqYuOwrqRfdyUJ+KyeWjtmvNfJ6EnR9IZdPPE8fDGXDTLHahYyd81pqfpText7Np4Cpw4qEJ4bjVNSc4R1fvRXE211slzbRZ2xd5qGKT7ua407ShLKSfkztMGsx5do3jf49J+ypcmntTnwbYAE1HAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHzOCkmmk08mmrp+hh/wD5MUmqc500/uOP0cotr0M4AYuA2ZTopqnGzk7ybbcpPrKTzZlAAAAAAAA+alNSVpJNPk1c+gYmN+JGkxu7q1pOz+7LT0fI0eJwzi7Ti4y/vR8ybnnXw8Zq04prx/ToUWs6Ew5e1i7Nvj7+PZOxa29eLcx8oFicNGcHGpGNSm9VJX+aI/X3adNqeHnNpclJd7FLRQnL3l8Mn5MsDG7vNZ0ndfdevo+fqaWrRzzTjJeFvmjmcmLU6G3VvG0fE/fdaUyUyxvWWJsftCqUvZxMXVpxtF1IRaqQ/wCtSftR83l4k72btWliIKdGpGcXzi7/AD6EDxmBhUt3iakso1IPhlHymuXg8nzTPLZ2ynQbnTku8esqa7ttcuKKfDfrZJPoW2l6b/TjbJz980bLo635rxKzARjZ29rXs14/zRX/ALR/p8iRYfEwqR4oSUl1TudJp9Xi1Eb459PFWZcF8U9qHqACU0gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABj4zAQqr21nyaya8mZAPF6VvXq2jeGYtNZ3hFsdsOdO7j7cPBZrzj+q+hq+D7uXhyJ6a7H7EhUu17M+q5+a5nM6zoKOb6afSf4/wB91lh13hk90SaUspKzPOEp0ZcVOTT6r9VzM/HbNnT99ZcpLT58vJmLwnOfuae+071mFnE1vHHMM/Db5zX+JBSXWPsv5aP6Gz2dvng6zUYV4Kby4ZtRd+ivk/Rsp7freOKcqFF3elRp5J84efX5dSC/tUr3uzt+jJ1F8fXyzxPd5qbV/pRbq44/LrYHPe7Pali8LaLn3tNZcFW7svhlrH8vAtTdrtRwWLtHvFRq6cFWSs38M9H62fgWqEmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+ZwTTTSaeTTIlvLsmdGFSpSi5xUZS4Vm00m7eXjyJeGiHqtHi1Vdrx3d0+LdhzWxTvVyzip8cpSlrJuTeebbu/qzDq4T1L03u7KaNfiqYXho1dXHSnN+S9x+WXhzKf2tsmthajp1qcoSXKXNdYvRrxWRLiIiNoaZndopQaEZJZaGxdNSMStgzIk27PaRjcFaMane0V/DqviSXwy1Rbm6vang8ZaMpdxW+7UeTfwz0+dvU5zfFF+B9RrLyf98wOvQc87n9qWKwloTl31JO3DUd7L4Zax/LwLl3a36wuNSVOfDU506jSl/Lyl6fJASEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1+2dg0MXT7vEU1OPK+Ti+sZapmwAFH73dk1fD8VTCt1qWtkvtIrxiveXivkiB9607SVmdWER3t7NsNjU5Jd1X144LKT+OPPzyYHP8qSZiVsMSXeTcrFYGVqsLwbtGcc4S8pcn4OzNF3vJ/UDWNuJ74baTi7ptNPlkZEqaZhV8B0AtDc/tmrUUqeKTr01pK/2iX4n73rn4lv7C3jw+Mpqph6kZrmtJR8JReaOSVKUX5WNlsfb1WhPjo1JU5J5ODaa/voB1uCptz+22MkoY9cMll3tOOXnOC084/ItPCYuFWEZ05xnCSupQakmvBoD2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB516EZxcZxUotWakk010aepW+9nY3Sq3ng2qc9e7m3wv8MtY+TuvIswAcq7Z2FiMJUcK1OcJL7y1XVPRrxRgxxi58tf8Ac6s2nsijiIOnXpxqQfKS08U9U/FFSb49hrs6mBk5Z37qbSlbpGekvJ282BV3dqWfXP8AoYVXC206/U9dp4bEYeThVpyjJOz4ouNra3T0PqOKil1/VgYdOo1qtfyJBurvzisE/wDl6rSvnCWcJW+9B+GV8n4mr7jiz+Xl/efqYKw8ldrr+aA6P3P7XsJi1GNZrD1nZWm/YlL4Z8r9Hb1J6cZUcRa/m0T3cztYxeDioSffUY5d3UbukuVOesfLNeAHSAI5uvv9g8dFd1U4aj1p1LRnfw5S9LkjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1m393MPjKXd4impx1XJxdrXjLkylt9OwarRi6uBnKtG7bpcKU1G2Tyft59En4F+ADjStjp024VIOM07NPK3XLkZ1KrHh1XXzZ05vduLhdo0nCtC0r8UakFFTjK1tbZq2qZQW+/Y9jNnQdaEliKCbu6UZ8VOKtZzjbJeKbSsBGY4TLTn/t+dzEjTa063PujtZcNrWei8jMpWau8m/afh4fKwGLgsdKHXW31yafXmWRup204rD2jXf7RSWXtu1RJc1U5/zXK4eGeb8bfLX63MaE3FvzA6t3c7QsFjbKnVUKj/AIdW0ZX+HlL0bJKcaYfHNcyebq9reMwrUZT7+ksuCs3JpfDP3l9V4AdHgim6PaRhcfeMb0qsY8bhUtpdJuM9GrtdHnofgEsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8aP0AVnv/2J4bGQc8HGnhsSm5eymqdS/KcV7r6SS5u6fKhdv7AxuAn3eLpTpt3s3Zxkk9YzV1JXtz6HYxrdvbu4fG0XRxVKNSm87S1i/vRks4y8UByXh8dHhWf/ANPqFBS9Xf56fQmfaR2K1MCu/wAF3lfDJXmnaVSlm82klxQtbNLKzvkV3Q2hLRv1528AP3FYdpu3p5HjGu0bp0U0tGmrqxj4nCxjTlJ8skusnp+r9ANzuBgsXia844RN1I0nJ2drR44LXz4fkC5ewrdH9k2f39RWrYq1XPVUVful6puf866ACygAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKW7WexnvOPF7Oh9pnKrQgkuPrOkl+91jz5Z5O6QBxPh8W4O0r5ZNdPQl/ZxurPau0IRkpfstJqrW1twJ5Qv96bVutlJ/uljdqW6GDltTBN0I3xDn3vC5w7xxtZvhazzeazfMs7dvdvDYKiqWFoxpQfttR4m3JpXcpSbcnktXyA2kYpJJKyWSS5LwB+gD//Z"&gt;&lt;img src="https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcRiqQVArzIzI5FNDDLFYUBt95zaPM34JFjuQy_N5WurjGhuJMzi2A"&gt;&lt;/p&gt; &lt;p&gt;They are &lt;em&gt;good&lt;/em&gt; tools, and they served you well for a while. But now you are reading about “Nail guns usage for better, faster and more effective framing or roofing". In the study, you read how there was a need to nail 3,000 shingles and using a nail gun the team was successfully able to complete the task with higher efficiency over the use of the standard hammer.&lt;/p&gt; &lt;p&gt;Being a conscientious professional, you head the advice and immediately buy the best nail gun you can find:&lt;/p&gt; &lt;p&gt;&lt;img src="http://t3.gstatic.com/images?q=tbn:ANd9GcRfyCDn8oURR8qaAa1GRyIvGQ22Y6a_pFdXsMHicNJh-pE8PrgMzw6HgL3diw"&gt;(This is just a random nail gun picture, I don’t know what brand, nor really care.)&lt;/p&gt; &lt;p&gt;And indeed, a nail gun is a great tool when you need to nail a lot of things very fast. But it is a highly effective tool that is extremely limited in what it can do.&lt;/p&gt; &lt;p&gt;But you know that a nail gun is 333% more efficient than the hammer, so you throw it away. And then you get a request: Can you hang this picture on the wall, please?&lt;/p&gt; &lt;p&gt;It would be &lt;em&gt;easy&lt;/em&gt; with a hammer, but with a nail gun:&lt;/p&gt; &lt;p&gt;&lt;img src="http://graeme.woaf.net/otherbits/jellypics/small_jelly_nailed_2.jpg"&gt;&lt;/p&gt; &lt;p&gt;It isn’t the stupid / lazy / ignorant people that go for the nail gun solutions.&lt;/p&gt; &lt;p&gt;It is the really hard working people, the guys who really try to make things better. Of course, what usually happen is this:&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;img src="http://greatpowerpointdesign.com/Presentation-Tips/Talking-Tips/Overcoming-Tough-Times-Through-Positive-Presentations/Guy-Nailed-to-Wall.jpg"&gt;&lt;/p&gt;  &lt;p&gt;And here we get back to the projects that I usually get called for. Those are projects that were created by really smart people, with the best of intentions, and with the clear understanding that they want to get quality stuff done.&lt;/p&gt; &lt;p&gt;The problem is that they are using Nail Guns for the architecture. For example, let us just look at &lt;a href="http://ayende.com/blog/19457/review-microsoft-n-layer-app-sample-part-i"&gt;this post.&lt;/a&gt; And the end is already written. &lt;/p&gt;</description><link>http://ayende.com/blog/160897/software-architecture-with-nail-guns?key=62a5658e-c743-4024-a06f-9d710f02ebc7</link><guid>http://ayende.com/blog/160897/software-architecture-with-nail-guns?key=62a5658e-c743-4024-a06f-9d710f02ebc7</guid><pubDate>Mon, 11 Feb 2013 10:00:00 GMT</pubDate></item><item><title>Hibernating Rhinos Practices: Design</title><description>&lt;p&gt;One of the things that I routinely get asked is how we design things. And the answer is that we usually do not. Most things does &lt;em&gt;not&lt;/em&gt; require complex design. The requirements we set pretty much dictate how things are going to work. Sometimes, users make suggestions that turn into a light bulb moment, and things shift very rapidly.&lt;/p&gt; &lt;p&gt;But sometimes, usually with the big things, we actually do need to do some design upfront. This is usually true in complex / user facing part of our projects. The Map/Reduce system, for example, was mostly re-written&amp;nbsp; in RavenDB 2.0, and that only happened after multiple design sessions internally, a full stand alone spike implementation and a lot of coffee, curses and sweat.&lt;/p&gt; &lt;p&gt;In many cases, when we can, we will post a suggested design on the mailing list and ask for feedback. Here is an example of such a scenario:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="https://groups.google.com/group/ravendb/browse_thread/thread/ff19340be0aa5e77/5ececad5208059b7?lnk=gst&amp;amp;q=TransformResults#5ececad5208059b7"&gt;Proposed change to TransformResults&lt;/a&gt; – May 18, 2012&lt;/li&gt; &lt;li&gt;&lt;a href="https://groups.google.com/group/ravendb/browse_thread/thread/c3d0e2cbcb9be4e3/3254eb72e99064d0?lnk=gst&amp;amp;q=Transform+Results#3254eb72e99064d0"&gt;The New Transform Results&lt;/a&gt; – Jan 25, 2013&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;In this case, we didn’t get to this feature in time for the 2.0 release, but we kept thinking and refining the approach for that. &lt;/p&gt; &lt;p&gt;The interesting things that in those cases, we usually “design” things by doing the high level user visible API and then just let it percolate. There are a &lt;em&gt;lot&lt;/em&gt; of additional things that we would need to change to make this work (backward compatibility being a major one), so there is a lot of additional work to be done, but that can be done during the work. Right now we can let it sit, get users’ feedback on the proposed design and get the current minor release out of the door.&lt;/p&gt;</description><link>http://ayende.com/blog/161025/hibernating-rhinos-practices-design?key=14707226-592c-4b71-a7e6-8b691543ebd9</link><guid>http://ayende.com/blog/161025/hibernating-rhinos-practices-design?key=14707226-592c-4b71-a7e6-8b691543ebd9</guid><pubDate>Wed, 06 Feb 2013 10:00:00 GMT</pubDate></item><item><title>Single Responsibility Principle, Object Orientation &amp; Active Code</title><description>&lt;p&gt;&lt;a href="http://jasonfolkens.dyndns.org/"&gt;Jason Folkens&lt;/a&gt; had a comment on &lt;a href="http://ayende.com/blog/160514/active-vs-passive-code-bases?key=1a6bad43b26947aebab268d923538825"&gt;my previous post&lt;/a&gt;:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;When people combine methods and data into a class in a way such that you are recommending, I wonder if they truly value the single responsibility principle. In my mind, storing both schema and behavior in the same class qualifies as a violation of the SRP. Do you disagree with me that this is a 'violation', or do you just not think the SRP is important?&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;I can’t disagree enough. From &lt;a href="http://en.wikipedia.org/wiki/Object-oriented_design"&gt;Wikipedia&lt;/a&gt;: &lt;blockquote&gt; &lt;p&gt;An object contains encapsulated data and procedures grouped together to represent an entity. &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;The whole &lt;em&gt;point&lt;/em&gt; of OOP is to encapsulate both data &amp;amp; behavior. To assume otherwise leads us to stateless functions and isolated DTOs. &lt;p&gt;Or, in other words, procedures and structures. And I think I’ll leave &lt;em&gt;that&lt;/em&gt; to C.&lt;/p&gt;</description><link>http://ayende.com/blog/160609/single-responsibility-principle-object-orientation-active-code?key=ae5f5b2d-e7ee-40f8-9d4a-82fabd57f4a0</link><guid>http://ayende.com/blog/160609/single-responsibility-principle-object-orientation-active-code?key=ae5f5b2d-e7ee-40f8-9d4a-82fabd57f4a0</guid><pubDate>Fri, 04 Jan 2013 10:00:00 GMT</pubDate></item><item><title>Active vs. Passive code bases</title><description>&lt;p&gt;I was review code at a customer site, and he had a lot of classes that looked something like this:&lt;/p&gt; &lt;blockquote&gt; &lt;div id="codeSnippetWrapper"&gt; &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ValidationData&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Type {get;set;}&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Value {get;set;}&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;In the database, he would have the data like this:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Active-vs.-Passing-code-bases_B440/image_2.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/Active-vs.-Passing-code-bases_B440/image_thumb.png" width="499" height="172"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is obviously a very simple example, but it gets the job done, I think.&lt;/p&gt;
&lt;p&gt;In his code base, the customer had several instance of this example, for validation of certain parts of the system, for handling business rules, for checking how to handle various events, and I think you get the picture. &lt;/p&gt;
&lt;p&gt;I seriously dislike such codebases. You take an innocent piece of code and make it so passive it… well, you can see:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Active-vs.-Passing-code-bases_B440/image_4.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/Active-vs.-Passing-code-bases_B440/image_thumb_1.png" width="198" height="206"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here is why this is bad. The code is passive, it is just a data holder. And that means that in order to process it you are going to have some &lt;em&gt;other&lt;/em&gt; code that handles that for you. That likely means a switch statement of the equivalent. And it also means that making any sort of change now have to happen on multiple locations. Puke.&lt;/p&gt;
&lt;p&gt;For fun, using this anti pattern all over your codebase result in you have to do this over and over again, for any new interesting thing that you are doing .It is a lot of work, and a lot of places that you have to change.&lt;/p&gt;
&lt;p&gt;But you can be a hero and set the code free:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.bigbadtoystore.com/images/products/out/large/HH10047.jpg" width="640" height="480"&gt;&lt;/p&gt;
&lt;p&gt;You do that by making a very simple change. Instead of having passive data containers that other pieces of the code need to react to, make them &lt;em&gt;active&lt;/em&gt;.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; AvoidCurseWordsValidator : IValidator&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;[] CurseWords {get;set;}&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Validate(...) { }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; MaxLenValidator : IValidator&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt; {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; MaxLen {get; set;}&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Validate(...) { }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; InvalidCharsValidator : IValidator&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt; {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum15"&gt;  15:&lt;/span&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;char&lt;/span&gt;[] InvalidChards {get;set;}&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum16"&gt;  16:&lt;/span&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Validate(...) { }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum17"&gt;  17:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now, if we want to modify / add something, we can do this in only one spot. Hurray for Single Responsibility and Open Closed principles.&lt;/p&gt;
&lt;p&gt;SO… don’t let your codebase be dominated by switch statements, parallel hierarchies and other nasties. Make it go active, and you’ll like the results.&lt;/p&gt;</description><link>http://ayende.com/blog/160514/active-vs-passive-code-bases?key=1a6bad43-b269-47ae-bab2-68d923538825</link><guid>http://ayende.com/blog/160514/active-vs-passive-code-bases?key=1a6bad43-b269-47ae-bab2-68d923538825</guid><pubDate>Thu, 03 Jan 2013 10:00:00 GMT</pubDate></item><item><title>Get thou out of my head, damn idea</title><description>&lt;p&gt;Sometimes I get ideas, and they just won’t leave my head no matter what I do.&lt;/p&gt; &lt;p&gt;In this case, I decided that I wanted to see what it would take to implement an event store in terms of writing a fully managed version.&lt;/p&gt; &lt;p&gt;I am not really interested in the actual event store, I care a lot more about the actual implementation idea that I had (I/O queues in append only mode, if you care to know).&lt;/p&gt; &lt;p&gt;After giving it some though, I managed to create a version that allow me to write the following code:&lt;/p&gt; &lt;blockquote&gt; &lt;div id="codeSnippetWrapper"&gt; &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; var diskData = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; OnDiskData(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; FileStreamSource(), &lt;span style="color: #006080"&gt;"Data"&lt;/span&gt;);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt; var data = JObject.Parse(&lt;span style="color: #006080"&gt;"{'Type': 'ItemCreated', 'ItemId': '1324'}"&lt;/span&gt;);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt; var sp = Stopwatch.StartNew();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt; Parallel.For(0, 1000*10, i =&amp;gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;     {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;         var tasks = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Task[1000];&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;for&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; j = 0; j &amp;lt; 1000; j++)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;         {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;             tasks[j] = diskData.Enqueue(&lt;span style="color: #006080"&gt;"users/"&lt;/span&gt; + i, data);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;         }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;         Task.WaitAll(tasks);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;     });&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum15"&gt;  15:&lt;/span&gt; Console.WriteLine(sp.ElapsedMilliseconds);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;Admittedly, it isn’t a really interesting client code, but it is plenty good enough for what I need, and it allowed me to check something really interesting, just how hard would I have to go to actually get really good performance. As it turned out, not that far.&lt;/p&gt;
&lt;p&gt;This code writes 10 million events, and it does so in under 1 minutes (on my laptop, SSD drive). Just to give you some idea, that is &amp;gt; 600 Mb of events, and about 230 events per &lt;em&gt;milliseconds&lt;/em&gt; or about 230 &lt;em&gt;thousands&lt;/em&gt; events per second. Yes, that is 230,000 events / sec.&lt;/p&gt;
&lt;p&gt;The limiting factor seems to be the disk, and I have some ideas on how to implement that. I still got roughly 12MB/s, so there is certainly room for improvement.&amp;nbsp; &lt;/p&gt;
&lt;p&gt;How does this work? Here is the implementation of the Enqueue method:&lt;/p&gt;
&lt;blockquote&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; Task Enqueue(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; id, JObject data)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     var item = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; WriteState&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;         {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;             Data = data,&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;             Id = id&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;         };&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;     writer.Enqueue(item);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;     hasItems.Set();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; item.TaskCompletionSource.Task;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;In other words, this is a classic producer/consumer problem.&lt;/p&gt;
&lt;p&gt;The other side is&amp;nbsp; reading the events from the queue and writing them to disk. There is just one thread that is doing that, and it is always appending to the end of the file. Moreover, because of the way it works, we are actually gaining the ability to batch a lot of them together into a stream of really nice IO calls that optimize the actual disk access. When we finished with a batch of items and flushed them to disk, only then are we going to complete the task, so the fun part is that for all intents and purposes, we are doing that while preserving transactionability of the system. Once the Enqueue task returned, we can be sure that the data is fully saved on disk.&lt;/p&gt;
&lt;p&gt;That was an interesting spike, and I wonder where else I would be able to make use of something like this in the future.&lt;/p&gt;
&lt;p&gt;Yes, those are pretty small events, and yes, that is a fake test, but the approach seems to be very solid.&lt;/p&gt;
&lt;p&gt;And just for fun, with absolutely no optimizations what so ever, no caching, no nothing, I am able to load 1,000 events per stream in less than 10 ms.&lt;/p&gt;</description><link>http://ayende.com/blog/159009/get-thou-out-of-my-head-damn-idea?key=5d0bb001-e47d-4565-9837-4b97b5199a02</link><guid>http://ayende.com/blog/159009/get-thou-out-of-my-head-damn-idea?key=5d0bb001-e47d-4565-9837-4b97b5199a02</guid><pubDate>Mon, 08 Oct 2012 10:00:00 GMT</pubDate></item><item><title>On Professional Code</title><description>&lt;p&gt;&lt;a href="http://trystans.blogspot.com/"&gt;Trystan&lt;/a&gt; made a &lt;a href="http://ayende.com/blog/157025/unprofessional-code-take-iindash-answer#comments-form-location"&gt;very interesting comment on my post about unprofessional code&lt;/a&gt;:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;I think it's interesting that your definition of professional is not about SOLID code, infrastructure, or any other technical issues. Professional means that you, or the support staff, can easily see what the system is doing in production and why.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;It is a pretty accurate statement, yes. More to the point, a professional system is one that can be supported in production easily. About the most unprofessional thing that you can say is: “I have no idea what is going on.”&lt;/p&gt; &lt;p&gt;Expanding on this, we have been paying a LOT of attention recently to production readiness. We can’t afford not to. Just building the software is often just not enough for us. In many cases, if there is a problem, we can’t just debug through the process. Either because reproducing the problem is too hard or because it happens at a client side with their own private data. Even more important than that, if we can give the ops team the tools to actually see what is going on within the system, we drastically reduce the number of support calls we have to take.&lt;/p&gt; &lt;p&gt;Not to mention that software that actively support and help the ops team gets into the actual data center a lot faster and easier than software that doesn’t. Sure, clean code is important, but production ready code is often &lt;em&gt;not&lt;/em&gt; clean code. I &lt;a href="http://www.joelonsoftware.com/articles/fog0000000069.html"&gt;read this&lt;/a&gt; a long time ago, and it stuck:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;Back to that two page function. Yes, I know, it's just a simple function to display a window, but it has grown little hairs and stuff on it and nobody knows why. Well, I'll tell you why: those are bug fixes. One of them fixes that bug that Nancy had when she tried to install the thing on a computer that didn't have Internet Explorer. Another one fixes that bug that occurs in low memory conditions. Another one fixes that bug that occurred when the file is on a floppy disk and the user yanks out the disk in the middle. That LoadLibrary call is ugly but it makes the code work on old versions of Windows 95. &lt;p&gt;Each of these bugs took weeks of real-world usage before they were found. The programmer might have spent a couple of days reproducing the bug in the lab and fixing it. If it's like a lot of bugs, the fix might be one line of code, or it might even be a couple of characters, but a lot of work and time went into those two characters.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Some parts of the RavenDB code are &lt;em&gt;ugly&lt;/em&gt;. HttpServer class, for example, goes on for over thousands lines of mostly error detection and recovery modes. But it works, and it allows us to inspect it on a running production server. &lt;p&gt;That is &lt;em&gt;important, &lt;/em&gt;and that make the separation from good code and production worthy code.&lt;/p&gt;</description><link>http://ayende.com/blog/158369/on-professional-code?key=db1ba5a0-134c-4e51-933d-168913a77e0a</link><guid>http://ayende.com/blog/158369/on-professional-code?key=db1ba5a0-134c-4e51-933d-168913a77e0a</guid><pubDate>Tue, 11 Sep 2012 09:00:00 GMT</pubDate></item><item><title>It isn’t a feature that is killing you, it is the intersection of features</title><description>&lt;p&gt;Over time, projects get more features. And that is fine, as long as they are orthogonal features. It is when those features overlap that they are really putting the hurt on us.&lt;/p&gt; &lt;p&gt;For example, with the recent Changes API addition to RavenDB, one of the things that was really annoying is that in order to actually implement this feature, I had to implement this to:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Embedded&lt;/li&gt; &lt;li&gt;Client Server&lt;/li&gt; &lt;li&gt;Sharded&lt;/li&gt; &lt;li&gt;Silverlight&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;And that one is easy. We have bugs right now that are happening because people are using two or three bundles at the same time, and each of them works &lt;em&gt;fine&lt;/em&gt;, but in conjunction, you get strange results.&lt;/p&gt; &lt;p&gt;What &lt;em&gt;should&lt;/em&gt; happen when the Unique Constraints bundle creates an internal document when you have the Versioning bundle enabled? How about when we add replication to the mix?&lt;/p&gt; &lt;p&gt;I am not sure if I have any good ideas about the matter. Most of the things that we do are orthogonal to one another, but when used in combination, they actually &lt;em&gt;have&lt;/em&gt; to know about their impact on other things. &lt;/p&gt; &lt;p&gt;My main worry is that as time goes by, we have more &amp;amp; more of those intersections. And that adds to the cost of maintaining and support the product.&lt;/p&gt;</description><link>http://ayende.com/blog/157249/it-isnt-a-feature-that-is-killing-you-it-is-the-intersection-of-features?key=411e52e7-5d29-452a-928b-b7fa4d40c2e0</link><guid>http://ayende.com/blog/157249/it-isnt-a-feature-that-is-killing-you-it-is-the-intersection-of-features?key=411e52e7-5d29-452a-928b-b7fa4d40c2e0</guid><pubDate>Wed, 08 Aug 2012 09:00:00 GMT</pubDate></item><item><title>System vs. User task security: Who pays the sports writer?</title><description>&lt;p&gt;Let us assume for a moment that we are building a system for a sports site. We have multiple authors, submitting articles, and we pay each author for those articles.&lt;/p&gt; &lt;p&gt;The data model might look like this:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/System-vs-user-tasks-Who-pays-the-sports_12FD2/image_2.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/System-vs-user-tasks-Who-pays-the-sports_12FD2/image_thumb.png" width="449" height="355"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;In this post, I want to talk about the security implications of such a system. Typically, this gets translated to requirements such as:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Authors can edit their articles.&lt;/li&gt; &lt;li&gt;Authors cannot modify / view any payments.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Which very often gets boiled down to something like this:&lt;/p&gt; &lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;GRANT&lt;/span&gt; &lt;span class="kwrd"&gt;SELECT&lt;/span&gt;,&lt;font color="#0000ff"&gt;INSERT&lt;/font&gt;,&lt;span class="kwrd"&gt;UPDATE&lt;/span&gt;,&lt;span class="kwrd"&gt;DELETE&lt;/span&gt; &lt;span class="kwrd"&gt;ON&lt;/span&gt; Articles &lt;span class="kwrd"&gt;TO&lt;/span&gt; Authors;
&lt;span class="kwrd"&gt;DENY&lt;/span&gt; &lt;span class="kwrd"&gt;SELECT&lt;/span&gt;,&lt;font color="#0000ff"&gt;INSERT&lt;/font&gt;,&lt;span class="kwrd"&gt;UPDATE&lt;/span&gt;,&lt;span class="kwrd"&gt;DELETE&lt;/span&gt; &lt;span class="kwrd"&gt;On&lt;/span&gt; Payments &lt;span class="kwrd"&gt;TO&lt;/span&gt; Authors;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;What do you think of such a system? My approach, this is a &lt;em&gt;horrible &lt;/em&gt;mess altogether. Think what it means for something like this:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; ActionResult SubmitArticle(Article article)
{
    &lt;span class="kwrd"&gt;if&lt;/span&gt;(IsValid(article)==&lt;span class="kwrd"&gt;false&lt;/span&gt;)
        &lt;span class="kwrd"&gt;return&lt;/span&gt; View();

    Session.Store(article);

    var payment = GetOrCreatePaymentFor(article.Author);

    payment.AddArticle(article);

    &lt;span class="kwrd"&gt;return&lt;/span&gt; RedirectToAction(&lt;span class="str"&gt;"index"&lt;/span&gt;);
}&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;In order to run, this code would actually have to run under &lt;em&gt;several different security credentials&lt;/em&gt; in order to work successfully.&lt;/p&gt;
&lt;p&gt;That is before we take into account how using multiple users for different operations would result in total chaos for small things like connection pooling.&lt;/p&gt;
&lt;p&gt;In real world systems, the security can’t really operate based on the physical structure of the data in the data store. It is far too complex to manage. Instead, we implement security by separating the notion of the &lt;em&gt;System&lt;/em&gt; performing tasks (such as adding a payment for an article) that are system tasks, and the System performing tasks &lt;em&gt;on behalf of&lt;/em&gt;&amp;nbsp; the user. &lt;/p&gt;
&lt;p&gt;The security rules are implemented in the system, and the application user have no physical manifestations (such as being DB users) in the system at all.&lt;/p&gt;
&lt;p&gt;And to the commentators, I know there are going to be some of you are going to claim that physical security at the database level is super critical, but while you are doing that, please also answer the problems of connection pooling and the complexities of multiple security contexts required for most real world business operations.&lt;/p&gt;</description><link>http://ayende.com/blog/157089/system-vs-user-task-security-who-pays-the-sports-writer?key=52a10f06-9436-43f0-9ed5-1512f0bd9cc2</link><guid>http://ayende.com/blog/157089/system-vs-user-task-security-who-pays-the-sports-writer?key=52a10f06-9436-43f0-9ed5-1512f0bd9cc2</guid><pubDate>Wed, 18 Jul 2012 09:00:00 GMT</pubDate></item><item><title>Geo Location &amp; Spatial Searches with RavenDB–Part VII–RavenDB Client vs. Separate REST Service</title><description>&lt;p&gt;In my previous post, I discussed how we put the GeoIP dataset in a separate database, and how we access it through a separate session. I also asked, why use RavenDB Client at all? I mean, we might as well just use the REST API and expose a service. &lt;/p&gt; &lt;p&gt;Here is how such a service would look like, by the way:&lt;/p&gt; &lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; GeoIPClient : IDisposable
{
    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; HttpClient httpClient;

    &lt;span class="kwrd"&gt;public&lt;/span&gt; GeoIPClient(&lt;span class="kwrd"&gt;string&lt;/span&gt; url, ICredentials credentials)
    {
        httpClient = &lt;span class="kwrd"&gt;new&lt;/span&gt; HttpClient(&lt;span class="kwrd"&gt;new&lt;/span&gt; HttpClientHandler{Credentials = credentials})
        {
            BaseAddress = &lt;span class="kwrd"&gt;new&lt;/span&gt; Uri(url),
                
        };
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; Task&amp;lt;Location&amp;gt; GetLocationByIp(IPAddress ip)
    {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (ip.AddressFamily != AddressFamily.InterNetwork)
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;

        var reverseIp = (&lt;span class="kwrd"&gt;long&lt;/span&gt;)BitConverter.ToUInt32(ip.GetAddressBytes().Reverse().ToArray(), 0);

        var query = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;"Start_Range:[* TO 0x{0:X16}] AND End_Range:[0x{0:X16} TO NULL]"&lt;/span&gt;, reverseIp);

        &lt;span class="kwrd"&gt;return&lt;/span&gt; httpClient.GetAsync(&lt;span class="str"&gt;"indexes/Locations/ByRange?pageSize=1&amp;amp;"&lt;/span&gt; + query)
            .ContinueWith(task =&amp;gt; task.Result.Content
                .ReadAsAsync&amp;lt;QueryResult&amp;gt;()
                .ContinueWith(task1 =&amp;gt; task1.Result.Results.FirstOrDefault())).Unwrap();

    } 

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Dispose()
    {
        httpClient.Dispose();
    }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;I think that you can agree that this is fairly simple and easy to understand. It make it explicit that we are just going to query the database and it is even fairly easy to read.&lt;/p&gt;
&lt;p&gt;Why not go with that route?&lt;/p&gt;
&lt;p&gt;Put simply, because it is doing only about 10% of the things that we do in the RavenDB Client. The first thing that pops to mind is that this service doesn’t support caching, HTTP ETag responses, etc. That means that we would have to implement that ourselves. This is &lt;em&gt;decidedly&lt;/em&gt; non trivial. &lt;/p&gt;
&lt;p&gt;The RavenDB Client will automatically cache all data for you if it can, you don’t have to think about it, worry about it or even pay it any mind. It is just there and working hard to make sure that you application is more performant.&lt;/p&gt;
&lt;p&gt;Next, this will only support Windows Authentication. RavenDB also support OAuth, so if you wanted to run this on RavenHQ, for example, which requires OAuth. You would have to write some additional stuff as well.&lt;/p&gt;
&lt;p&gt;Finally, using the RavenDB Client leaves us open to do additional things in the future very easily, while using a dedicate service means that we are on the hook for implementing from scratch basically anything else that we want.&lt;/p&gt;
&lt;p&gt;Sure, we could implement this service using RavenDB Client, but that is just adding layers, and I really don’t like that. There is no real point.&lt;/p&gt;</description><link>http://ayende.com/blog/156706/geo-location-spatial-searches-with-ravendb-part-vii-ravendb-client-vs-separate-rest-service?key=91ef58db-4bdf-4281-bf88-6c8686b5bce0</link><guid>http://ayende.com/blog/156706/geo-location-spatial-searches-with-ravendb-part-vii-ravendb-client-vs-separate-rest-service?key=91ef58db-4bdf-4281-bf88-6c8686b5bce0</guid><pubDate>Fri, 06 Jul 2012 09:00:00 GMT</pubDate></item><item><title>Geo Location &amp; Spatial Searches with RavenDB–Part VI–Database Modeling</title><description>&lt;p&gt;If you had sharp eyes, you might have noticed that in this code, I am actually using two different sessions:&lt;/p&gt; &lt;p&gt;&lt;img src="http://ayende.com/blog/Images/Windows-Live-Writer/Geo-Location--Spatial-Searches-with-Rave_7E0E/image_thumb_2.png"&gt;&lt;/p&gt; &lt;p&gt;We have the GeoSession, and we have the RavenSession.&lt;/p&gt; &lt;p&gt;The GeoSession is actually pointed at a different database, and it is a read only. In fact, here is how we use this:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/1d76da884e8b_AB56/image_2.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/1d76da884e8b_AB56/image_thumb.png" width="677" height="354"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;As you can see, we create this on as needed basis, and we only dispose it, we never actually call SaveChanges(). &lt;/p&gt; &lt;p&gt;So, those are the technical details, but what is the reasoning behind this?&lt;/p&gt; &lt;p&gt;Well, it is actually pretty simple. The GeoIP dataset is about 600 MB in size, and mostly it is about… well, geo location stuff. It is a very nice feature, but it is a self contained one, and not something that I really care for putting inside my app database. Instead, I have decided to go another way, and use a separate database.&lt;/p&gt; &lt;p&gt;That means that we have separation, at the data layer, between the different databases. It makes sense, about the only thing that we need from the GeoIP dataset is the ability to handle queries, and that is expressed only via GetLocationByIp, nothing more.&lt;/p&gt; &lt;p&gt;I don’t see a reason to make the app database bigger and more complex, or to have to support updates to the GeoIP dataset inside the app. This is a totally separate service. And having this in a separate database make it much easier to use this the next time that I want to use geo location. And it simplify my life &lt;em&gt;right now&lt;/em&gt; with regards to maintaining and working with my current app.&lt;/p&gt; &lt;p&gt;In fact, we could have taken it even further, and not use RavenDB access to this at all. We can use REST calls to get the data out directly. We have chosen to still use the RavenDB Client, I’ll discuss exactly why we chose not to do that.&lt;/p&gt;</description><link>http://ayende.com/blog/156705/geo-location-spatial-searches-with-ravendb-part-vi-database-modeling?key=7720a5f0-60ed-4dbc-a186-2c70ff5d1b86</link><guid>http://ayende.com/blog/156705/geo-location-spatial-searches-with-ravendb-part-vi-database-modeling?key=7720a5f0-60ed-4dbc-a186-2c70ff5d1b86</guid><pubDate>Fri, 29 Jun 2012 09:00:00 GMT</pubDate></item><item><title>Why scalability matters?</title><description>&lt;p&gt;Otherwise, you get this:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Why-scalability-matters_76E8/image_2.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/Why-scalability-matters_76E8/image_thumb.png" width="992" height="565"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;And that is one sale that isn’t going to happen!&lt;/p&gt;</description><link>http://ayende.com/blog/153217/why-scalability-matters?key=a23938a1-bb81-438e-973a-e24e7c2c961a</link><guid>http://ayende.com/blog/153217/why-scalability-matters?key=a23938a1-bb81-438e-973a-e24e7c2c961a</guid><pubDate>Wed, 13 Jun 2012 09:00:00 GMT</pubDate></item><item><title>Entities Associations: Point in Time vs. Current Associations</title><description>&lt;p&gt;Having just finished giving three courses (2 on RavenDB and 1 on NHibernate), you might want to say that I have a lot of data stuff on my mind. Teaching is always a pleasure to me, and one of the major reasons for that is that I get to actually learn a lot whenever I teach.&lt;/p&gt; &lt;p&gt;In this case, in all three courses, we run into an issue with modeling associations. For the sake of the example, let us talk about employees and paychecks. You can see the model below:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Point-in-Time-Relation.-Current-Relation_F76A/image_2.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/Point-in-Time-Relation.-Current-Relation_F76A/image_thumb.png" width="470" height="287"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Do you note the blue lines? Those represent Employee reference, but while they are both referencing the same employee, they are actually quite different associations.&lt;/p&gt; &lt;p&gt;The Manager association is a Current Association. It is just a pointer to the managing employee. What does this means?&lt;/p&gt; &lt;p&gt;Let us say that the manager of a certain employee changed her name. In that scenario, when we look at the current employee record, we should see the &lt;em&gt;updated employee manager name&lt;/em&gt;. In this case, we are always interested in the current status.&lt;/p&gt; &lt;p&gt;On the other hand when looking at the paycheck PaidTo reference to an employee, we have something all together different. We have a reference no to the current employee record, but to the employee record &lt;em&gt;as it was at a certain point in time&lt;/em&gt;. If the employee in question change his name, that paycheck was issued to Mr. Version One, not to Mr. Version Two, even though the name has been changed.&lt;/p&gt; &lt;p&gt;when dealing with associations, it is important to distinguish between the two options, as each require different way of working with the association. &lt;/p&gt;</description><link>http://ayende.com/blog/156353/entities-associations-point-in-time-vs-current-associations?key=a9e79514-d102-4693-ab5d-ed7126f2eb8d</link><guid>http://ayende.com/blog/156353/entities-associations-point-in-time-vs-current-associations?key=a9e79514-d102-4693-ab5d-ed7126f2eb8d</guid><pubDate>Tue, 12 Jun 2012 09:00:00 GMT</pubDate></item><item><title>Assuming that the laws of physics no longer apply, we can build this</title><description>&lt;p&gt;This is a reply to a &lt;a href="http://weblogs.asp.net/fbouma/archive/2012/06/08/azure-don-t-give-me-multiple-vms-give-me-one-elastic-vm.aspx"&gt;post by Frans Bouma&lt;/a&gt;, in which he asks for:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;…loud vendors should offer simply &lt;em&gt;one&lt;/em&gt; VM to me. On that VM I run the websites, store my DB and my files. As it's a &lt;em&gt;virtual&lt;/em&gt; machine, how this machine is actually ran on physical hardware (e.g. partitioned), I don't care, as that's the problem for the cloud vendor to solve. If I need more resources, e.g. I have more traffic to my server, way more visitors per day, the VM stretches, like I bought a bigger box. This frees me from the problem which comes with multiple VMs: I don't have any refactoring to do at all: I can simply build my website as if it runs on my local hardware server, upload it to the VM offered by the cloud vendor, install it on the VM and I'm done.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Um… no. &lt;/p&gt; &lt;p&gt;Go ahead and read the whole post, it is interesting. But the underlying premise that is rely on is flawed. It is like starting out with assuming that since TCP/IP contains no built in prohibition to send data faster than light, the cloud providers can and should create networks that can send data faster than light. After all, I can show a clear business case for the reduced ping time, and that is certainly something that can be abstracted from my application.&lt;/p&gt; &lt;p&gt;What aren’t those bozos doing that?&lt;/p&gt; &lt;p&gt;Well, the answer to that is that it just ain’t possible. There are several minor problems along the way. The CAP theorem, to start with, but even if we ignore that aspect of the problem, there are also the fallacies of distributed computing.&lt;/p&gt; &lt;p&gt;According to Frans’ premise, we can have a single VM that can scale up to as many machines as is needed, without any change required to the system. Let us start with Frans’ answer to the actual scope of the problem:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;strong&gt;But what about memory replication and other problems?&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;This environment isn't simple, at least not for the cloud vendor. But it &lt;em&gt;is&lt;/em&gt; simple for the customer who wants to run his sites in that cloud: no work needed. No refactoring needed of existing code. Upload it, run it.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Um.. no. &lt;/p&gt; &lt;p&gt;Let us take a look at a few pieces of code, and see what is going to happen to then in Frans’ cloud environment. For example, let us take a look at this:&lt;/p&gt; &lt;blockquote&gt;&lt;pre class="csharpcode"&gt;var tax = 0;
&lt;span class="kwrd"&gt;foreach&lt;/span&gt;(var item &lt;span class="kwrd"&gt;in&lt;/span&gt; order.Items)
{
  tax += item.CalculateTax();   
}
order.Tax = tax;&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;Problem, because of the elasticity of the VM, we actually spread things around so each of the items in the order collection is located in another physical machine. This is, of course, completely transparent to the code. But that means that each loop iteration is actually doing a network call behind the scene.&lt;/p&gt;
&lt;p&gt;OR/M users are familiar with this as the SELECT N+1 problem, but in this case, you have a potential problem on &lt;em&gt;every memory access&lt;/em&gt;. Network attached memory isn’t new, you can read about it in OS books and it is a nice theoretical idea, but it is just isn’t going to work, because you actually &lt;em&gt;care&lt;/em&gt; about the speed of accessing the data.&lt;/p&gt;
&lt;p align="left"&gt;In fact, we have many algorithms that were changed specifically to be able to take advantage of cache lines, L1 &amp;amp; L2 cache, etc. Because that has a &lt;em&gt;major&lt;/em&gt; increase in the system performance, and that is only on a single machine. Trying to imagine a transparent network memory is futile, you actually care about memory access speed, a &lt;em&gt;lot&lt;/em&gt;.&lt;/p&gt;
&lt;p align="left"&gt;But let us talk about another aspect, I want to make have an always incrementing order id number. So I do:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p align="left"&gt;Interlocked.Increment(ref lastOrderId);&lt;/p&gt;&lt;/blockquote&gt;
&lt;p align="left"&gt;All well and good when running on a single machine, but how should the VM make it work when running on multiple machines? &lt;/p&gt;
&lt;p align="left"&gt;And remember, this call actually translate to a purpose built assembly instruction (XADD or one of its friends). In this case, you need to do this across the network, and touch as many machines as your system currently runs on.&lt;/p&gt;
&lt;p align="left"&gt;But the whole &lt;em&gt;point&lt;/em&gt; here is to allow us to rapidly generate a new number. This has now turned into a total mess in terms of performance.&lt;/p&gt;
&lt;p align="left"&gt;What about parallel computing, for that matter?&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;var results = &lt;span class="kwrd"&gt;new&lt;/span&gt; Result[items.Length];
Parallel.For(items, (item, i) =&amp;gt; 
{
    results[i] = item.Calculate();
});&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p align="left"&gt;I have many items, and I want to be able to compute the result in parallel, so I run this fairly standard code. But we are actually going to execute this on multiple threads, so this get scheduled on several different machines. But now you have to copy the results buffer to all of those machines, as well as any related state that they have, then copy it back out when it is done, then somehow merge the different changes made by different systems into a coherent whole.&lt;/p&gt;
&lt;p align="left"&gt;Good luck with that.&lt;/p&gt;
&lt;p align="left"&gt;I could go on, but I think that you get the point by now.&lt;/p&gt;
&lt;p align="left"&gt;And we haven’t talked about the error condition yet. What happen if my system is running on 3 machines, and one of them goes down (power outage, hardware failure, etc)? 3rd of my memory, ongoing work and a lot of stuff just got lost. For that matter, I might have (actually, probably have) dangling references to memory that used to be on the failed machines, so the other two systems are likely to hit this inaccessible memory and fail themselves.&lt;/p&gt;
&lt;p align="left"&gt;So.. no, this idea is a pipe dream, it isn’t going to work, not because of some evil plot by dastardly folks conspiring to make your life harder, but for the simple reason that it is easier to fly by flapping your arms.&lt;/p&gt;</description><link>http://ayende.com/blog/156513/assuming-that-the-laws-of-physics-no-longer-apply-we-can-build-this?key=88a6ab8b-8444-4f28-97fe-97a80e5b0b84</link><guid>http://ayende.com/blog/156513/assuming-that-the-laws-of-physics-no-longer-apply-we-can-build-this?key=88a6ab8b-8444-4f28-97fe-97a80e5b0b84</guid><pubDate>Fri, 08 Jun 2012 08:03:00 GMT</pubDate></item><item><title>Your ATM doesn’t use transactions</title><description>&lt;p&gt;I just got a series of SMSes from my back, saying that someone just made several withdrawals from my account. As I am currently sitting and watching TV, I was a bit concerned. &lt;/p&gt; &lt;p&gt;It appears that my wife withdrew some money, but there was an issue with one ATM machine, so she used another one. &lt;/p&gt; &lt;p&gt;The problem, I got 3 SMS messages, saying that the follow activities happened on my account:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;ATM withdrawal for 2,000 NIS&lt;/li&gt; &lt;li&gt;ATM withdrawal for 2,000 NIS&lt;/li&gt; &lt;li&gt;ATM withdrawal for 2,900 NIS&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Checking with my wife, she had actually withdrawn only 2,900. &lt;/p&gt; &lt;p&gt;I was a bit concerned, so I logged into the bank and got this:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Your-ATM-doesnt-use-transactions_AE89/image_2.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/Your-ATM-doesnt-use-transactions_AE89/image_thumb.png" width="512" height="111"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;In English, this is:&lt;/p&gt; &lt;table border="0" cellspacing="0" cellpadding="2" width="492"&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign="top" width="120"&gt;Date&lt;/td&gt; &lt;td valign="top" width="120"&gt;Description&lt;/td&gt; &lt;td valign="top" width="120"&gt;Auth Code&lt;/td&gt; &lt;td valign="top" width="84"&gt;Debit&lt;/td&gt; &lt;td valign="top" width="46"&gt;Credit&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="120"&gt;10 Apr&lt;/td&gt; &lt;td valign="top" width="120"&gt;ATM withdrawal &lt;/td&gt; &lt;td valign="top" width="120"&gt;00003581&lt;/td&gt; &lt;td valign="top" width="84"&gt;2,000&lt;/td&gt; &lt;td valign="top" width="46"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="120"&gt;10 Apr&lt;/td&gt; &lt;td valign="top" width="120"&gt;ATM withdrawal &lt;/td&gt; &lt;td valign="top" width="120"&gt;00003581&lt;/td&gt; &lt;td valign="top" width="84"&gt;&amp;nbsp;&lt;/td&gt; &lt;td valign="top" width="46"&gt;2,000&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign="top" width="120"&gt;10 Apr&lt;/td&gt; &lt;td valign="top" width="120"&gt;ATM withdrawal &lt;/td&gt; &lt;td valign="top" width="120"&gt;00003581&lt;/td&gt; &lt;td valign="top" width="84"&gt;2,900&lt;/td&gt; &lt;td valign="top" width="46"&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;This is actually interesting, because the way my wife described it, she wen to the ATM, punch the right codes, and went through the motions of everything. Then, just before it was about to give her the money, it failed. &lt;/p&gt; &lt;p&gt;What is &lt;em&gt;really&lt;/em&gt; interesting? From my point of view, is that I can actually see this in my bank account. We didn’t have a transaction rollback because of failure to dispense the money. That isn’t how ATM works. We actually had a compensating action (that occurred as separate transaction) to show that the ATM refunded the money it wasn’t able to give.&lt;/p&gt; &lt;p&gt;So next time someone tries to quote you “banks use transactions”, you can tell them that the bank definition of what a transaction is would make &lt;a href="http://en.wikipedia.org/wiki/Distributed_Transaction_Coordinator"&gt;any decent DTC&lt;/a&gt; cry with shame. &lt;/p&gt;</description><link>http://ayende.com/blog/155969/your-atm-doesnt-use-transactions?key=f35e1cd1-5b54-473a-a882-92daf90ba9f9</link><guid>http://ayende.com/blog/155969/your-atm-doesnt-use-transactions?key=f35e1cd1-5b54-473a-a882-92daf90ba9f9</guid><pubDate>Mon, 04 Jun 2012 09:00:00 GMT</pubDate></item><item><title>Security decisions: Separate Operations &amp; Queries</title><description>&lt;p&gt;The question came up several times in the mailing list with regards to how the RavenDB Authorization Bundle operates, and I think it serves a broader discussion.&lt;/p&gt; &lt;p&gt;Let us imagine a system where we have contracts, which may be in several states: &lt;/p&gt; &lt;ul&gt; &lt;li&gt;Mine – Contracts that an employee signed.  &lt;li&gt;Done – Standard users can view, Lawyers assigned to the company can sign.  &lt;li&gt;Draft – Lawyers can view / edit, Partners can approve.  &lt;li&gt;Proposed – Lawyers can create / edit, but only the lawyer that created it can view it, Partners can accept.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;So far, fairly simple, right? Except the pure &lt;em&gt;hell&lt;/em&gt; that you are going to get into when you are trying to show the users all of the contracts that they can see, sorted by edit date and in the NDA category.&lt;/p&gt; &lt;p&gt;Why am I being so negative here? Well, let us look at what we are going to have to do in the most trivial of cases:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Security_9400/image_4.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/Security_9400/image_thumb_1.png" width="450" height="221"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;In this sort of system, we are going to have to show the user all of the contracts that they are allowed to see, and show them some indication what operations they can do on each.&lt;/p&gt; &lt;p&gt;The problem is that generating this sort of view is &lt;em&gt;expensive&lt;/em&gt;. Especially when you have large amount of data to work through. More interesting, from a UX perspective, it also doesn’t really work that well. Most users would want a better separation of the things that they can do, probably something like this:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Security_9400/image_9.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/Security_9400/image_thumb_3.png" width="450" height="221"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;This allows us to do a first level filtering on the data itself, rather than try to apply security rules to it.&lt;/p&gt; &lt;p&gt;In the first case, we need to get all the contracts that we are allowed to see. The security rules above are &lt;em&gt;really&lt;/em&gt; simple, mind. But trying to translate them into an efficient query is going to be pretty hard. Both in terms of the code requires and the cost to actually perform the query on the server. There are other things that are involved as well, such as paging and sorting in such an environment.&amp;nbsp; I have created several such systems in the past, Rhino Security is probably the most well known of them, and it gets really hard to optimize things and make sure that everything works when you start getting more complex security rules (especially when you have a user editable security system, which is a common request).&lt;/p&gt; &lt;p&gt;The second case is cheaper because we can limit the choices that we see in the query itself. We may still need to apply security concerns, but those goes through the query directly, rather than a security sub system. This kind of change usually force people to be more explicit in what they want, and it result in a system that tends to be simpler. The security rules aren’t just something arbitrary that can be defined, they are actually visible on the screen (My Contracts, Drafts, etc). Changing them isn’t something that is done on an administrator’s whim.&lt;/p&gt; &lt;p&gt;Yes, this is a way to manage the client and their expectations, but that is &lt;em&gt;important&lt;/em&gt;. But what about the complex security that they want? &lt;/p&gt; &lt;p&gt;That might still be there, certainly, but that would be active mostly for operations (stuff that happen on a single entity), not on things that happen over all entities. It is drastically easier to make a single entity security decisions work efficiently than make it work over the whole set inside the database.&lt;/p&gt;</description><link>http://ayende.com/blog/152929/security-decisions-separate-operations-queries?key=dd5d38bf-cf0b-4233-b6c5-b75582e2e82f</link><guid>http://ayende.com/blog/152929/security-decisions-separate-operations-queries?key=dd5d38bf-cf0b-4233-b6c5-b75582e2e82f</guid><pubDate>Tue, 10 Apr 2012 10:00:00 GMT</pubDate></item><item><title>Monika: A lesson in component based design</title><description>&lt;p&gt;I was giving a lecture on architecture recently, and the notion of components came in. The most important bit about that lecture was probably at the very end, when I discussed what it is that I consider to be a component. During that discussion, I introduced Monika, the payment processing component.&lt;/p&gt; &lt;p&gt;Monika has the following Service Level Agreement:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Payment initiation is done messages.&lt;/li&gt; &lt;li&gt;Notification about payment completion is handled via a callback REST call.&lt;/li&gt; &lt;li&gt;The SLA calls for 90% of all successful payments to be processed in 2 business days.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;So far, it doesn’t sound really complicated, right? And there isn’t even a hint of how Monika works in the SLA or the contracts.&lt;/p&gt; &lt;p&gt;This is Monica:&lt;/p&gt; &lt;p&gt;&lt;img src="http://blog.rounds.com/wp-content/uploads/2011/05/monica-friends.jpg"&gt;&lt;/p&gt;  &lt;p&gt;Well, not really, but it makes the point, doesn’t it.&lt;/p&gt; &lt;p&gt;Monica is a component in the system that respond to (SMTP) messages, does some work, and respond by clicking on a link in the email (REST call).&lt;/p&gt; &lt;p&gt;Monica has a really sucky SLA, since she has only 22% uptime over the course of the year, and then there are those two weeks when she has her yearly maintenance period (vacation), etc.&lt;/p&gt; &lt;p&gt;The most important thing about this is that we are able to abstract all of that away and treat this scenario as just another component in the system. &lt;/p&gt; &lt;p&gt;All too often, people hear components and they start thinking about things like this:&lt;/p&gt; &lt;p&gt;&lt;img src="http://www.agilemodeling.com/images/models/componentDesign.JPG"&gt;&lt;/p&gt; &lt;p&gt;A component in a system is usually something much larger than a single class or a set of classes. It is an independent agent in the system that has its own behavior, resources, dedicated team and deployment schedule separate from all other components.&lt;/p&gt;</description><link>http://ayende.com/blog/152961/monika-a-lesson-in-component-based-design?key=7e93ac65-10fb-4375-9771-4f958d8dab9a</link><guid>http://ayende.com/blog/152961/monika-a-lesson-in-component-based-design?key=7e93ac65-10fb-4375-9771-4f958d8dab9a</guid><pubDate>Fri, 06 Apr 2012 10:00:00 GMT</pubDate></item></channel></rss>