<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>Programming</title>
        <link>http://ayende.com/Blog/category/496.aspx</link>
        <description>Programming</description>
        <language>en-US</language>
        <copyright>Ayende Rahien</copyright>
        <managingEditor>Ayende@ayende.com</managingEditor>
        <generator>Subtext Version 2.0.0.43</generator>
        <item>
            <title>Stop! Or I am writing another framework!</title>
            <link>http://ayende.com/Blog/archive/2008/11/13/stop-or-i-am-writing-another-framework.aspx</link>
            <description>&lt;p&gt;There is a small dwarf in my head that whispers about persistent binary trees and RESTful services, views using DSL and JSON data interchange.&lt;/p&gt; &lt;p&gt;In other words, I really want to write NCouchDB. I had the exact same thing happening with queuing, and it didn't stop until I wrote Rhino Queues (five or six times!)&lt;/p&gt; &lt;p&gt;I keep trying to justify to myself that this is needed. But I already busy over my head. Please, help me stop this, before I lose all control.&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/10605.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2008/11/13/stop-or-i-am-writing-another-framework.aspx</guid>
            <pubDate>Thu, 13 Nov 2008 03:40:38 GMT</pubDate>
            <wfw:comment>http://ayende.com/Blog/comments/10605.aspx</wfw:comment>
            <comments>http://ayende.com/Blog/archive/2008/11/13/stop-or-i-am-writing-another-framework.aspx#feedback</comments>
            <slash:comments>9</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/10605.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Get that queue out of my head</title>
            <link>http://ayende.com/Blog/archive/2008/09/21/get-that-queue-out-of-my-head.aspx</link>
            <description>&lt;p&gt;For some reason, I am having a lot of trouble lately getting Rhino Queues out of my head. I don't actually have a project to use it on, but it keep popping up in my mind. Before committing to the fifth or sixth rewrite of the project, I decided to take a stub at testing its performance. &lt;/p&gt; &lt;p&gt;The scenario is sending a hundred thousand (100,000) messages, with sizes ranging from 4Kb to 16Kb, which are the most common sizes for most messages.&lt;/p&gt; &lt;p&gt;On my local machine, I can push that amount of data in 02:02.02. So just above two minutes. This is for pushing 1,024,540,307 bytes, or just under a gigabyte in size. This translate to over 800 messages a second and close to 8.5 MB per second.&lt;/p&gt; &lt;p&gt;Considering that I am pushing everything over HTTP, that is just fine by me. But the real test would be to see how it works over the Internet.&lt;/p&gt; &lt;p&gt;I have a limited upload capacity here, so trying to push a gigabyte up would take too long. Instead, I confined myself to 5,000 messages, of the same varying sizes as before.&lt;/p&gt; &lt;p&gt;This time, over the Internet, it took 27:25:95 minutes. Just short of half an hour to push 51,135,538 bytes (~48Mb). &lt;/p&gt; &lt;p&gt;But that is testing throughput. While that is interesting on its own, it doesn't really tell us much about another important quality of the system, latency. Over the Internet, it took an average of 25 seconds to send a message batch. This is pretty fast, but I don't think it is great.&lt;/p&gt; &lt;p&gt;Anyway, getting back into the code didn't really help much, and I think that I &lt;em&gt;will&lt;/em&gt; need to rewrite it again.&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/10512.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2008/09/21/get-that-queue-out-of-my-head.aspx</guid>
            <pubDate>Sun, 21 Sep 2008 09:18:05 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2008/09/21/get-that-queue-out-of-my-head.aspx#feedback</comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/10512.aspx</wfw:commentRss>
        </item>
        <item>
            <title>What I am working on...</title>
            <link>http://ayende.com/Blog/archive/2008/08/27/What-I-am-working-on.aspx</link>
            <description>&lt;p&gt;I am just going to post that, and watch what happens. I will note that this is code that I just wrote, from scratch.&lt;/p&gt;  &lt;pre&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; TaxCalculator
{
    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; conStr;
    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; DataSet rates;

    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; TaxCalculator(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; conStr)
    {
        &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.conStr = conStr;
        &lt;span style="color: #0000ff"&gt;using&lt;/span&gt; (SqlConnection con = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SqlConnection(conStr))
        {
            con.Open();
            &lt;span style="color: #0000ff"&gt;using&lt;/span&gt; (SqlCommand cmd = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SqlCommand("&lt;span style="color: #8b0000"&gt;SELECT * FROM tblTxRtes&lt;/span&gt;", con))
            {
                rates = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; DataSet();
                &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SqlDataAdapter(cmd).Fill(rates);
                Log.Write("&lt;span style="color: #8b0000"&gt;Read &lt;/span&gt;" + rates.Tables[0].Rows.Count + "&lt;span style="color: #8b0000"&gt; rates from database&lt;/span&gt;");
                &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (rates.Tables[0].Rows.Count == 0)
                {
                    MailMessage msg = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; MailMessage("&lt;span style="color: #8b0000"&gt;important@legacy.org&lt;/span&gt;", "&lt;span style="color: #8b0000"&gt;joe@legacy.com&lt;/span&gt;");
                    msg.Subject = "&lt;span style="color: #8b0000"&gt;NO RATES IN DATABASE!!!!!&lt;/span&gt;";
                    msg.Priority = MailPriority.High;
                    &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SmtpClient("&lt;span style="color: #8b0000"&gt;mail.legacy.com&lt;/span&gt;", 9089).Send(msg);
                    Log.Write("&lt;span style="color: #8b0000"&gt;No rates for taxes found in &lt;/span&gt;" + conStr);
                    &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ApplicationException("&lt;span style="color: #8b0000"&gt;No rates, Joe forgot to load the rates AGAIN!&lt;/span&gt;");
                }
            }
        }
    }

    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; Process(XmlDocument transaction)
    {
        &lt;span style="color: #0000ff"&gt;try&lt;/span&gt;
        {
            Hashtable tx2tot = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Hashtable();
            &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (XmlNode o &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; transaction.FirstChild.ChildNodes)
            {
            restart:
                &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (o.Attributes["&lt;span style="color: #8b0000"&gt;type&lt;/span&gt;"].Value == "&lt;span style="color: #8b0000"&gt;2&lt;/span&gt;")
                {
                    Log.Write("&lt;span style="color: #8b0000"&gt;Type two transaction processing&lt;/span&gt;");
                    &lt;span style="color: #0000ff"&gt;decimal&lt;/span&gt; total = &lt;span style="color: #0000ff"&gt;decimal&lt;/span&gt;.Parse(o.Attributes["&lt;span style="color: #8b0000"&gt;tot&lt;/span&gt;"].Value);
                    XmlAttribute attribute = transaction.CreateAttribute("&lt;span style="color: #8b0000"&gt;tax&lt;/span&gt;");
                    &lt;span style="color: #0000ff"&gt;decimal&lt;/span&gt; r = -1;
                    &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (DataRow dataRow &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; rates.Tables[0].Rows)
                    {
                        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; ((&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;)dataRow[2] == o.SelectSingleNode("&lt;span style="color: #8b0000"&gt;//cust-details/state&lt;/span&gt;").Value)
                        {
                            r = &lt;span style="color: #0000ff"&gt;decimal&lt;/span&gt;.Parse(dataRow[2].ToString());
                        }
                    }
                    Log.Write("&lt;span style="color: #8b0000"&gt;Rate calculated and is: &lt;/span&gt;" + r);
                    o.Attributes.Append(attribute);
                    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (r == -1)
                    {
                        MailMessage msg = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; MailMessage("&lt;span style="color: #8b0000"&gt;important@legacy.org&lt;/span&gt;", "&lt;span style="color: #8b0000"&gt;joe@legacy.com&lt;/span&gt;");
                        msg.Subject = "&lt;span style="color: #8b0000"&gt;NO RATES FOR &lt;/span&gt;" + o.SelectSingleNode("&lt;span style="color: #8b0000"&gt;//cust-details/state&lt;/span&gt;").Value + "&lt;span style="color: #8b0000"&gt; TRANSACTION !!!!ABORTED!!!!&lt;/span&gt;";
                        msg.Priority = MailPriority.High;
                        &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SmtpClient("&lt;span style="color: #8b0000"&gt;mail.legacy.com&lt;/span&gt;", 9089).Send(msg);
                        Log.Write("&lt;span style="color: #8b0000"&gt;No rate for transaction in tranasction state&lt;/span&gt;");
                        &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ApplicationException("&lt;span style="color: #8b0000"&gt;No rates, Joe forgot to load the rates AGAIN!&lt;/span&gt;");
                    }
                    tx2tot.Add(o.Attributes["&lt;span style="color: #8b0000"&gt;id&lt;/span&gt;"], total * r);
                    attribute.Value = (total * r).ToString();
                }
                &lt;span style="color: #0000ff"&gt;else&lt;/span&gt; &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (o.Attributes["&lt;span style="color: #8b0000"&gt;type&lt;/span&gt;"].Value == "&lt;span style="color: #8b0000"&gt;1&lt;/span&gt;")
                {
                    &lt;span style="color: #008000"&gt;//2006-05-02 just need to do the calc&lt;/span&gt;
                    &lt;span style="color: #0000ff"&gt;decimal&lt;/span&gt; total = 0;
                    &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (XmlNode i &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; o.ChildNodes)
                    {
                        total += ProductPriceByNode(i);
                    }
                    &lt;span style="color: #0000ff"&gt;try&lt;/span&gt;
                    {
                        &lt;span style="color: #008000"&gt;// 2007-02-19 not so simple, TX has different rule&lt;/span&gt;
                        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (o.SelectSingleNode("&lt;span style="color: #8b0000"&gt;//cust-details/state&lt;/span&gt;").Value == "&lt;span style="color: #8b0000"&gt;TX&lt;/span&gt;")
                        {
                            total *= (&lt;span style="color: #0000ff"&gt;decimal&lt;/span&gt;)1.02;
                        }
                    }
                    &lt;span style="color: #0000ff"&gt;catch&lt;/span&gt; (NullReferenceException)
                    {
                        XmlElement element = transaction.CreateElement("&lt;span style="color: #8b0000"&gt;state&lt;/span&gt;");
                        element.Value = "&lt;span style="color: #8b0000"&gt;NJ&lt;/span&gt;";
                        o.SelectSingleNode("&lt;span style="color: #8b0000"&gt;//cust-details&lt;/span&gt;").AppendChild(element);
                    }
                    XmlAttribute attribute = transaction.CreateAttribute("&lt;span style="color: #8b0000"&gt;tax&lt;/span&gt;");
                    &lt;span style="color: #0000ff"&gt;decimal&lt;/span&gt; r = -1;
                    &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (DataRow dataRow &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; rates.Tables[0].Rows)
                    {
                        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; ((&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;)dataRow[2] == o.SelectSingleNode("&lt;span style="color: #8b0000"&gt;//cust-details/state&lt;/span&gt;").Value)
                        {
                            r = &lt;span style="color: #0000ff"&gt;decimal&lt;/span&gt;.Parse(dataRow[2].ToString());
                        }
                    }
                    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (r == -1)
                    {
                        MailMessage msg = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; MailMessage("&lt;span style="color: #8b0000"&gt;important@legacy.org&lt;/span&gt;", "&lt;span style="color: #8b0000"&gt;joe@legacy.com&lt;/span&gt;");
                        msg.Subject = "&lt;span style="color: #8b0000"&gt;NO RATES FOR &lt;/span&gt;" + o.SelectSingleNode("&lt;span style="color: #8b0000"&gt;//cust-details/state&lt;/span&gt;").Value + "&lt;span style="color: #8b0000"&gt; TRANSACTION !!!!ABORTED!!!!&lt;/span&gt;";
                        msg.Priority = MailPriority.High;
                        &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SmtpClient("&lt;span style="color: #8b0000"&gt;mail.legacy.com&lt;/span&gt;", 9089).Send(msg);
                        &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ApplicationException("&lt;span style="color: #8b0000"&gt;No rates, Joe forgot to load the rates AGAIN!&lt;/span&gt;");
                    }
                    attribute.Value = (total * r).ToString();
                    tx2tot.Add(o.Attributes["&lt;span style="color: #8b0000"&gt;id&lt;/span&gt;"], total * r);
                    o.Attributes.Append(attribute);
                }
                &lt;span style="color: #0000ff"&gt;else&lt;/span&gt; &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (o.Attributes["&lt;span style="color: #8b0000"&gt;type&lt;/span&gt;"].Value == "&lt;span style="color: #8b0000"&gt;@&lt;/span&gt;")
                {
                    o.Attributes["&lt;span style="color: #8b0000"&gt;type&lt;/span&gt;"].Value = "&lt;span style="color: #8b0000"&gt;2&lt;/span&gt;";
                    &lt;span style="color: #0000ff"&gt;goto&lt;/span&gt; restart;
                    &lt;span style="color: #008000"&gt;// 2007-04-30 some bastard from northwind made a mistake and they have 3 months release cycle, so we have to&lt;/span&gt;
                    &lt;span style="color: #008000"&gt;// fix this because they won't until sep-07&lt;/span&gt;
                }
                &lt;span style="color: #0000ff"&gt;else&lt;/span&gt;
                {
                    &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Exception("&lt;span style="color: #8b0000"&gt;UNKNOWN TX TYPE&lt;/span&gt;");
                }
            }
            SqlConnection con2 = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SqlConnection(conStr);
            SqlCommand cmd2 = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SqlCommand();
            cmd2.Connection = con2;
            con2.Open();
            &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (DictionaryEntry d &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; tx2tot)
            {
                cmd2.CommandText = "&lt;span style="color: #8b0000"&gt;usp_TrackTxNew&lt;/span&gt;";
                cmd2.Parameters.Add("&lt;span style="color: #8b0000"&gt;cid&lt;/span&gt;", transaction.SelectSingleNode("&lt;span style="color: #8b0000"&gt;//cust-details/@id&lt;/span&gt;").Value);
                cmd2.Parameters.Add("&lt;span style="color: #8b0000"&gt;tx&lt;/span&gt;", d.Key);
                cmd2.Parameters.Add("&lt;span style="color: #8b0000"&gt;tot&lt;/span&gt;", d.Value);
                cmd2.ExecuteNonQuery();
            }
            con2.Close();
        }
        &lt;span style="color: #0000ff"&gt;catch&lt;/span&gt; (Exception e)
        {
            &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (e.Message == "&lt;span style="color: #8b0000"&gt;UNKNOWN TX TYPE&lt;/span&gt;")
            {
                &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;false&lt;/span&gt;;
            }
            &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; e;
        }
        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;;
    }

    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;decimal&lt;/span&gt; ProductPriceByNode(XmlNode item)
    {
        &lt;span style="color: #0000ff"&gt;using&lt;/span&gt; (SqlConnection con = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SqlConnection(conStr))
        {
            con.Open();
            &lt;span style="color: #0000ff"&gt;using&lt;/span&gt; (SqlCommand cmd = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SqlCommand("&lt;span style="color: #8b0000"&gt;SELECT * FROM tblProducts WHERE pid=&lt;/span&gt;" + item.Attributes["&lt;span style="color: #8b0000"&gt;id&lt;/span&gt;"], con))
            {
                DataSet &lt;span style="color: #0000ff"&gt;set&lt;/span&gt; = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; DataSet();
                &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; SqlDataAdapter(cmd).Fill(&lt;span style="color: #0000ff"&gt;set&lt;/span&gt;);
                &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;decimal&lt;/span&gt;)&lt;span style="color: #0000ff"&gt;set&lt;/span&gt;.Tables[0].Rows[0][4];

            }
        }
    }
}&lt;/pre&gt;&lt;img src="http://ayende.com/Blog/aggbug/10472.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2008/08/27/What-I-am-working-on.aspx</guid>
            <pubDate>Wed, 27 Aug 2008 19:39:25 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2008/08/27/What-I-am-working-on.aspx#feedback</comments>
            <slash:comments>59</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/10472.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Legacy Driven Development</title>
            <link>http://ayende.com/Blog/archive/2008/08/27/Legacy-Driven-Development.aspx</link>
            <description>&lt;p&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; margin: 0px 0px 0px 15px; border-right-width: 0px" height="407" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/LegacyDrivenDevelopment_BC6F/image_thumb.png" width="307" align="right" border="0" /&gt;Here is an interesting problem that I run into. I needed to produce an XML document for an external system to consume. This is a fairly complex document format, and there are a lot of scenarios to support. I began to test drive the creation of the XML document, but it turn out that I kept having to make changes as I run into more scenarios that invalidated previous assumptions that I made.&lt;/p&gt;  &lt;p&gt;Now, we are talking about a very short iteration cycle, I might write a test to validate an assumption (attempting to put two items in the same container should throws) and an hour later realize that it &lt;em&gt;is&lt;/em&gt; a legal, if strange, behavior. The tests became a pain point, I had to keep updating things because the invariant that they were based upon were wrong.&lt;/p&gt;  &lt;p&gt;At that point, I decided that TDD was exactly the wrong approach for this scenario. Therefor, I decided that I am going to fall back to the old "trial and error" method. In this case, producing the XML and comparing using a diff tool.&lt;/p&gt;  &lt;p&gt;The friction in the process went down significantly, because I didn't have to go and fix the tests all the time. I did break things that used to work, but I caught them mostly with manual diff checks.&lt;/p&gt;  &lt;p&gt;So far, not a really interesting story. What is interesting is what happens when I decided that I have done enough work to consider most scenarios to be completed. I took all the scenarios and started generating tests for those. So for each scenario I now have a test that tests the &lt;em&gt;current behavior of the system&lt;/em&gt;. This is blind testing. That is, I assume that the system is working correctly, and I want to ensure that it keeps working in this way. I am not sure what each test is doing, but the current behavior is assumed to be correct until proven otherwise..&lt;/p&gt;  &lt;p&gt;Now I am back to having my usual safety net, and it is a lot of fun to go from zero tests to nearly five hundred tests in a few minutes.&lt;/p&gt;  &lt;p&gt;This doesn't prove that the behavior of the system is correct, but it does ensure no regression and make sure that we have a stable platform to work from. We might find a bug, but then we can fix it in safety.&lt;/p&gt;  &lt;p&gt;I don't recommend this approach for general use, but for this case, it has proven to be very useful.&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/10471.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2008/08/27/Legacy-Driven-Development.aspx</guid>
            <pubDate>Wed, 27 Aug 2008 19:37:30 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2008/08/27/Legacy-Driven-Development.aspx#feedback</comments>
            <slash:comments>4</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/10471.aspx</wfw:commentRss>
        </item>
        <item>
            <title>re: MVC Storefront Part 19: Processing Orders With Windows Workflow</title>
            <link>http://ayende.com/Blog/archive/2008/08/17/re-MVC-Storefront-Part-19-Processing-Orders-With-Windows-Workflow.aspx</link>
            <description>&lt;p&gt;&lt;a href="http://blog.wekeroad.com/mvc-storefront/mvcstore-part-19/"&gt;Rob Conery&lt;/a&gt; has another &lt;a href="http://blog.wekeroad.com/mvc-storefront/mvcstore-part-19/"&gt;MVC Storefront&lt;/a&gt; post, this time focusing on using Windows Workflow.&lt;/p&gt;  &lt;p&gt;Those are my random impressions:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;You probably &lt;em&gt;do&lt;/em&gt; want to test your work flow. In the same way you want to have an integration test for the system.&lt;/li&gt;    &lt;li&gt;The sequence work flow seems to be a very heavy weight approach to just orchestrating actions in the application.&lt;/li&gt;    &lt;li&gt;I wonder what the perf implications of creating a workflow here would be. My gut feeling is that this is not good, but I don't really have data for that.&lt;/li&gt;    &lt;li&gt;There is probably an issue here with the WF being run in async, I am not sure where it is getting its threads, but if it is from the thread pool, then it is consuming request handling threads, which can kill a site.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;As an aside, here is the checkout workflow:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/reMVCStorefrontPart19ProcessingOrdersWit_5453/image_2.png"&gt;&lt;img height="367" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/reMVCStorefrontPart19ProcessingOrdersWit_5453/image_thumb.png" width="173" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;And here is how I would write this:&lt;/p&gt;  &lt;blockquote&gt;   &lt;pre&gt;ValidateOrder()
AuthorizePayment()
order.Status = OrderStatus.Verified
SaveOrder()&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;Much easier, I think :-) And even more flexible.&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/10442.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2008/08/17/re-MVC-Storefront-Part-19-Processing-Orders-With-Windows-Workflow.aspx</guid>
            <pubDate>Sun, 17 Aug 2008 02:59:59 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2008/08/17/re-MVC-Storefront-Part-19-Processing-Orders-With-Windows-Workflow.aspx#feedback</comments>
            <slash:comments>12</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/10442.aspx</wfw:commentRss>
        </item>
        <item>
            <title>3 Levels Of Failures</title>
            <link>http://ayende.com/Blog/archive/2008/08/01/3-Levels-Of-Failures.aspx</link>
            <description>&lt;ul&gt;   &lt;li&gt;You have the no-failure, everything completed successfully and everyone is happy.&lt;/li&gt;    &lt;li&gt;You have complete-failure, someone just pull the power cord off the machine.&lt;/li&gt;    &lt;li&gt;And in the middle, you have partial-failure, something bad happened, (network is down, someone pulled the USB key out) but the system can (and should) keep running. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Most people give up on the complete failure scenario, leaving that up to transactional storage to handle this. That is usually the smartest solution. &lt;/p&gt;  &lt;p&gt;The problem occur with partial failure, where you need to recover in meaningful ways. It is actually very easy to write a system where a complete failure is better than a partial failure.&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/10384.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2008/08/01/3-Levels-Of-Failures.aspx</guid>
            <pubDate>Fri, 01 Aug 2008 13:24:51 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2008/08/01/3-Levels-Of-Failures.aspx#feedback</comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/10384.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Useless Java</title>
            <link>http://ayende.com/Blog/archive/2008/07/30/Useless-Java.aspx</link>
            <description>&lt;p&gt;This article (&lt;a href="http://itmanagement.earthweb.com/entdev/article.php/11070_3761921_1"&gt;The 'Anti-Java' Professor and the Jobless Programmers&lt;/a&gt;) has really annoyed me. Not because of its content, but because the professor being interview is so narrowly focused that he is completely out of it.&lt;/p&gt;  &lt;p&gt;Let us take this quote:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;“Furthermore, Java is mainly used in Web applications that are mostly fairly trivial,” Dewar says, with his characteristic candor. “If all we do is train students to be able to do simple Web programming in Java, they won't get jobs, since those &lt;i&gt;are&lt;/i&gt; the jobs that can be easily outsourced. What we need are software engineers who understand how to build complex systems.” &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;You know what, I might agree with this, trivial web programming is something that doesn't require highly skilled worker. But the context in which he says this makes all the difference in the world. Here is the next statement:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;“By the way Java has almost no presence in such systems. At least as of a few months ago, there was not a single line of safety-critical Java flying in commercial or military aircraft. I recently talked to a customer who had a medium-sized application in Java, which was to be adapted to be part of a safety-critical avionics system. They immediately decided that this meant it would have to be recoded in a suitable language, probably either C or Ada.” &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;So, if it is not aircraft code, it is "simple Web programming"? Excuse me?!&lt;/p&gt;  &lt;p&gt;Leaving aside the part about Java's license not being suitable for life critical systems, it annoys me that this is the only criteria that he think is worth mentioning. His bank is running Java, as well as the stock exchange, it is likely that the payroll system in his university as well. Relegating Java to "simple Web programming" is a huge mistake. Java sweet spot &lt;em&gt;is&lt;/em&gt; building complex systems, where a lot of the design decisions that make it hard to do the simple stuff pay off tremendously.&lt;/p&gt;  &lt;p&gt;I can think of quite a few mission critical (people life on the balance) that are written in C# (for the purpose of this post, equivalent to Java). That is not to say that aircraft systems shouldn't be written in Ada or C, I never written one, so I won't comment, but to say that this is the only field of any complexity is showing a remarkable amount of ignorance and bigotry.&lt;/p&gt;  &lt;p&gt;There was another part that caught my eye, this professor interviewing's technique:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Dewar says that if he were interviewing applicants for a development job, he would quickly eliminate the under-trained by asking the following questions: &lt;/p&gt;    &lt;p&gt;&lt;b&gt;1.)&lt;/b&gt; You begin to suspect that a problem you are having is due to the compiler generating incorrect code. How would you track this down? How would you prepare a bug report for the compiler vendor? How would you work around the problem? &lt;/p&gt;    &lt;p&gt;&lt;b&gt;2.)&lt;/b&gt; You begin to suspect that a problem you are having is due to a hardware problem, where the processor is not conforming to its specification. How would you track this down? How would you prepare a bug report for the chip manufacturer, and how would you work around the problem? &lt;/p&gt;    &lt;p&gt;“I am afraid I would be met by blank stares from most recent CS graduates, many of whom have never seen assembly or machine language!” he says&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;I can tell quite a lot about what he is doing, just by the questions he ask, but let me try answering them.&lt;/p&gt;  &lt;p&gt;1) Well, I would start by creating an isolated test case, seeing if I can still see the odd behavior. I would remove all code that is even half way smart, trying to reduce the amount of work that the compiler has to do. I would get the language spec and pore over it, trying to make sure that I am not relying on unspecified behavior or misunderstanding the spec. Hopefully, I have a decompiler as well, since that would be an independent corroboration that there is or isn't an issue. Then I would take the output and verify disassemble it, comparing it to what is supposed to happen. I will take that info and submit to the compiler vendor. Working around this issue... by now I have some understanding on what triggers it, so I would change the code accordingly, simplifying it, removing any smart tricks, etc. I'll also leave a big comment about why this is done.&lt;/p&gt;  &lt;p&gt;2) Try it on a different machine with the same processor, try it on another machine with a different processor. That rules problems with a specific machine and problems with my code, respectively. Reduce the problem to the smallest thing that can repro it, go over the spec, verify understanding. Eventually I should have a small program that demonstrate the issue. This can be incredibly hard to do if you run into something like memory barriers do not work in some scenario on SMP machines, for example. Work around it... depending on context...&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/10374.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2008/07/30/Useless-Java.aspx</guid>
            <pubDate>Wed, 30 Jul 2008 13:36:18 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2008/07/30/Useless-Java.aspx#feedback</comments>
            <slash:comments>33</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/10374.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Not all objects are created equals</title>
            <link>http://ayende.com/Blog/archive/2008/07/29/Not-all-objects-are-created-equals.aspx</link>
            <description>&lt;p&gt;I found something extremely surprising while profiling a project. Take a look at this piece of code:&lt;/p&gt;  &lt;blockquote&gt;   &lt;pre&gt;Stopwatch stop = Stopwatch.StartNew();
&lt;span style="color: #0000ff"&gt;for&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; i = 0; i &amp;lt; 1000000; i++)
{
	&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; WeakReference(&lt;span style="color: #0000ff"&gt;null&lt;/span&gt;);
}
stop.Stop();
Console.WriteLine("&lt;span style="color: #8b0000"&gt;WeakRef: &lt;/span&gt;" + stop.ElapsedMilliseconds);

stop = Stopwatch.StartNew();
&lt;span style="color: #0000ff"&gt;for&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; i = 0; i &amp;lt; 1000000; i++)
{
	&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;('a', 5);
}
stop.Stop();
Console.WriteLine("&lt;span style="color: #8b0000"&gt;'aaaaa': &lt;/span&gt;" + stop.ElapsedMilliseconds);&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;On my machine, this has the following output:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;WeakRef: 980
    &lt;br /&gt;'aaaaa': 35&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Creating a WeakReference is much more costly than creating a normal object. Not surprising, when you think of it, WeakReference has deep ties to the CLR, but I couldn't really believe it when I saw it the first time.&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/10365.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2008/07/29/Not-all-objects-are-created-equals.aspx</guid>
            <pubDate>Mon, 28 Jul 2008 22:53:52 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2008/07/29/Not-all-objects-are-created-equals.aspx#feedback</comments>
            <slash:comments>7</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/10365.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Testing interleaved async file writing</title>
            <link>http://ayende.com/Blog/archive/2008/07/26/Testing-interleaved-async-file-writing.aspx</link>
            <description>&lt;p&gt;Here is another interesting aspect that I run into when thinking about writing to files. What will happen if I start two async write operations? Will they get interleaved? Will they get interleaved? Will I get errors when using this?&lt;/p&gt;  &lt;p&gt;Here is using a single stream:&lt;/p&gt;  &lt;blockquote&gt;   &lt;pre&gt;var path = "&lt;span style="color: #8b0000"&gt;test.txt&lt;/span&gt;";

&lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (File.Exists(path))
	File.Delete(path);

var handles = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;WaitHandle&amp;gt;();
&lt;span style="color: #0000ff"&gt;using&lt;/span&gt; (
	var stream = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; FileStream(path, FileMode.CreateNew, FileAccess.Write, FileShare.None, 0x1000,
								 FileOptions.Asynchronous))
{
	&lt;span style="color: #0000ff"&gt;for&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; i = 0; i &amp;lt; 64; i++)
	{
		var handle = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ManualResetEvent(&lt;span style="color: #0000ff"&gt;false&lt;/span&gt;);
		var bytes = Encoding.UTF8.GetBytes( i + Environment.NewLine);
		stream.BeginWrite(bytes, 0, bytes.Length, &lt;span style="color: #0000ff"&gt;delegate&lt;/span&gt;(IAsyncResult ar)
		{
			stream.EndWrite(ar);
			handle.Set();
		}, stream);
		handles.Add(handle);
	}
	WaitHandle.WaitAll(handles.ToArray());
	stream.Flush();

}&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;This worked perfectly, the writes are written in a sequential manner, with no interleaving.&lt;/p&gt;

&lt;p&gt;The situation changes somewhat when we work with several streams, instead. Here is the code:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre&gt;var path = "&lt;span style="color: #8b0000"&gt;test.txt&lt;/span&gt;";

&lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (File.Exists(path))
	File.Delete(path);

var handles = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;WaitHandle&amp;gt;();

&lt;span style="color: #0000ff"&gt;for&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; i = 0; i &amp;lt; 64; i++)
{
	var stream = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite, 0x1000,
	                            FileOptions.Asynchronous);
	var handle = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ManualResetEvent(&lt;span style="color: #0000ff"&gt;false&lt;/span&gt;);
	var bytes = Encoding.UTF8.GetBytes(i + Environment.NewLine);
	stream.BeginWrite(bytes, 0, bytes.Length, &lt;span style="color: #0000ff"&gt;delegate&lt;/span&gt;(IAsyncResult ar)
	{
		stream.EndWrite(ar);
		stream.Flush();
		stream.Dispose();
		handle.Set();
	}, stream);
	handles.Add(handle);
}
WaitHandle.WaitAll(handles.ToArray());&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;The output of this code on my machine is: 63&lt;/p&gt;

&lt;p&gt;Although I am pretty sure that it is possible to get other things as well.  But considering that the way IO operations work in generate ( Write( position, buffer) ), that makes a lot of sense. &lt;/p&gt;

&lt;p&gt;Interestingly, in regards to the single stream version, the documentation states:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Multiple simultaneous asynchronous requests render the request completion order uncertain.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It doesn't say anything about the actual write order, however, the completion order is not an issue, as far as I am concerned, but the order of the data on disk is very important.&lt;/p&gt;

&lt;p&gt;Another interesting question was how a single file stream work with multiple threads calling BeginWrite in parallel. Here is the code:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre&gt;var path = "&lt;span style="color: #8b0000"&gt;test.txt&lt;/span&gt;";

&lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (File.Exists(path))
	File.Delete(path);

var handles = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;WaitHandle&amp;gt;();
&lt;span style="color: #0000ff"&gt;using&lt;/span&gt; (
	var stream = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; FileStream(path, FileMode.CreateNew, FileAccess.Write, FileShare.None, 0x1000,
								 FileOptions.Asynchronous))
{
	&lt;span style="color: #0000ff"&gt;for&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; i = 0; i &amp;lt; 64; i++)
	{
		var handle = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ManualResetEvent(&lt;span style="color: #0000ff"&gt;false&lt;/span&gt;);
		var bytes = Encoding.UTF8.GetBytes(i + Environment.NewLine);
		ThreadPool.QueueUserWorkItem(&lt;span style="color: #0000ff"&gt;delegate&lt;/span&gt;
		{
			Thread.Sleep(10);
			stream.BeginWrite(bytes, 0, bytes.Length, &lt;span style="color: #0000ff"&gt;delegate&lt;/span&gt;(IAsyncResult ar)
			{
				stream.EndWrite(ar);
				handle.Set();
			}, stream);
		});
		handles.Add(handle);
	}
	WaitHandle.WaitAll(handles.ToArray());
	stream.Flush();

}&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;The result of this code looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/Testinginterleavedasyncfilewriting_14065/image_2.png"&gt;&lt;img height="103" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/Testinginterleavedasyncfilewriting_14065/image_thumb.png" width="216" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Obviously, we have a race condition with the known position of the stream. Adding a lock for the stream.BeginWrite results in this:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/Testinginterleavedasyncfilewriting_14065/image_4.png"&gt;&lt;img height="85" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/Testinginterleavedasyncfilewriting_14065/image_thumb_1.png" width="187" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;I am actually fine with this, because as far as I can tell, this might very well be the actual execution order.&lt;/p&gt;

&lt;p&gt;Another observation that is very important is the fact that the Position property of the stream is update immediately when you can BeginWrite(). &lt;/p&gt;

&lt;p&gt;That was a somewhat random walk over the BeginWrite implementation, I admit, but I hope it will make sense soon.&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/10356.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2008/07/26/Testing-interleaved-async-file-writing.aspx</guid>
            <pubDate>Sat, 26 Jul 2008 19:47:09 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2008/07/26/Testing-interleaved-async-file-writing.aspx#feedback</comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/10356.aspx</wfw:commentRss>
        </item>
        <item>
            <title>In search of an embedded DB</title>
            <link>http://ayende.com/Blog/archive/2008/07/03/In-search-of-an-embedded-DB.aspx</link>
            <description>&lt;p&gt;I need to use an embedded DB in a project. Naturally, I turned to my old friend, SQLite. It has served me well in the past, and I am well versed in all its tricks. Except... SQLite really fall apart when you are talking about even moderately multi threaded applications. By that I mean, it works just as advertised, for sure. It just lock the entire DB when used, which tend to kill other threads who want to access the poor DB.&lt;/p&gt;  &lt;p&gt;I then turned to FireBird, but a short spike told me that it is... inadequate. I managed to get the database into inconsistent state, but I am not sure how or why. There seem to be very little information about it as well, so at the moment it is out of the game.&lt;/p&gt;  &lt;p&gt;Sql CE is worse than SQLite when it comes to handling multiple threads, so that wasn't even in the running.&lt;/p&gt;  &lt;p&gt;Vista DB is commercial, and I plan to make this an OSS project, so that is out as well. &lt;/p&gt;  &lt;p&gt;I &lt;em&gt;want &lt;/em&gt;to use Berkeley DB, but is seems like the .Net story is hard. There are &lt;a href="http://sourceforge.net/projects/libdb-dotnet"&gt;CLR Binding&lt;/a&gt;, but I run into several blocking issues with them. There is no 1:1 mapping to the C API or the Java API, the error messages are... terse. And there aren't any tests at all! Even worse, the code is interfacing with native code, so it is C# after a rail road has hit it at 200 kph and having spent three days crying in a desert.&lt;/p&gt;  &lt;p&gt;I put some time into trying to get this to work, and once the initial hump is over (understanding the association between environments, databases and transactions), it makes a lot of sense. Of course, there are a &lt;em&gt;lot&lt;/em&gt; of features that I wouldn't even try to figure out.&lt;/p&gt;  &lt;p&gt;First order of business, create a .Netified wrapper that will abstract the C like API away from me.&lt;/p&gt;  &lt;p&gt;Okay, I am being ungracious here, the API make a lot of sense and the code is good for the purpose it was built, it was just that I had a moment of existential uncertainty when I looked at the code and it looked like C++#.&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/10306.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2008/07/03/In-search-of-an-embedded-DB.aspx</guid>
            <pubDate>Thu, 03 Jul 2008 08:04:48 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2008/07/03/In-search-of-an-embedded-DB.aspx#feedback</comments>
            <slash:comments>24</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/10306.aspx</wfw:commentRss>
        </item>
    </channel>
</rss>