﻿<?xml version="1.0" encoding="utf-8"?><rss version="2.0"><channel><title>Ayende @ Rahien</title><link>http://ayende.com/blog/</link><description>Ayende @ Rahien</description><copyright>Copyright (C) Ayende Rahien  2004 - 2012 (c) 2012</copyright><ttl>60</ttl><item><title>When using the Task Parallel Library, Wait() is a BAD warning sign</title><description>&lt;p&gt;Take a look at the following code:&lt;/p&gt; &lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; Task ParseAsync(IPartialDataAccess source, IPartialDataAccess seed, Stream output, IEnumerable&amp;lt;RdcNeed&amp;gt; needList)
{
    &lt;span class="kwrd"&gt;return&lt;/span&gt; Task.Factory.StartNew(() =&amp;gt;
    {
        &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (var item &lt;span class="kwrd"&gt;in&lt;/span&gt; needList)
        {
            &lt;span class="kwrd"&gt;switch&lt;/span&gt; (item.BlockType)
            {
                &lt;span class="kwrd"&gt;case&lt;/span&gt; RdcNeedType.Source:
                    source.CopyToAsync(output, Convert.ToInt64(item.FileOffset), Convert.ToInt64(item.BlockLength)).Wait();
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                &lt;span class="kwrd"&gt;case&lt;/span&gt; RdcNeedType.Seed:
                    seed.CopyToAsync(output, Convert.ToInt64(item.FileOffset), Convert.ToInt64(item.BlockLength)).Wait();
                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                &lt;span class="kwrd"&gt;default&lt;/span&gt;:
                    &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; NotSupportedException();
            }
        }
    });
}&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;Do you see the problem in here?&lt;/p&gt;
&lt;p&gt;It is a result of a code review comment about improper use of async in a project. This resulted in a lot of Task showing up in the return methods, but not in any measurable improvement in the actual codebase use of asynchronicity.&lt;/p&gt;
&lt;p&gt;The problem is that when you need to work with such things in C# 4.0, you have to do some annoying things to get the code to work properly. In particular, this method was modified to be:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; Task ParseAsync(IPartialDataAccess source, IPartialDataAccess seed, Stream output, IList&amp;lt;RdcNeed&amp;gt; needList, &lt;span class="kwrd"&gt;int&lt;/span&gt; position = 0)
{
  &lt;span class="kwrd"&gt;if&lt;/span&gt;(position&amp;gt;= needList.Count)
  {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; CompletedTask();
  }
  var item = needList[position];
  Task task;
            
  &lt;span class="kwrd"&gt;switch&lt;/span&gt; (item.BlockType)
  {
        &lt;span class="kwrd"&gt;case&lt;/span&gt; RdcNeedType.Source:
            task = source.CopyToAsync(output, Convert.ToInt64(item.FileOffset), Convert.ToInt64(item.BlockLength));
            &lt;span class="kwrd"&gt;break&lt;/span&gt;;
        &lt;span class="kwrd"&gt;case&lt;/span&gt; RdcNeedType.Seed:
            task = seed.CopyToAsync(output, Convert.ToInt64(item.FileOffset), Convert.ToInt64(item.BlockLength));
            &lt;span class="kwrd"&gt;break&lt;/span&gt;;
        &lt;span class="kwrd"&gt;default&lt;/span&gt;:
            &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; NotSupportedException();
  }

  &lt;span class="kwrd"&gt;return&lt;/span&gt; task.ContinueWith(resultTask =&amp;gt;
    {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (resultTask.Status == TaskStatus.Faulted)
            resultTask.Wait(); &lt;span class="rem"&gt;// throws&lt;/span&gt;
        &lt;span class="kwrd"&gt;return&lt;/span&gt; ParseAsync(source, seed, output, needList, position + 1);
    }).Unwrap();
}&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;This code is more complex, but it is actually making proper use of the TPL. We have changed the loop into a recursive function, so we can take advantage of ContinueWith to the next iteration of the loop.&lt;/p&gt;
&lt;p&gt;And no, I can’t &lt;em&gt;wait&lt;/em&gt; to get to C# 5.0 and have proper await work.&lt;/p&gt;</description><link>http://ayende.com/blog/155585/when-using-the-task-parallel-library-wait-is-a-bad-warning-sign?key=08f9a2f5-c34a-4961-8c19-e5782bcc39a1</link><guid>http://ayende.com/blog/155585/when-using-the-task-parallel-library-wait-is-a-bad-warning-sign?key=08f9a2f5-c34a-4961-8c19-e5782bcc39a1</guid><pubDate>Thu, 17 May 2012 09:00:00 GMT</pubDate></item><item><title>Security decisions: Separate Operations &amp;amp; Queries</title><description>&lt;p&gt;The question came up several times in the mailing list with regards to how the RavenDB Authorization Bundle operates, and I think it serves a broader discussion.&lt;/p&gt; &lt;p&gt;Let us imagine a system where we have contracts, which may be in several states: &lt;/p&gt; &lt;ul&gt; &lt;li&gt;Mine – Contracts that an employee signed.  &lt;li&gt;Done – Standard users can view, Lawyers assigned to the company can sign.  &lt;li&gt;Draft – Lawyers can view / edit, Partners can approve.  &lt;li&gt;Proposed – Lawyers can create / edit, but only the lawyer that created it can view it, Partners can accept.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;So far, fairly simple, right? Except the pure &lt;em&gt;hell&lt;/em&gt; that you are going to get into when you are trying to show the users all of the contracts that they can see, sorted by edit date and in the NDA category.&lt;/p&gt; &lt;p&gt;Why am I being so negative here? Well, let us look at what we are going to have to do in the most trivial of cases:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Security_9400/image_4.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/Security_9400/image_thumb_1.png" width="450" height="221"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;In this sort of system, we are going to have to show the user all of the contracts that they are allowed to see, and show them some indication what operations they can do on each.&lt;/p&gt; &lt;p&gt;The problem is that generating this sort of view is &lt;em&gt;expensive&lt;/em&gt;. Especially when you have large amount of data to work through. More interesting, from a UX perspective, it also doesn’t really work that well. Most users would want a better separation of the things that they can do, probably something like this:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Security_9400/image_9.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/Security_9400/image_thumb_3.png" width="450" height="221"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;This allows us to do a first level filtering on the data itself, rather than try to apply security rules to it.&lt;/p&gt; &lt;p&gt;In the first case, we need to get all the contracts that we are allowed to see. The security rules above are &lt;em&gt;really&lt;/em&gt; simple, mind. But trying to translate them into an efficient query is going to be pretty hard. Both in terms of the code requires and the cost to actually perform the query on the server. There are other things that are involved as well, such as paging and sorting in such an environment.&amp;nbsp; I have created several such systems in the past, Rhino Security is probably the most well known of them, and it gets really hard to optimize things and make sure that everything works when you start getting more complex security rules (especially when you have a user editable security system, which is a common request).&lt;/p&gt; &lt;p&gt;The second case is cheaper because we can limit the choices that we see in the query itself. We may still need to apply security concerns, but those goes through the query directly, rather than a security sub system. This kind of change usually force people to be more explicit in what they want, and it result in a system that tends to be simpler. The security rules aren’t just something arbitrary that can be defined, they are actually visible on the screen (My Contracts, Drafts, etc). Changing them isn’t something that is done on an administrator’s whim.&lt;/p&gt; &lt;p&gt;Yes, this is a way to manage the client and their expectations, but that is &lt;em&gt;important&lt;/em&gt;. But what about the complex security that they want? &lt;/p&gt; &lt;p&gt;That might still be there, certainly, but that would be active mostly for operations (stuff that happen on a single entity), not on things that happen over all entities. It is drastically easier to make a single entity security decisions work efficiently than make it work over the whole set inside the database.&lt;/p&gt;</description><link>http://ayende.com/blog/152929/security-decisions-separate-operations-amp-queries?key=dd5d38bf-cf0b-4233-b6c5-b75582e2e82f</link><guid>http://ayende.com/blog/152929/security-decisions-separate-operations-amp-queries?key=dd5d38bf-cf0b-4233-b6c5-b75582e2e82f</guid><pubDate>Tue, 10 Apr 2012 10:00:00 GMT</pubDate></item><item><title>Hiding values, API keys and other fun stuff</title><description>&lt;p&gt;This post is mostly about fun ideas. In one scenario, we had the need to show data to the user, but there was some concern with regards to the hackability of the URL.&lt;/p&gt; &lt;p&gt;In general, you should be handle such things within your code, checking permissions, etc. But I decided to see if I can do something nice with things, and I got this:&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;static&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; HideValues(&lt;span class="kwrd"&gt;string&lt;/span&gt; entityId, &lt;span class="kwrd"&gt;string&lt;/span&gt; tenantId, &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] key, &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] iv)
{
    &lt;span class="kwrd"&gt;using&lt;/span&gt; (var rijndael = Rijndael.Create())
    {
        rijndael.Key = key;
        rijndael.IV = iv;
        var memoryStream = &lt;span class="kwrd"&gt;new&lt;/span&gt; MemoryStream();
        &lt;span class="kwrd"&gt;using&lt;/span&gt; (var cryptoStream = &lt;span class="kwrd"&gt;new&lt;/span&gt; CryptoStream(memoryStream, rijndael.CreateEncryptor(), CryptoStreamMode.Write))
        &lt;span class="kwrd"&gt;using&lt;/span&gt; (var binaryWriter = &lt;span class="kwrd"&gt;new&lt;/span&gt; BinaryWriter(cryptoStream))
        {
            binaryWriter.Write(entityId);
            binaryWriter.Write(tenantId);
            binaryWriter.Flush();

            cryptoStream.Flush();
        }
        var bytes = memoryStream.ToArray();
        var sb = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringBuilder();
        &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; index = 0; index &amp;lt; bytes.Length; index++)
        {
            var b = bytes[index];
            sb.Append(b.ToString(&lt;span class="str"&gt;"X"&lt;/span&gt;));
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (index % (bytes.Length/4) == 0 &amp;amp;&amp;amp; index &amp;gt; 0)
                sb.Append(&lt;span class="str"&gt;'-'&lt;/span&gt;);
        }
        &lt;span class="kwrd"&gt;return&lt;/span&gt; sb;
    }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;This will generate a “guid looking” value that we can send to the user. When they send it back to us, we can decrypt it and figure out what is actually going on in there.&lt;/p&gt;
