<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>Reviews</title>
        <link>http://ayende.com/Blog/category/524.aspx</link>
        <description>Reviews</description>
        <language>en-US</language>
        <copyright>Ayende Rahien</copyright>
        <managingEditor>Ayende@ayende.com</managingEditor>
        <generator>Subtext Version 2.0.0.0</generator>
        <item>
            <title>Responding to Effectus commentary</title>
            <link>http://ayende.com/Blog/archive/2010/01/08/responding-to-effectus-commentary.aspx</link>
            <description>&lt;p&gt;Jose was kind enough to &lt;a href="http://jfromaniello.blogspot.com/2009/12/reviewing-and-changing-effectus.html"&gt;post a review&lt;/a&gt; of my sample Effectus application. This post is a reply to that.&lt;/p&gt;  &lt;p&gt;The first thing that Jose didn’t like was the fact that I didn’t put an abstraction layer in front of NHibernate’s usage in my application. There are several reasons for that, the first, and simplest, is that I was trying to explain how to use NHibernate, and for that, I wanted to deal with the lowest common denominator, not show off a particular wrapper implementation. Showing NHibernate usage directly means that even if you are using another library with it, you would still be able to take advantage of the information that I give you.&lt;/p&gt;  &lt;p&gt;Second, and quite important, is that by using NHibernate directly I can take advantage of NHibernate features explicitly meant to support certain scenarios, but which are not likely to be expose when libraries wrap NHibernate. A good example of that is in Jose’s sample code, which make use of an ISession instead of IStatelessSession to load the data for the main screen. As explained in the article, the difference between the two is &lt;em&gt;important&lt;/em&gt;, and in the context where it is used it introduce what is effectively a memory leak into Jose’s implementation, as well as the chance for some really interesting errors down the road if the session will run into an error.&lt;/p&gt;  &lt;p&gt;Third, Jose bring up the following:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;This presenter is &lt;strong&gt;&lt;u&gt;GLUED&lt;/u&gt;&lt;/strong&gt; to NHibernate. And this means for instance that you can’t test it without NHibernate, and this means that you can’t change your persistence layer.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Yes, and that is intentional. That is the very &lt;em&gt;task&lt;/em&gt; that those presenters are &lt;em&gt;for&lt;/em&gt;. Trying to abstract that away just means that I put an additional layer of abstraction that does absolutely nothing. For that matter, let us look at Jose’s implementation using an abstraction layer compared to mine.&lt;/p&gt;  &lt;p&gt;Here is my implementation:&lt;/p&gt;  &lt;blockquote&gt;   &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; LoadPage(&lt;span class="kwrd"&gt;int&lt;/span&gt; page)
{
    &lt;span class="kwrd"&gt;using&lt;/span&gt; (var tx = StatelessSession.BeginTransaction())
    {
        var actions = StatelessSession.CreateCriteria&amp;lt;ToDoAction&amp;gt;()
            .SetFirstResult(page * PageSize)
            .SetMaxResults(PageSize)
            .List&amp;lt;ToDoAction&amp;gt;();

        var total = StatelessSession.CreateCriteria&amp;lt;ToDoAction&amp;gt;()
            .SetProjection(Projections.RowCount())
            .UniqueResult&amp;lt;&lt;span class="kwrd"&gt;int&lt;/span&gt;&amp;gt;();

        &lt;span class="kwrd"&gt;this&lt;/span&gt;.NumberOfPages.Value = total / PageSize + (total % PageSize == 0 ? 0 : 1);
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.Model = &lt;span class="kwrd"&gt;new&lt;/span&gt; Model
        {
            Actions = &lt;span class="kwrd"&gt;new&lt;/span&gt; ObservableCollection&amp;lt;ToDoAction&amp;gt;(actions),
            NumberOfPages = NumberOfPages,
            CurrentPage = CurrentPage + 1
        };
        &lt;span class="kwrd"&gt;this&lt;/span&gt;.CurrentPage.Value = page;

        tx.Commit();
    }
}&lt;/pre&gt;
  &lt;style type="text/css"&gt;&lt;![CDATA[
.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; }]]&gt;&lt;/style&gt;&lt;/blockquote&gt;

&lt;p&gt;And here is Jose’s:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; LoadPage(&lt;span class="kwrd"&gt;int&lt;/span&gt; page)
{
    var actions = _toDoActionsDao.RetrieveAll()
                                 .Skip(page * PageSize)
                                 .Take(PageSize).ToList();

    var total = _toDoActionsDao.RetrieveAll().Count();
    
    NumberOfPages.Value = total / PageSize 
                        + (total % PageSize == 0 ? 0 : 1);
    
    Model = &lt;span class="kwrd"&gt;new&lt;/span&gt; Model
    {
        Actions = &lt;span class="kwrd"&gt;new&lt;/span&gt; ObservableCollection&amp;lt;ToDoAction&amp;gt;(actions),
        NumberOfPages = NumberOfPages,
        CurrentPage = CurrentPage + 1
    };
    
    CurrentPage.Value = page;
}&lt;/pre&gt;
  &lt;style type="text/css"&gt;&lt;![CDATA[
.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; }]]&gt;&lt;/style&gt;&lt;/blockquote&gt;

&lt;p&gt;The code is &lt;em&gt;still&lt;/em&gt; doing the exact same thing, in other words, we haven’t moved any logic away, and most of the code is dealing with data access details. My approach for testing this is to make use of an in memory database, which result in a single test that make sure that the code works, instead of a series of tests that verifies that each piece work independently and then my single test. I find it much more effective in terms of time &amp;amp; effort.&lt;/p&gt;

&lt;p&gt;As for the idea of changing your persistence layer, forget about it. It isn’t going to happen in any real world application without a lot of effort, so you might as well save yourself the effort of working with the lowest common denominator and take full advantage of the framework. Just to note, when I ported the &lt;a href="http://NerdDinner.com"&gt;NerdDinner&lt;/a&gt; code to NHibernate (an application that make use of a &lt;em&gt;single&lt;/em&gt; table), I had to make major changes to the application.&lt;/p&gt;

