﻿<?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) 2012</copyright><ttl>60</ttl><item><title>Reviewing RavenDB app: ReleaseCandidateTracker</title><description>&lt;p&gt;&lt;a href="https://github.com/SzymonPobiega/ReleaseCandidateTracker"&gt;ReleaseCandidateTracker&lt;/a&gt; is a new RavenDB based application by Szymon Pobiega. I reviewed version 5f7e42e0fb1dea70e53bace63f3e18d95d2a62dd. At this point, I don’t know anything about this application, including what exactly it means, Release Tracking.&lt;/p&gt; &lt;p&gt;I downloaded the code and started VS, there is one project in the solution, which is already a Good Thing. I decided to randomize my review approach and go and check the Models directory first. &lt;/p&gt; &lt;p&gt;Here is how it looks:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Reviewing-RavenDB-app-ReleaseCandidateTr_A3DC/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/Reviewing-RavenDB-app-ReleaseCandidateTr_A3DC/image_thumb_1.png" width="983" height="671"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;This is interesting for several reasons. First, it looks like it is meant to keep a record of all deployments to multiple environments, and that you can lookup the history of each deployment both on the environment side and on the release candidate side.&lt;/p&gt; &lt;p&gt;Note that we use rich models, which have collections in them. In fact, take a look at this method:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Reviewing-RavenDB-app-ReleaseCandidateTr_A3DC/image_6.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/Reviewing-RavenDB-app-ReleaseCandidateTr_A3DC/image_thumb_2.png" width="1081" height="349"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Which calls to this method:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Reviewing-RavenDB-app-ReleaseCandidateTr_A3DC/image_8.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/Reviewing-RavenDB-app-ReleaseCandidateTr_A3DC/image_thumb_3.png" width="602" height="243"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;You know what the &lt;em&gt;really&lt;/em&gt; fun part about this? &lt;/p&gt; &lt;p&gt;It ain’t relational model. There is &lt;em&gt;no cost &lt;/em&gt;of actually making all of these calls!&lt;/p&gt; &lt;p&gt;Next, we move to the Infrastructure folder, where we have a couple of action results and the RavenDB management stuff. Here it how RCT uses RavenDB:&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;static&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Database
{
    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; IDocumentStore storeInstance;

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; IDocumentStore Instance
    {
        get
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (storeInstance == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
            {
                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; InvalidOperationException(&lt;span class="str"&gt;"Document store has not been initialized."&lt;/span&gt;);
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; storeInstance;
        }
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Initialize()
    {
        var embeddableDocumentStore = &lt;span class="kwrd"&gt;new&lt;/span&gt; EmbeddableDocumentStore {DataDirectory = &lt;span class="str"&gt;@"~\App_Data\Database"&lt;/span&gt;};
        embeddableDocumentStore.Initialize();
        storeInstance = embeddableDocumentStore;
    }
}
&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;It is using an embedded database to do that, which makes it very easy to use the app. Just hit F5 and go. In fact, if we do, we see the fully functional website, which is quite awesome &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://ayende.com/blog/Images/Windows-Live-Writer/Reviewing-RavenDB-app-ReleaseCandidateTr_A3DC/wlEmoticon-smile_2.png"&gt;.&lt;/p&gt;
&lt;p&gt;Let us move to seeing how we are managing the sessions:&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; BaseController : Controller
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; IDocumentSession DocumentSession { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }
    &lt;span class="kwrd"&gt;public&lt;/span&gt; CandidateService CandidateService { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }
    &lt;span class="kwrd"&gt;public&lt;/span&gt; ScriptService ScriptService { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }

    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnActionExecuting(ActionExecutingContext filterContext)
    {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (filterContext.IsChildAction)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt;;
        }
        DocumentSession = Database.Instance.OpenSession();
        CandidateService = &lt;span class="kwrd"&gt;new&lt;/span&gt; CandidateService(DocumentSession);
        ScriptService = &lt;span class="kwrd"&gt;new&lt;/span&gt; ScriptService(DocumentSession);
        &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnActionExecuting(filterContext);
    }
    
    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnActionExecuted(ActionExecutedContext filterContext)
    {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (filterContext.IsChildAction)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt;;
        }
        &lt;span class="kwrd"&gt;if&lt;/span&gt;(DocumentSession != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (filterContext.Exception == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
            {
                DocumentSession.SaveChanges();
            }
            DocumentSession.Dispose();
        }
        &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnActionExecuted(filterContext);
    }
}
&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;This is all handled inside the base controller, and it is very similar to how I am doing that in my own apps.&lt;/p&gt;
&lt;p&gt;However, ScriptService and CandidateService seems strange, let us explore them a bit.&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; ScriptService
{
    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; IDocumentSession documentSession;

    &lt;span class="kwrd"&gt;public&lt;/span&gt; ScriptService(IDocumentSession documentSession)
    {
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.documentSession = documentSession;
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; AttachScript(&lt;span class="kwrd"&gt;string&lt;/span&gt; versionNumber, Stream fileContents)
    {
        var metadata = &lt;span class="kwrd"&gt;new&lt;/span&gt; RavenJObject();
        documentSession.Advanced.DatabaseCommands.PutAttachment(versionNumber, &lt;span class="kwrd"&gt;null&lt;/span&gt;, fileContents, metadata);
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; Stream GetScript(&lt;span class="kwrd"&gt;string&lt;/span&gt; versionNumber)
    {
        var attachment = documentSession.Advanced.DatabaseCommands.GetAttachment(versionNumber);
        &lt;span class="kwrd"&gt;return&lt;/span&gt; attachment != &lt;span class="kwrd"&gt;null&lt;/span&gt; 
            ? attachment.Data() 
            : &lt;span class="kwrd"&gt;null&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;So this is using RavenDB attachment to store stuff, I am not quite sure what yet, so let us track it down.&lt;/p&gt;
&lt;p&gt;This is being used like this:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;[HttpGet]
&lt;span class="kwrd"&gt;public&lt;/span&gt; ActionResult GetScript(&lt;span class="kwrd"&gt;string&lt;/span&gt; versionNumber)
{
    var candidate = CandidateService.FindOneByVersionNumber(versionNumber);
    var attachment = ScriptService.GetScript(versionNumber);
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (attachment != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
    {
        var result = &lt;span class="kwrd"&gt;new&lt;/span&gt; FileStreamResult(attachment, &lt;span class="str"&gt;"text/plain"&lt;/span&gt;);
        var version = candidate.VersionNumber;
        var product = candidate.ProductName;
        result.FileDownloadName = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;"deploy-{0}-{1}.ps1"&lt;/span&gt;, product, version);
        &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
    }
    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; HttpNotFoundResult(&lt;span class="str"&gt;"Deployment script missing."&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;So I am assuming that the scripts are deployment scripts for different versions, and that they get uploaded on every new release candidate.&lt;/p&gt;
&lt;p&gt;But look at the CandidateService, it looks like a traditional service wrapping RavenDB, and I have spoken against it multiple times.&lt;/p&gt;
&lt;p&gt;In particular, I dislike this bit of code:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; ReleaseCandidate FindOneByVersionNumber(&lt;span class="kwrd"&gt;string&lt;/span&gt; versionNumber)
{
    var result = documentSession.Query&amp;lt;ReleaseCandidate&amp;gt;()
        .Where(x =&amp;gt; x.VersionNumber == versionNumber)
        .FirstOrDefault();
    &lt;span class="kwrd"&gt;if&lt;/span&gt;(result == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
    {
        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ReleaseCandidateNotFoundException(versionNumber);
    }
    &lt;span class="kwrd"&gt;return&lt;/span&gt; result;
}

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Store(ReleaseCandidate candidate)
{
    var existing = documentSession.Query&amp;lt;ReleaseCandidate&amp;gt;()
        .Where(x =&amp;gt; x.VersionNumber == candidate.VersionNumber)
        .Any();
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (existing)
    {
        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ReleaseCandidateAlreadyExistsException(candidate.VersionNumber);
    }
    documentSession.Store(candidate);
}&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;From looking at the code, it looks like the version number of the release candidate is the primary way to look it up. More than that, in the entire codebase, there is never a case where we load a document by id.&lt;/p&gt;
&lt;p&gt;When I see a VersionNumber, I think about things like “1.0.812.0”, but I think that in this case the version number is likely to include the product name as well, “RavenDB-1.0.812.0”, otherwise you couldn’t have two products with the same version.&lt;/p&gt;
&lt;p&gt;That said, the code above it wrong, because it doesn’t take into account RavenDB’s indexes BASE nature. Instead, the version number should actually be the ReleaseCandidate id. This way, because RavenDB’s document store is fully ACID, we don’t have to worry about index update times, and we can load things very efficiently.&lt;/p&gt;
&lt;p&gt;Pretty much all of the rest of the code in the CandidateService is only used in a single location, and I don’t really see a value in it being there.&lt;/p&gt;
&lt;p&gt;For example, let us look at this one:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;[HttpPost]
&lt;span class="kwrd"&gt;public&lt;/span&gt; ActionResult MarkAsDeployed(&lt;span class="kwrd"&gt;string&lt;/span&gt; versionNumber, &lt;span class="kwrd"&gt;string&lt;/span&gt; environment, &lt;span class="kwrd"&gt;bool&lt;/span&gt; success)
{
    CandidateService.MarkAsDeployed(versionNumber, environment, success);
    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; EmptyResult();
}&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;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Reviewing-RavenDB-app-ReleaseCandidateTr_A3DC/image_10.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/Reviewing-RavenDB-app-ReleaseCandidateTr_A3DC/image_thumb_4.png" width="600" height="729"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As you can see, it is merely loading the appropriate release candidate, and calling the MarkAsDeployed method on it.&lt;/p&gt;
&lt;p&gt;Instead of doing this needless, forwarding, and assuming that we have the VersionNumber as the id, I would write:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;[HttpPost]
&lt;span class="kwrd"&gt;public&lt;/span&gt; ActionResult MarkAsDeployed(&lt;span class="kwrd"&gt;string&lt;/span&gt; versionNumber, &lt;span class="kwrd"&gt;string&lt;/span&gt; environment, &lt;span class="kwrd"&gt;bool&lt;/span&gt; success)
{
    var cadnidate = DocumentSession.Load&amp;lt;ReleaseCandidate&amp;gt;(versionNumber);
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (cadnidate == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ReleaseCandidateNotFoundException(versionNumber);
    var env = DocumentSession.Load&amp;lt;DeploymentEnvironment&amp;gt;(environment);
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (env == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; InvalidOperationException(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;"Environment {0} not found"&lt;/span&gt;, environment));

    cadnidate.MarkAsDeployed(success, env);
    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; EmptyResult();
}
&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;Finally, a word about the error handling, this is handled via:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnException(ExceptionContext filterContext)
{
    filterContext.Result = &lt;span class="kwrd"&gt;new&lt;/span&gt; ErrorResult(filterContext.Exception.Message);
    filterContext.ExceptionHandled = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
}

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ErrorResult : ActionResult
{
    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; message;

    &lt;span class="kwrd"&gt;public&lt;/span&gt; ErrorResult(&lt;span class="kwrd"&gt;string&lt;/span&gt; message)
    {
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.message = message;
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ExecuteResult(ControllerContext context)
    {
        context.HttpContext.Response.Write(message);
        context.HttpContext.Response.StatusCode = 500;
    }
}
&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;The crazy part is that OnException is overridden only on some of the controllers, rather than in the base controller, and even worse. This sort of code leads to error details loss.&lt;/p&gt;
&lt;p&gt;For example, let us say that I get a NullReferenceException. This code will dutifully tell me all about it, &lt;em&gt;but will not tell me where it happened&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This sort of thing make debugging &lt;em&gt;extremely&lt;/em&gt; hard.&lt;/p&gt;</description><link>http://ayende.com/blog/155553/reviewing-ravendb-app-releasecandidatetracker?key=ebf8a35d-96b1-419c-be31-518497decac2</link><guid>http://ayende.com/blog/155553/reviewing-ravendb-app-releasecandidatetracker?key=ebf8a35d-96b1-419c-be31-518497decac2</guid><pubDate>Wed, 16 May 2012 09:00:00 GMT</pubDate></item><item><title>Reviewing Xenta and wishing I hadn&amp;rsquo;t</title><description>&lt;p&gt;&lt;a href="http://xenta.codeplex.com/team/view"&gt;Xenta Framework&lt;/a&gt; is the extensible enterprise n-tier application framework with multilayered architecture.&lt;/p&gt; &lt;p&gt;I was asked by the coordinator for the project to review it.&lt;/p&gt; &lt;p&gt;This isn’t going to take long. I looked at the code, and I got this:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Reviewing-Xenta_BAF4/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/Reviewing-Xenta_BAF4/image_thumb.png" width="235" height="134"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;I am sure you remember the last time when I run into something like this, except that the number of projects at that solution was a quarter of what we had here, and I already had to hold my nose.&lt;/p&gt; &lt;p&gt;Looking a bit deeper:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Reviewing-Xenta_BAF4/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/Reviewing-Xenta_BAF4/image_thumb_1.png" width="325" height="380"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Here is a hint, you &lt;em&gt;are&lt;/em&gt; allowed to have more than one class per project. &lt;/p&gt; &lt;p&gt;Having that many project is a nightmare in trying to manage them. Finding things, actually making &lt;em&gt;use&lt;/em&gt; of how things work. Not to mention that the level of abstractness required to support that is giving me a headache.&lt;/p&gt; &lt;p&gt;This is still without looking at the code, mind.&lt;/p&gt; &lt;p&gt;Now, let us look at the actual code. I like to start the controllers. The following code is from ForumController:&lt;/p&gt; &lt;blockquote&gt;&lt;pre class="csharpcode"&gt;[HttpPost, ValidateInput(&lt;span class="kwrd"&gt;false&lt;/span&gt;)]
&lt;span class="kwrd"&gt;public&lt;/span&gt; ActionResult Update(&lt;span class="kwrd"&gt;int&lt;/span&gt; forumID, FormCollection form)
{
    ForumModel m = &lt;span class="kwrd"&gt;new&lt;/span&gt; ForumModel()
    {
        ForumID = forumID
    };

&lt;font style="background-color: #ffff00"&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt;(!m.Load())&lt;/font&gt;
    {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; HttpNotFound();
    }

    &lt;span class="kwrd"&gt;if&lt;/span&gt;(TryUpdateModel&amp;lt;ForumModel&amp;gt;(m, &lt;span class="str"&gt;"Model"&lt;/span&gt;, form))
    {
        &lt;span class="kwrd"&gt;try&lt;/span&gt;
        {
&lt;font style="background-color: #ffff00"&gt;            m.Update();&lt;/font&gt;
        }
        &lt;span class="kwrd"&gt;catch&lt;/span&gt;(Exception ex)
        {
            ModelState.AddModelError(&lt;span class="str"&gt;"API"&lt;/span&gt;, ex);
        }
    }

    &lt;span class="kwrd"&gt;if&lt;/span&gt;(!ModelState.IsValid)
    {
        TempData.OperationStatus(&lt;span class="str"&gt;"Failed"&lt;/span&gt;);
        TempData.PersistObject(&lt;span class="str"&gt;"Model"&lt;/span&gt;, m);
        TempData.PersistModelState(ModelState);
    }
    &lt;span class="kwrd"&gt;else&lt;/span&gt;
    {
        TempData.OperationStatus(&lt;span class="str"&gt;"Success"&lt;/span&gt;);
    }

    &lt;span class="kwrd"&gt;return&lt;/span&gt; RedirectToAction(&lt;span class="str"&gt;"Edit"&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt;
    {
        ForumID = m.ForumID
    });
}&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;Seriously, I haven’t seen this style of architecture in a while. Let us dig deeper:&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;bool&lt;/span&gt; Update()
{
    &lt;span class="kwrd"&gt;using&lt;/span&gt;(ForumApiClient api = &lt;span class="kwrd"&gt;new&lt;/span&gt; ForumApiClient())
    {
        var dto = api.UpdateForum(ForumID, ParentForumID, DisplayOrder, Flags);

        &lt;span class="kwrd"&gt;return&lt;/span&gt; Load(dto);
    }
}

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; Load()
{
    &lt;span class="kwrd"&gt;using&lt;/span&gt;(ForumApiClient api = &lt;span class="kwrd"&gt;new&lt;/span&gt; ForumApiClient())
    {
        var dto = api.GetForum(ForumID);

        &lt;span class="kwrd"&gt;return&lt;/span&gt; Load(dto);
    }
}
&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 case you are wondering, those are on the ForumModel class.&lt;/p&gt;
&lt;p&gt;This piece of code is from the ForumPostModel class, it may look familiar:&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;bool&lt;/span&gt; Load()
{
    &lt;span class="kwrd"&gt;using&lt;/span&gt;(ForumApiClient api = &lt;span class="kwrd"&gt;new&lt;/span&gt; ForumApiClient())
    {
        var dto = api.GetPost(PostID);

        &lt;span class="kwrd"&gt;return&lt;/span&gt; Load(dto);
    }
}
&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;This ForumApiClient is actually a WCF Proxy class, which leads us to this interface:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Reviewing-Xenta_BAF4/image_6.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/Reviewing-Xenta_BAF4/image_thumb_2.png" width="1075" height="894"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I won’t comment on this any further, but will go directly to ForumApiService, where we actually update a forum using the following code:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; ForumDto UpdateForum(&lt;span class="kwrd"&gt;int&lt;/span&gt; forumID,
    &lt;span class="kwrd"&gt;int&lt;/span&gt; parentForumID,
    &lt;span class="kwrd"&gt;int&lt;/span&gt; displayOrder,
    ForumFlags flags)
{
    ForumService forumService = Infrastructure.Component&amp;lt;ForumService&amp;gt;();

    &lt;span class="kwrd"&gt;if&lt;/span&gt;(forumService == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
    {
        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; FaultException(&lt;span class="kwrd"&gt;new&lt;/span&gt; FaultReason(&lt;span class="str"&gt;"forum service"&lt;/span&gt;), &lt;span class="kwrd"&gt;new&lt;/span&gt; FaultCode(ErrorCode.Infrastructure.ToString()));
    }

    &lt;span class="kwrd"&gt;try&lt;/span&gt;
    {
        ForumEntity entity = forumService.UpdateForum(forumID, parentForumID, displayOrder, flags, DateTime.UtcNow);

        &lt;span class="kwrd"&gt;return&lt;/span&gt; Map(entity);
    }
    &lt;span class="kwrd"&gt;catch&lt;/span&gt;(XentaException ex)
    {
         &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; FaultException(&lt;span class="kwrd"&gt;new&lt;/span&gt; FaultReason(ex.Message), &lt;span class="kwrd"&gt;new&lt;/span&gt; FaultCode(ex.Code.ToString()));
    }
}&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;Infrastructure.Component represent a &lt;em&gt;home grown&lt;/em&gt; service locator. Note that we have manual exception handling for absolutely no reason whatsoever (you can do this in a behavior &lt;em&gt;once&lt;/em&gt;, and since this is repeated for &lt;em&gt;each and every one of the methods&lt;/em&gt;…).&lt;/p&gt;
&lt;p&gt;I apologize in advance, but here is the full UpdateForum method:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; ForumEntity UpdateForum(&lt;span class="kwrd"&gt;int&lt;/span&gt; forumID,
    &lt;span class="kwrd"&gt;int&lt;/span&gt; parentForumID,
    &lt;span class="kwrd"&gt;int&lt;/span&gt; displayOrder,
    ForumFlags flags, 
    DateTime updatedOn)
{
    ForumEntity oldForum = GetForum(forumID);
            
    &lt;span class="kwrd"&gt;if&lt;/span&gt;(oldForum == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
    {
        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; XentaException(ErrorCode.NotFound, &lt;span class="str"&gt;"forum"&lt;/span&gt;);
    }

    ForumEntity parentForum = &lt;span class="kwrd"&gt;null&lt;/span&gt;;

    &lt;span class="kwrd"&gt;if&lt;/span&gt;(parentForumID != 0)
    {
        parentForum = GetForum(parentForumID);

        &lt;span class="kwrd"&gt;if&lt;/span&gt;(parentForum == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
        {
            &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; XentaException(ErrorCode.NotFound, &lt;span class="str"&gt;"forum"&lt;/span&gt;);
        }

        ForumEntity tmp = parentForum;

&lt;font style="background-color: #ffff00"&gt;    HierarchyCheck:&lt;/font&gt;

        &lt;span class="kwrd"&gt;if&lt;/span&gt;(tmp.ForumID == forumID)
        {
            &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; XentaException(ErrorCode.InvalidArgument, &lt;span class="str"&gt;"parentForumID"&lt;/span&gt;);
        }
        &lt;span class="kwrd"&gt;if&lt;/span&gt;(tmp.ParentForumID != 0)
        {
            tmp = tmp.Parent;

       &lt;font style="background-color: #ffff00"&gt;     &lt;span class="kwrd"&gt;goto&lt;/span&gt; HierarchyCheck;
&lt;/font&gt;        }
    }

    ForumEntity newForum = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
    &lt;span class="kwrd"&gt;bool&lt;/span&gt; res = Provider.UpdateForum(forumID,
        parentForumID,
        oldForum.LastTopicID,
        oldForum.TopicCount,
        oldForum.PostCount,
        displayOrder,
        flags,
        oldForum.CreatedOn,
        updatedOn);

    &lt;span class="kwrd"&gt;if&lt;/span&gt;(res)
    {
        &lt;span class="kwrd"&gt;if&lt;/span&gt;(Cache != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
        {
            Cache.Remove(&lt;span class="str"&gt;"ForumService_GetForum_{0}"&lt;/span&gt;, oldForum.ForumID);
        }

        newForum = GetForum(forumID);

        &lt;span class="kwrd"&gt;if&lt;/span&gt;(EventBroker != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
        {
            EventBroker.Publish&amp;lt;PostEntityUpdate&amp;lt;ForumEntity&amp;gt;&amp;gt;(&lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; PostEntityUpdate&amp;lt;ForumEntity&amp;gt;(newForum, oldForum));
        }
    }
    &lt;span class="kwrd"&gt;return&lt;/span&gt; newForum;
}&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;Yes, it &lt;em&gt;is&lt;/em&gt; a goto there, for the life of me I can’t figure out why.&lt;/p&gt;
&lt;p&gt;Note that there is also this Provider in here, which is an IForumProvider, which is implemented by… ForumProvider, which looks like this:&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;bool&lt;/span&gt; UpdateForum(&lt;span class="kwrd"&gt;int&lt;/span&gt; forumID,
    &lt;span class="kwrd"&gt;int&lt;/span&gt; parentForumID,
    &lt;span class="kwrd"&gt;int&lt;/span&gt; lastTopicID,
    &lt;span class="kwrd"&gt;int&lt;/span&gt; topicCount,
    &lt;span class="kwrd"&gt;int&lt;/span&gt; postCount,
    &lt;span class="kwrd"&gt;int&lt;/span&gt; displayOrder,
    ForumFlags flags,
    DateTime createdOn,
    DateTime updatedOn)
{
    &lt;span class="kwrd"&gt;bool&lt;/span&gt; res = &lt;span class="kwrd"&gt;false&lt;/span&gt;;

    &lt;span class="kwrd"&gt;using&lt;/span&gt;(DbCommand cmd = DataSource.GetStoredProcCommand(&lt;span class="str"&gt;"fwk_Forums_Update"&lt;/span&gt;))
    {
        SqlServerHelper.SetInt32(DataSource, cmd, &lt;span class="str"&gt;"ForumID"&lt;/span&gt;, forumID);
        SqlServerHelper.SetInt32(DataSource, cmd, &lt;span class="str"&gt;"ParentForumID"&lt;/span&gt;, parentForumID);
        SqlServerHelper.SetInt32(DataSource, cmd, &lt;span class="str"&gt;"LastTopicID"&lt;/span&gt;, lastTopicID);
        SqlServerHelper.SetInt32(DataSource, cmd, &lt;span class="str"&gt;"TopicCount"&lt;/span&gt;, topicCount);
        SqlServerHelper.SetInt32(DataSource, cmd, &lt;span class="str"&gt;"PostCount"&lt;/span&gt;, postCount);
        SqlServerHelper.SetInt32(DataSource, cmd, &lt;span class="str"&gt;"DisplayOrder"&lt;/span&gt;, displayOrder);
        SqlServerHelper.SetInt32(DataSource, cmd, &lt;span class="str"&gt;"Flags"&lt;/span&gt;, (&lt;span class="kwrd"&gt;int&lt;/span&gt;)flags);
        SqlServerHelper.SetDateTime(DataSource, cmd, &lt;span class="str"&gt;"CreatedOn"&lt;/span&gt;, createdOn);
        SqlServerHelper.SetDateTime(DataSource, cmd, &lt;span class="str"&gt;"UpdatedOn"&lt;/span&gt;, updatedOn);

        res = DataSource.ExecuteNonQuery(cmd) &amp;gt; 0;
    }
    &lt;span class="kwrd"&gt;return&lt;/span&gt; res;
}&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;And… this is about it guys.&lt;/p&gt;
&lt;p&gt;I checked the source control, and the source control history for this goes back only to the beginning of February 2012. I assume that this is older than this, because the codebase is pretty large.&lt;/p&gt;
&lt;p&gt;But to summarize, what we actually have is a highly abstracted project, a &lt;em&gt;lot&lt;/em&gt; of abstraction. A lot of really bad code even if you ignore the abstractions, seemingly modern codebase that still uses direct ADO.Net for pretty much everything, putting a WCF service in the middle of the application just for the fun of it.&lt;/p&gt;
&lt;p&gt;Tons of code dedicated to error handling, caching, etc. All of which can be handled as cross cutting concerns.&lt;/p&gt;
&lt;p&gt;This is the kind of application that I would expect to see circa 2002, not a decade later.&lt;/p&gt;
&lt;p&gt;And please note, I actually got the review request exactly 34 minutes ago. I didn’t review the entire application (nor do I intend to). I merely took a reprehensive* vertical slide of the app and followed up on that.&lt;/p&gt;
&lt;p&gt;*Yes, this is intentional.&lt;/p&gt;</description><link>http://ayende.com/blog/155073/reviewing-xenta-and-wishing-i-hadnrsquo-t?key=ee820864-79e7-4ad3-b5a7-43bc23624c02</link><guid>http://ayende.com/blog/155073/reviewing-xenta-and-wishing-i-hadnrsquo-t?key=ee820864-79e7-4ad3-b5a7-43bc23624c02</guid><pubDate>Thu, 10 May 2012 09:00:00 GMT</pubDate></item><item><title>Thoughts after using ASP.Net Web API (beta) in anger for a week</title><description>&lt;blockquote&gt; &lt;p&gt;Nitpicker corner: Yes, I know about Open Rasta, NancyFX, FubuMVC and all of the other cool frameworks out there. I am not here today to talk about them. I am not &lt;em&gt;interested&lt;/em&gt; in talking about them and why they are so much better in this post.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;You might be aware that I am doing a &lt;em&gt;lot&lt;/em&gt; of stuff at the HTTP level, owing to the fact that both RavenDB and RavenFS are REST based servers.&lt;/p&gt; &lt;p&gt;As such, I had to become intimately familiar with the HTTP spec, how things work at the low level ASP.Net level, etc. I even had to write my own abstractions to be able to run both inside IIS and as a service. Suffice to say, I feel that I have a lot of experience in building HTTP based system. That said, I am also approaching things from a relatively different angle than most people. I am not aiming to build a business application, I am actually building infrastructure servers.&lt;/p&gt; &lt;p&gt;There was a lot of buzz about the ASP.Net Web API, and I took a brief look at the demo, marked it as “nice, need to check it out some day” in my head and moved on. Then I run into a strange problem in RavenFS. RavenFS is a sibling to RavenDB. Whereas RavenDB is a document database, RavenFS is a distributed &amp;amp; replicated file server for (potentially) very large files. (It is currently in beta testing ,and when we are doing giving it all the bells and whistle of a real product, we will show it to the world &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://ayende.com/blog/Images/Windows-Live-Writer/Thoughts-after-us.Net-Web-API-for-a-week_C904/wlEmoticon-smile_2.png"&gt;, it isn’t really important to this post).&lt;/p&gt; &lt;p&gt;What is important is that I run into a problem with RavenFS, and I felt that there was a strong likelihood that I was doing something &lt;em&gt;wrong&lt;/em&gt; in the HTTP layer that was causing this. Despite its outward simplicity, HTTP is pretty complex when you get down to business. So I decided to see what would happen if I would replace the HTTP layer for RavenFS with ASP.Net Web API.&lt;/p&gt; &lt;p&gt;That means that I have been using it in anger for the last week, and here is what I think about it so far.&lt;/p&gt; &lt;p&gt;First, it is a &lt;em&gt;beta&lt;/em&gt;. That is something that is important to remember, because it means that it isn’t done yet. &lt;/p&gt; &lt;p&gt;Second, I am talking strictly about the server API. I haven’t even &lt;em&gt;touched&lt;/em&gt; the client API as of now.&lt;/p&gt; &lt;p&gt;Third, and most important. I am impressed. It is a really clean API, nice interface, &lt;em&gt;well&lt;/em&gt; thought out and quite nice to work with.&lt;/p&gt; &lt;p&gt;More than that, I had to do a bunch of stuff that really isn’t trivial. And there are very little docs for it as of now. I was able to do pretty much everything I wanted by just walking the API and figuring things out on my own.&lt;/p&gt; &lt;p&gt;Things that I particularly liked:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;The API guides you to do the &lt;em&gt;right&lt;/em&gt; thing. For example, different headers have different meaning, and you can see that when you look at the different headers collections. You have headers that goes in the response, headers that go in the request, headers that goes for the content, and so on. It really guides you properly to using this as you should.&lt;/li&gt; &lt;li&gt;A lot of the stuff that is usually hard is now pretty easy to do. Multi part responses, for example. Ranged requests, or proper routing.&lt;/li&gt; &lt;li&gt;I was able to plug in DI for what I was doing in a couple of minutes without really knowing anything about how things work. And I could do that by providing a single delegate, rather than implement a complex interface.&lt;/li&gt; &lt;li&gt;I provides support for self hosting, which is &lt;em&gt;crucial &lt;/em&gt;for doing things like unit testing the server.&lt;/li&gt; &lt;li&gt;It is Async to the core. &lt;/li&gt; &lt;li&gt;I &lt;em&gt;really&lt;/em&gt; like the ability to return a value, or a task, or a task of a value, or return an HttpResponseMessage which I can customize to my heart content. &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Overall, it &lt;em&gt;just makes sense&lt;/em&gt;. I get how it works, and it doesn’t seems like I have to fight anything to get things done.&lt;/p&gt; &lt;p&gt;Please note that this is porting a major project to a completely new platform, and doing some really non trivial things in there while doing this.&lt;/p&gt; &lt;p&gt;Things that I didn’t like with it:&lt;/p&gt; &lt;p&gt;Put simply, errors. To be fair, this isn’t a complaint about the standard error handling, this works just fine. The issue is with infrastructure errors.&lt;/p&gt; &lt;p&gt;For example, if you try to push a 5MB request to the server, by default the request will just die. No error message, and the status code is 503 (message unavailable). This can be pretty frustrating to try to figure out, because there is nothing to tell you what the problem &lt;em&gt;is&lt;/em&gt;. And I didn’t look at the request size at first. It just seemed that some request worked, and some didn’t. Even after that I found that it is the size that mattered, it was hard to figure out where we need to fix that (and the answer to that is different depending on where you are running!).&lt;/p&gt; &lt;p&gt;Another example is using PUT or DELETE in your requests. As long as you are running in SelfHost, everything will work just fine. If you switch to IIS, you will get an error (405, Method Not Allowed), again, with no idea how to fix this or why this is happening. This is something that you can fix in the config (sometimes), but it is another error that has horrible usability.&lt;/p&gt; &lt;p&gt;Those are going to be pretty common errors, I am guessing, and any error like that is actually a road block for the users. Having an error code and nothing else thrown at you is really frustrating, and this is something that can really use a &lt;em&gt;good&lt;/em&gt; error report. Including details about how to fix the problem.&lt;/p&gt; &lt;p&gt;There are a bunch of other issues that I run into (an NRE when misconfiguring the routing that was really confusing and other stuff like that), but this is beta software, and those are things that will be fixed.&lt;/p&gt; &lt;p&gt;The one thing that I miss as a feature is good support for nested resources (/accounts/1/people/2/notes), which can be a great way to provide additional context for the application. What I actually want to use this for is to be able to do things like: /folders &amp;lt;—FoldersController.Get, Post, Put, Delete and then have: /folders/search &amp;lt;- FolderController.GetSearch., PostSearch, etc.&lt;/p&gt; &lt;p&gt;So I can get the routing by http method even when I am doing controller and action calls. &lt;/p&gt; &lt;p&gt;Final thoughts, RavenFS is now completely working using this model, and I like it. It is really nice API, it works, but most importantly, it &lt;em&gt;makes sense&lt;/em&gt;.&lt;/p&gt;</description><link>http://ayende.com/blog/155137/thoughts-after-using-asp-net-web-api-beta-in-anger-for-a-week?key=c76e3788-e349-45ce-b2e9-cb659dfe1773</link><guid>http://ayende.com/blog/155137/thoughts-after-using-asp-net-web-api-beta-in-anger-for-a-week?key=c76e3788-e349-45ce-b2e9-cb659dfe1773</guid><pubDate>Mon, 12 Mar 2012 08:00:00 GMT</pubDate></item><item><title>Reviewing Postman</title><description>&lt;p&gt;I enjoy reading code, and I decided that of a change, I want to read code that isn’t in .NET. The following is a review of &lt;a href="https://github.com/Buildstarted/Postman"&gt;Postman&lt;/a&gt;:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;Postman is a little JavaScript library (well it's actually &lt;a href="http://coffeescript.org/"&gt;Coffeescript&lt;/a&gt; but the Cakefile handles a build for me) which is similar to a traditional pub/ sub library, just a whole lot smarter.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;This is actually the first time that I looked at Coffescript code (beyond cursory glance at the tutorial a time or two). I got to say, it looks pretty neat. Take a look at the definition of&amp;nbsp; a linked list: &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Reviewing-Postman_CDCD/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/Reviewing-Postman_CDCD/image_thumb.png" width="287" height="549"&gt;&lt;/a&gt; &lt;p&gt;Pretty, readable and to the point. I like that. &lt;p&gt;Then I got to a head scratching piece: &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Reviewing-Postman_CDCD/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/Reviewing-Postman_CDCD/image_thumb_1.png" width="159" height="38"&gt;&lt;/a&gt; &lt;p&gt;There are various things that refer to postie, but it wasn’t until I got to the bottom of the code that I saw: &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Reviewing-Postman_CDCD/image_6.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/Reviewing-Postman_CDCD/image_thumb_2.png" width="242" height="79"&gt;&lt;/a&gt; &lt;p&gt;So I guess that postie line is actually defining a null argument, so it can be captured by the class Postman class methods. &lt;p&gt;I’ll be the first to admit that I am not a JS / CoffeeScript guy, so sometimes I am a little slow to figure things out, this method gave me a pause: &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Reviewing-Postman_CDCD/image_8.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/Reviewing-Postman_CDCD/image_thumb_3.png" width="276" height="292"&gt;&lt;/a&gt; &lt;p&gt;It took a while to figure out what is going on there. &lt;p&gt;The first few lines basically say, skip the first argument and capture the rest, then call all the subscriptions with the new msg. &lt;p&gt;Note that this is preserving history. So we can do something with this. &lt;p&gt;There is also an async version of this, confusing called deliverSync. &lt;p&gt;Getting the notification is done via:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Reviewing-Postman_CDCD/image_10.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/Reviewing-Postman_CDCD/image_thumb_4.png" width="294" height="164"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;This is quite elegant, because it means that you don’t lose out on messages that have already been published. &lt;/p&gt; &lt;p&gt;I guess that you might need to worry about memory usage, but there seems to be some mechanism to sort that out too. So you can explicitly clean things out. Which works well enough, I guess, but I would probably do some sort of builtin limits for how many msgs it can hold at any one time, just to be on the safe side. I don’t actually &lt;em&gt;know&lt;/em&gt; how you would debug a memory leak in such a system, but I am guessing it can’t be fun.&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Reviewing-Postman_CDCD/image_12.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/Reviewing-Postman_CDCD/image_thumb_5.png" width="682" height="408"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;This code makes my head hurt a big, because of the ability to pass a date or a function. I would rather have an options argument here, rather than overloading the parameter. It might be that I am a bad JS / CoffeScript coder and try to impose standards of behavior from C#, though.&lt;/p&gt; &lt;p&gt;All in all, this seems to be a fairly nice system, there is a test suite that is &lt;em&gt;quite&lt;/em&gt; readable, and it is a fun codebase to read.&lt;/p&gt;</description><link>http://ayende.com/blog/153601/reviewing-postman?key=60af822d-88ed-4902-80d0-e59c50f23306</link><guid>http://ayende.com/blog/153601/reviewing-postman?key=60af822d-88ed-4902-80d0-e59c50f23306</guid><pubDate>Fri, 09 Mar 2012 10:00:00 GMT</pubDate></item><item><title>Taking a look at S#arp Lite&amp;ndash;final thoughts</title><description>&lt;p&gt;&lt;img style="display: inline; float: right" align="right" src="http://devlicio.us/resized-image.ashx/__size/300x0/__key/CommunityServer.Blogs.Components.WeblogFiles/billy_5F00_mccafferty/SharpLite_5F00_Logo.png"&gt;This is a review of the &lt;a href="https://github.com/codai/Sharp-Lite"&gt;S#arp Lite project&lt;/a&gt;, the version from Nov 4, 2011.  &lt;p&gt;This project is significantly better than the S#arp Arch project that I reviewed a while ago, but that doesn’t mean that it is good. There is a lot to like, but frankly, the insistence to &lt;em&gt;again&lt;/em&gt; abstract the data access behind complex base classes and repositories makes things much harder in the longer run.  &lt;p&gt;If you are writing an application and you find yourself writing abstractions on top of CUD operations, stop, you are doing it wrong.  &lt;p&gt;I quite like S#arp approach for querying, though. You expose things directly, and if it is ugly, you just wrap it in a dedicated query object. That is how you should be handling things.  &lt;p&gt;Finally, whenever possible, push things to the infrastructure, it is usually pretty good and that is the right level of handling things like persistence, validation, etc. And no, you don’t have to write that, it is already there.  &lt;p&gt;A lot of the code in the sample project was simply to manage persistence and validation (in fact, there was an entire project for that) that could be safely deleted in favor of:  &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; ValidationListener : NHibernate.Event.IPreUpdateEventListener, NHibernate.Event.IPreInsertEventListener
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; OnPreUpdate(PreUpdateEvent @&lt;span class="kwrd"&gt;event&lt;/span&gt;)
    {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!DataAnnotationsValidator.TryValidate(@&lt;span class="kwrd"&gt;event&lt;/span&gt;.Entity)) 
            &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; InvalidOperationException(&lt;span class="str"&gt;"Updated entity is in an invalid state"&lt;/span&gt;);

        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; OnPreInsert(PreInsertEvent @&lt;span class="kwrd"&gt;event&lt;/span&gt;)
    {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!DataAnnotationsValidator.TryValidate(@&lt;span class="kwrd"&gt;event&lt;/span&gt;.Entity))
            &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; InvalidOperationException(&lt;span class="str"&gt;"Updated entity is in an invalid state"&lt;/span&gt;);

        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&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;Register that with NHibernate, and it will do that validation work for you, for example. Don’t try too hard, it &lt;em&gt;should&lt;/em&gt; be simple, if it ain’t, you are either doing something very strange or you are doing it wrong, and I am willing to bet on the later.&lt;/p&gt;
&lt;p&gt;To be clear, the problems that I had with the codebase were mostly with regards to the data access portions. I didn’t have any issues with the rest of the architecture.&lt;/p&gt;</description><link>http://ayende.com/blog/153569/taking-a-look-at-s-arp-litendash-final-thoughts?key=fcab01f8-ca05-4dbe-be7d-ed4105b552ed</link><guid>http://ayende.com/blog/153569/taking-a-look-at-s-arp-litendash-final-thoughts?key=fcab01f8-ca05-4dbe-be7d-ed4105b552ed</guid><pubDate>Thu, 08 Mar 2012 10:00:00 GMT</pubDate></item><item><title>Taking a look at S#arp Lite&amp;ndash; The MVC parts</title><description>&lt;p&gt;This is a review of the &lt;a href="https://github.com/codai/Sharp-Lite"&gt;S#arp Lite project&lt;/a&gt;, the version from Nov 4, 2011.&lt;/p&gt; &lt;p&gt;Okay, after going over all of the rest of the application, let us take a look a the parts that actually &lt;em&gt;do&lt;/em&gt; something. &lt;/p&gt; &lt;p&gt;the following are from the CustomerController:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Taking-a-look-at-Sarp-Lite-The-MVC-parts_1058/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/Taking-a-look-at-Sarp-Lite-The-MVC-parts_1058/image_thumb.png" width="456" height="314"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;It is fairly straight forward, all in all. Of course, the problem is that is isn’t doing much. The moment that it does, we are going to run into problems. Let us move a different controller, ProductController and the Index action:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Taking-a-look-at-Sarp-Lite-The-MVC-parts_1058/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/Taking-a-look-at-Sarp-Lite-The-MVC-parts_1058/image_thumb_1.png" width="432" height="92"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Seems fine, right? Except that in the view…&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Taking-a-look-at-Sarp-Lite-The-MVC-parts_1058/image_6.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/Taking-a-look-at-Sarp-Lite-The-MVC-parts_1058/image_thumb_2.png" width="435" height="231"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;As you can see, we got a Select N+1 here. I’ll admit, I actually had to spend a moment or two to look for it (hint, look for @foreach&amp;nbsp; in the view, that is usually an indication of a place that requires attention).&lt;/p&gt; &lt;p&gt;The problem is that we really don’t have anything to do about it. If we want to resolve this, we would have to create our own query object to completely encapsulate the query. But all we need is to just add a FetchMany and we are done, except that there is that nasty OR/M abstraction that doesn’t do much except make our life harder.&lt;/p&gt;</description><link>http://ayende.com/blog/153537/taking-a-look-at-s-arp-litendash-the-mvc-parts?key=a56dbd94-bda5-400c-99a3-7da804aceed4</link><guid>http://ayende.com/blog/153537/taking-a-look-at-s-arp-litendash-the-mvc-parts?key=a56dbd94-bda5-400c-99a3-7da804aceed4</guid><pubDate>Wed, 07 Mar 2012 10:00:00 GMT</pubDate></item><item><title>Taking a look at S#arp Lite, Part III&amp;ndash;tasks</title><description>&lt;p&gt;This is a review of the &lt;a href="https://github.com/codai/Sharp-Lite"&gt;S#arp Lite project&lt;/a&gt;, the version from Nov 4, 2011.&lt;/p&gt; &lt;p&gt;So far, we have gone over the general structure and the domain. Next on the list is going over the tasks project. No idea what this is. I would expect that to be some sort of long running, background tasks, but haven’t checked it yet.&lt;/p&gt; &lt;p&gt;Unfortunately, this isn’t the case. Tasks seems to be about another name for DAL. And to make matter worse, this is a DAL on top or a Repository on top of an OR/M. &lt;/p&gt; &lt;p&gt;And as if that wasn’t enough to put my teeth on edge, we got some really strange things going on there. Let us see how it goes.&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/0efd1e3fa8b9_79F/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/0efd1e3fa8b9_79F/image_thumb.png" width="628" height="196"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Basically, a CudTask seems to be all about translating from the data model (I intentionally don’t call it domain model) to the view model. I spoke about the issues with repositories many times before, so I’ll suffice with saying that this is still wasteful and serve no real purpose and be done with it.&lt;/p&gt; &lt;p&gt;This TransferFormValuesTo() is a strange beast, and it took me a while to figure out what is going on here. let us look in the parent class to figure out what is going on there.&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/0efd1e3fa8b9_79F/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/0efd1e3fa8b9_79F/image_thumb_1.png" width="1010" height="475"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Let me count the things that are wrong here.&lt;/p&gt; &lt;p&gt;First, we have this IsTransient() method, why do we have that? All we need to do is just to call SaveOrUpdate and it will do it for us. Then the rest of the method sunk in. &lt;/p&gt; &lt;p&gt;The way this system works, you are going to have &lt;em&gt;two &lt;/em&gt;instances of every entity that you load (not really true, by the way, because you have leakage for references, which must cause some really interesting bugs). One instance is the one that is managed by NHibernate, dealing with lazy loading, change management, etc. The second is the value that &lt;em&gt;isn’t&lt;/em&gt; managed by NHibernate. I assume that this is an instance that you get when you bind the entity view the action parameters.&lt;/p&gt; &lt;p&gt;NHibernate contains &lt;em&gt;explicit &lt;/em&gt;support for handling that (session.Merge), and that support is there for &lt;em&gt;bad application&lt;/em&gt;s. You shouldn’t be doing things this way. Extend the model binder so it would load the entity from NHibernate and bind to that instance directly. You wouldn’t have to worry about all of this code, it would just work.&lt;/p&gt; &lt;p&gt;For that matter, the same goes for validation as well, you can push that into NHibernate as a listener. So all of this code just goes away, poof!&lt;/p&gt; &lt;p&gt;And then there is the Delete method:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/0efd1e3fa8b9_79F/image_6.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/0efd1e3fa8b9_79F/image_thumb_2.png" width="902" height="374"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;I mean, is there a &lt;strong&gt;rule&lt;/strong&gt; that says “developers should discard error information as soon as possible, because it is useless.” I mean, the next step is to see C# code littered with things like:&lt;/p&gt; &lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;catch&lt;/span&gt;(Exception e)
{
   &lt;font color="#0000ff"&gt;delete&lt;/font&gt; e; &lt;span class="rem"&gt;// early release for the memory held by the exception&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;The one good thing that I can say about the CudTasks is that at least they are explicit about not handling reads, and that reads seems to be handled properly so far (but I haven’t looked at the actual code yet).&lt;/p&gt;</description><link>http://ayende.com/blog/153505/taking-a-look-at-s-arp-lite-part-iiindash-tasks?key=6228ac6f-7151-45e1-8b29-dd873e7a6d99</link><guid>http://ayende.com/blog/153505/taking-a-look-at-s-arp-lite-part-iiindash-tasks?key=6228ac6f-7151-45e1-8b29-dd873e7a6d99</guid><pubDate>Tue, 06 Mar 2012 10:00:00 GMT</pubDate></item><item><title>Taking a look at S#arp Lite, Part II&amp;ndash;the domain</title><description>&lt;p&gt;This is a review of the &lt;a href="https://github.com/codai/Sharp-Lite"&gt;S#arp Lite project&lt;/a&gt;, the version from Nov 4, 2011.&lt;/p&gt; &lt;p&gt;In my previous post, I looked at the general structure, but not much more. In this one, we are going to focus on the Domain project.&lt;/p&gt; &lt;p&gt;We start with the actual domain:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/ff52a6fb7643_340/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/ff52a6fb7643_340/image_thumb.png" width="781" height="533"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;I have only few comments about this sort of model:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;This is a pure CRUD model, which is good, since it is simple and easy to understand, but one does wonder where the actual business logic of the system is. It might be that there isn’t any (we &lt;em&gt;are&lt;/em&gt; talking about a sample app, after all).  &lt;li&gt;The few methods that are there are also about data (in this case, aggregation, and Order.GetTotal() will trigger a lazy loaded query when called, which might be a surprise to the caller.  &lt;li&gt;Probably the worst point of this object model is that it is &lt;em&gt;highly connected&lt;/em&gt;, which encourages people to try to walk the object graphs where they should issue a separate query instead.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Next, let us look at the queries. We have seen one example where NHibernate low level API was hidden behind an interface, but that was explicitly called out as rare. So how does this get handled on a regular basis?&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/ff52a6fb7643_340/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/ff52a6fb7643_340/image_thumb_1.png" width="863" height="603"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Hm… I have some issues here with regards to the naming. I don’t like the “Find” vs. “Query” naming. I would use WhereXyz to add a filter and SelectXyz to add a transformation. It would read better when writing Linq queries, but that is about it for the domain. &lt;/p&gt; &lt;p&gt;One thing that I haven’t touched so far is the entities base class:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/ff52a6fb7643_340/image_6.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/ff52a6fb7643_340/image_thumb_2.png" width="398" height="72"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;And its parent:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/ff52a6fb7643_340/image_8.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/ff52a6fb7643_340/image_thumb_3.png" width="651" height="265"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;I strongly support the notion of ComparableObject, this is recommended when you use NHibernate. But what is it about GetTypeSpecificSignatureProperties? What it actually does is select all the properties that has the [DomainSignature] attribute. But what would you want something like that? &lt;/p&gt; &lt;p&gt;Looking at the code, the Customer.FirstName and Customer.LastName have this attribute, looking at the code, I really can’t understand what went on here. This seems to be selected specifically to create hard to understand and debug bugs.&lt;/p&gt; &lt;p&gt;Why do I say that? The ComparableObject uses properties marked with [DomainSignature] for the GetHashCode() calculation. What this means is that &lt;em&gt;if you change the customer name you change its hash code value&lt;/em&gt;. This hash code value is used for, among other things, finding the entity in the unit of work, so changing the customer name can cause NHibernate to loose track of it and behave in some really strange ways.&lt;/p&gt; &lt;p&gt;This is also violating one of the &lt;strong&gt;core &lt;/strong&gt;principals of &lt;a href="https://www.google.com/search?sourceid=chrome&amp;amp;ie=UTF-8&amp;amp;q=entity#hl=en&amp;amp;q=entity&amp;amp;tbs=dfn:1&amp;amp;tbo=u&amp;amp;sa=X&amp;amp;ei=ItwHT87DIs2gtwfz7qnQBg&amp;amp;ved=0CC8QkQ4&amp;amp;bav=on.2,or.r_gc.r_pw.,cf.osb&amp;amp;fp=a832e4bee034e5be&amp;amp;biw=1599&amp;amp;bih=815"&gt;entities&lt;/a&gt;:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;A thing with distinct and independent existence.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;In other words, an entity doesn’t exists because of the particular values that are there for the first and last names. If those change, the customer doesn’t change. It is the same as saying that by changing the shirt I wear, I becomes a completely different person.&lt;/p&gt; &lt;p&gt;Domain Signature is something that I am completely opposed, not only for the implementation problems, but because it has no meaning when you start to consider what an entity &lt;em&gt;is&lt;/em&gt;.&lt;/p&gt; &lt;p&gt;Next, we are going to explore tasks…&lt;/p&gt;</description><link>http://ayende.com/blog/153473/taking-a-look-at-s-arp-lite-part-iindash-the-domain?key=489a72ca-eb04-45d9-9d78-826e4eb042d0</link><guid>http://ayende.com/blog/153473/taking-a-look-at-s-arp-lite-part-iindash-the-domain?key=489a72ca-eb04-45d9-9d78-826e4eb042d0</guid><pubDate>Fri, 02 Mar 2012 10:00:00 GMT</pubDate></item><item><title>Taking a look at S#arp Lite, Part I</title><description>&lt;p&gt;This is a review of the &lt;a href="https://github.com/codai/Sharp-Lite"&gt;S#arp Lite project&lt;/a&gt;, the version from Nov 4, 2011.&lt;/p&gt; &lt;p&gt;I was asked to review this project a long time ago, but I never got around to it. I had some time and I decided that I might take a look and see how it goes. I don’t like the S#arp Arch project, because it seems too complex and heavy weight for the purpose.&lt;/p&gt; &lt;p&gt;The project comes with a sample application, which is good, because it is easy to see how the framework is intended to be used. Unfortunately, it is &lt;em&gt;yet another&lt;/em&gt; online store example, I am getting heartily sick of that. On the other hand, it is a fairly simple model and easy to understand, so I grok why this keeps getting chosen.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;Review Rule, I look at the &lt;em&gt;code&lt;/em&gt;. If I wanted to deal with documentation, I would write some for our products. I am doing this because I find it fun to look at other people’s code. So skip any comments about “if you read the docs…”. &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;We start from the project structure:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Taking-a-look-at-Sarp-Lite_14CDC/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/Taking-a-look-at-Sarp-Lite_14CDC/image_thumb.png" width="232" height="157"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;I am not sure if I like it, I don’t know if I agree that all of those splits are needed, but this is well within reasonable limits, so I am willing to let it slide on the grounds that this is personal taste more than anything else. Looking at the dependencies, we see:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Taking-a-look-at-Sarp-Lite_14CDC/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/Taking-a-look-at-Sarp-Lite_14CDC/image_thumb_1.png" width="897" height="645"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;The Init project contains two files, which are responsible for… well, starting up, it seems. Again, I don’t see any reason why this would be a separate project, but that is about it so far.&lt;/p&gt; &lt;p&gt;Next in line is the NHibernateProvider project, in this case, we have the following:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Taking-a-look-at-Sarp-Lite_14CDC/image_6.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/Taking-a-look-at-Sarp-Lite_14CDC/image_thumb_2.png" width="292" height="173"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;So far, I am cautiously optimistic. All of the files / folders marked with red are actually all about &lt;em&gt;setting NHibernate up&lt;/em&gt;, not about hiding it. But then we get to the read me file, which reads in part:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;This folder contains any concrete, NHibernate-specific query classes.&lt;br&gt;There should only be classes in here for any respective query *interfaces* found in &lt;br&gt;/MyStore.Domain/Queries/&lt;/p&gt; &lt;p&gt;This folder will usually be empty except for very exceptive cases.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;This is… interesting. Can’t say whatever I agree or not yet. Looking at the QueryForProductOrderSummaries, we see:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Taking-a-look-at-Sarp-Lite_14CDC/image_8.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/Taking-a-look-at-Sarp-Lite_14CDC/image_thumb_3.png" width="700" height="375"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Note the comment, there &lt;em&gt;are&lt;/em&gt; better ways to do it, but we demonstrate an ugly way, and how to nicely encapsulate it.&lt;/p&gt; &lt;p&gt;That is enough for now, I think, next post, I’ll touch on the actual model…&lt;/p&gt;</description><link>http://ayende.com/blog/153441/taking-a-look-at-s-arp-lite-part-i?key=e698d1fe-b6e2-4f35-b4d0-2ed2701b59b5</link><guid>http://ayende.com/blog/153441/taking-a-look-at-s-arp-lite-part-i?key=e698d1fe-b6e2-4f35-b4d0-2ed2701b59b5</guid><pubDate>Thu, 01 Mar 2012 10:00:00 GMT</pubDate></item><item><title>Northwind Starter Kit Review: Conclusion</title><description>&lt;p&gt;This is a review of the &lt;a href="http://nsk.codeplex.com/"&gt;Northwind Starter Kit project&lt;/a&gt;, this review revision &lt;a href="http://nsk.codeplex.com/SourceControl/changeset/changes/94815"&gt;94815&lt;/a&gt; from Dec 18 2011.  &lt;p&gt;A while ago I said:  &lt;blockquote&gt; &lt;p&gt;Seriously?!&amp;nbsp; 22(!) projects to do a sample application using Northwind?&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;And people took me up to task about it. The criticism was mostly focused on two parts:  &lt;ul&gt; &lt;li&gt;I didn’t get that the project wasn’t about Northwind, but about being a sample app for architectural design patterns.  &lt;li&gt;I couldn’t actually decide that a project was bad simply by looking at the project structure and some minor code browsing.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;I am sad to say that after taking a detailed look at the code, I am even more firmly back at my original conclusion.&amp;nbsp; I started to do a review of the UI code, but there really is no real need to do so.&lt;/p&gt; &lt;p&gt;The entire project, as I said in the beginning, is supposed to be a sample application for Northwind. Northwind is a CRUD application. Well, not exactly, it is supposed to be an example of an Online Store, which is something much bigger than just Northwind. But it isn’t. &lt;/p&gt; &lt;p&gt;Say what you will, the Northwind Starter Kit is a CRUD application. It does exactly that, and nothing else. It does so in an incredibly complicated fashion, mind, but that is what it does.&lt;/p&gt; &lt;p&gt;Well, it doesn’t do updates, or deletes, or creates. So it is just an R application (I certainly consider the codebase to be R rated, not for impressionable developers).&lt;/p&gt; &lt;p&gt;If you want to have a sample application to show off architectural ideas, make sure that the application can actually, you know, show them. The only thing that NSK does is loading stuff from the database, try as I might, I found no real piece of business logic, no any reason why it is so complicated.&lt;/p&gt; &lt;p&gt;So, to the guys who commented on that, it isn’t a good project. If you like it, I am happy for you, there are also people who loves &lt;a href="http://ugliestdogs.net/ugliestdogwinners.html"&gt;this guy&lt;/a&gt;:&lt;/p&gt; &lt;p&gt;&lt;img src="http://ugliestdogs.net/sitebuilder/images/Picture_144_1_-387x251.jpg"&gt;&lt;/p&gt; &lt;p&gt;Personally, I would call pest control.&lt;/p&gt;</description><link>http://ayende.com/blog/153062/northwind-starter-kit-review-conclusion?key=8b9a7e78-40f5-40f0-9ee4-ab82db0c68ee</link><guid>http://ayende.com/blog/153062/northwind-starter-kit-review-conclusion?key=8b9a7e78-40f5-40f0-9ee4-ab82db0c68ee</guid><pubDate>Thu, 26 Jan 2012 10:00:00 GMT</pubDate></item><item><title>Northwind Starter Kit Review: That CQRS thing</title><description>&lt;p&gt;This is a review of the &lt;a href="http://nsk.codeplex.com/"&gt;Northwind Starter Kit project&lt;/a&gt;, this review revision &lt;a href="http://nsk.codeplex.com/SourceControl/changeset/changes/94815"&gt;94815&lt;/a&gt; from Dec 18 2011. &lt;p&gt;It is obvious from reading the code that there was some attention given to CQRS. Unfortunately, I can’t really figure out what for. &lt;p&gt;To start with, both the Read Model and the Domain Model are actually sitting &lt;em&gt;on the same physical location&lt;/em&gt;. If you are doing that, there is a 95% chance that you don’t need CQRS. If you have that, you are going to waste a lot of time and effort and are &lt;em&gt;very&lt;/em&gt; unlikely to get anything from it.  &lt;p&gt;In the case of NSK, here is the domain model vs. the read model for the customer. &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Northwind-Starter-Kit_11A1/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/Northwind-Starter-Kit_11A1/image_thumb.png" width="357" height="448"&gt;&lt;/a&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Northwind-Starter-Kit_11A1/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/Northwind-Starter-Kit_11A1/image_thumb_1.png" width="382" height="279"&gt;&lt;/a&gt;  &lt;p&gt;I marked the difference.&lt;/p&gt; &lt;p&gt;I am sorry, there is nothing that justify a different model here. Just needless complexity.&lt;/p&gt; &lt;p&gt;Remember, our job is to make things &lt;strong&gt;simpler&lt;/strong&gt;, not make it hard to work with the application.&lt;/p&gt;</description><link>http://ayende.com/blog/153154/northwind-starter-kit-review-that-cqrs-thing?key=b2e6840c-c298-446e-afbf-83e31c1ae003</link><guid>http://ayende.com/blog/153154/northwind-starter-kit-review-that-cqrs-thing?key=b2e6840c-c298-446e-afbf-83e31c1ae003</guid><pubDate>Tue, 24 Jan 2012 10:00:00 GMT</pubDate></item><item><title>Northwind Starter Kit Review: It is all about the services</title><description>&lt;p&gt;This is a review of the &lt;a href="http://nsk.codeplex.com/"&gt;Northwind Starter Kit project&lt;/a&gt;, this review revision &lt;a href="http://nsk.codeplex.com/SourceControl/changeset/changes/94815"&gt;94815&lt;/a&gt; from Dec 18 2011.  &lt;p&gt;Okay, enough about the data access parts. Let us see take a look at a few of the other things that are going on in the application. In particular, this is supposed to be an application with…  &lt;blockquote&gt; &lt;p&gt;Domain logic is implemented by means of a Domain Model, onto a layer of services adds application logic. The model is persisted by a DAL designed around the principles of the "Repository" patterns, which has been implemented in a LINQ-friendly way.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Let us try to figure this out one at a time, okay?  &lt;p&gt;The only method in the domain model that have even a hint of domain logic is the CalculateTotalIncome method. Yes, you got it right, that is &lt;em&gt;a &lt;/em&gt;method, as in singular. And that method should be replaced with a query, it has no business being on the domain model. &lt;p&gt;So let us move to the services, okay? Here are the service definitions in the entire project: &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/0ae6875d1b24_71A7/image_6.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/0ae6875d1b24_71A7/image_thumb_2.png" width="885" height="690"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Look at the methods carefully. Do you see any &lt;em&gt;action&lt;/em&gt; at all? You don’t, the entire thing is just about &lt;em&gt;queries&lt;/em&gt;. &lt;/p&gt; &lt;p&gt;And queries should be &lt;em&gt;simple&lt;/em&gt;, not abstracted away and made very hard to figure out.&lt;/p&gt; &lt;p&gt;The rule of the thumb is that you try hard to not abstract queries, it is operations that you try to abstract. Operations is where you usually actually find the business logic.&lt;/p&gt;</description><link>http://ayende.com/blog/153061/northwind-starter-kit-review-it-is-all-about-the-services?key=7f5a17e7-68be-468a-8660-a83386aa31a4</link><guid>http://ayende.com/blog/153061/northwind-starter-kit-review-it-is-all-about-the-services?key=7f5a17e7-68be-468a-8660-a83386aa31a4</guid><pubDate>Mon, 23 Jan 2012 10:00:00 GMT</pubDate></item><item><title>Northwind Starter Kit Review: From start to finishing&amp;ndash;tracing a request</title><description>&lt;p&gt;This is a review of the &lt;a href="http://nsk.codeplex.com/"&gt;Northwind Starter Kit project&lt;/a&gt;, this review revision &lt;a href="http://nsk.codeplex.com/SourceControl/changeset/changes/94815"&gt;94815&lt;/a&gt; from Dec 18 2011.&lt;/p&gt; &lt;p&gt;One of the things that I repeatedly call out is the forwarding type of architecture, a simple operation that is hidden away by a large number of abstractions that serves no real purpose. &lt;/p&gt; &lt;p&gt;Instead of a controller, let us look at a web service, just to make things slightly different. We have the following:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Northwind-Starter-Kit-Review-From-start-_72A0/image_8.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/Northwind-Starter-Kit-Review-From-start-_72A0/image_thumb_3.png" width="650" height="497"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Okay, let us dig deeper:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Northwind-Starter-Kit-Review-From-start-_72A0/image_12.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/Northwind-Starter-Kit-Review-From-start-_72A0/image_thumb_5.png" width="451" height="121"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;I &lt;em&gt;really &lt;/em&gt;like the fact that this repository actually &lt;em&gt;have&lt;/em&gt; have FindById method, which this service promptly ignores in favor of using the IQueryable&amp;lt;Customer&amp;gt; implementation. If you want to know how that is implemented, just look (using the EF Code First repository implementations, the others are fairly similar):&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Northwind-Starter-Kit-Review-From-start-_72A0/image_14.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/Northwind-Starter-Kit-Review-From-start-_72A0/image_thumb_6.png" width="501" height="376"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;All in all, the entire thing only serves to make things harder to understand and maintain. &lt;/p&gt; &lt;p&gt;Does anyone really think that this abstraction adds anything? What is the &lt;strong&gt;&lt;em&gt;point&lt;/em&gt;&lt;/strong&gt;?!&lt;/p&gt;</description><link>http://ayende.com/blog/153060/northwind-starter-kit-review-from-start-to-finishingndash-tracing-a-request?key=ed569a76-c10c-41a2-a602-27bb9bb06d04</link><guid>http://ayende.com/blog/153060/northwind-starter-kit-review-from-start-to-finishingndash-tracing-a-request?key=ed569a76-c10c-41a2-a602-27bb9bb06d04</guid><pubDate>Fri, 20 Jan 2012 10:00:00 GMT</pubDate></item><item><title>Northwind Starter Kit Review: If you won&amp;rsquo;t respect the database, there will be pain</title><description>&lt;p&gt;This is a review of the &lt;a href="http://nsk.codeplex.com"&gt;Northwind Starter Kit project&lt;/a&gt;, this review revision &lt;a href="http://nsk.codeplex.com/SourceControl/changeset/changes/94815"&gt;94815&lt;/a&gt; from Dec 18 2011.&lt;/p&gt; &lt;p&gt;The database is usually a pretty important piece in your application, and it likes to remind you that it should be respected. If you don’t take care of that, it will make sure that there will be a lot of pain in your future. Case in point, let us look at this method:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Northwind-Starter-Kit-Review-Data-Access_60A8/image_10.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/Northwind-Starter-Kit-Review-Data-Access_60A8/image_thumb_4.png" width="559" height="263"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;It looks nice, it is certainly something that looks like a business service. So let us dig down and see how it works.&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Northwind-Starter-Kit-Review-Data-Access_60A8/image_12.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/Northwind-Starter-Kit-Review-Data-Access_60A8/image_thumb_5.png" width="847" height="459"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;It seems like a nice thing, the code is clear, and beside the bug where you get 100% discount if you buy enough and the dissonance between the comment and the code, fairly clear. And it seems that we have service logic and entity logic, which is always nice.&lt;/p&gt; &lt;p&gt;Except that this piece of code issues the following queries (let us assume a customer with 50 orders).&lt;/p&gt; &lt;p&gt;1 Query to load the customer, line 34 in this code. And now let us look at line 35… what is actually going on here:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Northwind-Starter-Kit-Review-Data-Access_60A8/image_14.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/Northwind-Starter-Kit-Review-Data-Access_60A8/image_thumb_6.png" width="450" height="185"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Okay, so we have an additional query for loading the customer’s orders. Let us dig deeper.&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Northwind-Starter-Kit-Review-Data-Access_60A8/image_16.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/Northwind-Starter-Kit-Review-Data-Access_60A8/image_thumb_7.png" width="336" height="138"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;And for each order, we have &lt;em&gt;another &lt;/em&gt;query for loading all of that order’s items. Does it gets worse?&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Northwind-Starter-Kit-Review-Data-Access_60A8/image_8.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/Northwind-Starter-Kit-Review-Data-Access_60A8/image_thumb_3.png" width="507" height="356"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Phew! I was worried here for a second. &lt;/p&gt; &lt;p&gt;But it turns out that we only have a Select N+2 here, where N is the number of orders that a customer has.&lt;/p&gt; &lt;p&gt;What do you want, calculating the discount for the order is &lt;em&gt;complicated&lt;/em&gt;, it is supposed to take a lot of time. Of course, the entire thing can be expressed in SQL as:&lt;/p&gt; &lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; 
  &lt;span class="kwrd"&gt;SUM&lt;/span&gt;((UnitPrice * Quantity) * (1 - Discount) Income
&lt;span class="kwrd"&gt;FROM&lt;/span&gt; OrderItems o
&lt;span class="kwrd"&gt;WHERE&lt;/span&gt; o.OrderID &lt;span class="kwrd"&gt;in&lt;/span&gt; (
  &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; Id &lt;span class="kwrd"&gt;FROM&lt;/span&gt; Orders
  &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; CustomerId = @CustomerId
)&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;But go ahead and try putting that optimization in. The architecture for the application will actively fight you on that.&lt;/p&gt;</description><link>http://ayende.com/blog/153059/northwind-starter-kit-review-if-you-wonrsquo-t-respect-the-database-there-will-be-pain?key=fb89b714-2ffb-4cf4-b33d-7a524d70a8ae</link><guid>http://ayende.com/blog/153059/northwind-starter-kit-review-if-you-wonrsquo-t-respect-the-database-there-will-be-pain?key=fb89b714-2ffb-4cf4-b33d-7a524d70a8ae</guid><pubDate>Wed, 18 Jan 2012 10:00:00 GMT</pubDate></item><item><title>Northwind Starter Kit Review: Refactoring to an actual read model</title><description>&lt;p&gt;This is a review of the &lt;a href="http://nsk.codeplex.com"&gt;Northwind Starter Kit project&lt;/a&gt;, this review revision &lt;a href="http://nsk.codeplex.com/SourceControl/changeset/changes/94815"&gt;94815&lt;/a&gt; from Dec 18 2011.&lt;/p&gt; &lt;p&gt;In my previous post, I talked about how the CatalogController.Product(id) action was completely ridiculous in the level of abstraction that it used to do its work and promised to show how to do the same work on an actual read model in a much simpler fashion. Here is the code.&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Northwind-Starter-Kit-Review_628/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/Northwind-Starter-Kit-Review_628/image_thumb.png" width="849" height="538"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&lt;img style="display: inline; float: right" align="right" src="http://psalmsinpurgatory.files.wordpress.com/2011/07/pitchfork-mob1.jpg"&gt;&lt;/p&gt; &lt;p&gt;There are several things that you might note about this code:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;It is all inline, so it is possible to analyze, optimize and figure out what the hell is going on easily.&lt;/li&gt; &lt;li&gt;It doesn’t got to the database to load data that it already has.&lt;/li&gt; &lt;li&gt;The code actually does something meaningful.&lt;/li&gt; &lt;li&gt;It only do one thing, and it does this elegantly.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;This is actually using a read model. By, you know, &lt;em&gt;reading&lt;/em&gt; from it, instead of abstracting it.&lt;/p&gt; &lt;p&gt;But there is a problem here, I hear you shout (already reaching for the pitchfork, at least let me finish this post).&lt;/p&gt; &lt;p&gt;Previously, we have hidden the logic of discontinued products and available products behind the following abstraction:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Northwind-Starter-Kit-Review_628/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/Northwind-Starter-Kit-Review_628/image_thumb_1.png" width="507" height="96"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Now we are embedding this inside the query itself, what happens if this logic changes? We would now need to go everywhere we used this logic and update it.&lt;/p&gt; &lt;p&gt;Well, yes. Except that there are two mitigating factors.&lt;/p&gt; &lt;ul&gt; &lt;li&gt;This nice abstraction is &lt;strong&gt;never used elsewhere&lt;/strong&gt;.&lt;/li&gt; &lt;li&gt;It is easy to create our own abstraction.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Here is an example on how to do this without adding additional layers of abstractions.&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Northwind-Starter-Kit-Review_628/image_6.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/Northwind-Starter-Kit-Review_628/image_thumb_2.png" width="672" height="197"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Which means that our action method now looks like this:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Northwind-Starter-Kit-Review_628/image_8.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/Northwind-Starter-Kit-Review_628/image_thumb_3.png" width="680" height="541"&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Simple, easy, performant, maintainable.&lt;/p&gt; &lt;p&gt;And it doesn’t make my head hurt or cause me to stay up until 4 AM feeling like &lt;a href="http://xkcd.com/386/"&gt;an XKCD item&lt;/a&gt;.&lt;/p&gt;</description><link>http://ayende.com/blog/153153/northwind-starter-kit-review-refactoring-to-an-actual-read-model?key=4cc1a59d-3842-4154-a6c7-c4f85525e4b2</link><guid>http://ayende.com/blog/153153/northwind-starter-kit-review-refactoring-to-an-actual-read-model?key=4cc1a59d-3842-4154-a6c7-c4f85525e4b2</guid><pubDate>Mon, 16 Jan 2012 10:00:00 GMT</pubDate></item><item><title>A meta post about negative code reviews</title><description>&lt;p&gt;A lot of people seems to have problems whenever I post a code review. The general theme of the comments is mostly along the lines of:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;You are an evil person and a cyber bully to actually do those sort of things and humiliate people.&lt;/li&gt; &lt;li&gt;You have something against the author of the personally, and you set out to avenge them.&lt;/li&gt; &lt;li&gt;There is no value in doing a negative code review.&lt;/li&gt; &lt;li&gt;You never do any good reviews, only bad ones.&lt;/li&gt; &lt;li&gt;You only tells us what is wrong, but not what is right.&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;There are a bunch of other stuff, but those are the main points.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;For point 1 &amp;amp; 2, I have the same answer:&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;I talk about the &lt;em&gt;code&lt;/em&gt;, not the person. I am actually very careful with my phrasing whenever I do this sort of a review. The code or the architecture is wrong, not the person. There is a difference, and a big one. &lt;/p&gt; &lt;p&gt;&lt;strong&gt;For point 3:&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Most of those code reviews are generated because someone asks me to do them. And given some of the responses to the posts, I feel that they serve a very good purpose. Here is one such comment. I redacted the project name, because it doesn’t really matter, but the point stands:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;I grew up on *** as it was my first layered application, almost 5 years ago and I personally believe that the effort ****** has put into this project during the years is simply amazing. The architecture reflect the most common architectural design patterns and represents almost the concepts expressed by Fowler and Evans. *** is not a project to teach you how to work with Northwind and it is not a project designed exclusively for Nhb. It is designed to show how a layered application should be architected in .NET and there is also a book wrote around this project.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;My professional opinioned, backed by over a decade of practical experience and work in the field tells me that the project in question is actually &lt;em&gt;not&lt;/em&gt; a good template for an application. And I feel that by pointing out exactly why, I am doing a service to the community.&lt;/p&gt; &lt;p&gt;Look, it is actually quite simple. The major reason that I do those negative code reviews is because I keep seeing the same types of mistakes repeated over and over again at customer sites. And the major reason is that those projects follow &lt;em&gt;best practices&lt;/em&gt; as they see it. The problem is that they usually ignore the context of those best practices, so it becomes a horrible mess.&lt;/p&gt; &lt;p&gt;What is worse, there is the issue of the non coding architect, when you have someone that doesn’t actually have responsibility for the output making decisions about how it is going to be built. And those things are actually hard to fight against, precisely because they are considered to be best practices. One of the reasons that I am pointing out the problems in those projects is to serve as a reference point for other people when they need a way to escape the over architecture.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;For point 4:&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;It takes something out of the ordinary to get me to actually post something to the blog. The barrier for a negative code review is how much is annoys me. The barrier for a positive code review is how much it impresses me. It is easier to annoy me to impress me, admittedly, but I quite frequently do good code reviews.&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://ayende.com/blog/3207/nservicebus-review"&gt;NServiceBus&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://ayende.com/blog/3607/reading-erlang-inspecting-couchdb"&gt;CouchDB&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://ayende.com/blog/92161/reviewing-signalrndash-part-i"&gt;SignalR&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href="http://ayende.com/blog/4564/reviewing-communitycourses-a-ravendb-application"&gt;Community.Courses&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;The problem is that most good code bases are actually fairly boring. That is pretty much the definition of a good codebase, of course &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://ayende.com/blog/Images/Windows-Live-Writer/A-meta-post-about-code-reviews_7E69/wlEmoticon-smile_2.png"&gt;, so there isn’t really that much to talk about.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;For point 5:&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;That usually come up when I do negative code reviews, “you only show the bad stuff, it doesn’t teach us how to do it right”. Well, that is pretty much the &lt;em&gt;point&lt;/em&gt; of a negative code review. To show the bad stuff so you would know how to avoid it. There are literally thousands of posts in this blog, and quite a few of them are actually devoted to discussions on how to do it right. I have very little inclination to repeat that advice again in every post.&lt;/p&gt; &lt;p&gt;Even a blog post must obey the single responsibility principle.&lt;/p&gt;</description><link>http://ayende.com/blog/153697/a-meta-post-about-negative-code-reviews?key=a725ecee-8002-45e6-8fdb-08901d9cc2b9</link><guid>http://ayende.com/blog/153697/a-meta-post-about-negative-code-reviews?key=a725ecee-8002-45e6-8fdb-08901d9cc2b9</guid><pubDate>Sun, 15 Jan 2012 10:00:00 GMT</pubDate></item><item><title>Northwind Starter Kit Review: Data Access review thoughts</title><description>&lt;p&gt;This is a review of the &lt;a href="http://nsk.codeplex.com"&gt;Northwind Starter Kit project&lt;/a&gt;, this review revision &lt;a href="http://nsk.codeplex.com/SourceControl/changeset/changes/94815"&gt;94815&lt;/a&gt; from Dec 18 2011.&lt;/p&gt; &lt;p&gt;In my last few posts, I have gone over the data access strategy used in NSK. I haven’t been impressed. In fact, I am somewhere between horrified, shocked and amused in the same way you feel when you see a clown slipping on a banana peel.&amp;nbsp; Why do I say that? Let us trace a single call from the front end all the way to the back.&lt;/p&gt; &lt;p&gt;The case in point, CatalogController.Product(id) action. This is something that should just display the product on the screen, so it should be fairly simple, right? Here is how it works when drawn as UML:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/6a03ddd05a08_46EE/image_11.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/6a03ddd05a08_46EE/image_thumb.png" width="1025" height="826"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;To simplify things, I decided to skip any method calls on the same objects (there are more than a few).&lt;/p&gt; &lt;p&gt;Let me show you how this looks like in actual code:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/6a03ddd05a08_46EE/image_6.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/6a03ddd05a08_46EE/image_thumb_2.png" width="647" height="124"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Digging deeper, we get:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/6a03ddd05a08_46EE/image_8.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/6a03ddd05a08_46EE/image_thumb_3.png" width="826" height="488"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;We will deal with the first method call to CatalogServices now, which looks like:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/6a03ddd05a08_46EE/image_10.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/6a03ddd05a08_46EE/image_thumb_4.png" width="670" height="68"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;I’ll skip going deeper, because this is just a layer of needless abstraction on top of Entity Framework and that is quite enough already.&lt;/p&gt; &lt;p&gt;Now let us deal with the second call to CatalogServices, which is actually more interesting:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/6a03ddd05a08_46EE/image_14.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/6a03ddd05a08_46EE/image_thumb_6.png" width="831" height="205"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Note the marked line? This is generating a query. This is interesting, because we have &lt;em&gt;already loaded the product. &lt;/em&gt;There is no way of optimizing that, of course, because the architecture doesn’t let you.&lt;/p&gt; &lt;p&gt;Now, you need all of this &lt;em&gt;just to show a single product on the screen&lt;/em&gt;. I mean, &lt;strong&gt;seriously.&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;You might have noticed some references to things like Read Model in the code. Which I find highly ironic. Read Models are about making the read side of things &lt;em&gt;simple&lt;/em&gt;, not drowning the code in abstraction on top of abstraction on top of abstraction.&lt;/p&gt; &lt;p&gt;In my next post, I’ll show a better way to handle this scenario. A way that is actually simpler and make use an of actual read model and not infinite levels of indirection.&lt;/p&gt;</description><link>http://ayende.com/blog/153058/northwind-starter-kit-review-data-access-review-thoughts?key=852c1fa5-de55-4460-b9a8-b4fbc2e2843a</link><guid>http://ayende.com/blog/153058/northwind-starter-kit-review-data-access-review-thoughts?key=852c1fa5-de55-4460-b9a8-b4fbc2e2843a</guid><pubDate>Fri, 13 Jan 2012 10:00:00 GMT</pubDate></item><item><title>Northwind Starter Kit Review: The parents have eaten sour grapes, and the children&amp;rsquo;s teeth are set on edge</title><description>&lt;p&gt;This is a review of the &lt;a href="http://nsk.codeplex.com"&gt;Northwind Starter Kit project&lt;/a&gt;, this review revision &lt;a href="http://nsk.codeplex.com/SourceControl/changeset/changes/94815"&gt;94815&lt;/a&gt; from Dec 18 2011.&lt;/p&gt; &lt;p&gt;In my previous posts, I focused mostly on the needlessness of the repositories implementation and why you want to avoid that (especially implementing it multiple times). In this post, I want to talk about other problems regarding the data access. In this case, the sudden urge to wash my hands that occurred when I saw this:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/The-parents-have-eaten-sour-grapes-and-t_43DD/image_14.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/The-parents-have-eaten-sour-grapes-and-t_43DD/image_thumb_6.png" width="857" height="319"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;I mean, you are &lt;em&gt;already using an OR/M&lt;/em&gt;. I don’t like the Repository implementation, but dropping down to SQL (and unparapetrized one at that) seems uncalled for.&lt;/p&gt; &lt;p&gt;By the way, the most logical reason for this to be done is to avoid mapping the Picture column to the category, since the OR/M in use here (EF) doesn’t support the notion of lazy properties.&lt;/p&gt; &lt;p&gt;Again, this is a problem when you are trying to use multiple OR/Ms, and that is neither required nor really useful.&lt;/p&gt; &lt;p&gt;Okay, enough about the low level data access details. On my next post I’ll deal with how those repositories are actually being used.&lt;/p&gt;</description><link>http://ayende.com/blog/153057/northwind-starter-kit-review-the-parents-have-eaten-sour-grapes-and-the-childrenrsquo-s-teeth-are-set-on-edge?key=92f4042c-ece0-4777-8256-64b6346caec1</link><guid>http://ayende.com/blog/153057/northwind-starter-kit-review-the-parents-have-eaten-sour-grapes-and-the-childrenrsquo-s-teeth-are-set-on-edge?key=92f4042c-ece0-4777-8256-64b6346caec1</guid><pubDate>Thu, 12 Jan 2012 10:00:00 GMT</pubDate></item><item><title>Northwind Starter Kit Review: Data Access and the essence of needless work, Part II</title><description>&lt;p&gt;This is a review of the &lt;a href="http://nsk.codeplex.com"&gt;Northwind Starter Kit project&lt;/a&gt;, this review revision &lt;a href="http://nsk.codeplex.com/SourceControl/changeset/changes/94815"&gt;94815&lt;/a&gt; from Dec 18 2011.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;strong&gt;Update: &lt;/strong&gt;Andrea, the project’s leader has posted a &lt;a href="http://blogs.ugidotnet.org/mrbrightside/archive/2012/01/10/no-nsk-is-not-about-northwind.aspx"&gt;reply to this series of posts&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Yes, this is another repositories are evil if you are using an OR/M post.&lt;/p&gt; &lt;p&gt; &lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;That is probably going to cause some reaction, so I am going to back this up with code from this NSK project. Let us talk about repositories, in particular. Let us see what we have here:  &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Northwind-Starter-Kit-Review-Data-Access_4221/image_12.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/Northwind-Starter-Kit-Review-Data-Access_4221/image_thumb_5.png" width="859" height="401"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Okaay…&lt;/p&gt; &lt;p&gt;Now here are a few problems that I have with this:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;There is no value gained by introducing this abstraction. You aren’t adding any capability what so ever.  &lt;li&gt;In fact, since all OR/Ms provide an abstraction that isn’t dependent on type, creating IRepository&amp;lt;T&amp;gt; and things like ICustomerRepository is just making things &lt;em&gt;more &lt;/em&gt;complicated.  &lt;li&gt;There are going to be changes in behavior between different repositories implementations that &lt;em&gt;will break your code&lt;/em&gt;.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Let us see what we actually have as a result. This is the Entity Framework POCO implementation:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Northwind-Starter-Kit-Review-Data-Access_4221/image_14.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/Northwind-Starter-Kit-Review-Data-Access_4221/image_thumb_6.png" width="608" height="283"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;You can probably guess how the rest of it is actually implemented. Yes, we have a LOT of code that is dedicated solely for this sort of forwarding operations.&lt;/p&gt; &lt;p&gt;And then we have the actual implementation of the delete:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Northwind-Starter-Kit-Review-Data-Access_4221/image_16.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/Northwind-Starter-Kit-Review-Data-Access_4221/image_thumb_7.png" width="339" height="235"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Just to remind you, here is the NHibernate implementation of the same function:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Northwind-Starter-Kit-Review-Data-Access_4221/image_18.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/Northwind-Starter-Kit-Review-Data-Access_4221/image_thumb_8.png" width="334" height="82"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Leaving aside the atrocious error handling code, the EF POCO version will do an immediate delete. The NHibernate version will wait for the transaction to be committed.&lt;/p&gt; &lt;p&gt;And don’t worry, I do remember the error handling. This is simply &lt;strong&gt;wrong&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;And then we have implementations such as this:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Northwind-Starter-Kit-Review-Data-Access_4221/image_20.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/Northwind-Starter-Kit-Review-Data-Access_4221/image_thumb_9.png" width="770" height="75"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;This is for the Entity Framework Code First implementation. There is a message here that is coming to me loud and clear. This code wants to be deleted. It is neglected and abused and doesn’t serve any purpose in life except gobble up pieces of valuable disk space that could be filled with the much more valuable result of&amp;nbsp; reading from/dev/random.&lt;/p&gt;</description><link>http://ayende.com/blog/153029/northwind-starter-kit-review-data-access-and-the-essence-of-needless-work-part-ii?key=01a97aa2-3ec0-4983-9c3f-b2dd91421e61</link><guid>http://ayende.com/blog/153029/northwind-starter-kit-review-data-access-and-the-essence-of-needless-work-part-ii?key=01a97aa2-3ec0-4983-9c3f-b2dd91421e61</guid><pubDate>Wed, 11 Jan 2012 10:00:00 GMT</pubDate></item><item><title>Northwind Starter Kit Review: Data Access and the essence of needless work, Part I</title><description>&lt;p&gt;This is a review of the &lt;a href="http://nsk.codeplex.com"&gt;Northwind Starter Kit project&lt;/a&gt;, this review revision &lt;a href="http://nsk.codeplex.com/SourceControl/changeset/changes/94815"&gt;94815&lt;/a&gt; from Dec 18 2011.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;strong&gt;Update: &lt;/strong&gt;Andrea, the project’s leader has posted a &lt;a href="http://blogs.ugidotnet.org/mrbrightside/archive/2012/01/10/no-nsk-is-not-about-northwind.aspx"&gt;reply to this series of posts&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;I like to start reviewing applications from their database interactions. That it usually low level enough to tell me what is actually going on, and it is critical to the app, so a lot of thought usually goes there.&lt;/p&gt; &lt;p&gt;In good applications, I have hard time finding the data access code, because it isn’t there. It is in the OR/M or the server client API (in the case of RavenDB). In some applications, if they work against legacy databases or without the benefit of OR/M or against a strange data source (such as a remote web service target) may need an explicit data layer, but most don’t.&lt;/p&gt; &lt;p&gt;NSK actually have 5 projects dedicated solely to data access. I find this.. scary.&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Northwind-Starter-Kit-Review_3B93/image_8.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/Northwind-Starter-Kit-Review_3B93/image_thumb_3.png" width="351" height="144"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Okay, let me start outlying things in simple terms. You &lt;strong&gt;don’t &lt;/strong&gt;want to do things with regards to data access the way NSK does them.&lt;/p&gt; &lt;p&gt;Let us explore all the ways it is broken. First, in terms of actual ROI. There is absolutely no reason to have multiple implementations with different OR/Ms. There is really not a shred of reason to do so. The OR/M is already doing the work of handling the abstraction from the database layer, and the only thing that you get is an inconsistent API, inability to actually important features and a whole lot &lt;em&gt;more work&lt;/em&gt; that doesn’t' get you anything.&lt;/p&gt; &lt;p&gt;Second, there are the abstractions used:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Northwind-Starter-Kit-Review_3B93/image_10.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/Northwind-Starter-Kit-Review_3B93/image_thumb_4.png" width="1095" height="360"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;I don’t like repositories, because they abstract important details about the way you work with the database. But let us give this the benefit of the doubt and look at the implementation. There is only one implementation of IRepository, which uses NHibernate.&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Northwind-Starter-Kit-Review_3B93/image_12.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/Northwind-Starter-Kit-Review_3B93/image_thumb_5.png" width="613" height="401"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;As you can see, this is pretty basic stuff. You can also see that there are several methods that aren’t implemented. That is because they make no sense to a data. The reason they are there is because IRepository&amp;lt;T&amp;gt; inherits from ICollection&amp;lt;T&amp;gt;. And the reason for &lt;em&gt;that&lt;/em&gt; is likely because of &lt;a href="http://martinfowler.com/eaaCatalog/repository.html"&gt;this&lt;/a&gt;:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;i&gt;Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.&lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;The fact that this is totally the wrong abstraction to use doesn’t enter to the design, it seems.&lt;/p&gt; &lt;p&gt;Note that we also violate the contract of &lt;a href="http://msdn.microsoft.com/en-us/library/bye7h94w.aspx"&gt;ICollection&amp;lt;T&amp;gt;.Remove&lt;/a&gt;:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;true if item was successfully removed from the &lt;a href="http://msdn.microsoft.com/en-us/library/92t2ye13.aspx"&gt;ICollection&amp;lt;T&amp;gt;&lt;/a&gt;; otherwise, false. This method also returns false if item is not found in the original &lt;a href="http://msdn.microsoft.com/en-us/library/92t2ye13.aspx"&gt;ICollection&amp;lt;T&amp;gt;&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;There are other reasons to dislike this sort of thing, but I’ll touch on that on my next post.&lt;/p&gt;</description><link>http://ayende.com/blog/153028/northwind-starter-kit-review-data-access-and-the-essence-of-needless-work-part-i?key=a3c79694-45fd-4efb-a2ee-8b2b4a3f11c6</link><guid>http://ayende.com/blog/153028/northwind-starter-kit-review-data-access-and-the-essence-of-needless-work-part-i?key=a3c79694-45fd-4efb-a2ee-8b2b4a3f11c6</guid><pubDate>Tue, 10 Jan 2012 10:00:00 GMT</pubDate></item></channel></rss>