&lt;p&gt;Because it is encrypted, we know that this is a valid key, because otherwise we wouldn’t be able to decrypt it to valid data.&lt;/p&gt;
&lt;p&gt;Passing 15 and 32 as the first two values, I got the following value back: 2A8AC8888-46B92092-BFD81393-7A6FB1&lt;/p&gt;
&lt;p&gt;And it handle larger values as easily, of course. Quite fun, even if I say so myself. Not sure if this is &lt;em&gt;useful&lt;/em&gt;, but I got into writing code because it is a great hobby.&lt;/p&gt;</description><link>http://ayende.com/blog/153345/hiding-values-api-keys-and-other-fun-stuff?key=280b7c8b-e590-4671-8c69-ef25955eaa3f</link><guid>http://ayende.com/blog/153345/hiding-values-api-keys-and-other-fun-stuff?key=280b7c8b-e590-4671-8c69-ef25955eaa3f</guid><pubDate>Mon, 09 Apr 2012 10:00:00 GMT</pubDate></item><item><title>The economics of continuous deployment</title><description>&lt;p&gt;
	One of the things that I did, almost by accident, when we started Hibernating Rhinos was to create a CI server and a public daily build server. And every single successful build ended up in customer hands. That was awesome in many respects, it removed a lot of the &amp;ldquo;we have got to make a new release&amp;rdquo; pressure, because we were making new releases, sometimes multiple times a day.&lt;/p&gt;
&lt;p&gt;
	When we started with RavenDB, it was obvious to me that this was what we were going to do with it as well, because the advantages to this approach as so clear. With RavenDB, we needed a two stage system, but still, every single build gets to the customer hands.&lt;/p&gt;
&lt;p&gt;
	Awesome, great, outstanding, exceptional and other such synonyms. As long as you look at this from one angle, the one in which we are only concerned about the technical challenges of delivering software .The problem is that there are additional things to note here. Economic challenges.&lt;/p&gt;
&lt;p&gt;
	Let us take the profiler as a good example. It was released in beta on the Jan 1, 2009, and since then we had 920 separate builds, adding a &lt;em&gt;ton &lt;/em&gt;of new features, capabilities, improving performance, making things smoother and in general making it a better product.&lt;/p&gt;
&lt;p&gt;
	That is over &lt;em&gt;3 years&lt;/em&gt; without a major release, mostly because we never had the need to do this, we kept delivering software on a day to day basis.&lt;/p&gt;
&lt;p&gt;
	During that time, we delivered features such as viewing the result set, checking the query plan of a query (in all major databases), exporting the entire session to HTML so you can send it to your DBA, CI integration and &lt;em&gt;so much more&lt;/em&gt;. It has been wonderful.&lt;/p&gt;
&lt;p&gt;
	Except&amp;hellip; this has one implications that I didn&amp;rsquo;t think of at the time. If you bought NH Prof on the 1st Jan, 2009 you got 3 years of product updates, for no additional costs. And unless we create a new major version, you can keep using the software, including all the updates and improvements, without paying.&lt;/p&gt;
&lt;p&gt;
	That is great for the very early customers, but not so good for the people who need to eat so they can work on the profiler. Let us think about the implications of this a bit more, okay?&lt;/p&gt;
&lt;p&gt;
	In order for us to actually make money, we have to:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;
		keep expanding our one-off customer base, which is going to hit a limit at some point.&lt;/li&gt;
	&lt;li&gt;
		create a new version, getting the old customer to purchase the updates.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
	Seems simple, right? This is what most companies do, and how most software is sold. You get a license for version 1 and you buy a license for version 2.&lt;/p&gt;
&lt;p&gt;
	So far, so good. But let us consider the implications of that. In order to get the old users to buy the new one, I have to put some really nice stuff in the next version. Which means that I have to do a lot of &amp;ldquo;secret&amp;rdquo; development because I can&amp;rsquo;t just release it on our usual continuous deployment mode. That sucks. And it also means that features that are already coded are actually disabled because we defer them to the next version.&lt;/p&gt;
&lt;p&gt;
	So, the next version of the profilers is going to have to have some interesting features to get people to buy it. One of them is production profiling. It has actually been around for quite a while. It has simply been #ifdef&amp;rsquo;ed out of the product, because it is something that we keep for the next version.&lt;/p&gt;
&lt;p&gt;
	I just checked, and I was acutely surprised by what I found. The initial work for production profiling was done in Jan 2010, it is &lt;em&gt;working &lt;/em&gt;since then. I got side tracked with RavenDB so I never had the chance to actually complete the rest of the features for 2.x and release them all.&lt;/p&gt;
&lt;p&gt;
	In mid 2010 we started experimenting with subscriptions. Instead of having a one time payment model, we moved to a pay as you go. So as long as you were using the profiler, you were paying for it, and in return, we provided all of those new features.&lt;/p&gt;
&lt;p&gt;
	I have been thinking about this a lot lately. I strongly lean toward making the next version of the profiler (coming soon, and it will have a &lt;em&gt;bunch&lt;/em&gt; of nice features) subscription only.&lt;/p&gt;
&lt;p&gt;
	My current thinking it to allow two modes of buying the product. Monthly / yearly subscription and a one time fee that give you 18 months of usage (and doesn&amp;rsquo;t re-charge). That would allow us to keep producing software in incremental steps, without having to go away for a while and work in secret on big ticket features just so we can have enough stuff to put on &amp;ldquo;why you should buy 2.x&amp;rdquo; list.&lt;/p&gt;
&lt;p&gt;
	I would appreciate any feedback that you may have.&lt;/p&gt;