&lt;p&gt;Jose didn’t like this method:&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;void&lt;/span&gt; OnSave()
{
    &lt;span class="kwrd"&gt;bool&lt;/span&gt; successfulSave;
    &lt;span class="kwrd"&gt;try&lt;/span&gt;
    {
        &lt;span class="kwrd"&gt;using&lt;/span&gt; (var tx = Session.BeginTransaction())
        {
            &lt;span class="rem"&gt;// this isn't strictly necessary, NHibernate will &lt;/span&gt;
            &lt;span class="rem"&gt;// automatically do it for us, but it make things&lt;/span&gt;
            &lt;span class="rem"&gt;// more explicit&lt;/span&gt;
            Session.Update(Model.Action);

            tx.Commit();
        }
        successfulSave = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
    }
    &lt;span class="kwrd"&gt;catch&lt;/span&gt; (StaleObjectStateException)
    {
        var mergeResult = Presenters.ShowDialog&amp;lt;MergeResult?&amp;gt;(&lt;span class="str"&gt;"Merge"&lt;/span&gt;, Model.Action);
        successfulSave = mergeResult != &lt;span class="kwrd"&gt;null&lt;/span&gt;;

        ReplaceSessionAfterError();
    }

    &lt;span class="rem"&gt;// we call ActionUpdated anyway, either we updated the value ourselves&lt;/span&gt;
    &lt;span class="rem"&gt;// or we encountered a concurrency conflict, in which case we _still_&lt;/span&gt;
    &lt;span class="rem"&gt;// want other parts of the application to update themselves with the values&lt;/span&gt;
    &lt;span class="rem"&gt;// from the db&lt;/span&gt;
    EventPublisher.Publish(&lt;span class="kwrd"&gt;new&lt;/span&gt; ActionUpdated
    {
        Id = Model.Action.Id
    }, &lt;span class="kwrd"&gt;this&lt;/span&gt;);

    &lt;span class="kwrd"&gt;if&lt;/span&gt; (successfulSave)
        View.Close();
}&lt;/pre&gt;
  &lt;style type="text/css"&gt;&lt;![CDATA[
.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; }]]&gt;&lt;/style&gt;&lt;/blockquote&gt;

&lt;p&gt;Because:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;ReplaceSessionAfterError, to much responsibility for a presenter. &lt;/li&gt;

  &lt;li&gt;Session/Transaction again. &lt;/li&gt;

  &lt;li&gt;There is a BUG, the publish mechanism work in sync with the rest of the code. This means… that this windows is not going to close until others have finished handling the event. For the given example, the Edit windows is not going to close until the main window finish to refresh the current page. &lt;/li&gt;

  &lt;li&gt;Too much logic for this method = hard to test.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I fully agree that this is a complex method, and Jose’s refactoring for that is an improvement indeed.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre class="csharpcode"&gt;[PersistenceConversation(ConversationEndMode = EndMode.End)]&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnSave()
{
    _toDoActionsDao.Update(Model.Action);

    EventPublisher.Enlist(&lt;span class="kwrd"&gt;new&lt;/span&gt; ActionUpdated
    {
        Id = Model.Action.Id
    }, &lt;span class="kwrd"&gt;this&lt;/span&gt;);

    View.Close();
}

&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; OnException(Exception exception)
{
    &lt;span class="kwrd"&gt;if&lt;/span&gt;(exception &lt;span class="kwrd"&gt;is&lt;/span&gt; StaleEntityException)
    {
        Presenters.ShowDialog&amp;lt;MergeResult?&amp;gt;(&lt;span class="str"&gt;"Merge"&lt;/span&gt;, Model.Action);

        EventPublisher.Enlist(&lt;span class="kwrd"&gt;new&lt;/span&gt; ActionUpdated
        {
            Id = Model.Action.Id
        }, &lt;span class="kwrd"&gt;this&lt;/span&gt;);

    }
}&lt;/pre&gt;
  &lt;style type="text/css"&gt;&lt;![CDATA[
.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; }]]&gt;&lt;/style&gt;&lt;/blockquote&gt;

&lt;p&gt;Jose has implemented the following changes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;I’ve defined a new convention, if a public method in the presenter throw an exception, the OnException method will be called. This is done by a castle interceptor, and this is the last line of defense for unhandled exceptions. &lt;/li&gt;

  &lt;li&gt;I’m using “StaleEntityException” rather than “StaleObjectStateException”, this is MY exception. This is easily done by a CpBT artifact. &lt;/li&gt;

  &lt;li&gt;I’m not calling “EventPublisher.Publish” anymore, this code use EventPublisher.Enlist. Here, I’ve split the “Publish” code in two different methods one for Enlist and other for Raise. The enlisted events will be raised right after the OnSave method is called and thus after the windows is closed. &lt;/li&gt;

  &lt;li&gt;Also, notice that here is the conversation per business transaction pattern with all its splendor. The two former methods are conversation participants, with EndMode equals to continue. This means that the NH Session will remain opened. The OnSave method has EndMode equals to End, this means that right after the method finished, CpBT internally will flush the Unit of Work and close it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is better than the original implementation, but I think it can be made better still. First, OnException as a generic method is a bad idea. For the simple reason that the exception logic for different method is different, I would probably define a [MethodName]Error(Exception e) convention instead, which would make it easier to separate the error logic for different methods.&lt;/p&gt;

&lt;p&gt;Again, I don’t find any usefulness in abstracting the underlying framework, I haven’t seen a single case where it was useful, but I have seen a lot of cases where it was hurting the team &amp;amp; the project.&lt;/p&gt;

&lt;p&gt;The idea about splitting the publication and raising is really nice, I agree.&lt;/p&gt;

&lt;p&gt;However, there is a problem in the code with regards to session handling in cases of error. There is a pretty good reason why I introduced the ReplaceSessionAfterError method. In general, I want to keep my session alive for the duration of the form, because I get a lot of benefits out of that. &lt;em&gt;But&lt;/em&gt;, if the session has run into an error, I need to replace it &lt;em&gt;and all the objects associated with it&lt;/em&gt;. Closing the session no matter what is going on is not a good solution, and you can’t really solve the problem in a generic way without calling back to the presenter that generated the error.&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/11271.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2010/01/08/responding-to-effectus-commentary.aspx</guid>
            <pubDate>Fri, 08 Jan 2010 10:00:00 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2010/01/08/responding-to-effectus-commentary.aspx#feedback</comments>
            <slash:comments>10</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/11271.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Git commits as code review?</title>
            <link>http://ayende.com/Blog/archive/2009/10/15/git-commits-as-code-review.aspx</link>
            <description>&lt;p&gt;I just had to go through a code base where I had a bunch of of comments. &lt;/p&gt;  &lt;p&gt;Instead of going with the usual route of just noting the changes that I think should be done, I decided to do something else. I fixed each individual change, and commit them individually. &lt;/p&gt;  &lt;p&gt;This is how it looks like, each commit is usually less than a single screen of changes (diff mode).&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/Gitcommitsascodereview_EB0A/image_2.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/Gitcommitsascodereview_EB0A/image_thumb.png" width="284" height="618" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;I wonder if it is something that I can apply more generally.&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/11147.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2009/10/15/git-commits-as-code-review.aspx</guid>
            <pubDate>Thu, 15 Oct 2009 04:40:00 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2009/10/15/git-commits-as-code-review.aspx#feedback</comments>
            <slash:comments>13</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/11147.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Reviewing NerdDinner: The Select N+1 pitfall</title>
            <link>http://ayende.com/Blog/archive/2009/07/30/reviewing-nerddinner-the-select-n1-pitfall.aspx</link>
            <description>&lt;p&gt;During my review of NerdDinner, I came across the following piece of code:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinnerTheSelectN1pitfall_27B/image_2.png"&gt;&lt;img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="121" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinnerTheSelectN1pitfall_27B/image_thumb.png" width="498" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;And I &lt;em&gt;knew&lt;/em&gt; that there is a Select N+1 problem here. This is quite similar to the problem that I described &lt;a href="http://ayende.com/Blog/archive/2009/06/08/analyzing-a-performance-problem-ndash-is-a-prisoner-dangerous.aspx"&gt;here&lt;/a&gt;. RSVPs is a lazily loaded collection. As such, calling Any() on it will result in a database query. &lt;/p&gt;  &lt;p&gt;Now the question was whatever or not it is used somewhere in a loop. ReSharper will help us figure that one out:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinnerTheSelectN1pitfall_27B/image_4.png"&gt;&lt;img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="111" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinnerTheSelectN1pitfall_27B/image_thumb_1.png" width="627" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;The first usage location is here:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinnerTheSelectN1pitfall_27B/image_6.png"&gt;&lt;img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="331" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinnerTheSelectN1pitfall_27B/image_thumb_2.png" width="531" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;And this certainly doesn’t look like it can cause a Select N+1, right. Just to be sure, I checked where it is called from the client side as well:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinnerTheSelectN1pitfall_27B/image_8.png"&gt;&lt;img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="72" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinnerTheSelectN1pitfall_27B/image_thumb_3.png" width="522" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;This looks all right, we will have a query, but it is only one per request.&lt;/p&gt;  &lt;p&gt;Great, now let us take a look at the &lt;em&gt;second&lt;/em&gt; usage. You can tell that this is going to be a problem just by the ascx suffix. The code is pretty simple:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinnerTheSelectN1pitfall_27B/image_10.png"&gt;&lt;img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="120" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinnerTheSelectN1pitfall_27B/image_thumb_4.png" width="580" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;I have a moral issue with the view generating a call to the database, but at least it isn’t being done in a loop.&lt;/p&gt;  &lt;p&gt;I am certain, however, that we are going to find this .ascx file in a grid, which &lt;em&gt;will &lt;/em&gt;cause a loop. This .ASCX file is being used in Details.aspx and is used like this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinnerTheSelectN1pitfall_27B/image_12.png"&gt;&lt;img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="48" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinnerTheSelectN1pitfall_27B/image_thumb_5.png" width="377" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;em&gt;However&lt;/em&gt;, it is &lt;em&gt;not&lt;/em&gt; actually being used in a loop.&lt;/p&gt;  &lt;p&gt;There is &lt;strong&gt;not&lt;/strong&gt; a Select N+1 issue, which renders this entire post moot. &lt;/p&gt;  &lt;p&gt;However, while it is not an &lt;em&gt;active&lt;/em&gt; Select N+1, it is a dormant one. It would be very easy to have a new requirements that &lt;em&gt;would &lt;/em&gt;make use of the RSVPStatus.ascx file in a loop and cause the issue.&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/11001.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2009/07/30/reviewing-nerddinner-the-select-n1-pitfall.aspx</guid>
            <pubDate>Thu, 30 Jul 2009 20:55:00 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2009/07/30/reviewing-nerddinner-the-select-n1-pitfall.aspx#feedback</comments>
            <slash:comments>17</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/11001.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Reviewing NerdDinner</title>
            <link>http://ayende.com/Blog/archive/2009/07/30/reviewing-nerddinner.aspx</link>
            <description>&lt;p&gt;&lt;a href="http://www.hanselman.com/blog/"&gt;Scott Hanselman&lt;/a&gt; has asked me to see if I can port NerdDinner to NHibernate, now that Linq for NHibernate has made RTM. I thought that I might as well take the time to look at the code and do a code review.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;I would like to say a few things before actually even starting to look at the code. I am &lt;em&gt;not&lt;/em&gt; going to review the code as a sample application, I am going to review it as if it was a standard production project. I am assuming that (remember, haven’t seen the code yet) there are things there that are done that way explicitly because they are easier to explain as a sample app than a more complex project would be.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The first thing that I opened was HomeController, which I am going to show you in full.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinner_14E15/image_6.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="190" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinner_14E15/image_thumb_2.png" width="348" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p /&gt;  &lt;p&gt;There are two things that I don’t like here. &lt;/p&gt;  &lt;p&gt;First, the empty actions (return View() is empty as far as I am concerned) resulting in what is, for all intents and purposes, an empty controller (one that contains empty actions). In other words, the only reason that this controller exists is because it is the way ASP.Net MVC want it to. A brief overview of the codebase show me that there are more than a few of method like that. &lt;/p&gt;  &lt;p&gt;I would deal with something like that completely on the view side, having a routing action that would check the view directly and just render the view, rather than creating empty actions and controllers.&lt;/p&gt;  &lt;p&gt;Second, [HandleErrorWithELMAH], such things should &lt;em&gt;not&lt;/em&gt; be on controllers (and that attribute appears on all controllers). It should be on a base controller, because right now, it is a violation of DRY, and it is easy to forget.&lt;/p&gt;  &lt;p&gt;Then there are the tests for HomeController, which are… less than useful, shall we say?&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinner_14E15/image_14.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="187" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinner_14E15/image_thumb_6.png" width="468" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Next, let us take a look at the following interface:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinner_14E15/image_8.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="205" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinner_14E15/image_thumb_3.png" width="597" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p /&gt;  &lt;p&gt;I have a &lt;em&gt;serious &lt;/em&gt;problem with the Save() method. I had to look at the implementation to figure out what it is doing. It &lt;em&gt;should&lt;/em&gt; be called FlushToDatabase, or SubmitChanges. Save() is a totally unexpected name for the method who implementation is:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinner_14E15/image_10.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="56" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinner_14E15/image_thumb_4.png" width="199" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;You are not, actually, saving anything.&lt;/p&gt;  &lt;p&gt;As an aside, I don’t like seeing things like this one:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinner_14E15/image_12.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="66" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinner_14E15/image_thumb_5.png" width="375" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Linq to SQL actually have a way of handling cascading deletes, and it should have been used.&lt;/p&gt;  &lt;p&gt;For that matter, coming back to the tests, there &lt;em&gt;aren’t&lt;/em&gt; any persistence tests. Since there are some complexity involved in the queries (geo located queries), I would have liked to see at least those queries being covered.&lt;/p&gt;  &lt;p&gt;I don’t want to rehash the poor man’s IoC story, but this is &lt;em&gt;really&lt;/em&gt; pissing me off:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinner_14E15/image_16.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="190" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinner_14E15/image_thumb_7.png" width="697" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;I mean, if you want to do poor man’s IoC, go ahead. But &lt;em&gt;please&lt;/em&gt; don’t create this bastard child. &lt;/p&gt;  &lt;p&gt;This is more about code style than hygiene, but I don’t like it:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinner_14E15/image_18.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="439" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNerdDinner_14E15/image_thumb_8.png" width="421" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p /&gt;  &lt;p /&gt;  &lt;p&gt;Those classes should be in separated files, they should not be in AccountController.&lt;/p&gt;  &lt;p&gt;Overall, I don’t see too many issues with the codebase. The only thing that pissed me off was the Mad Man IoC.&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/11005.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2009/07/30/reviewing-nerddinner.aspx</guid>
            <pubDate>Thu, 30 Jul 2009 20:19:00 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2009/07/30/reviewing-nerddinner.aspx#feedback</comments>
            <slash:comments>60</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/11005.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Review: C# in Depth</title>
            <link>http://ayende.com/Blog/archive/2009/05/12/review-c-in-depth.aspx</link>
            <description>&lt;p&gt;&lt;img style="display: inline; margin: 0px 0px 0px 30px" src="http://www.manning.com/skeet/skeet_cover150.jpg" align="right" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.manning.com/skeet/"&gt;C# in Depth&lt;/a&gt; has a very different focus from most “Learn language X” books. Starting from the premise that you are already am familiar with the basic language syntax (for 1.0, or maybe you are a Java or C++ programmer), it focus entirely on the new additions to the language and platform.&lt;/p&gt;  &lt;p&gt;Its stated goal is to take C# 1.0 developers and give them all the changes that happened to the language in the C# 2.0 and 3.0 versions. And it most certainly deserves the “in Depth” part of the name.&lt;/p&gt;  &lt;p&gt;I consider myself a fairly proficient developer, and I believe that I have adequate knowledge in both C# 2.0 and 3.0, but I still found myself learning new things. More to the point, as someone who &lt;em&gt;do&lt;/em&gt; know much of the material in the book, I was quite impress with the quality of the material, the depth of the discussion and the &lt;em&gt;level in which it is being presented&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;I think that Jon has managed to capture a lot of the complexities of the language in a way that is approachable, easy to understand and complete.&lt;/p&gt;  &lt;p&gt;I have been recommending that book for clients ever since I read it, and only recently realized that I have never actually posted about it. I kept &lt;em&gt;intending &lt;/em&gt;to, but that doesn’t seem to put words on the blog, unfortunately (otherwise I would blog even &lt;em&gt;more)&lt;/em&gt;. &lt;/p&gt;  &lt;p&gt;The complexity of the C# is a personal worry of mine, mostly because I see how hard it is for people to bridge the gap when moving to the newer versions of the language and having to face the explosion of possibilities. I think that this book is a big step in closing that gap.&lt;/p&gt;  &lt;p&gt;Perhaps the best compliment that I can give to the book is that I fully intend to use the &lt;a href="http://msmvps.com/blogs/jon_skeet/archive/2009/04/16/rfc-c-in-depth-2nd-edition-proposed-changes-and-additions.aspx"&gt;2nd edition&lt;/a&gt; as the text to read to get into C# 4.0 when it is out. No reason not to let Jon &lt;a href="http://www.askjonskeet.com/"&gt;do all the hard work&lt;/a&gt; :-) &lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/10917.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2009/05/12/review-c-in-depth.aspx</guid>
            <pubDate>Tue, 12 May 2009 10:10:00 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2009/05/12/review-c-in-depth.aspx#feedback</comments>
            <slash:comments>9</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/10917.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Ode to ReSharper</title>
            <link>http://ayende.com/Blog/archive/2009/04/22/ode-to-resharper.aspx</link>
            <description>&lt;p&gt;I am using R# 4.5, and I have to say, for  a release that is supposedly all about perf, they managed to squeeze in some really nice new smarts:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/OdetoReSharper_12146/image_2.png"&gt;&lt;img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="212" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/OdetoReSharper_12146/image_thumb.png" width="705" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Figuring out all the implementations that use or do not use parameters.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/OdetoReSharper_12146/image_4.png"&gt;&lt;img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="52" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/OdetoReSharper_12146/image_thumb_1.png" width="726" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Killing off BDD :-)&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/10890.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2009/04/22/ode-to-resharper.aspx</guid>
            <pubDate>Wed, 22 Apr 2009 17:34:48 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2009/04/22/ode-to-resharper.aspx#feedback</comments>
            <slash:comments>7</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/10890.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Reviewing NChord: A codebase that makes me twitch</title>
            <link>http://ayende.com/Blog/archive/2009/04/07/reviewing-nchord-a-codebase-that-makes-me-twitch.aspx</link>
            <description>&lt;p&gt;I was referred to &lt;a href="http://nchord.sourceforge.net/"&gt;NChord&lt;/a&gt; by one of the comments, and it looked very interesting on the surface, so I downloaded the code and took a peek. &lt;/p&gt; &lt;p&gt;It is not typically my style to criticize code openly, especially after a very brief glance, but I thought that it  might be a good idea to point some of the things that made me decide that the codebase isn't worth the time to pursue in details.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Single Responsibility Principle doesn't apply to the file level&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNChordAcodebasethatmakesmetwitc_4200/image_4.png"&gt;&lt;img height="199" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNChordAcodebasethatmakesmetwitc_4200/image_thumb_1.png" width="355" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;What you see here are no less than &lt;em&gt;11&lt;/em&gt;(!) files that are all parts of the same class. That is.. bad, from a whole lot of reasons, not least of which is that you have to jump through a lot of files to understand what is going on, and that ChordInstance is at least a demi-god, rapidly moving upward.&lt;/p&gt; &lt;p&gt;Then we have things like this:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNChordAcodebasethatmakesmetwitc_4200/image_6.png"&gt;&lt;img height="120" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNChordAcodebasethatmakesmetwitc_4200/image_thumb_2.png" width="639" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Now, this is a matter of taste more than anything else, but it strongly hints that there is lack of threading experience going on here. Indeed, a brief look at the code shows numerous potential race conditions. &lt;/p&gt; &lt;p&gt;Code like this &lt;em&gt;really&lt;/em&gt; make me twitch:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNChordAcodebasethatmakesmetwitc_4200/image_8.png"&gt;&lt;img height="196" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ReviewingNChordAcodebasethatmakesmetwitc_4200/image_thumb_3.png" width="482" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;All of that trend toward making me doubt the maturity and stability of the codebase.&lt;/p&gt; &lt;p&gt;In short, after a very brief scan, I find numerous issues that I really didn't like in the code base. And I am not willing to put up the effort to try to make headway into this with so many early warning signs already in place.&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/10846.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2009/04/07/reviewing-nchord-a-codebase-that-makes-me-twitch.aspx</guid>
            <pubDate>Tue, 07 Apr 2009 01:41:09 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2009/04/07/reviewing-nchord-a-codebase-that-makes-me-twitch.aspx#feedback</comments>
            <slash:comments>16</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/10846.aspx</wfw:commentRss>
        </item>
        <item>
            <title>First Steps with Post Sharp</title>
            <link>http://ayende.com/Blog/archive/2008/10/09/first-steps-with-post-sharp.aspx</link>
            <description>&lt;p&gt;&lt;a href="http://postsharp.org/"&gt;PostSharp&lt;/a&gt; is an AOP framework that works using byte code weaving. That is, it re-writes your IL to add behaviors to it. From my point of view, it is like having the cake (interception, byte code weaving) and eating it (I haven't even &lt;em&gt;looked&lt;/em&gt; at the PostSharp source code, just used the binary release).&lt;/p&gt; &lt;p&gt;My initial spike with it went very well. Here it is:&lt;/p&gt; &lt;blockquote&gt;&lt;pre&gt;[Serializable]
&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Logger : OnFieldAccessAspect
{
    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; OnGetValue(FieldAccessEventArgs eventArgs)
    {
        Console.WriteLine(eventArgs.InstanceTag);
        Console.WriteLine("&lt;span style="color: #8b0000"&gt;get value&lt;/span&gt;");
        &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;.OnGetValue(eventArgs);
    }

    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; InstanceTagRequest GetInstanceTagRequest()
    {
        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; InstanceTagRequest("&lt;span style="color: #8b0000"&gt;logger&lt;/span&gt;", &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Guid("&lt;span style="color: #8b0000"&gt;4f8a4963-82bf-4d32-8775-42cc3cd119bd&lt;/span&gt;"), &lt;span style="color: #0000ff"&gt;false&lt;/span&gt;);
    }

    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; OnSetValue(FieldAccessEventArgs eventArgs)
    {
        &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; i = (&lt;span style="color: #0000ff"&gt;int&lt;/span&gt;?)eventArgs.InstanceTag ?? 0;
        eventArgs.InstanceTag = i + 1;
        Console.WriteLine("&lt;span style="color: #8b0000"&gt;set value&lt;/span&gt;");
        &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;.OnSetValue(eventArgs);
    }
}&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;This is an aspect that run on each field access. It is not really useful, but it helps to show how things works. A couple of things that are I think are insanely useful:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Aspects are instantiated at compile time, allowed time to set themselves up, then serialized to an resource in the assembly. At runtime, they are de-serialized and ready to run. The possibilities this give you are amazing.&lt;/li&gt;
&lt;li&gt;InstanceTag is a way to keep additional data &lt;em&gt;per aspect&lt;/em&gt;.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Now, let us assume that I want to add the aspect to this code:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;[Logger]
&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Customer
{
    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Name { &lt;span style="color: #0000ff"&gt;get&lt;/span&gt;; &lt;span style="color: #0000ff"&gt;set&lt;/span&gt;; }
}&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;Note, there &lt;em&gt;is&lt;/em&gt; no field. (Well, there is, it is generated by the compiler). Now we compile and run the PostSharp post compile step. With that, we can now investigate what is going on.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/FirstStepswithPostSharp_1175E/image_2.png"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="345" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/FirstStepswithPostSharp_1175E/image_thumb.png" width="860" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;As you can see, we are deserializing the attribute and storing it in a field that we can now access. Let us check the Customer implementation now:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/FirstStepswithPostSharp_1175E/image_6.png"&gt;&lt;img height="287" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/FirstStepswithPostSharp_1175E/image_thumb_2.png" width="391" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;We have the logger field, which is used for something, but we also have the ~get~&amp;lt;Name&amp;gt;k__Backingfield and ~set~&amp;lt;Name&amp;gt;k__BackingField. &amp;lt;Name&amp;gt;k__BackingField (and I would love to hear the story behind that) is the compiler generated field that was created for us. The ~get~... and ~set~ are generated by PostSharp. Before we look at them, we will look at the implementation of Name.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/FirstStepswithPostSharp_1175E/image_10.png"&gt;&lt;img height="189" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/FirstStepswithPostSharp_1175E/image_thumb_4.png" width="264" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Where it used to call the field directly, now it is doing this via a method call. And now we can look at those method calls.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/FirstStepswithPostSharp_1175E/image_12.png"&gt;&lt;img height="303" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/FirstStepswithPostSharp_1175E/image_thumb_5.png" width="890" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;There is a lot going on here. We create a new field access event arg, call the aspect method, and return the value. Note that the &lt;em&gt;state&lt;/em&gt; (instance tag) is stored in the object as well, for each field access.&lt;/p&gt;
&lt;p&gt;It looks &lt;em&gt;very &lt;/em&gt;well done.&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/10551.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2008/10/09/first-steps-with-post-sharp.aspx</guid>
            <pubDate>Thu, 09 Oct 2008 17:52:25 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2008/10/09/first-steps-with-post-sharp.aspx#feedback</comments>
            <slash:comments>10</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/10551.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Reading Eralng: CouchDB Streams</title>
            <link>http://ayende.com/Blog/archive/2008/10/06/reading-eralng-couchdb-streams.aspx</link>
            <description>&lt;p&gt;A question to my dear readers, do you find this series valuable? Do you consider it interesting? It is a significant departure from my usual set of topics.&lt;/p&gt;
&lt;p&gt;In my &lt;a href="http://ayende.com/Blog/archive/2008/10/04/erlang-reading-couchdb-digging-down-to-disk.aspx"&gt;recent post&lt;/a&gt; I wondered about the concept of summary streams, and how they related to the way CouchDB works. I couldn't figure out what they were doing. As it turn out, there is a good documentation for them in &lt;a href="http://damienkatz.net/2005/04/couchdb-archite.html"&gt;this post&lt;/a&gt;. There were two things that mislead me. The first was the notion of summary. I think that this is a misnomer, because this is the only place in CouchDB where that term is used. It is not a summary, it is the actual document. As a matter of fact, I think that it is a term that was carried over from Notes.&lt;/p&gt;
&lt;p&gt;The second misleading clue was stream. I am used to think about streams in the classic sense, as a way to access a stream of bytes. The CouchDB notion of stream is quite different. It is a way to optimize disk access, it seems. I wondered about that, because the nature of CouchDB append only file seems certain to cause a lot of issues with regards to internal fragmentation in the file (which would require a lot of seeks, which are slow).&lt;/p&gt;
&lt;p&gt;Let me see if I can deconstruct what is going on in couch_stream, first, we have the structure declaration:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810060047.jpg" width="205" height="229" alt="200810060047.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;This seems to be pretty reasonable. The write_stream is defining a reserved space in the file, note the next_alloc field. It looks like we are allocating memory (or disk space). Should be interesting. The stream structure just hold the process and the file description, and isn't really interesting.&lt;/p&gt;
&lt;p&gt;The initialization of a stream is interesting in itself:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810060049.jpg" width="308" height="117" alt="200810060049.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Here we just create a new write stream and copy the initialization values to the state. There seems to be a 1 to 1 mapping between a stream and an erlang process. Let us examine how we write the data. First, we have the stop condition of running out of data to write:&lt;/p&gt;
&lt;p&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810060052.jpg" width="200" height="40" alt="200810060052.jpg" /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;You can learn a lot about the a function in erlang just from its declaration. In this case, &amp;lt;&amp;lt;&amp;gt;&amp;gt; means a binary with no items in it, hence, we run out of things to write.&lt;/p&gt;
&lt;p&gt;And now we come to the function clause that deals with the issue of running out of room to write it.&lt;br /&gt;
&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810060054.jpg" width="804" height="393" alt="200810060054.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;The first part of the function is using variable binding to extract the values out of the stream. It goes against the grain, I know, to see CurrentPos being "set" when it is on the right side of the assignment, but that how it works. (Well, actually it isn't being set, it is being matched, or bound, but that is another issue).&lt;/p&gt;
&lt;p&gt;Next we find what is the next size that we have to allocate, and ask the file to expand. I don't think that I have seen this before, let us take a look:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810060059.jpg" width="456" height="56" alt="200810060059.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;We first get a the end of the file, and then we write a single byte at the end of the file plus the expansion value. In other words, we increase the length of the file by however big Num is. For .NET, this is the equivalent of the SetLength call, and it is important to create continuos files, with as little fragmentation as possible.&lt;/p&gt;
&lt;p&gt;Going back to write_data, we have this line:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810060111.jpg" width="755" height="20" alt="200810060111.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;The syntax isn't really nice, in my opinion, but what we have here is basically: Write to the file Fd at position CurrentPos the value of NewPos (with pack to FILE_POINTER_BITS and then the value of NewSize (packed to STREAM_OFFSET_BITS).&lt;/p&gt;
&lt;p&gt;It is important to note &lt;em&gt;where&lt;/em&gt; this is written. Go and take a look at the case statement in which this expression is. First, we setup enough size for the data we want to write &lt;em&gt;and for the next allocation&lt;/em&gt;. When we come to the end of the current chunk, we create a new one (by expanding the file) and then write the address of the new chunk into the end of the chunk, following that by a move to the new chunk.&lt;/p&gt;
&lt;p&gt;The last part of write_data is very simple:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810060122.jpg" width="711" height="174" alt="200810060122.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;We start by figuring out how many bytes we have to write, and then split the binary data by that. We write what we can to the file, and then recursively call ourself (which will either exit (nothing to write) or create a new chunk of the file and continue writing it.&lt;/p&gt;
&lt;p&gt;Elegant, short and to the point. It take more time to describe how it works than it is to write the code. The code for reading is just as sweet:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810060125.jpg" width="601" height="394" alt="200810060125.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;The stop condition is when we have no more data to read. The second clause is when we have run out of data to read in the current stream, and we need to read about the next one. Again, erlang's pattern matching is useful here, because it allow to easily unpack the values from the file to in memory representation.&lt;/p&gt;
&lt;p&gt;The last clause is where things are actually happening. We select the number of bytes to read, offset is a really misleading term here, it is not the offset from the beginning of the chunk (like most of us would think), it is the amount of bytes remaining in the current chunk.&lt;/p&gt;
&lt;p&gt;We read the data to memory, update the Sp (stream position?) and then call the function that we were passed, to find out if we should read more or stop.&lt;/p&gt;
&lt;p&gt;Now, how are those streams used?&lt;/p&gt;
&lt;p&gt;From reading the code, it looks like there are two streams used in CouchDB. The first is the document stream (called the summary_stream). And the second (actually, the seconds) is a stream for all the binary attachments for a document (a stream per a set of document attachments).&lt;/p&gt;
&lt;p&gt;And with this, we conclude the reading of CouchDB persistence architecture. Next topic, views, and how they are used.&lt;/p&gt;
&lt;img src="http://ayende.com/Blog/aggbug/10546.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2008/10/06/reading-eralng-couchdb-streams.aspx</guid>
            <pubDate>Sun, 05 Oct 2008 23:37:58 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2008/10/06/reading-eralng-couchdb-streams.aspx#feedback</comments>
            <slash:comments>7</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/10546.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Erlang Reading: CouchDB - Digging Down to Disk</title>
            <link>http://ayende.com/Blog/archive/2008/10/04/erlang-reading-couchdb-digging-down-to-disk.aspx</link>
            <description>&lt;p&gt;Jan has &lt;a href="http://ayende.com/Blog/archive/2008/10/04/reading-erlang-couchdb-from-rest-to-disk-in-a.aspx#26253"&gt;corrected&lt;/a&gt; a misconception that I had &lt;a href="http://ayende.com/Blog/archive/2008/10/04/reading-erlang-couchdb-from-rest-to-disk-in-a.aspx"&gt;here&lt;/a&gt;, where I assumed that PUT was create and POST was update. Apparently this is not quite correct. A PUT request will update/create a new document with a user supplied name, while a POST request will create a new document with a server generated name.&lt;/p&gt;
&lt;p&gt;That narrows down my search for "create new document" code path again. Here is the method in couch_httpd_db that handles a POST request on a document.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041143.jpg" width="480" height="376" alt="200810041143.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;It parse the form, get the revision of the document, and then it calls to open_doc_revs, which we haven't explored so far. I feel confident that I understand what &lt;em&gt;this&lt;/em&gt; is doing, however:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041145.jpg" width="440" height="53" alt="200810041145.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;I'll not show the open_doc_revs_int, because it is too big, but it contains some references that so far I haven't encountered. Specifically, couch_key_tree, which I don't think that I seen before, and to get_full_doc_infos, which looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041150.jpg" width="432" height="39" alt="200810041150.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Oh, now we are on a more familiar territory. Lookup performs a search on a binary tree, and we have gone over it in &lt;a href="http://ayende.com/Blog/archive/2008/09/24/more-couchdb-reading-btreelookup.aspx"&gt;depth&lt;/a&gt; before. However, we can now see that the we pass to it a fulldocinfo_by_id_tree... I don't think we have explored how CouchDB make use of the btree, so let us head to the db structure and see what else we have there.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041153.jpg" width="316" height="432" alt="200810041153.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Here is what I know about this structure at the moment. db_header container the data that is actually written to the file, while db is the in memory structure. Not sure what write_version is all about, update_seq looks like the the internal sequence number for CouchDB. I don't think that I have even seen the concept of stream before, but it is there, and look like most stream implementations that I am already familiar with.&lt;/p&gt;
&lt;p&gt;get_state on that returns a {Position, BytesRemaining}, since I don't understand how this is used at the moment, I don't understand why this is important. fulldocsinfo_by_id_btree_state contains the root of the btree, and the same holds for docinfo_by_seq_btree_state, I assume that local_docs_btree_state is also the same.&lt;/p&gt;
&lt;p&gt;purge_seq is a counter for the last purge (physical delete), and it is used in conjunction with the views in order to ensure that there are no purged documents in the view. purged_docs keeps track of the documents that were last purged.&lt;/p&gt;
&lt;p&gt;db, the runtime structure, is considerably more interesting. It took me a while to figure out where it is created, but I finally found the init_db function in couch_db_updater:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041217.jpg" width="650" height="549" alt="200810041217.jpg" /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;The first part is to open the summary_state stream, still not sure what this is about, though. We then define a comparison function for use when opening the fulldocsinfo btree, and we pass several additional functions when we create the btree. Reduce is usually used when we compact the tree, and to get information about the btree (such as count of documents). The join and split also prepare the data to be written to disk in a consistent fashion.&lt;/p&gt;
&lt;p&gt;I don't like the name join/split. The internal names, assemble and extract seems to be much more accurate.&lt;/p&gt;
&lt;p&gt;Finally, we get to the actual creation of the db structure itself. An interesting thing to note is that only the update_pid is filled. Since CouchDB implements the many readers / single writer, I assume that this is how we ensure the single reader, because only a single process ever handle writes to the DB. I am assuming for now that main_pid is for readers, and compactor_pid if for compacting (obviously). I'll track them next.&lt;/p&gt;
&lt;p&gt;Well, that took some doing, the main_pid is set in the couch_db_updater:init (the same function that calls the init_db function):&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;
&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041256.jpg" width="480" height="262" alt="200810041256.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;I had hard time tracking this because I couldn't figure out what who was calling couch_db_updater:init (and what is the MainPid). Usually, in gen_server processes, there is a start_link function that you call, but in this case, there wasn't. Some digging revealed that the couch_db process is the one that actually call start_link on the couch_db_updater. I wonder if this is a common pattern in erlang, because it sure did caught me by surprise.&lt;/p&gt;
&lt;p&gt;So main_pid is the couch_db process, and update_pid is the couch_db_updater. It actually goes a lot further than that. couch_db_updater doesn't actually have a public interface. It looks like couch_db is the one that exposes the interface, and send synchronous messages to the couch_db_updater process:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041301.jpg" width="659" height="93" alt="200810041301.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;That is the way in which CouchDB ensures that we have only a single write, I presume. Compaction is handled in couch_db_updater as well, the implementation is interesting:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041313.jpg" width="466" height="205" alt="200810041313.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;We create a new process and return before we finish compacting. It is interesting because it is the first example of explicit concurrency that I saw. Let us dig a bit better into start_copy_compact_int, which is pretty straight forward:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041315.jpg" width="544" height="318" alt="200810041315.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;This just create a new file, init a database and call_compact_docs, finishing by notifying the updater that it finished compacting. copy_compact_docs is interesting in itself:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041320.jpg" width="767" height="360" alt="200810041320.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;We start by defining the EnumBySeqFun, which batches documents to write to disk until should_flush returns true. should_flush is funny, it check memory thresholds and flush to disk whenever there is about 10 MB of data ready to be flushed.&lt;/p&gt;
&lt;p&gt;The usage of foldl here is a good reason to go back and examine it in more details:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041328.jpg" width="243" height="39" alt="200810041328.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;And fold is defined as:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041329.jpg" width="738" height="57" alt="200810041329.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;So we have this stream_node, whatever that is, let us take an additional look.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041332.jpg" width="616" height="136" alt="200810041332.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;We are already familiar with get_node(), but adjust_dir and stream_kp_node and stream_kv_node are new. The first is easy:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041334.jpg" width="187" height="75" alt="200810041334.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Let us explore stream_kv_node, which is likely to be easier than stream_kp_node.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041337.jpg" width="610" height="354" alt="200810041337.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;This is slightly complex. We start by defining the drop off point (smaller / greater from the current key). The important bit is in the last function, the call to our function and the recursion back into the function. As a reminder, here is the function that we pass:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041340.jpg" width="663" height="171" alt="200810041340.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;I hope that this make it clear how this works. We simply stream all the items to the function, and it copies it. Note that an important subtlety is that we have several btree over the same data (we will touch down in a bit) and in this case we are only copying the items that are greater than the update_seq in the current DB. Still not sure what this update_seq is all about. We will go all the way back to copy_compact_docs_int's last line, where it notify the updater that it finished the current compaction. This message arrive to this method:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041348.jpg" width="616" height="616" alt="200810041348.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;This looks complex, but it really isn't. It is simply opening the new database, and checking if the current update_seq equal to the latest in the new database. If it isn't, we restart the process. If it is, then we copy the local documents (not sure why they get special treatment, and it looks like it is expected to have very few of them), move the files and move on with our lives.&lt;/p&gt;
&lt;p&gt;Now, it looks like update_seq is updated whenever someone make a change to the database, but let us verify this, shall we?&lt;/p&gt;
&lt;p&gt;Looking at couch_db_updater:update_docs_int, we can see that the update_seq is updated for each new document that is modified (see merge_rev_trees).&lt;/p&gt;
&lt;p&gt;Okay, that was interesting. But I still don't know how we save a document to disk. Let us go back to couch_db:update_docs, and see what is going on here. This is pretty complex, so we will break it apart to discrete pieces.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041409.jpg" width="722" height="260" alt="200810041409.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;We start by generating a new revision for the documents. Note that in the case local revisions, we just increment the revision, if it is a standard document, we generate a random revision number. I think that this is done in order to support farm wide revisions, so if I update document #1 in server A and in server B, I get two different revisions, which would be detected as conflicts.&lt;/p&gt;
&lt;p&gt;We extract all the new revisions, group all the documents by id and extract all the ids. So far, so good. Let us see the rest of the function:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041418.jpg" width="819" height="296" alt="200810041418.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;We get the current existing documents, and then we merge the existing with the new bucket. That requires some explanation.&lt;/p&gt;
&lt;p&gt;The first function clause uses list comprehensions in order to ensure that if we couldn't find a document in the DB, we didn't specify a previous version. The second is more complex and require us to understand about key trees. CouchDB defines them as:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041423.jpg" width="425" height="92" alt="200810041423.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Based on that and the dict:from_list arguments, we can deduct what the structure of a revision is. It should be noted that it looks like there is an expectation that the number of revisions wouldn't be too big. This make sense, CouchDB does keep previous versions, but it make no guarantees about their life spans. Also, we should note that we have both revs and rev_tree, I am not quite sure why.&lt;/p&gt;
&lt;p&gt;The last line in the zipwith function is prepare_doc_for_new_edit, which is called for each document, let us take a look at it.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041429.jpg" width="733" height="479" alt="200810041429.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;This is an example of how condense functional code can get. Let us see what it does:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Get the new revisions and all the previous revisions&lt;/li&gt;

  &lt;li&gt;If the previous revisions has a value, it perform a lookup based on the revision to the revision tree, to get the revision information. (Which answers the question of why we need both revs and rev_tree. revs is an ordered list of revision keys. rev_tree is apparently the metadata).&lt;/li&gt;

  &lt;li&gt;Now, the LeafRevsDict contains only the most recent one, so failing to find it in the dictionary means that we trying to update a non current version, so we error.&lt;/li&gt;

  &lt;li&gt;I am not sure what a stub is, but the rest of it seems pretty simple.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The last part is interesting, however, we check that we aren't trying to create a new document with the same id as existing one (although we allow it if that document is deleted).&lt;/p&gt;
&lt;p&gt;After the call to zipwith(), we have a call to doc_flush_binaries, which we totally ignored so far. It flushes all the documents to disk, it is not really interesting, it is dealing with writing the attachments to disk. I am not quite sure what is going on (it is complex), mostly because I don't follow to &lt;em&gt;which&lt;/em&gt; file it is writing. Or, to be rather more exact, I am not following how the attachment can be written to a different file, which is what the code seems to imply.&lt;/p&gt;
&lt;p&gt;Anyway, the code there is pretty clear about what is going on, we append to the current file (except if we write to a different file, again, not following that) and update the in memory structure of the document to point to the range of data that each attachment contains.&lt;/p&gt;
&lt;p&gt;Let us look at the last part of the couch_db:update_docs:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041452.jpg" width="751" height="242" alt="200810041452.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;And is looks like we have hit the place where it is actually happening. We call to the couch_db_updater in order to do the actual update, and we make be asked to retry (this will require more study), in which case we do try.&lt;/p&gt;
&lt;p&gt;Let us look at update_docs at the couch_db_updater.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041456.jpg" width="471" height="205" alt="200810041456.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Sigh, I can feel it in my waters, update_docs_int is going to be complex... once more, we will try to divide and conquer.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041459.jpg" width="616" height="345" alt="200810041459.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;We start by extracting variable from the Db, then we split the list based on whatever this is local or not. NonRep documents (local) are not replicated, have only a single version and are expected to have very few of them. I still don't know what is the use case for those, however. It looks like DocsList is a list of lists of docs, probably this is the buckets that we had to deal with earlier.&lt;/p&gt;
&lt;p&gt;We finish the snipper by extracting the ids from the documents, what comes next?&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041504.jpg" width="708" height="275" alt="200810041504.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;We lookup the existing documents, and then we merge them into a file info (note that we create a new full_doc_info with just the id if this is a new file). We then create the new doc infos by calling merge_rev_trees. We will ignore the implementation for now.&lt;/p&gt;
&lt;p&gt;Finally, we gather all the sequences that we would like to remove. Moving on, we see that we start by updating the local docs and then flushing the trees. Both of which looks promising for my quest to understand how the data is stored on the disk:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041516.jpg" width="621" height="158" alt="200810041516.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;update_local_docs just modify the in memory btree, so I am not going to show it, flush_trees should be more interesting, based on just the comment.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041523.jpg" width="795" height="566" alt="200810041523.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;This &lt;em&gt;is&lt;/em&gt; interesting. What we see here is that we write the attachment references and the document body to the &lt;em&gt;summary stream&lt;/em&gt;. That is interesting, because I am still not sure what the summary stream &lt;em&gt;is&lt;/em&gt;. Note that here we have the issue of writing to a file during compaction, so we ask the higher level code to retry that again.&lt;/p&gt;
&lt;p&gt;We still have to see how the indexes are maintained, but that just update the in memory structure, the real bit happens next:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://ayende.com/Blog/images/ayende_com/Blog/200810041528.jpg" width="696" height="264" alt="200810041528.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Here we see our good old friend the btree, and we add/remove the new index to the file. We have seen how this works &lt;a href="http://ayende.com/Blog/archive/2008/09/24/more-couchdb-reading-btreequery_modify.aspx"&gt;here&lt;/a&gt;. We finish by updating the Db structure with the new values and committing the data.&lt;/p&gt;
&lt;p&gt;I now feel that I have a much better understanding on how CouchDB file handling works. Except that I still don't know what this summary stream is. That is a topic for later, though.&lt;/p&gt;
&lt;img src="http://ayende.com/Blog/aggbug/10539.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2008/10/04/erlang-reading-couchdb-digging-down-to-disk.aspx</guid>
            <pubDate>Sat, 04 Oct 2008 12:32:46 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2008/10/04/erlang-reading-couchdb-digging-down-to-disk.aspx#feedback</comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/10539.aspx</wfw:commentRss>
        </item>
    </channel>
</rss>