</description><link>http://ayende.com/blog/154689/the-economics-of-continuous-deployment?key=d1efe164-c458-461b-a2c7-def34546a071</link><guid>http://ayende.com/blog/154689/the-economics-of-continuous-deployment?key=d1efe164-c458-461b-a2c7-def34546a071</guid><pubDate>Fri, 10 Feb 2012 14:51:34 GMT</pubDate></item><item><title>Architecture &amp;gt; Code</title><description>&lt;p&gt;Steve Py asks an interesting question in one of the comments to my &lt;a href="http://ayende.com/blog/152769/on-infinite-scalability"&gt;On Infinite Scalability post&lt;/a&gt;:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;Can you elaborate more on: "Note, those changes are not changes to the code, they are architectural and system changes. Where before you had a single database, now you have many. Where before you could use ACID, now you have to use BASE. You need to push a lot more tasks to the background, the user interaction changes, etc."&lt;/p&gt;&lt;/blockquote&gt; &lt;blockquote&gt; &lt;p&gt;When you talk about jumping from 1 server to multiple servers, ACID to BASE, and how user interaction changes, how do you quantify that this is done without code changes?&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;The answer to that is that there is a mistaken assumption here. Changing the architecture &lt;em&gt;is &lt;/em&gt;going to change the code. But usually that is rarely relevant, because changing the architecture is a &lt;em&gt;big&lt;/em&gt; change. If you are moving from a single DB to multiple database, for example, there &lt;strong&gt;are&lt;/strong&gt; going to be code changes, but that isn’t what you worry about. The major change is the architecture differences (how do you split the data, how do you do reporting, can some of the dbs be down, etc).&lt;/p&gt; &lt;p&gt;Moving from ACID to BASE is an even greater change. The code might change a little or change drastically, but that isn’t where a lot of the effort is. Just defining the new system behavior on those scenarios is going to be much more complex. For example, taking something as simple as “user names are unique” would move from being a unique constraint in the database to &lt;em&gt;something&lt;/em&gt; that needs to be able to handle those sort of things in a reasonable fashion.&lt;/p&gt; &lt;p&gt;Depending on your original architecture, it might be anything from replacing a single service implementation to re-writing significant parts of the code. &lt;/p&gt;</description><link>http://ayende.com/blog/153122/architecture-gt-code?key=6a2f7d55-942e-49c6-ab25-0deebd1c3f36</link><guid>http://ayende.com/blog/153122/architecture-gt-code?key=6a2f7d55-942e-49c6-ab25-0deebd1c3f36</guid><pubDate>Fri, 06 Jan 2012 10:00:00 GMT</pubDate></item><item><title>Expanding your horizons: Actions</title><description>&lt;blockquote&gt; &lt;p&gt;In theory, there is no difference between theory and real life.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;In my previous blog post, I discussed my belief that the best value you get from learning is learning the very basic of how our machines operate. From learning about memory management in operating systems to the details of how network protocols like TCP/IP work.&lt;/p&gt; &lt;p&gt;Some of that has got to be theoretical study, actually reading about how those things work, but theory isn’t enough. I don’t care if you know the TCP specs by heart, if you haven’t actually built a real system with it, and &lt;em&gt;experienced &lt;/em&gt;the pain points, it isn’t really meaningful. The best way to learn, at least from my own experiences, is to actually do something.&lt;/p&gt; &lt;p&gt;Because that teaches you several very interesting things:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;What are the differences between the spec and what is actually implemented?&lt;/li&gt; &lt;li&gt;How to resolve common (and not so common problems)?&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;The later is probably the most important thing. I think that I learned most of what I know about HTTP in the process of building an RSS feed reader. I learned a lot about TCP from implementing a proxy system, and I did a lot of learning from a series of failed projects regarding distributed programming in general.&lt;/p&gt; &lt;p&gt;I learned a lot about file systems and how to work with file based storage from &lt;a href="http://www.amazon.com/Practical-System-Design-Dominic-Giampaolo/dp/1558604979"&gt;Practical File System Design&lt;/a&gt; and from building Rhino Queues and Rhino DHT. In retrospect, I did &lt;a href="http://ayende.com/blog/4361/the-nih-dance"&gt;a lot of very different projects&lt;/a&gt; in various areas and technologies. &lt;/p&gt; &lt;p&gt;The best way that I know to get better is to do, to fail, and to learn from what didn’t work. I don’t know of any shortcuts, although I am familiar with plenty of ways of making the road much longer (and usually not very pleasant).&lt;/p&gt; &lt;p&gt;In short, if you want to get better, pick something that you don’t know how to do, and then do it. You might fail, you likely will, but you’ll learn a lot from failing. &lt;/p&gt; &lt;p&gt;I keep drawing a blank when people ask me to suggest options for things to try building, so I thought that I would ask the readers of this blog. What sort of things do you think would be useful to build? Things that would push most people out of their comfort zone and make them learn the fundamentals of how things work.&lt;/p&gt;</description><link>http://ayende.com/blog/152641/expanding-your-horizons-actions?key=a89b5611-3e03-4de8-b260-590bdd61fc14</link><guid>http://ayende.com/blog/152641/expanding-your-horizons-actions?key=a89b5611-3e03-4de8-b260-590bdd61fc14</guid><pubDate>Wed, 28 Dec 2011 10:00:00 GMT</pubDate></item><item><title>Expanding your horizons</title><description>&lt;p&gt;One of the questions that I routinely get asked is “how do you learn”. And the answer that I keep giving is that I had accidently started learning things from the basic building blocks. I still count a C/C++ course that I took over a decade ago as one of the chief reasons why I have a good grounding in how computers actually operate. During that course, we had to do anything from building parts of the C standard library on our own to construct much of the foundation of C++ features in plain C.&lt;/p&gt; &lt;p&gt;That gave me enough understanding of how things are actually implemented to be able to grasp how things are behaving elsewhere. Digging deep into the implementation is almost never a wasted effort. And if you can’t peel away the layer of abstractions, you can’t really say that you know what you are doing. &lt;/p&gt; &lt;p&gt;For example, I count myself ignorant in all manners about WCF, but I have full confidence that I can build a system using it. Not because I understand WCF itself, but because I understand the &lt;em&gt;arena in which it plays&lt;/em&gt;. I don’t need to really understand how a certain technology works, if I already know what are the rules it has to play &lt;em&gt;with&lt;/em&gt;.&lt;/p&gt; &lt;p&gt;Picking on WCF again, if you don’t know firewalls and routers, you can’t really build a WCF system, regardless of how good your memory is about the myriad ways of configuring WCF to do you will. If you can’t use WireShark to figure out why the system is slow to respond to requests, it doesn’t matter if you can compose an WCF envelope message literally on the back of a real world envelope.&amp;nbsp; If you don’t &lt;em&gt;grok&lt;/em&gt; the Fallacies of Distributes Computing, you shouldn’t be trying to build a real system where WCF is used, regardless of whatever certificate you have from Microsoft.&lt;/p&gt; &lt;p&gt;The interesting bit is that for most of what we do, the rules are fairly consistent. We all have to play in Turing’s sand box, after all.&lt;/p&gt; &lt;p&gt;What this means is that learning the details of IP and TCP will be worth it over and over again. Understanding things like memory fetch latencies would be relevant in 5 years and in ten. Knowing what actually goes on in the system, even if it at a somewhat abstracted level is &lt;em&gt;important&lt;/em&gt;. That is what make you the master of the system, instead of its slave.&lt;/p&gt; &lt;p&gt;Some of the things that I especially value, and that is of the top of my head and isn’t a closed list are:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;TCP / UDP – how do they actually work.&lt;/li&gt; &lt;li&gt;HTTP – and implications (for example, state management).&lt;/li&gt; &lt;li&gt;The Fallacies of Distributed Computing.&lt;/li&gt; &lt;li&gt;Disk based storage – efficiently working with it, how file system works.&lt;/li&gt; &lt;li&gt;Memory management in OS and your environment.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Obviously, this is a very short list, and again, it isn’t comprehensive.&amp;nbsp; It is just meant to give you some indications for things that I have found to be useful over and over and over again.&lt;/p&gt; &lt;p&gt;That kind of knowledge isn’t something that is replaced often, and it will help you understand how anyone else has to interact with the same constraints. In fact, it often allows you to accurately guess how they solve a certain problem, because you are aware of the same alternatives that the other side had to solve.&lt;/p&gt; &lt;p&gt;In short, if you seek to be a better developer, dig deep and learn the real basic building blocks for our profession.&lt;/p&gt; &lt;p&gt;In my next post, I’ll discuss strategies for doing that.&lt;/p&gt;</description><link>http://ayende.com/blog/151553/expanding-your-horizons?key=725dd40a-6274-41e5-88fc-6cfe5bbaf3f9</link><guid>http://ayende.com/blog/151553/expanding-your-horizons?key=725dd40a-6274-41e5-88fc-6cfe5bbaf3f9</guid><pubDate>Mon, 26 Dec 2011 10:00:00 GMT</pubDate></item><item><title>Frictionless development: Web.config and connection strings</title><description>&lt;p&gt;This is something that I actually run into a lot at customer sites. They have a lot of friction during development between different connection strings that developers use during development. For example, we may have one developer using:&lt;/p&gt; &lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="RavenDB"&lt;/span&gt; &lt;span class="attr"&gt;connectionString&lt;/span&gt;&lt;span class="kwrd"&gt;="Url=http://localhost:8080"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;While another is using:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="RavenDB"&lt;/span&gt; &lt;span class="attr"&gt;connectionString&lt;/span&gt;&lt;span class="kwrd"&gt;="Url=http://localhost:8191;Database=TheApp"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;This usually causes a hell of a lot of trouble in most teams (or maybe you have developers that use SQL Express, and some who installed SQL Development, etc). &lt;/p&gt;
&lt;p&gt;That is friction, and you want to deal with that as soon as possible. The easiest thing to do is actually:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="Ayende-PC"&lt;/span&gt; &lt;span class="attr"&gt;connectionString&lt;/span&gt;&lt;span class="kwrd"&gt;="Url=http://localhost:8080"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="Ayende-Laptop"&lt;/span&gt; &lt;span class="attr"&gt;connectionString&lt;/span&gt;&lt;span class="kwrd"&gt;="Url=http://localhost:8191;Database=TheApp"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;This works, because the connection string name is now the machine name (System.Environment.MachineName). That is a great first step, because it means that you can get things done without fighting over the connection string in the web.config.&lt;/p&gt;
&lt;p&gt;Another alternative is to have a default connection string, and allow to “override” it with the specification of a connection string specific for the machine.&lt;/p&gt;
&lt;p&gt;It is a small thing, but it actually helps quite a lot. You can extend this to other settings as well. For apps that have a lot of settings, I usually take them out of the Web.config into a Default.config file, and the configuration reader is set to look for [MachineName].config first, and only then at the Default.config file. &lt;/p&gt;</description><link>http://ayende.com/blog/135169/frictionless-development-web-config-and-connection-strings?key=d1ed7eea-7c29-43aa-8fab-522d43590e32</link><guid>http://ayende.com/blog/135169/frictionless-development-web-config-and-connection-strings?key=d1ed7eea-7c29-43aa-8fab-522d43590e32</guid><pubDate>Tue, 15 Nov 2011 10:00:00 GMT</pubDate></item><item><title>Negative hiring decisions, Part II</title><description>&lt;p&gt;&lt;img style="display: inline; float: right" align="right" src="http://ih3.redbubble.net/work.4446603.1.sticker,220x200-pad,220x200,f8f8f8.the-straw-that-broke-the-camels-back-v1.png"&gt;Another case of a candidate completing a task at home and sending it to me which resulted in a negative hiring decision is this:&lt;/p&gt; &lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Button1_Click(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)
{
    &lt;span class="kwrd"&gt;string&lt;/span&gt; connectionString = &lt;span class="str"&gt;@"Data Source=OFFICE7-PC\SQLEXPRESS;Integrated Security=True"&lt;/span&gt;;
    &lt;span class="kwrd"&gt;string&lt;/span&gt; sqlQuery = &lt;span class="str"&gt;"Select UserName From  [Users].[dbo].[UsersInfo] Where UserName = ' "&lt;/span&gt; + TextBox1.Text + &lt;span class="str"&gt;"' and Password = ' "&lt;/span&gt; + TextBox2.Text+&lt;span class="str"&gt;"'"&lt;/span&gt;;
    
    &lt;span class="kwrd"&gt;using&lt;/span&gt; (SqlConnection connection = &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlConnection(connectionString))
    {
        SqlCommand command = &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlCommand(sqlQuery, connection);
        connection.Open();
        SqlDataReader reader = command.ExecuteReader();
        &lt;span class="kwrd"&gt;try&lt;/span&gt;
        {
            &lt;span class="kwrd"&gt;while&lt;/span&gt; (reader.Read())
            {
           
            }
        }
        &lt;span class="kwrd"&gt;finally&lt;/span&gt;
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (reader.HasRows)
            {
                reader.Close();
                Response.Redirect(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;"&lt;font style="background-color: #ffff00"&gt;WebForm2&lt;/font&gt;.aspx?UserName={0}&amp;amp;Password={1}"&lt;/span&gt;, TextBox1.Text, TextBox2.Text));
            }
            &lt;span class="kwrd"&gt;else&lt;/span&gt;
            {
                reader.Close();
                Label1.Text = &lt;span class="str"&gt;"Wrong user or password"&lt;/span&gt;;
            }
        }
    }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;The straw that really broke the camel’s back in this case was the naming of WebForm2. I could sort of figure out the rest, but not bothering to give a real name to the page was over the top.&lt;/p&gt;</description><link>http://ayende.com/blog/102402/negative-hiring-decisions-part-ii?key=1262a2ac-28b4-4a5d-9a6d-a72612340586</link><guid>http://ayende.com/blog/102402/negative-hiring-decisions-part-ii?key=1262a2ac-28b4-4a5d-9a6d-a72612340586</guid><pubDate>Mon, 10 Oct 2011 10:00:00 GMT</pubDate></item><item><title>Full Throttle at TekPub</title><description>&lt;p&gt;&lt;a href="http://wekeroad.com/2011/10/01/the-specialist"&gt;Rob Conery&lt;/a&gt; pinged me a few weeks back, wanting to do another TekPub episode. So I show up, &lt;em&gt;very&lt;/em&gt; early in the morning, and he starts throwing curve balls at me:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;The website is down and we aren’t accepting orders, DO SOMETHING ABOUT THIS NOW!&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;And that was in the first minute or so!&lt;/p&gt; &lt;p&gt;Wait a minute! I thought we were doing a show about… &lt;/p&gt; &lt;p&gt;Oh, this is the Full Throttle episode… &lt;/p&gt; &lt;p&gt;Basically, Rob is just piling requirements and I am trying to play catch up. It is just over an hour, but I think it should be interesting to watch.&amp;nbsp; I really liked &lt;a href="http://wekeroad.com/2011/10/01/the-specialist"&gt;Rob’s post about the show&lt;/a&gt;. But you can also skip this and go directly to &lt;a href="http://tekpub.com/view/ft_triage_oren/1"&gt;the actual show&lt;/a&gt;.&lt;/p&gt;</description><link>http://ayende.com/blog/113665/full-throttle-at-tekpub?key=fd588f7f-69d7-417b-9e53-c3dfc6a1c887</link><guid>http://ayende.com/blog/113665/full-throttle-at-tekpub?key=fd588f7f-69d7-417b-9e53-c3dfc6a1c887</guid><pubDate>Mon, 03 Oct 2011 11:00:00 GMT</pubDate></item><item><title>Hiring Questions&amp;ndash;The phone book&amp;ndash;responding to commentary</title><description>&lt;p&gt;Wow, &lt;a href="http://ayende.com/blog/104449/hiring-questionsndash-the-phone-book"&gt;this post&lt;/a&gt; got a lot more attention than I thought it would. Most of it was along the same lines, so I’ll answer it here.&lt;/p&gt; &lt;p&gt;Anyone suggesting, SQLite, Excel, Access, Esent, Embedded RavenDB, Munin, Embedded FireBird, MS SQL CE, DB4O or anything like it – that isn’t the purpose of the question. I am not trying to figure out if the candidate knows about embedded databases.&lt;/p&gt; &lt;p&gt;Performance isn’t &lt;em&gt;much&lt;/em&gt; of a concern, we expect up to several thousands entries per phonebook, but not beyond that, and speed should be in the human response time range (hundreds of milliseconds).&lt;/p&gt; &lt;p&gt;I rejected JSON / XML file formats because I wanted to make the task harder than just using the built-in Linq API and serializing to a file.&amp;nbsp; &lt;/p&gt; &lt;p&gt;Out of this question, I want actual code that I can try out, not just some high level design. I estimate that if you know what you are doing, this should take less than half an hour. At high school, I think it took about two hours, and that was in unmanaged land.&lt;/p&gt; &lt;p&gt;Some people questioned what is the purpose of this question, under what scenarios is it valid, etc. &lt;/p&gt; &lt;p&gt;Put simply, it is valid because it tests a wide range of topics in a candidate abilities. I don’t feel that I need to go into world building to setup a scenario for an interview question.&lt;/p&gt; &lt;p&gt;&lt;a href="http://scrambledbrains.net/"&gt;Mike McG&lt;/a&gt; &lt;a href="http://ayende.com/blog/104449/hiring-questionsndash-the-phone-book"&gt;put it&lt;/a&gt; beautifully:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;He spells out the requirements for a basic database engine with indexing. It's a multifaceted problem that can expose a lot about a candidate in their solution. Are concerns separated logically? How is performance addressed against disk I/O? How is code correctness validated (e.g. testing)? To submit a project that just wraps another database is disingenuous. He's looking for people that can solve problems head-on, not just pass the buck. &lt;p&gt;&lt;a name="comment20"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;em&gt;Exactly&lt;/em&gt;. More to the point, it forces a candidate to actually do a fairly complex task that still can be done in a short amount of time. It shows me how they think, whatever they have any idea how computers actually work. If you can’t complete this task, you don’t understand basic file IO. That means that you might be a great front end developer, but I need someone who can do more than that. &lt;/p&gt;</description><link>http://ayende.com/blog/112641/hiring-questionsndash-the-phone-bookndash-responding-to-commentary?key=c1db0731-30f5-451d-9e5c-c1df5a04bfde</link><guid>http://ayende.com/blog/112641/hiring-questionsndash-the-phone-bookndash-responding-to-commentary?key=c1db0731-30f5-451d-9e5c-c1df5a04bfde</guid><pubDate>Mon, 03 Oct 2011 09:00:00 GMT</pubDate></item><item><title>Hiring Questions&amp;ndash;The phone book</title><description>&lt;p&gt;One of the things that we ask some of our interviewees is to give us a project that would answer the following:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;We need a reusable library to manage phone books for users. User interface is not required, but we do need an API to create, delete and edit phone book entries. An entry contains a Name (first and last), type (Work, Cellphone or Home) and number. Multiple entries under the same name are allowed. The persistence format of the phone book library is a file, and text based format such as XML or Json has been ruled out. &lt;/p&gt; &lt;p&gt;In addition to creating / editing / deleting, the library also need to support iterating over the list in alphabetical order or by the first or last name of each entry.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;The fun part with this question is that it is testing so many things at the same time, it gives me a &lt;em&gt;lot&lt;/em&gt; of details about the kind of candidate that I have in front of me. From their actual ability to solve a non trivial problem, the way they design and organize code, the way they can understand and implement a set of requirements, etc.&lt;/p&gt; &lt;p&gt;The actual problem is something that I remember doing as an exercise during high school (in Pascal, IIRC).&lt;/p&gt;</description><link>http://ayende.com/blog/104449/hiring-questionsndash-the-phone-book?key=125499a2-4fda-47b2-813f-fd1c83db34a5</link><guid>http://ayende.com/blog/104449/hiring-questionsndash-the-phone-book?key=125499a2-4fda-47b2-813f-fd1c83db34a5</guid><pubDate>Thu, 29 Sep 2011 09:00:00 GMT</pubDate></item><item><title>Pet Projects and Hiring Decisions</title><description>&lt;p&gt;&lt;em&gt;Wow!&lt;/em&gt; The last time I had &lt;a href="http://ayende.com/blog/90113/if-you-donrsquo-t-have-pet-projects-i-donrsquo-t-think-i-want-you"&gt;a post&lt;/a&gt; that roused that sort of reaction, I was talking about politics &lt;em&gt;and &lt;/em&gt;religion. Let us see if I can clarify my thinking and also answer many of the people who commented on the previous post. &lt;/p&gt; &lt;p&gt;One of the core values that I look for when getting new people is their passion for the profession. Put simply, I think about what I do as a hobby that I actually get paid for, and I am looking for people who have the same mentality as I do. There are many ways to actually check for that. We recently made an offer to a candidate simply because her eyes lighted up when she spoke about how she build games to teach kids how to learn Math.&lt;/p&gt; &lt;p&gt;There were a lot of fairly common issues with my approach.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;strong&gt;Indignation &lt;/strong&gt;– how dare you expect me to put my own &lt;em&gt;personal&lt;/em&gt; time into something that looks like work. That also came with a lot of explanation about family, kids and references to me being a slave driver bastard.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Put simply, if you can’t be bothered to improve your own skills, &lt;em&gt;I don’t want you&lt;/em&gt;. &lt;/p&gt; &lt;p&gt;Hibernating Rhinos absolutely believes that you need to invest in your developers, and I strongly believe that we are doing that. It starts from basic policies like if you want a tech book, we’ll buy it for you. Sending developers to courses and conferences, sitting down with people and making sure that they are thinking about their career properly. And a whole lot of other things aside. &lt;/p&gt; &lt;p&gt;Personally, my goal is to keep everyone who works for us right now for at least 5 years, and hopefully longer. And I think that the best way of doing that is to ensure that developers are appreciated, they have a place to grow in professionally and are having to deal with fun, complex and interesting problems for significant parts of their time at work. This does &lt;em&gt;not&lt;/em&gt; remove any obligations on your part to maintain your own skills.&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/Pet-Projects-Hiring-Decisions-and-You_395A/image_5.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: right; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" align="right" src="http://ayende.com/blog/Images/Windows-Live-Writer/Pet-Projects-Hiring-Decisions-and-You_395A/image_thumb_1.png" width="433" height="294"&gt;&lt;/a&gt;In the same sense that I would expect a football player to be playing on a regular basis even in the off session, in the same sense that I wouldn’t visit a doctor who doesn’t spend time getting updated on what is changing in his field, in the same sense that I wouldn’t trust a book critic that doesn’t read for fun – I don’t believe that you can abjurate &lt;em&gt;your own &lt;/em&gt;responsibility to keeping yourself aware of what is actually going on out there.&lt;/p&gt; &lt;p&gt;And I am sorry, I don’t &lt;em&gt;care&lt;/em&gt; if you read a blog or two or ten. If you want to actually &lt;em&gt;learn&lt;/em&gt; new stuff in development, you actually have to sit down and write some code. Anything that isn’t code isn’t really meaningful in our profession. And it is far too easy to talk the talk without being able to walk the walk. My company have absolutely no intention of doing anything with Node.js in the future, I still wrote some code in Node.js, just to be able to see how it feels like to actually do that. I still spend time writing code that is never going to reach production or be in any way useful, just for me to see if I can do something. &lt;/p&gt; &lt;p&gt;If you are a developer, your output is code, and that is what prospective employees will look for. From my perspective, it is like hiring a photographer without looking at any of their pictures. Like getting a cook without tasting anything that he made. &lt;/p&gt; &lt;p&gt;And yes, it is your &lt;em&gt;professional responsibility&lt;/em&gt; to make sure that you are hirable. That means that you keep your skills up to date and that you have something to show to someone that will give them some idea about what you are doing.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;strong&gt;Time &lt;/strong&gt;– I can’t find none.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;There are 168 hours in a week, if you can put 4 – 6 hours a week to hone your own skills, to try things, to just explore… well, that probably indicate something about your priorities. I would like to hire people who think about what they do as a hobby. I usually work 8 – 10 hours days, 5 – 6 days a week. I am married, we’ve got two dogs, I usually read / watch TV for at least 1 – 3 hours a day.&lt;/p&gt; &lt;p&gt;I have &lt;em&gt;been&lt;/em&gt; at the Work Work Work Work All The Time Work Work Work And Some More Work parade. I got the T Shirt, I got the scary Burn Out Episode. I fully understand that working all the time is a Bad Idea. It is Bad Idea for you, it is Bad Idea for the company. This isn’t what I am talking about here.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;strong&gt;Think about the children &lt;/strong&gt;– I have kids, I can’t spend any time out of work doing this.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;That one showed up a lot, actually. I &lt;em&gt;am&lt;/em&gt; thinking about the children. I think it is absolutely irresponsible for someone with kids not to make &lt;em&gt;damn&lt;/em&gt; sure that he is hirable. I am not talking about spending 8 hours at the office, 8 hours doing pet projects and 1.5 minutes with your children (while you got some code compiling). And updating your skills and maintaining a portfolio of projects is something that I think is certainly part of that.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;strong&gt;I read professionally, but I don’t code&amp;nbsp; &lt;/strong&gt;- this is a variation on all of the other excuses, basically. Here is a direct quote: “I often find that well written blog entry/article will provide more education that can be picked up in a few minutes reading than several hours coding. And I can do that in my lunch break.” &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;That is nice, I also like to read a lot of Science Fiction, but I am a terrible writer. If you don’t actually &lt;em&gt;practice&lt;/em&gt;, you aren’t any good. Sure, reading will teach you the high level concepts, but it doesn’t teach you how to apply them. You can read about WCF all day long, but it doesn’t teach you how to handle binding errors. Actually &lt;em&gt;doing &lt;/em&gt;things will teach you that. You need actual practice to become good at something. In theory, there is no difference between reality and theory, and all of that.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;strong&gt;I legally can’t&lt;/strong&gt; - You signed a contract that said that you can’t do any pet projects, or that all of your work is owned by the company.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;I sure do hope that you are well compensated for that, because it is going to make it harder for you to get hired.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;strong&gt;You have a life – &lt;/strong&gt;therefor you can’t spend time on pet projects.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;So do I, I managed. If you can’t, I probably don’t want you.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;strong&gt;Wrong this to do &lt;/strong&gt;- I shouldn’t want someone who is on Stack Overflow all the time, or will spend work time on pet projects.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;This is usually from someone who think that the only thing that I care about is lines of code committed. If someone is on Stack Overflow a lot, or reading a lot of blogs, or &lt;em&gt;writing&lt;/em&gt; a lot of blogs. That is awesome, as long as they manages to complete their tasks I a reasonable amount of time. I routinely write blog posts during work. It helps me think, it clarify my thinking, and it usually gets me a lot of feedback on my ideas. That is a net benefit for me and for the company. &lt;/p&gt; &lt;p&gt;Some people hit a problem and may spin on that for hours, and VS will be the active window for all of that time. That isn’t a good thing!&amp;nbsp; Others will go and answer totally unrelated questions on Stack Overflow while they are thinking on the problem, they come back to VS and resolve the problem in 2 minutes. As long as they manage to do the work, I don’t really care. In fact, having them in Stack Overflow probably means that answers about our products will be answered faster.&lt;/p&gt; &lt;p&gt;As for working on their own personal projects during work. The only thing that you need to do is somehow tie it to actual work. For example, that pet project may be converted to be a sample application for our products. Or it can be a library that we will use, or any of a &lt;em&gt;number&lt;/em&gt; of options that you can use to make sure things interesting.&lt;/p&gt; &lt;p&gt;You should note as well that I am speaking here from our requirements from the candidate, not from what I consider to be our responsibilities toward our employees, I’ll talk about those in another post in more detail.&lt;/p&gt; &lt;p&gt;Then there was this guy, who actively offended me. &lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;The author is a selfish ego maniac who only cares about himself. As an employer, you can choose to consume a resource (employee), get all you can out of it, then discard it. Doing so adds to the evil and bad in the world.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;This is spoken like someone who never actually had to recruit someone, or actually pay to recruit someone. It costs a &lt;em&gt;freaking boatload of money &lt;/em&gt;and take a &lt;em&gt;freaking huge amount of time&lt;/em&gt; to actually find someone that you want to hire. Treating employees as disposable resources is about as stupid as you can get, because we aren’t talking about getting someone that can flip burgers at minimum wage here.&lt;/p&gt; &lt;p&gt;We are talking about 3 – 6 months training period just to get to the point where you can get good results out of a new guy. We are talking about 1 – 3 months of actually looking for the right person before that. I consider employees to be a valuable resource, something that I actively need to encourage, protect and grow. Absolutely the last thing that I want is to try to have a chain of disposable same-as-the-last-one developers in my company.&lt;/p&gt; &lt;p&gt;I &lt;em&gt;have&lt;/em&gt; kicked people out of the office with instructions to go home and rest, because I would like to have them available tomorrow and the next day and month and year. Doing anything else is short sighted, morally repugnant and &lt;em&gt;stupid.&lt;/em&gt;&lt;/p&gt;</description><link>http://ayende.com/blog/102403/pet-projects-and-hiring-decisions?key=40266632-bfac-4c2d-9d22-7456d2d95f53</link><guid>http://ayende.com/blog/102403/pet-projects-and-hiring-decisions?key=40266632-bfac-4c2d-9d22-7456d2d95f53</guid><pubDate>Thu, 15 Sep 2011 05:41:21 GMT</pubDate></item><item><title>If you don&amp;rsquo;t have pet projects, I don&amp;rsquo;t think I want you</title><description>&lt;p&gt;I am busy hiring people now, and it got me thinking a &lt;em&gt;lot&lt;/em&gt; about the sort of things that I want from my developers. In particular, I was inundated in CVs, and I used the following standard reply to help me narrow things down.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;Thank you for your CV. Do you have any projects that you wrote that I can review? Have you done any OSS work that I can look at?&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;The replies are fairly interesting. In particular, I had a somewhat unpleasant exchange with one respondent. In reply for my question, the reply was:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;My employer doesn’t allow any sharing of code. I can find some old projects that I did a while ago and send them to you, I guess.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Obviously, I don’t want to read any code that belong to someone without that someone’s explicit authorization. Someone sending me their current company code is about as bad manner as someone setting up an invite for a job interview on their work calendar (the later actually happened today).&lt;/p&gt; &lt;p&gt;After getting the projects and looking them over a bit, I replied that I don’t think this would be the appropriate position for this respondent. I got the following reply:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;Wait a minute…&lt;/p&gt; &lt;p&gt;Can I know why? I took the trouble to send you stuff that I have done, maybe not the highest quality and caliber, but what I could send right now. You didn’t even interview me. &lt;/p&gt; &lt;p&gt;How exactly did you reach the unequivocal conclusion that I am not a good fit for this job? &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;My response to that was:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;Put simply, we are looking for a .NET developer and one of the most important things that we look for is &lt;em&gt;passion&lt;/em&gt;. In general, we have found that people that care and are interested in what they are doing tend to do other stuff rather than just their work assignments. &lt;/p&gt; &lt;p&gt;In other words, they have their own pet projects, it can be a personal site, a project for a friend, or just some code written to get familiar with some technology.&lt;/p&gt; &lt;p&gt;When you tell me that your only projects outside of work are 5+ years old, that is a bad indication for us. &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;There is more, but it gets to the details and not really relevant for this discussion.&lt;/p&gt; &lt;p&gt;Let me try to preempt the nitpickers. Not having pet projects doesn’t mean that you are a bad developer, nor vice versa.&lt;/p&gt; &lt;p&gt;But I don’t really care about experience, and assuming that you already know the syntax and has some basic knowledge in the framework, we can use you. But the one thing that I learned you can’t give people is the &lt;em&gt;passion&lt;/em&gt; for the field. And that is &lt;em&gt;critical&lt;/em&gt;. Not only because it means that they are either already good or going to be good (it is pretty hard to be passionate about something that you sucks at), but because it means that they &lt;em&gt;care&lt;/em&gt;. &lt;/p&gt; &lt;p&gt;And if they care, it means two very important things:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;The culture of the company is about caring for doing the appropriate thing.&lt;/li&gt; &lt;li&gt;The end result is going to be as awesome as we can get.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Now, if you’ll excuse me, I am going to check out SignalR, because I don’t feel like doing any more RavenDB work today.&lt;/p&gt;</description><link>http://ayende.com/blog/90113/if-you-donrsquo-t-have-pet-projects-i-donrsquo-t-think-i-want-you?key=004444be-9ef7-4fdf-ba67-63448aed6fa6</link><guid>http://ayende.com/blog/90113/if-you-donrsquo-t-have-pet-projects-i-donrsquo-t-think-i-want-you?key=004444be-9ef7-4fdf-ba67-63448aed6fa6</guid><pubDate>Tue, 13 Sep 2011 09:00:00 GMT</pubDate></item><item><title>Node.cs</title><description>&lt;p&gt;No, the title is not a typo. There is so much noise around &lt;a href="http://nodejs.org/"&gt;Node.js&lt;/a&gt;, I thought it would be fun to make a sample of how it would work in C# using the TPL. Here is how the hello world sample would look like:&lt;/p&gt; &lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; HelloHandler : AbstractAsyncHandler
{
    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; Task ProcessRequestAsync(HttpContext context)
    {
        context.Response.ContentType = &lt;span class="str"&gt;"text/plain"&lt;/span&gt;;
        &lt;span class="kwrd"&gt;return&lt;/span&gt; context.Response.Output.WriteAsync(&lt;span class="str"&gt;"Hello World!"&lt;/span&gt;);
    }
}
&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;And the code to make this happen:&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;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; AbstractAsyncHandler : IHttpAsyncHandler
{
    &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; Task ProcessRequestAsync(HttpContext context);

    &lt;span class="kwrd"&gt;private&lt;/span&gt; Task ProcessRequestAsync(HttpContext context, AsyncCallback cb)
    {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; ProcessRequestAsync(context)
            .ContinueWith(task =&amp;gt; cb(task));
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ProcessRequest(HttpContext context)
    {
        ProcessRequestAsync(context).Wait();
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsReusable
    {
        get { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;; }
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, &lt;span class="kwrd"&gt;object&lt;/span&gt; extraData)
    {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; ProcessRequestAsync(context, cb);
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; EndProcessRequest(IAsyncResult result)
    {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (result == &lt;span class="kwrd"&gt;null&lt;/span&gt;)
            &lt;span class="kwrd"&gt;return&lt;/span&gt;;
        ((Task)result).Dispose();
    }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;And you are pretty much done. I combined this with a HttpHandlerFactory which does the routing, and you get fully async, and quite beautiful code.&lt;/p&gt;</description><link>http://ayende.com/blog/72705/node-cs?key=c0f0557a-3072-4075-beef-2aa3acfe7207</link><guid>http://ayende.com/blog/72705/node-cs?key=c0f0557a-3072-4075-beef-2aa3acfe7207</guid><pubDate>Fri, 29 Jul 2011 09:00:00 GMT</pubDate></item><item><title>The evil tricks of &amp;ldquo;It Works On My Machine&amp;rdquo;, in reverse</title><description>&lt;p&gt;The following is quite annoying. I am trying to make an authenticated request to a web server. In this instance, we are talking about communication from one IIS application to another IIS application (the second application is RavenDB hosted inside IIS).&lt;/p&gt; &lt;p&gt;The part that drives me CRAZY is that I am getting this error when I am trying to make an authenticated request, but &lt;em&gt;using the exact same code and credentials&lt;/em&gt;, from another machine, I can make this work just fine.&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/blog/Images/Windows-Live-Writer/56d84ef863a9_E9FE/image_2.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://ayende.com/blog/Images/Windows-Live-Writer/56d84ef863a9_E9FE/image_thumb.png" width="1291" height="193"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;It took me a while to figure out that most important part, when running locally, I was running under my own account, when running remotely, the application run under IIS account. The really annoying part was that even when running on IIS locally, it still worked locally and failed remotely. &lt;/p&gt; &lt;p&gt;It took me even longer to figure out that the local IIS was configure to run under my own account as well &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-sadsmile" alt="Sad smile" src="http://ayende.com/blog/Images/Windows-Live-Writer/56d84ef863a9_E9FE/wlEmoticon-sadsmile_2.png"&gt;&lt;/p&gt; &lt;p&gt;Once that discovery was made, I was able to figure out what is wrong and implement a work around (run the remote IIS site under a custom user name). I know that the actual problem is something relating to permissions on certificate store, but I have no idea &lt;em&gt;how&lt;/em&gt;, or, for that matter, &lt;em&gt;which certificate&lt;/em&gt;?&lt;/p&gt; &lt;p&gt;This is plain old HTTP auth, no SSL, client certs, etc. I am assuming that this is raised because we are using Windows Auth, but I am not sure what is going on here with regards to which certificate should I grant to which user, or even how to do this.&lt;/p&gt; &lt;p&gt;Any ideas?&lt;/p&gt;</description><link>http://ayende.com/blog/15361/the-evil-tricks-of-ldquo-it-works-on-my-machinerdquo-in-reverse?key=ea3b77d1-d219-42ef-b19c-6eed14c92264</link><guid>http://ayende.com/blog/15361/the-evil-tricks-of-ldquo-it-works-on-my-machinerdquo-in-reverse?key=ea3b77d1-d219-42ef-b19c-6eed14c92264</guid><pubDate>Tue, 14 Jun 2011 09:00:00 GMT</pubDate></item><item><title>Generating API Documentation</title><description>&lt;p&gt;I want to generate API documentation for Raven DB. I decided to take the plunge and generate XML documentation, and to ensure that I’ll be good, I marked the “Warnings as Errors” checkbox.&lt;/p&gt;  &lt;p&gt;864 compiler errors later (I spiked this with a single project), I had a compiling build and a pretty good initial XML documentation. The next step was to decide how to go from simple XML documentation to a human readable documentation.&lt;/p&gt;  &lt;p&gt;Almost by default, I checked &lt;a href="http://sandcastle.codeplex.com"&gt;Sandcastle&lt;/a&gt;, unfortunately, I couldn’t figure out how to get this working at all. &lt;a href="http://shfb.codeplex.com/"&gt;Sandcastle Help File Builder&lt;/a&gt; seems the way to go, though. And using that GUI, I had a working project in a minute or two. There are a &lt;em&gt;lot&lt;/em&gt; of options, but I just went with the default ones and hit build. While it was building, I had the following thoughts:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;I didn’t like that it required installation.&lt;/li&gt;    &lt;li&gt;I didn’t know whatever you can easily put it in a build script.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The problem was that generating the documentation (a CHM) took over three and a half minutes.&lt;/p&gt;  &lt;p&gt;I then tried &lt;a href="http://docu.jagregory.com/"&gt;Docu&lt;/a&gt;. It didn’t work, saying that my assembly was in the wrong format. Took me a while to figure out exactly why, but eventually it dawned on me that Raven is a 4.0 project, while Docu is a 3.5. I tried recompiling it for 4.0, but it gave me an error there as well, something about duplicate mscorlib, at which point I decided to drop it. That was also because I didn’t really like the format of the API it generated, but that is beside the point.&lt;/p&gt;  &lt;p&gt;I then tried &lt;a href="http://www.stack.nl/~dimitri/doxygen/"&gt;doxygen&lt;/a&gt;, which I have used in the past. The problem here is the sheer number of &lt;em&gt;options&lt;/em&gt; you have. Luckily, it is very simple to setup using Doxywizard, and the generated documentation looks pretty nice as well. It also take a while, but significantly faster than Sandcastle.&lt;/p&gt;  &lt;p&gt;Next on the list was &lt;a href="http://www.mono-project.com/Generating_Documentation"&gt;MonoDoc&lt;/a&gt;, where I could generate the initial set of XML files, but was unable to run the actual mono doc browser. I am not quite sure why that happened, but it kept complaining that the result was too large. &lt;/p&gt;  &lt;p&gt;I also checked &lt;a href="http://www.helixoft.com/vsdocman/overview.html"&gt;VSDocman&lt;/a&gt;, which is pretty nice. &lt;/p&gt;  &lt;p&gt;All in all, I think that I’ll go with doxygen, it being the simplest by far and generating (OOTB) HTML format that I really like.&lt;/p&gt;</description><link>http://ayende.com/blog/4635/generating-api-documentation?key=b4eab466-e7c6-4ef3-a91d-1a24c96aee33</link><guid>http://ayende.com/blog/4635/generating-api-documentation?key=b4eab466-e7c6-4ef3-a91d-1a24c96aee33</guid><pubDate>Mon, 20 Sep 2010 10:00:00 GMT</pubDate></item><item><title>Being a product owner</title><description>&lt;p&gt;A while ago I have come to the realization that it is impossible for me to everything alone, so I got other people to help me build my projects. In some cases, that was done using OSS, by soliciting contribution from the community. In others, it is a simple commercial transaction, where I give someone money for code.&lt;/p&gt;  &lt;p&gt;I think that I have gotten too used to the OSS model, because I got the following reply for this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/Beingaproductowner_12CF7/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/Beingaproductowner_12CF7/image_thumb.png" width="550" height="440" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;That was somewhat of a rude shock, I was using the same loose language that I always hated when I got specs to implement.&lt;/p&gt;  &lt;p&gt;Those are all &lt;em&gt;really&lt;/em&gt; good questions. &lt;/p&gt;</description><link>http://ayende.com/blog/4621/being-a-product-owner?key=5e499ad3-937a-450a-80a5-47d78deb1619</link><guid>http://ayende.com/blog/4621/being-a-product-owner?key=5e499ad3-937a-450a-80a5-47d78deb1619</guid><pubDate>Tue, 07 Sep 2010 09:00:00 GMT</pubDate></item><item><title>The Law of Conservation of Tradeoffs</title><description>&lt;p&gt;Every so often I see a group of people or a company come up with a new Thing. That new Thing is supposed to solve a set of problems. The common set of problems that people keep trying to solve are:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Data access with relational databases &lt;/li&gt;    &lt;li&gt;Building applications without needing developers &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;And &lt;em&gt;every single time&lt;/em&gt; that I see this, I know that there is going to be a catch involved. For the most part, I can usually even tell you &lt;em&gt;what&lt;/em&gt; the catches involved going to be.&lt;/p&gt;  &lt;p&gt;It isn’t because I am smart, and it is certain that I am not omnificent. It is an issue  of knowing the problem set that is being set out to solve. &lt;/p&gt;  &lt;p&gt;If we will take data access as a good example, there aren’t that many ways tat you can approach it, when all is said and done. There is a set of competing tradeoffs that you have to make. Simplicity vs. usability would probably be the best way to describe it. For example, you can create a very simple data access layer, but you’ll give up on doing automatic change tracking. If you want change tracking, then you need to have Identity Map (even data sets had that, in the sense that every row represented a single row :-) )&lt;/p&gt;  &lt;p&gt;When I need to evaluate a new data access tool, I don’t really need to go too deeply into how it does things, all I need to do is to look at the set of tradeoffs that this tool made. Because you &lt;em&gt;have&lt;/em&gt; to make those tradeoffs, and because I know the play field, it is very easy for me to tell what is actually going on.&lt;/p&gt;  &lt;p&gt;It is pretty much the same thing when we start talking about the options for building applications without developers (a dream that the industry had chased for the last 30 – 40 years or so, unsuccessfully). The problem isn’t in lack of trying, the amount of resources that were invested in the matter are staggering. But again you come into the realm of tradeoffs.&lt;/p&gt;  &lt;p&gt;The best that a system for non developers can give you is CRUD. Which is important, certainly, but for developers, CRUD is mostly a solved problem. If we want plain CRUD screens, we can utilize a whole host of tools and approaches to do them, but beyond the simplest departmental apps, the parts of the application that really matter aren’t really CRUD. For one application, the major point was being able to assign people to their proper slot, a task with significant algorithmic complexity. In another, it was fine tuning the user experience so they would have a seamless journey into the annals of the organization decision making processes.&lt;/p&gt;  &lt;p&gt;And here we get to the same tradeoffs that you have to makes. Developer friendly CRUD system exists in abundance, ASP.Net MVC support for Editor.For(model) is one such example. And they are developer friendly because they give you he bare bones of functionality you need, allow you to define broad swaths.  of the application in general terms, but allow you to fine tune the system easily where you need it. They are also totally incomprehensible if you aren’t a developer. &lt;/p&gt;  &lt;p&gt;A system that is aimed at paradevelopers focus a lot more of visual tooling to aid the paradeveloper achieve their goal. The problem is that in order to do that, we give up the ability to do things in broad strokes, and have to pretty much do anything from scratch for everything that we do. That is acceptable for a paradeveloper, without the concepts of reuse and DRY, but those same features that make it so good for a paradeveloper would be a thorn in a developer’s side. Because they would mean having to do the same thing over &amp;amp; over &amp;amp; over again.&lt;/p&gt;  &lt;p&gt;Tradeoffs, remember?&lt;/p&gt;  &lt;p&gt;And you can’t really create a system that satisfy both. Oh, you can try, but you are going to fail. And you are going to fail because the requirement set of a developer and the requirement set of a paradeveloper are so different as to be totally opposed to one another. For example, one of the things that developers absolutely &lt;em&gt;require&lt;/em&gt; is good version control support. And by good version control support i mean that you can diff between two versions of the application and get a meaningful result from the diff.&lt;/p&gt;  &lt;p&gt;A system for paradeveloper, however, is going to be so choke full of metadata describing what is going on that even if the metadata is in a format that is possible to diff (and all too often it is located in some database, in a format that make it utterly impossible to work with using source control tools). &lt;/p&gt;  &lt;p&gt;Paradeveloper systems encourage you to write what amounts to Bottun1_Click handlers, if they give you even that. Because the paradevelopers that they are meant for have no notion about things like architecture. The problem with that approach when developers do that is that it is obviously one that is unmaintainable.&lt;/p&gt;  &lt;p&gt;And so on, and so on.&lt;/p&gt;  &lt;p&gt;Whenever I see a new system cropping up in a field that I am familiar with, I evaluate it based on the tradeoffs that it must have made. And that is why I tend to be suspicious of the claims made about the new tool around the block, whatever that tool is at any given week. &lt;/p&gt;</description><link>http://ayende.com/blog/4617/the-law-of-conservation-of-tradeoffs?key=e047f079-436d-4163-b120-df25721239c7</link><guid>http://ayende.com/blog/4617/the-law-of-conservation-of-tradeoffs?key=e047f079-436d-4163-b120-df25721239c7</guid><pubDate>Fri, 03 Sep 2010 09:00:00 GMT</pubDate></item><item><title>Horror stories from the trenches: My very first project</title><description>&lt;p&gt;My first day at work, and I am but a young whippersnapper. I arrived, did the usual meet &amp;amp; greet with everybody (and promptly forgot their names), then I was shown to a desk, given a laptop and one of my new coworkers rummaged in a desk drawer for a while before throwing me a document. Well, I &lt;em&gt;say&lt;/em&gt; a document, what I mean is a &lt;em&gt;book&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;It was couple hundred pages, and it was titled: Specs for the Ergaster module in the Heidelbergensis System. When asked what I was supposed to do with it, I was given a very simple answer: &lt;em&gt;Implement&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;I later found on some very interesting aspects on the spec:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The document represented over a year and a half of work.&lt;/li&gt;    &lt;li&gt;The module was being developed for a client of our client.&lt;/li&gt;    &lt;li&gt;The module was meant to be both specific for the sub client needs and at the same time generic enough to used by other clients of our clients.&lt;/li&gt;    &lt;li&gt;The system that we were supposed to be a module in was currently under development and wasn’t in a position to be used by us.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Can you say &lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/HorrorstoriesfromthetrenchesMyveryfirstp_C3F9/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/HorrorstoriesfromthetrenchesMyveryfirstp_C3F9/image_thumb.png" width="217" height="55" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Well, I spent close to two years working on this project. I learned a &lt;em&gt;lot&lt;/em&gt;, from how to proof myself from upstream teams to how &lt;em&gt;not&lt;/em&gt; to design a system. I poured a whole lot of work and effort into this.&lt;/p&gt;  &lt;p&gt;Along the way, I also learned something very interesting about the spec. That was the first time that I actually had to &lt;em&gt;reverse engineer&lt;/em&gt; a specification to understand what the customer actually wanted.&lt;/p&gt;  &lt;p&gt;Two years after we handed off the module to the client, I had the chance to go to lunch with the team leader from that client, so I asked him about the module. He informed me that they still haven’t deployed to production.&lt;/p&gt;  &lt;p&gt;&lt;img src="http://mediahora.files.wordpress.com/2008/01/dvdrewindervs4.jpg" /&gt;&lt;/p&gt;  &lt;p&gt;I was depressed for a week afterward.&lt;/p&gt;</description><link>http://ayende.com/blog/4469/horror-stories-from-the-trenches-my-very-first-project?key=cec41efd-c298-4aa1-9da1-cb0080ad989a</link><guid>http://ayende.com/blog/4469/horror-stories-from-the-trenches-my-very-first-project?key=cec41efd-c298-4aa1-9da1-cb0080ad989a</guid><pubDate>Fri, 23 Apr 2010 09:00:00 GMT</pubDate></item></channel></rss>
