<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:a10="http://www.w3.org/2005/Atom" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel xml:base="http://www.codingforfunandprofit.com/Feed"><title>Coding for Fun and Profit</title><description>A blog of coding tips, tricks, grief and despair.</description><language>en-AU</language><copyright>Copyright (C) Andrew Harcourt. All rights reserved.</copyright><managingEditor>andrewh@uglybugger.org</managingEditor><lastBuildDate>Mon, 30 Jan 2012 08:12:00 +1000</lastBuildDate><image><url>http://www.codingforfunandprofit.com/Content/Me.jpg</url><title>Coding for Fun and Profit</title><link /></image><a10:id>http://www.codingforfunandprofit.com/Feed</a10:id><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/CodingForFunAndProfit" /><feedburner:info uri="codingforfunandprofit" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><geo:lat>-27.45532185226382</geo:lat><geo:long>153.0486810207367</geo:long><item xml:base="Home/Post/2012.01.30.0812"><guid isPermaLink="false">2012.01.30.0812</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/Ynonk3oxskE/2012.01.30.0812</link><author>andrewh@uglybugger.org</author><title>Software Project Rescue: A Fairy Tale (@QALMUG on Friday the 3rd)</title><description>&lt;p&gt;I'm presenting &lt;a href="http://qalmug.org/?p=95"&gt;this&lt;/a&gt; on Friday morning at the &lt;a href="http://www.qalmug.org/"&gt;QLD ALM User Group&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;This is a tale of a naïve protagonist, misguided advisors, princesses[1], dragons[2] and knights[3] in
  shining armour[4].&lt;br /&gt;
  &lt;br /&gt;
  Like most fairy tales, this story has an idyllic beginning, a middle, and a happy ending. Also like most
  fairy tales, the middle of this tale is a grim, dark, scary journey through the Woods of Requirements,
  blithely past the Ivory Tower of Architecture, into the Depths of Design Despair, under the Mountain of
  Technical Debt and finishing with an agile leap of faith over the Waterfall of Doom to reach the rainbow
  on the other side.[5]&lt;br /&gt;
  &lt;br /&gt;
  This talk starts with a post-mortem of a 3.5-year, $2m project that went horribly wrong. We’ll look at
  where the project failed: the architectural choices; the management strategies; the personalities
  involved and some sample code. We’ll also look at the changes that were made to bring the project back
  on track, get its wildly spiralling technical debt under control, re-release a functioning version and
  refactor it to something testable – and all in 3.5 weeks.&lt;br /&gt;
  &lt;br /&gt;
  Finally, we’ll discuss ways to identify the issues encountered in this project so that you can spot them
  before they bite, strategies for regaining control over a project that’s already in trouble, and
  effective methods for managing troublesome stakeholders.&lt;br /&gt;
  &lt;br /&gt;
  [1] There may or may not be actual princesses.&lt;br/&gt;
  [2] Or dragons.&lt;br/&gt;
  [3] Or knights.&lt;br/&gt;
  [4] Motorcycle helmets.&lt;br/&gt;
  [5] Bingo!  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I hope people think it's worth getting up early for :)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/Ynonk3oxskE" height="1" width="1"/&gt;</description><pubDate>Mon, 30 Jan 2012 08:12:00 +1000</pubDate><a10:updated>2012-01-30T08:12:00+10:00</a10:updated><a10:content type="xhtml"><p>I'm presenting <a href="http://qalmug.org/?p=95">this</a> on Friday morning at the <a href="http://www.qalmug.org/">QLD ALM User Group</a>:</p>

<blockquote>
  <p>This is a tale of a naïve protagonist, misguided advisors, princesses[1], dragons[2] and knights[3] in
  shining armour[4].<br />
  <br />
  Like most fairy tales, this story has an idyllic beginning, a middle, and a happy ending. Also like most
  fairy tales, the middle of this tale is a grim, dark, scary journey through the Woods of Requirements,
  blithely past the Ivory Tower of Architecture, into the Depths of Design Despair, under the Mountain of
  Technical Debt and finishing with an agile leap of faith over the Waterfall of Doom to reach the rainbow
  on the other side.[5]<br />
  <br />
  This talk starts with a post-mortem of a 3.5-year, $2m project that went horribly wrong. We’ll look at
  where the project failed: the architectural choices; the management strategies; the personalities
  involved and some sample code. We’ll also look at the changes that were made to bring the project back
  on track, get its wildly spiralling technical debt under control, re-release a functioning version and
  refactor it to something testable – and all in 3.5 weeks.<br />
  <br />
  Finally, we’ll discuss ways to identify the issues encountered in this project so that you can spot them
  before they bite, strategies for regaining control over a project that’s already in trouble, and
  effective methods for managing troublesome stakeholders.<br />
  <br />
  [1] There may or may not be actual princesses.<br />
  [2] Or dragons.<br />
  [3] Or knights.<br />
  [4] Motorcycle helmets.<br />
  [5] Bingo!  </p>
</blockquote>

<p>I hope people think it's worth getting up early for :)</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2012.01.30.0812</feedburner:origLink></item><item xml:base="Home/Post/2012.01.25.1528"><guid isPermaLink="false">2012.01.25.1528</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/3PGTNMWqKpU/2012.01.25.1528</link><author>andrewh@uglybugger.org</author><title>Dear VMware</title><description>&lt;p&gt;Hi,&lt;/p&gt;

&lt;p&gt;I didn't even think you remembered me. I used to have a huge crush on you in university. You were my
first virtual crush and I lusted after what you could do for a long time. We even dated a couple of
times. Nothing serious; just a few dinners, movies and virtual servers.&lt;/p&gt;

&lt;p&gt;Then we both moved on.&lt;/p&gt;

&lt;p&gt;We both got older and wiser over the years, and when you asked me to try things again I was at
first surprised that you even remembered me, but I thought it might be worth a shot.&lt;/p&gt;

&lt;p&gt;I was wrong.&lt;/p&gt;

&lt;p&gt;You're fitter than before, I'll grant. You look even more attractive now than then; you're faster and
more versatile, and those are good things. You were the first to show me what Windows 8 could look
like, and I'll never forget that.&lt;/p&gt;

&lt;p&gt;But here's the killer: you're an unpredictable bitch.&lt;/p&gt;

&lt;p&gt;It's not okay to promise one thing and then do another. When I changed the memory settings on a
VM, you told me that you'd need apply those changes once I restarted the VM. You didn't tell me
that you'd suspend the VM to disk and break what I was doing. I'm not arguing about who's more
important; I'm upset that you didn't ask.&lt;/p&gt;

&lt;p&gt;It's not okay to lie about your connections. You said that Bridged Networking was a mutual
friend, but it turns out you don't really know him that well at all. You spend all your time hanging
out with his loser cousins, NAT and Host-only. What sort of loser name is Host-only, anyway?&lt;/p&gt;

&lt;p&gt;It's not okay to spew services all over the couch (I count five) after a big night of installing,
to leave your toothbrush in my bathroom or your icons in my system tray without asking. You keep
changing them, too, so it always feels like there's a stranger in the house. Which, I guess, there is.&lt;/p&gt;

&lt;p&gt;The last straw, however, is this: just like changing the furnishings in my apartment, it's not
okay to rearrange my underwear drawer, hang your own pictures or remove my Visual Studio keyboard
mappings and replace them with your own. You messed with my Visual Studio keyboard mappings! That's
total relationship death right there.&lt;/p&gt;

&lt;p&gt;Maybe you can sort out your issues and maybe you can't. Either way, you need to get some help. Even
your parents (&lt;a href="https://twitter.com/#!/VMware"&gt;@vmware&lt;/a&gt;) don't answer when people tell them what you've
been up to.&lt;/p&gt;

&lt;p&gt;VMware, I'm over you. I'm off to take your cute little sister, Hyper-V, out to dinner.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/3PGTNMWqKpU" height="1" width="1"/&gt;</description><pubDate>Wed, 25 Jan 2012 15:28:00 +1000</pubDate><a10:updated>2012-01-25T15:28:00+10:00</a10:updated><a10:content type="xhtml"><p>Hi,</p>

<p>I didn't even think you remembered me. I used to have a huge crush on you in university. You were my
first virtual crush and I lusted after what you could do for a long time. We even dated a couple of
times. Nothing serious; just a few dinners, movies and virtual servers.</p>

<p>Then we both moved on.</p>

<p>We both got older and wiser over the years, and when you asked me to try things again I was at
first surprised that you even remembered me, but I thought it might be worth a shot.</p>

<p>I was wrong.</p>

<p>You're fitter than before, I'll grant. You look even more attractive now than then; you're faster and
more versatile, and those are good things. You were the first to show me what Windows 8 could look
like, and I'll never forget that.</p>

<p>But here's the killer: you're an unpredictable bitch.</p>

<p>It's not okay to promise one thing and then do another. When I changed the memory settings on a
VM, you told me that you'd need apply those changes once I restarted the VM. You didn't tell me
that you'd suspend the VM to disk and break what I was doing. I'm not arguing about who's more
important; I'm upset that you didn't ask.</p>

<p>It's not okay to lie about your connections. You said that Bridged Networking was a mutual
friend, but it turns out you don't really know him that well at all. You spend all your time hanging
out with his loser cousins, NAT and Host-only. What sort of loser name is Host-only, anyway?</p>

<p>It's not okay to spew services all over the couch (I count five) after a big night of installing,
to leave your toothbrush in my bathroom or your icons in my system tray without asking. You keep
changing them, too, so it always feels like there's a stranger in the house. Which, I guess, there is.</p>

<p>The last straw, however, is this: just like changing the furnishings in my apartment, it's not
okay to rearrange my underwear drawer, hang your own pictures or remove my Visual Studio keyboard
mappings and replace them with your own. You messed with my Visual Studio keyboard mappings! That's
total relationship death right there.</p>

<p>Maybe you can sort out your issues and maybe you can't. Either way, you need to get some help. Even
your parents (<a href="https://twitter.com/#!/VMware">@vmware</a>) don't answer when people tell them what you've
been up to.</p>

<p>VMware, I'm over you. I'm off to take your cute little sister, Hyper-V, out to dinner.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2012.01.25.1528</feedburner:origLink></item><item xml:base="Home/Post/2012.01.09.2127"><guid isPermaLink="false">2012.01.09.2127</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/Ckb5Kch7Gg8/2012.01.09.2127</link><author>andrewh@uglybugger.org</author><title>Wow. DISQUS rocks.</title><description>&lt;p&gt;Wow. I was introduced today by &lt;a href="http://aussiecoder.com/"&gt;Andrew Tobin&lt;/a&gt; (&lt;a href="https://twitter.com/#!/tobin"&gt;@tobin&lt;/a&gt;) to &lt;a href="http://disqus.com/"&gt;DISQUS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'd tweeted about my replacement blog engine, and mentioned in my previous post that I hadn't yet
implemented commenting. He suggested DISQUS, which is an online commenting service that I'd somehow
never heard of. How had I not heard of this?!&lt;/p&gt;

&lt;p&gt;From sign-up to comments working and tested, it's taken about half an hour of effort. If you need
a public commenting solution, I genuinely can't think why you'd write your own any more. Nice work :)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/Ckb5Kch7Gg8" height="1" width="1"/&gt;</description><pubDate>Mon, 09 Jan 2012 21:27:00 +1000</pubDate><a10:updated>2012-01-09T21:27:00+10:00</a10:updated><a10:content type="xhtml"><p>Wow. I was introduced today by <a href="http://aussiecoder.com/">Andrew Tobin</a> (<a href="https://twitter.com/#!/tobin">@tobin</a>) to <a href="http://disqus.com/">DISQUS</a>.</p>

<p>I'd tweeted about my replacement blog engine, and mentioned in my previous post that I hadn't yet
implemented commenting. He suggested DISQUS, which is an online commenting service that I'd somehow
never heard of. How had I not heard of this?!</p>

<p>From sign-up to comments working and tested, it's taken about half an hour of effort. If you need
a public commenting solution, I genuinely can't think why you'd write your own any more. Nice work :)</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2012.01.09.2127</feedburner:origLink></item><item xml:base="Home/Post/2012.01.08.2342"><guid isPermaLink="false">2012.01.08.2342</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/84yTkw-D0Uk/2012.01.08.2342</link><author>andrewh@uglybugger.org</author><title>New Blog Engine</title><description>&lt;p&gt;As per my &lt;a href="http://www.uglybugger.org/Home/Post/2011.12.30.2005"&gt;New Beginnings&lt;/a&gt; post, I've tried a
couple of times recently to move to &lt;a href="http://www.funnelweblog.com/"&gt;FunnelWeb&lt;/a&gt;. I've failed. The reasons
for my failure are simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I wanted to host everything on &lt;a href="http://www.appharbor.com"&gt;AppHarbor&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;I wanted everything (including posts and comments) under source control.&lt;/li&gt;
&lt;li&gt;I wanted a custom look and feel.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything that I wanted &lt;em&gt;could&lt;/em&gt; be done using FunnelWeb, but when I started doing it I realised that
I was re-working lots of code that I didn't actually expect to use in production and that, in a nutshell,
a blog is just a web site and making a database-driven web site only really makes sense when there are
frequently-changing data.&lt;/p&gt;

&lt;p&gt;In addition, I kept finding myself firing up Visual Studio in order to write code snippets, then doing
horrible things to them (I'm looking at you, Windows Live Writer) in order to make them appear. If I'd
used FunnelWeb then I could use markdown (good) but then I'd have had to use Visual Studio to write any
code snippets anyway.&lt;/p&gt;

&lt;p&gt;I thought about it some more, and decided that I &lt;em&gt;like&lt;/em&gt; writing code in Visual Studio, and can live with
using it as my main blog text editor. So... blog posts are all now written using VS.&lt;/p&gt;

&lt;p&gt;The other advantage of having a blog that's entirely under source control is that it's trivial to back up,
restore and redeploy - and I can deploy it anywhere.&lt;/p&gt;

&lt;p&gt;There's a bunch of stuff that doesn't work yet, but I can live with that. RSS isn't hooked up properly;
hence feeding to Twitter (TwitterFeed via RSS) doesn't work. Comments aren't ready for prime-time either,
but I expect they'll be done shortly. There's also no mobile browser detection, but that's in the pipeline.&lt;/p&gt;

&lt;p&gt;Why did I want to change in the first place? Because there have been lots of blog posts that I've
found myself wanting to write, but needing to include too many code snippets. Gists are fine but hurt to
include via script tags; pre-formatted code blocks are ick and screenshots are kind of pointless when
my goal is to allow people to easily copy/paste the code I'm posting. So... now that my roadblocks are mostly
out of the way, expect to see more useful stuff here. You can hold me to that :)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/84yTkw-D0Uk" height="1" width="1"/&gt;</description><pubDate>Sun, 08 Jan 2012 23:42:00 +1000</pubDate><a10:updated>2012-01-08T23:42:00+10:00</a10:updated><a10:content type="xhtml"><p>As per my <a href="http://www.uglybugger.org/Home/Post/2011.12.30.2005">New Beginnings</a> post, I've tried a
couple of times recently to move to <a href="http://www.funnelweblog.com/">FunnelWeb</a>. I've failed. The reasons
for my failure are simple:</p>

<ul>
<li>I wanted to host everything on <a href="http://www.appharbor.com">AppHarbor</a>.</li>
<li>I wanted everything (including posts and comments) under source control.</li>
<li>I wanted a custom look and feel.</li>
</ul>

<p>Everything that I wanted <em>could</em> be done using FunnelWeb, but when I started doing it I realised that
I was re-working lots of code that I didn't actually expect to use in production and that, in a nutshell,
a blog is just a web site and making a database-driven web site only really makes sense when there are
frequently-changing data.</p>

<p>In addition, I kept finding myself firing up Visual Studio in order to write code snippets, then doing
horrible things to them (I'm looking at you, Windows Live Writer) in order to make them appear. If I'd
used FunnelWeb then I could use markdown (good) but then I'd have had to use Visual Studio to write any
code snippets anyway.</p>

<p>I thought about it some more, and decided that I <em>like</em> writing code in Visual Studio, and can live with
using it as my main blog text editor. So... blog posts are all now written using VS.</p>

<p>The other advantage of having a blog that's entirely under source control is that it's trivial to back up,
restore and redeploy - and I can deploy it anywhere.</p>

<p>There's a bunch of stuff that doesn't work yet, but I can live with that. RSS isn't hooked up properly;
hence feeding to Twitter (TwitterFeed via RSS) doesn't work. Comments aren't ready for prime-time either,
but I expect they'll be done shortly. There's also no mobile browser detection, but that's in the pipeline.</p>

<p>Why did I want to change in the first place? Because there have been lots of blog posts that I've
found myself wanting to write, but needing to include too many code snippets. Gists are fine but hurt to
include via script tags; pre-formatted code blocks are ick and screenshots are kind of pointless when
my goal is to allow people to easily copy/paste the code I'm posting. So... now that my roadblocks are mostly
out of the way, expect to see more useful stuff here. You can hold me to that :)</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2012.01.08.2342</feedburner:origLink></item><item xml:base="Home/Post/2011.10.14.0450"><guid isPermaLink="false">2011.10.14.0450</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/hnD635vT6iM/2011.10.14.0450</link><author>andrewh@uglybugger.org</author><title>The Book of Process</title><description>&lt;blockquote&gt;
  &lt;ol&gt;
  &lt;li&gt;&lt;p&gt;Once upon a time, a company's youthful founder lucked upon a successful method of performing a task.&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;&lt;p&gt;The task was profitable, and therefore it was good.&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;&lt;p&gt;The founder wrote down that method and bestowed it unto her minions.&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;&lt;p&gt;She said unto them, "This is The Process, and it is good."&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;&lt;p&gt;The minions performed The Process until the end of days.&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;&lt;p&gt;And they all lived happily ever after.&lt;/p&gt;&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;Bollocks.&lt;/p&gt;

&lt;p&gt;The adage, "If it ain't broke, don't fix it" has a corollary best expressed by Tess Ferrandez: "&lt;a href="http://blogs.msdn.com/b/tess/" target="_blank"&gt;If broken it is, fix it you should&lt;/a&gt;." Or at least, "If broken it is, don't sodding well inflict it on everyone just because you're too lazy or stupid to bother changing it."&lt;/p&gt;

&lt;p&gt;If you haven't figured it out yet, I'm referring to internal corporate processes that serve no purpose other than demonstrating to some ISO 9000 certification minion that a documented process exists.&lt;/p&gt;

&lt;p&gt;It seems as if every organisation, once it reaches a certain size, goes into the "create process and perish" stage. If it's a private enterprise it'll die a long, slow, horrible death of three-thousand triplicate signatures, but if it's a government enterprise then it's never going to die and we're all going to hate it.&lt;/p&gt;

&lt;p&gt;Is hate too strong a word? I don't think so. Show me a single person who's dealt with a government department and left happy, and I'll show you someone who's on far too many psychedelics to be on the same planet as the rest of us. &lt;em&gt;We hate government agencies because they're slow, bloated and inefficient.&lt;/em&gt; (We hate individual governments, too, but for different reasons. That's just not the point of this post.)&lt;/p&gt;

&lt;p&gt;So, given the choice, why do organisations choose to have processes that make them slow, bloated and despised? Your guess is as good as mine, but I think it's to do with some misguided idea that they should be able to have any muppet follow the process and get the same result. Guess what, ladies and gentlemen: if you have a muppet-followable process then you'll end up hiring muppets to implement it - which is at best embarrassing while the process makes sense, but an utter disaster once the process becomes obsolete and everyone refuses to recognise it.&lt;/p&gt;

&lt;p&gt;The Book of Process above &lt;em&gt;should&lt;/em&gt; read something like this:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;ol&gt;
  &lt;li&gt;&lt;p&gt;The minions performed The Process until the end of days.&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;&lt;p&gt;The end of days arrived with a pitchfork-waving, torch-brandishing mob of angry citizens who burned the company's offices down around the minions.&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;&lt;p&gt;The minions could not find &lt;strike&gt;their backsides with both hands&lt;/strike&gt; the "In Case of Fire" process document quickly enough to escape.&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;&lt;p&gt;And the citizens all rejoiced, and lived happily ever after.&lt;/p&gt;&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;Is process hurting your company? If so, it might be worth considering whether you actually &lt;em&gt;need&lt;/em&gt; all your documented processes, or whether you can just set desired outcomes and performance metrics, and leave your smart people to figure things out for themselv...&lt;/p&gt;

&lt;p&gt;... oh. I get it. Smart people. They've already left. Never mind.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/hnD635vT6iM" height="1" width="1"/&gt;</description><pubDate>Fri, 14 Oct 2011 04:50:00 +1000</pubDate><a10:updated>2011-10-14T04:50:00+10:00</a10:updated><a10:content type="xhtml"><blockquote>
  <ol>
  <li><p>Once upon a time, a company's youthful founder lucked upon a successful method of performing a task.</p></li>
  <li><p>The task was profitable, and therefore it was good.</p></li>
  <li><p>The founder wrote down that method and bestowed it unto her minions.</p></li>
  <li><p>She said unto them, "This is The Process, and it is good."</p></li>
  <li><p>The minions performed The Process until the end of days.</p></li>
  <li><p>And they all lived happily ever after.</p></li>
  </ol>
</blockquote>

<p>Bollocks.</p>

<p>The adage, "If it ain't broke, don't fix it" has a corollary best expressed by Tess Ferrandez: "<a href="http://blogs.msdn.com/b/tess/" target="_blank">If broken it is, fix it you should</a>." Or at least, "If broken it is, don't sodding well inflict it on everyone just because you're too lazy or stupid to bother changing it."</p>

<p>If you haven't figured it out yet, I'm referring to internal corporate processes that serve no purpose other than demonstrating to some ISO 9000 certification minion that a documented process exists.</p>

<p>It seems as if every organisation, once it reaches a certain size, goes into the "create process and perish" stage. If it's a private enterprise it'll die a long, slow, horrible death of three-thousand triplicate signatures, but if it's a government enterprise then it's never going to die and we're all going to hate it.</p>

<p>Is hate too strong a word? I don't think so. Show me a single person who's dealt with a government department and left happy, and I'll show you someone who's on far too many psychedelics to be on the same planet as the rest of us. <em>We hate government agencies because they're slow, bloated and inefficient.</em> (We hate individual governments, too, but for different reasons. That's just not the point of this post.)</p>

<p>So, given the choice, why do organisations choose to have processes that make them slow, bloated and despised? Your guess is as good as mine, but I think it's to do with some misguided idea that they should be able to have any muppet follow the process and get the same result. Guess what, ladies and gentlemen: if you have a muppet-followable process then you'll end up hiring muppets to implement it - which is at best embarrassing while the process makes sense, but an utter disaster once the process becomes obsolete and everyone refuses to recognise it.</p>

<p>The Book of Process above <em>should</em> read something like this:</p>

<blockquote>
  <ol>
  <li><p>The minions performed The Process until the end of days.</p></li>
  <li><p>The end of days arrived with a pitchfork-waving, torch-brandishing mob of angry citizens who burned the company's offices down around the minions.</p></li>
  <li><p>The minions could not find <strike>their backsides with both hands</strike> the "In Case of Fire" process document quickly enough to escape.</p></li>
  <li><p>And the citizens all rejoiced, and lived happily ever after.</p></li>
  </ol>
</blockquote>

<p>Is process hurting your company? If so, it might be worth considering whether you actually <em>need</em> all your documented processes, or whether you can just set desired outcomes and performance metrics, and leave your smart people to figure things out for themselv...</p>

<p>... oh. I get it. Smart people. They've already left. Never mind.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2011.10.14.0450</feedburner:origLink></item><item xml:base="Home/Post/2011.10.06.1146"><guid isPermaLink="false">2011.10.06.1146</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/AjoH3QvVZwQ/2011.10.06.1146</link><author>andrewh@uglybugger.org</author><title>Farewell, Steve</title><description>&lt;p&gt;There's nothing I can say that hasn't been said before by someone else, about someone else, for similar reasons. Nonetheless: today the world has lost a giant and we are all the poorer for it.&lt;/p&gt;

&lt;p&gt;Steve Jobs changed the game so many times that people lost count. His visionary genius, his personal drive and his dedication to making absolute perfection commonplace have left an indelible legacy in which we all share.&lt;/p&gt;

&lt;p&gt;His arrogance, his of-course-my-way-is-better approach and his unwillingness to compromise cultivated dislike amongst many, but then, nobody else gave the world the iPhone or the MacBook. Steve's arrogance was justified and, well, his way generally &lt;em&gt;was&lt;/em&gt; better.&lt;/p&gt;

&lt;p&gt;Steve's example should prompt all of us - in all industries - to treat elegant, beautiful design as a first-class consideration when creating something. If you build something people love, they will love you for it.&lt;/p&gt;

&lt;p&gt;Farewell, Steve.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.apple.com/" target="_blank"&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://lh6.ggpht.com/-sHIUBdzzW1U/To0IZOak0kI/AAAAAAAAAUw/Frefutp_DuY/image%25255B9%25255D.png?imgmax=800" width="595" height="484" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/AjoH3QvVZwQ" height="1" width="1"/&gt;</description><pubDate>Thu, 06 Oct 2011 11:46:00 +1000</pubDate><a10:updated>2011-10-06T11:46:00+10:00</a10:updated><a10:content type="xhtml"><p>There's nothing I can say that hasn't been said before by someone else, about someone else, for similar reasons. Nonetheless: today the world has lost a giant and we are all the poorer for it.</p>

<p>Steve Jobs changed the game so many times that people lost count. His visionary genius, his personal drive and his dedication to making absolute perfection commonplace have left an indelible legacy in which we all share.</p>

<p>His arrogance, his of-course-my-way-is-better approach and his unwillingness to compromise cultivated dislike amongst many, but then, nobody else gave the world the iPhone or the MacBook. Steve's arrogance was justified and, well, his way generally <em>was</em> better.</p>

<p>Steve's example should prompt all of us - in all industries - to treat elegant, beautiful design as a first-class consideration when creating something. If you build something people love, they will love you for it.</p>

<p>Farewell, Steve.</p>

<p><a href="http://www.apple.com/" target="_blank"><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://lh6.ggpht.com/-sHIUBdzzW1U/To0IZOak0kI/AAAAAAAAAUw/Frefutp_DuY/image%25255B9%25255D.png?imgmax=800" width="595" height="484" /></a></p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2011.10.06.1146</feedburner:origLink></item><item xml:base="Home/Post/2011.09.29.0931"><guid isPermaLink="false">2011.09.29.0931</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/HcuD4Fe9oF4/2011.09.29.0931</link><author>andrewh@uglybugger.org</author><title>The Forgotten Convention-Based Test Harness</title><description>&lt;p&gt;I'm writing another MVC3 app. I'm in the same world of pain with respect to magic strings and anonymous classes.
I don't like it here.&lt;/p&gt;

&lt;p&gt;I'm sorry, but who on earth thought that this was a good idea for a method signature?&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.codingforfunandprofit.com/Posts/2011/2011.09.29.0931/Screenshot1.png" alt="Screenshot"/&gt;&lt;/p&gt;

&lt;p&gt;I mean, seriously? Six strings and a Dictionary&amp;lt;string, object&amp;gt;? And that's a sensible collection of arguments? Why
not add in a RouteValueDictionary (another string/object dictionary) for good measure? Oh, never mind.&lt;/p&gt;

&lt;p&gt;But surely there are smarter overloads than that, right? Well, yes - and honestly, you just couldn't make this stuff up:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.codingforfunandprofit.com/Posts/2011/2011.09.29.0931/Screenshot2.png" alt="Screenshot"/&gt;&lt;/p&gt;

&lt;p&gt;Oh My Friendly Geranium, but who on earth thought of this - and why wasn't it knocked on the head by someone sensible?
MVC team: I'm really sorry, but IMO you've completely missed the point of a strongly-typed language. I know you've
taken a lot of flak for this over the past few years but, to be honest, it's kind-of deserved :(&lt;/p&gt;

&lt;p&gt;So, what on earth do we do about it?&lt;/p&gt;

&lt;p&gt;When we're in a world of magic-string pain, the first thing to do is generally start creating some conventions. The
second thing, of course, is that we test those conventions using unit tests. Hold on a second, though: we're using a
strongly-typed language and yet we're *writing unit tests *to test our conventions because we're using strings and
anonymous classes? Why don't we have a tool that does this for us?&lt;/p&gt;

&lt;p&gt;We want a convention-based test harness that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Runs on every build. &lt;/li&gt;
&lt;li&gt;Has a set of conventions that are clear and unambiguous. &lt;/li&gt;
&lt;li&gt;Doesn't make us manually write tests. &lt;/li&gt;
&lt;li&gt;Will auto-generate test cases for every new piece of code we write. &lt;/li&gt;
&lt;li&gt;Is refactoring-friendly. &lt;/li&gt;
&lt;li&gt;Is fast. &lt;/li&gt;
&lt;li&gt;Will fail the build if something's wrong. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I think we've forgotten something important. Can anyone point to a tool that's all of the above, comes pre-installed
with every version of Visual Studio and requires zero integration work, no NuGet packages and &lt;em&gt;just works&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;Anyone? Anyone? No? Here's one: csc.exe. Yep, that's right: use the compiler.&lt;/p&gt;

&lt;p&gt;Call me old-school, but a compiler is all of the above. Consider this method:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.codingforfunandprofit.com/Posts/2011/2011.09.29.0931/Screenshot3.png" alt="Screenshot"/&gt;&lt;/p&gt;

&lt;p&gt;Think about it: why don't I have to test that a and b are integers? Sure, I should be testing for edge cases here, but
I don't have to type-check or null-check my inputs. Why not? Because the compiler is enforcing the convention that
when I say "int", I mean a 32-bit integer and it simply won't let anyone pass in anything else.&lt;/p&gt;

&lt;p&gt;I don't have to write a single unit test to enforce these conventions. The compiler will provide me with fast and
reliable feedback - at compile time - if I've broken anything, which is far better than getting the feedback at
run-time using unit tests (or worse, at run-time when a user hits an issue).&lt;/p&gt;

&lt;p&gt;I think we as developers can afford to take a bit more time to write strongly-typed code, e.g. HtmlHelpers for
controller actions. Try this one:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.codingforfunandprofit.com/Posts/2011/2011.09.29.0931/Screenshot4.png" alt="Screenshot"/&gt;&lt;/p&gt;

&lt;p&gt;You can make your code infer the controller name, the action name, the area and all sorts of things without ever having
a magic string. You could even add strongly-typed parameters to it (built using a fluent interface) so that it's
effectively impossible to get it wrong without the compiler complaining.&lt;/p&gt;

&lt;p&gt;So why don't more people use such a great convention-based test tool? I have no idea.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/HcuD4Fe9oF4" height="1" width="1"/&gt;</description><pubDate>Thu, 29 Sep 2011 09:31:00 +1000</pubDate><a10:updated>2011-09-29T09:31:00+10:00</a10:updated><a10:content type="xhtml"><p>I'm writing another MVC3 app. I'm in the same world of pain with respect to magic strings and anonymous classes.
I don't like it here.</p>

<p>I'm sorry, but who on earth thought that this was a good idea for a method signature?</p>

<p><img src="http://www.codingforfunandprofit.com/Posts/2011/2011.09.29.0931/Screenshot1.png" alt="Screenshot" /></p>

<p>I mean, seriously? Six strings and a Dictionary&lt;string, object&gt;? And that's a sensible collection of arguments? Why
not add in a RouteValueDictionary (another string/object dictionary) for good measure? Oh, never mind.</p>

<p>But surely there are smarter overloads than that, right? Well, yes - and honestly, you just couldn't make this stuff up:</p>

<p><img src="http://www.codingforfunandprofit.com/Posts/2011/2011.09.29.0931/Screenshot2.png" alt="Screenshot" /></p>

<p>Oh My Friendly Geranium, but who on earth thought of this - and why wasn't it knocked on the head by someone sensible?
MVC team: I'm really sorry, but IMO you've completely missed the point of a strongly-typed language. I know you've
taken a lot of flak for this over the past few years but, to be honest, it's kind-of deserved :(</p>

<p>So, what on earth do we do about it?</p>

<p>When we're in a world of magic-string pain, the first thing to do is generally start creating some conventions. The
second thing, of course, is that we test those conventions using unit tests. Hold on a second, though: we're using a
strongly-typed language and yet we're *writing unit tests *to test our conventions because we're using strings and
anonymous classes? Why don't we have a tool that does this for us?</p>

<p>We want a convention-based test harness that:</p>

<ol>
<li>Runs on every build. </li>
<li>Has a set of conventions that are clear and unambiguous. </li>
<li>Doesn't make us manually write tests. </li>
<li>Will auto-generate test cases for every new piece of code we write. </li>
<li>Is refactoring-friendly. </li>
<li>Is fast. </li>
<li>Will fail the build if something's wrong. </li>
</ol>

<p>I think we've forgotten something important. Can anyone point to a tool that's all of the above, comes pre-installed
with every version of Visual Studio and requires zero integration work, no NuGet packages and <em>just works</em>?</p>

<p>Anyone? Anyone? No? Here's one: csc.exe. Yep, that's right: use the compiler.</p>

<p>Call me old-school, but a compiler is all of the above. Consider this method:</p>

<p><img src="http://www.codingforfunandprofit.com/Posts/2011/2011.09.29.0931/Screenshot3.png" alt="Screenshot" /></p>

<p>Think about it: why don't I have to test that a and b are integers? Sure, I should be testing for edge cases here, but
I don't have to type-check or null-check my inputs. Why not? Because the compiler is enforcing the convention that
when I say "int", I mean a 32-bit integer and it simply won't let anyone pass in anything else.</p>

<p>I don't have to write a single unit test to enforce these conventions. The compiler will provide me with fast and
reliable feedback - at compile time - if I've broken anything, which is far better than getting the feedback at
run-time using unit tests (or worse, at run-time when a user hits an issue).</p>

<p>I think we as developers can afford to take a bit more time to write strongly-typed code, e.g. HtmlHelpers for
controller actions. Try this one:</p>

<p><img src="http://www.codingforfunandprofit.com/Posts/2011/2011.09.29.0931/Screenshot4.png" alt="Screenshot" /></p>

<p>You can make your code infer the controller name, the action name, the area and all sorts of things without ever having
a magic string. You could even add strongly-typed parameters to it (built using a fluent interface) so that it's
effectively impossible to get it wrong without the compiler complaining.</p>

<p>So why don't more people use such a great convention-based test tool? I have no idea.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2011.09.29.0931</feedburner:origLink></item><item xml:base="Home/Post/2011.09.26.0919"><guid isPermaLink="false">2011.09.26.0919</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/tBSOvitUSUQ/2011.09.26.0919</link><author>andrewh@uglybugger.org</author><title>iPhone/MonoTouch Unit Testing with Team Foundation Server</title><description>&lt;p&gt;I know, I know: apples, oranges etc. It's not really, though - this is actually quite straight-forward. But first, some background.&lt;/p&gt;

&lt;p&gt;I was recently involved in building another iPhone application for an enterprise customer. We had previously dealt with that customer and had a good working relationship and level of trust with them, but a huge part of that trust was the visibility that we provided as to what was going on. It's mostly off-topic for this post, but the way we did it involved using Team Foundation Server, giving the client's people accounts and making sure that the client's product owner could log in at any time and see how the project was going.&lt;/p&gt;

&lt;p&gt;With the iPhone application, we wanted to do exactly the same. The problem was that we hadn't had that much experience using TFS to build iPhone apps. Most of our collective efforts had either been in Objective C using git (the stock-standard approach that Xcode pushes) or C#/MonoTouch using Mercurial (my experience). While both of those approaches are fine for personal and small projects, we really wanted all the other bonus points that TFS provides (continuous integration, work item tracking, reporting, web-based project portal etc.)&lt;/p&gt;

&lt;p&gt;So how'd we do it? Well, the first thing to note is that we're not actually building the application bundle using TFS - yet. That still requires a MacBook, MonoDevelop and a bunch of other stuff. We'll probably get there soon using custom build tasks, rsync, ssh and a few other things, but we're not quite there yet.&lt;/p&gt;

&lt;p&gt;What we &lt;em&gt;do&lt;/em&gt; have is a working continuous integration and nightly build, plus running tests using MSTest. The nice thing is that it actually wasn't that hard.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the project in Visual Studio (not MonoDevelop). You'll probably need something like Chris Small's &lt;a href="https://bitbucket.org/mrshrinkray/monotouch-samples/src/b1983c0a8d68/MonotouchProjectConverter/" target="_blank"&gt;MonoTouch Project Converter&lt;/a&gt; to make this work happily.&lt;/li&gt;
&lt;li&gt;Include monotouch.dll in your /lib directory and reference it from there rather than from the GAC. (It won't be in the GAC on your build server, and nor should it be.)&lt;/li&gt;
&lt;li&gt;If you have other dependencies (e.g. System.Data), copy those from your MacBook into /lib as well and reference those from there.&lt;/li&gt;
&lt;li&gt;Done :)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The key point to note when you're building your app is that you're not going to be able to easily test your ViewController classes using MSTest, so make them dumb. If there's business logic in there, extract it out into your domain model. If there's data access logic in there... well... you're doing it wrong anyway and you should &lt;em&gt;definitely&lt;/em&gt; extract that out :)&lt;/p&gt;

&lt;p&gt;You'll end up with an app that has a dumb(ish) UI shell wrapped around a bunch of well-tested business logic classes. The added bonus of doing it this way is that you can then re-use a lot of that code when you write your WP7 or Android version.&lt;/p&gt;

&lt;p&gt;The outcome? The visibility we wanted from the reporting and work item tracking side of things, plus a CI build that didn't require witchcraft to configure, plus automated unit tests.&lt;/p&gt;

&lt;p&gt;The only real down-side of this approach is that the build we're unit-testing isn't the build we're shipping - we still have to build that manually on a MacBook somewhere. It does, however, give us a good indication of our overall code quality and a reliable safety net for refactoring.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/tBSOvitUSUQ" height="1" width="1"/&gt;</description><pubDate>Mon, 26 Sep 2011 09:19:00 +1000</pubDate><a10:updated>2011-09-26T09:19:00+10:00</a10:updated><a10:content type="xhtml"><p>I know, I know: apples, oranges etc. It's not really, though - this is actually quite straight-forward. But first, some background.</p>

<p>I was recently involved in building another iPhone application for an enterprise customer. We had previously dealt with that customer and had a good working relationship and level of trust with them, but a huge part of that trust was the visibility that we provided as to what was going on. It's mostly off-topic for this post, but the way we did it involved using Team Foundation Server, giving the client's people accounts and making sure that the client's product owner could log in at any time and see how the project was going.</p>

<p>With the iPhone application, we wanted to do exactly the same. The problem was that we hadn't had that much experience using TFS to build iPhone apps. Most of our collective efforts had either been in Objective C using git (the stock-standard approach that Xcode pushes) or C#/MonoTouch using Mercurial (my experience). While both of those approaches are fine for personal and small projects, we really wanted all the other bonus points that TFS provides (continuous integration, work item tracking, reporting, web-based project portal etc.)</p>

<p>So how'd we do it? Well, the first thing to note is that we're not actually building the application bundle using TFS - yet. That still requires a MacBook, MonoDevelop and a bunch of other stuff. We'll probably get there soon using custom build tasks, rsync, ssh and a few other things, but we're not quite there yet.</p>

<p>What we <em>do</em> have is a working continuous integration and nightly build, plus running tests using MSTest. The nice thing is that it actually wasn't that hard.</p>

<ol>
<li>Open the project in Visual Studio (not MonoDevelop). You'll probably need something like Chris Small's <a href="https://bitbucket.org/mrshrinkray/monotouch-samples/src/b1983c0a8d68/MonotouchProjectConverter/" target="_blank">MonoTouch Project Converter</a> to make this work happily.</li>
<li>Include monotouch.dll in your /lib directory and reference it from there rather than from the GAC. (It won't be in the GAC on your build server, and nor should it be.)</li>
<li>If you have other dependencies (e.g. System.Data), copy those from your MacBook into /lib as well and reference those from there.</li>
<li>Done :)</li>
</ol>

<p>The key point to note when you're building your app is that you're not going to be able to easily test your ViewController classes using MSTest, so make them dumb. If there's business logic in there, extract it out into your domain model. If there's data access logic in there... well... you're doing it wrong anyway and you should <em>definitely</em> extract that out :)</p>

<p>You'll end up with an app that has a dumb(ish) UI shell wrapped around a bunch of well-tested business logic classes. The added bonus of doing it this way is that you can then re-use a lot of that code when you write your WP7 or Android version.</p>

<p>The outcome? The visibility we wanted from the reporting and work item tracking side of things, plus a CI build that didn't require witchcraft to configure, plus automated unit tests.</p>

<p>The only real down-side of this approach is that the build we're unit-testing isn't the build we're shipping - we still have to build that manually on a MacBook somewhere. It does, however, give us a good indication of our overall code quality and a reliable safety net for refactoring.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2011.09.26.0919</feedburner:origLink></item><item xml:base="Home/Post/2011.08.27.1028"><guid isPermaLink="false">2011.08.27.1028</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/fHLE8cQuDP4/2011.08.27.1028</link><author>andrewh@uglybugger.org</author><title>An iPhone Eye for the C# Guy at @dddbrisbane</title><description>&lt;p&gt;I just submitted this abstract for &lt;a href="http://www.dddbrisbane.com/" target="_blank"&gt;DDD Brisbane 2011&lt;/a&gt;. Don't forget to vote for me!&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;An iPhone Eye for the C# Guy&lt;/strong&gt;&lt;/p&gt;
  
  &lt;p&gt;&lt;em&gt;iPhone Development using MonoTouch&lt;/em&gt;&lt;/p&gt;
  
  &lt;p&gt;This session will cover the basics of developing an iPhone application using C#/MonoTouch, from how to create a "Hello, world!" app through to a look at a real-world, production codebase.&lt;/p&gt;
  
  &lt;p&gt;We'll cover the use of web services, threads, databases, generics (yes, you &lt;em&gt;can&lt;/em&gt; use generics), reflection, inversion of control (yes, you can use IoC, too!) and general application architecture, and finish with a look at some tools, tips and tricks to make life as an iPhone developer much less painful.&lt;/p&gt;
  
  &lt;p&gt;This session will assume prior knowledge of threading, reflection, generics, inversion of control and why you'd want to use all of these, but don't let that scare you :)&lt;/p&gt;
&lt;/blockquote&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/fHLE8cQuDP4" height="1" width="1"/&gt;</description><pubDate>Sat, 27 Aug 2011 10:28:00 +1000</pubDate><a10:updated>2011-08-27T10:28:00+10:00</a10:updated><a10:content type="xhtml"><p>I just submitted this abstract for <a href="http://www.dddbrisbane.com/" target="_blank">DDD Brisbane 2011</a>. Don't forget to vote for me!</p>

<blockquote>
  <p><strong>An iPhone Eye for the C# Guy</strong></p>
  
  <p><em>iPhone Development using MonoTouch</em></p>
  
  <p>This session will cover the basics of developing an iPhone application using C#/MonoTouch, from how to create a "Hello, world!" app through to a look at a real-world, production codebase.</p>
  
  <p>We'll cover the use of web services, threads, databases, generics (yes, you <em>can</em> use generics), reflection, inversion of control (yes, you can use IoC, too!) and general application architecture, and finish with a look at some tools, tips and tricks to make life as an iPhone developer much less painful.</p>
  
  <p>This session will assume prior knowledge of threading, reflection, generics, inversion of control and why you'd want to use all of these, but don't let that scare you :)</p>
</blockquote>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2011.08.27.1028</feedburner:origLink></item><item xml:base="Home/Post/2011.08.26.1058"><guid isPermaLink="false">2011.08.26.1058</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/fDb8cKiAqFI/2011.08.26.1058</link><author>andrewh@uglybugger.org</author><title>Crash Logging in a MonoTouch App</title><description>&lt;p&gt;Customer: Your app crashed again.&lt;br/&gt;
Developer: How? What were you doing when it crashed? What happened?&lt;br/&gt;
Customer: I don't know. I was playing with it and it crashed.&lt;br/&gt;
Developer: Do you remember which page you were on?&lt;br/&gt;
Customer: ?&lt;br/&gt;
Developer: &lt;em&gt;bangs head against wall&lt;/em&gt;&lt;br/&gt;
Sound familiar?&lt;br/&gt;
One of the first things I do when I start a project (or when I inherit one) is set up logging. You'd be amazed and depressed at how many projects just don't have any, or bolt it on as an after thought. Here's a hint: &lt;em&gt;it's much easier to debug your app while you're developing it if you know where it's breaking&lt;/em&gt;. Ground-breaking, I know &lt;img alt="Smile with tongue out" class="wlEmoticon wlEmoticon-smilewithtongueout" src="http://lh4.ggpht.com/-3fKyPNGZM5k/TlhCKOHjPgI/AAAAAAAAAUE/16CIyFW1aLg/wlEmoticon-smilewithtongueout2.png?imgmax=800" style="border-bottom-style: none; border-left-style: none; border-right-style: none; border-top-style: none;" /&gt;&lt;br/&gt;
There are a couple of things we want to do:&lt;br/&gt;
1.  Log when the app crashes. Do it quickly and reliably, and don't rely on any app infrastructure (e.g. injected loggers) as it's already been torn down at this point. 
2.  Send the log message the next time the app starts. This will allow us to use all our nice web services etc. and means we can use just the one logging mechanism rather than having several different ones.  MonoDevelop creates a fairly standard-looking Main.cs for us: &lt;/p&gt;

&lt;p&gt;Let's change that to add a simple try/catch block:  &lt;/p&gt;

&lt;p&gt;The key here is line 11 - it makes it simple and obvious as to what it's doing.&lt;br/&gt;
So... the CrashLog class itself is a static class and doesn't do very much at all. The idea is that it's simple to call and doesn't rely on having any of the app's components still available.  &lt;/p&gt;

&lt;p&gt;We're using the &lt;em&gt;My Documents&lt;/em&gt; special folder as that's where we're reliably allowed to write things to on the filesystem.&lt;br/&gt;
So now that we have our crash logger, let's hook things up so that we can log when the app starts again. In our AppDelegate class:  &lt;/p&gt;

&lt;p&gt;Yes, we're using our IoC container as a service locator. This isn't good, but we can't use constructor injection in our AppDelegate as it's the class responsible for creating our IoC container.&lt;br/&gt;
So how does the logger work? Well, that's up to you. You can choose to make a web-service call; you could spit it to another text file and periodically upload it; you could even send an email if you really wanted to.&lt;br/&gt;
My preference is using a web service as I tend to just hook it straight to the server-side logger (which usually uses log4net under the covers), but your mileage may vary.&lt;br/&gt;
The next time a customer tells you that your app crashed, though, you'll be able to respond with, "I know - and I've already fixed that bug."&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/fDb8cKiAqFI" height="1" width="1"/&gt;</description><pubDate>Fri, 26 Aug 2011 10:58:00 +1000</pubDate><a10:updated>2011-08-26T10:58:00+10:00</a10:updated><a10:content type="xhtml"><p>Customer: Your app crashed again.<br />
Developer: How? What were you doing when it crashed? What happened?<br />
Customer: I don't know. I was playing with it and it crashed.<br />
Developer: Do you remember which page you were on?<br />
Customer: ?<br />
Developer: <em>bangs head against wall</em><br />
Sound familiar?<br />
One of the first things I do when I start a project (or when I inherit one) is set up logging. You'd be amazed and depressed at how many projects just don't have any, or bolt it on as an after thought. Here's a hint: <em>it's much easier to debug your app while you're developing it if you know where it's breaking</em>. Ground-breaking, I know <img alt="Smile with tongue out" class="wlEmoticon wlEmoticon-smilewithtongueout" src="http://lh4.ggpht.com/-3fKyPNGZM5k/TlhCKOHjPgI/AAAAAAAAAUE/16CIyFW1aLg/wlEmoticon-smilewithtongueout2.png?imgmax=800" style="border-bottom-style: none; border-left-style: none; border-right-style: none; border-top-style: none;" /><br />
There are a couple of things we want to do:<br />
1.  Log when the app crashes. Do it quickly and reliably, and don't rely on any app infrastructure (e.g. injected loggers) as it's already been torn down at this point. 
2.  Send the log message the next time the app starts. This will allow us to use all our nice web services etc. and means we can use just the one logging mechanism rather than having several different ones.  MonoDevelop creates a fairly standard-looking Main.cs for us: </p>

<p>Let's change that to add a simple try/catch block:  </p>

<p>The key here is line 11 - it makes it simple and obvious as to what it's doing.<br />
So... the CrashLog class itself is a static class and doesn't do very much at all. The idea is that it's simple to call and doesn't rely on having any of the app's components still available.  </p>

<p>We're using the <em>My Documents</em> special folder as that's where we're reliably allowed to write things to on the filesystem.<br />
So now that we have our crash logger, let's hook things up so that we can log when the app starts again. In our AppDelegate class:  </p>

<p>Yes, we're using our IoC container as a service locator. This isn't good, but we can't use constructor injection in our AppDelegate as it's the class responsible for creating our IoC container.<br />
So how does the logger work? Well, that's up to you. You can choose to make a web-service call; you could spit it to another text file and periodically upload it; you could even send an email if you really wanted to.<br />
My preference is using a web service as I tend to just hook it straight to the server-side logger (which usually uses log4net under the covers), but your mileage may vary.<br />
The next time a customer tells you that your app crashed, though, you'll be able to respond with, "I know - and I've already fixed that bug."</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2011.08.26.1058</feedburner:origLink></item><item xml:base="Home/Post/2011.04.26.0413"><guid isPermaLink="false">2011.04.26.0413</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/Dqo6c_9cYEc/2011.04.26.0413</link><author>andrewh@uglybugger.org</author><title>Cargo Cult Software</title><description>&lt;p&gt;Ever heard of a &lt;a href="http://en.wikipedia.org/wiki/Cargo_cult" target="_blank"&gt;cargo cult&lt;/a&gt;? It's a term describing the philosophy of many pre-industrial tribes in the Pacific during World War II with respect to the "cargo"; i.e. the foodstuffs and equipment called in by American and Japanese radio operators. The thinking went that the Americans and Japanese had appropriated (stolen) the cargo that rightfully belonged to the natives by means of liaising with the gods.&lt;/p&gt;

&lt;p&gt;The interesting thing isn't the belief that the cargo was stolen but more that the means of stealing it back were novel. The natives began to imitate the radio operators in the hope that building the same items of worship (realistic-looking radio sets, landing strips and in some cases even mock aircraft), and memorising the noises that the operators made and faithfully reproducing them, would help them divert the cargo back to its rightful recipients.&lt;/p&gt;

&lt;p&gt;So what on earth does this have to do with software? Well, take a look around at most software projects you've been involved in. Why do we have multiple web service layers? Why do we separate concerns? Why do we abstract our data layer(s)?&lt;/p&gt;

&lt;p&gt;There are legitimate (and good) answers to these questions, but the most common one is "because everyone else does it." In other words, other people do these things and receive good software ("cargo") in return, so if we do it then perhaps *we'll* receive the cargo instead. The key is that some people &lt;em&gt;understand&lt;/em&gt; why they do it, and some people just mimic it.&lt;/p&gt;

&lt;p&gt;This post was prompted by a recent experience in which I ended up tearing apart an entire application (data access layer, service layer to access data, business logic layer, view/presenter layer etc.) and rebuilding it with something sensible - and all because someone tried to do it right and sadly had no idea how to do it.&lt;/p&gt;

&lt;p&gt;I've seen so many software projects started with the absolute best of intentions. In most cases I honestly can't fault the effort or the diligence displayed by the original developers - after all, almost nobody deliberately sets out to do a poor job. It's heartbreaking, for example, to see someone having spent weeks or even months of their life inserting a web service layer for data access without understanding why they're doing it, then complaining that their app's too slow because every action ends up requiring a full table fetch. Equally, I've seen people follow the &lt;a href="http://lmgtfy.com/?q=Single+Responsibility+Principle" target="_blank"&gt;Single Responsibility Principle&lt;/a&gt; to a ridiculous extent but end up with utterly unmaintainable code because they didn't properly understand &lt;em&gt;why&lt;/em&gt; it's important. MVC, MVVM, n-tier... they're all useful tools in the box, but all too often they're just fake radio sets made of wood or landing lights that don't emit light.&lt;/p&gt;

&lt;p&gt;Go on. Laugh. Laugh rudely at the natives. You know you want to.&lt;/p&gt;

&lt;p&gt;Then cry, because you know it's true - and because, at least once, each of us has been one of them &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://lh4.ggpht.com/_-XUzf_kGi5I/TbZikg5b2gI/AAAAAAAAAKQ/mFqfVC1vIhA/wlEmoticon-smile%5B2%5D.png?imgmax=800" /&gt;&lt;/p&gt;

&lt;p&gt;Finally, to stand on my fake soapbox for a second: go and &lt;em&gt;teach&lt;/em&gt; your craft, so that you (and all of the rest of us) don't have to clean up messes like these, and destroy someone's prized wooden radio set while we're at it.&lt;/p&gt;

&lt;p&gt;P.S. Credit to &lt;a href="http://www.paulstovell.com/" target="_blank"&gt;Paul Stovell&lt;/a&gt;, whose &lt;a href="http://twitter.com/#!/paulstovell/status/62752415509782528" target="_blank"&gt;tweet&lt;/a&gt; finally prompted me to finish and publish this blog post.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/Dqo6c_9cYEc" height="1" width="1"/&gt;</description><pubDate>Tue, 26 Apr 2011 04:13:00 +1000</pubDate><a10:updated>2011-04-26T04:13:00+10:00</a10:updated><a10:content type="xhtml"><p>Ever heard of a <a href="http://en.wikipedia.org/wiki/Cargo_cult" target="_blank">cargo cult</a>? It's a term describing the philosophy of many pre-industrial tribes in the Pacific during World War II with respect to the "cargo"; i.e. the foodstuffs and equipment called in by American and Japanese radio operators. The thinking went that the Americans and Japanese had appropriated (stolen) the cargo that rightfully belonged to the natives by means of liaising with the gods.</p>

<p>The interesting thing isn't the belief that the cargo was stolen but more that the means of stealing it back were novel. The natives began to imitate the radio operators in the hope that building the same items of worship (realistic-looking radio sets, landing strips and in some cases even mock aircraft), and memorising the noises that the operators made and faithfully reproducing them, would help them divert the cargo back to its rightful recipients.</p>

<p>So what on earth does this have to do with software? Well, take a look around at most software projects you've been involved in. Why do we have multiple web service layers? Why do we separate concerns? Why do we abstract our data layer(s)?</p>

<p>There are legitimate (and good) answers to these questions, but the most common one is "because everyone else does it." In other words, other people do these things and receive good software ("cargo") in return, so if we do it then perhaps *we'll* receive the cargo instead. The key is that some people <em>understand</em> why they do it, and some people just mimic it.</p>

<p>This post was prompted by a recent experience in which I ended up tearing apart an entire application (data access layer, service layer to access data, business logic layer, view/presenter layer etc.) and rebuilding it with something sensible - and all because someone tried to do it right and sadly had no idea how to do it.</p>

<p>I've seen so many software projects started with the absolute best of intentions. In most cases I honestly can't fault the effort or the diligence displayed by the original developers - after all, almost nobody deliberately sets out to do a poor job. It's heartbreaking, for example, to see someone having spent weeks or even months of their life inserting a web service layer for data access without understanding why they're doing it, then complaining that their app's too slow because every action ends up requiring a full table fetch. Equally, I've seen people follow the <a href="http://lmgtfy.com/?q=Single+Responsibility+Principle" target="_blank">Single Responsibility Principle</a> to a ridiculous extent but end up with utterly unmaintainable code because they didn't properly understand <em>why</em> it's important. MVC, MVVM, n-tier... they're all useful tools in the box, but all too often they're just fake radio sets made of wood or landing lights that don't emit light.</p>

<p>Go on. Laugh. Laugh rudely at the natives. You know you want to.</p>

<p>Then cry, because you know it's true - and because, at least once, each of us has been one of them <img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://lh4.ggpht.com/_-XUzf_kGi5I/TbZikg5b2gI/AAAAAAAAAKQ/mFqfVC1vIhA/wlEmoticon-smile%5B2%5D.png?imgmax=800" /></p>

<p>Finally, to stand on my fake soapbox for a second: go and <em>teach</em> your craft, so that you (and all of the rest of us) don't have to clean up messes like these, and destroy someone's prized wooden radio set while we're at it.</p>

<p>P.S. Credit to <a href="http://www.paulstovell.com/" target="_blank">Paul Stovell</a>, whose <a href="http://twitter.com/#!/paulstovell/status/62752415509782528" target="_blank">tweet</a> finally prompted me to finish and publish this blog post.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2011.04.26.0413</feedburner:origLink></item><item xml:base="Home/Post/2011.04.21.1210"><guid isPermaLink="false">2011.04.21.1210</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/8dHQ-ysVWb8/2011.04.21.1210</link><author>andrewh@uglybugger.org</author><title>Why merely "very good" employees don’t get promoted</title><description>&lt;p&gt;I saw a &lt;a href="http://news.slashdot.org/story/11/04/20/0823213/Promotion-Or-Job-Change-Which-Is-the-Best-Way-To-Advance-In-IT?utm_source=rss1.0&amp;amp;utm_medium=feed" target="_blank"&gt;question on /.&lt;/a&gt; this morning about exactly this and decided to blog it rather than comment as it's another one of those "I hear this question all the time" posts.&lt;/p&gt;

&lt;p&gt;The question's usually along the lines of, "I'm really good at my job. How come I can't get promoted?"&lt;/p&gt;

&lt;p&gt;The simple-yet-offensive answer is this: you haven't done a good enough job to be promoted.&lt;/p&gt;

&lt;p&gt;Before everyone starts screaming, let's look at this from the perspective of a mythical manager who actually &lt;em&gt;wants&lt;/em&gt; his/her employees to succeed. I know, I know, but they really are out there. So... what goes on?&lt;/p&gt;

&lt;p&gt;Usually the internal monologue goes something like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;John's doing a really good job running X/Y/X.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I like John and want to promote him.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There's a position running a new project and I'd really like to offer it to him.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I have nobody to replace him with and would need to train a replacement.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Oh, bollocks. John's just made it impossible for even the best-intentioned manager to promote him. Now imagine what a less-well-intentioned one would do.&lt;/p&gt;

&lt;p&gt;At any one of these stages a promotion is easily killable. If John isn't doing a really good job running X/Y/ then there's no way that he's going to be promoted except under the Dilbert Principle. Similarly, if John isn't well-liked then there's no way he's going to get promoted simply because dealing with unpleasant people is unpleasant and a good manager isn't going to inflict an unpleasant person on other people if he/she can at all avoid it. The third one's obvious: if there's no promotion available then there's no promotion available.&lt;/p&gt;

&lt;p&gt;The fourth point, though, is the one that almost invariably gets forgotten. I've &lt;a href="http://www.codingforfunandprofit.com/2010/07/if-youre-so-smart-why-does-all-your.html"&gt;blogged about this before&lt;/a&gt; but the gist of it is that if John's made himself indispensible then that's the end of it. Indispensible means that he cannot be done without; in other words, he's locked himself into his current position all by himself. John hasn't done a good enough job to get promoted because &lt;em&gt;he hasn't trained his own replacement&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;Training your replacement is part of your job.&lt;/h2&gt;

&lt;p&gt;So why don't people do it?&lt;/p&gt;

&lt;p&gt;The most obvious answer is fear. Fear of being replaced by someone younger and cheaper; fear of being shown up by someone who ends up knowing more than you; fear that your management won't see this as a valuable use of your time. There's also fear of the unknown - it's much easier in many cases to perennially gripe about being really good but not getting promoted than it is to actually &lt;em&gt;get&lt;/em&gt; promoted and run the risk of failing in your new position.&lt;/p&gt;

&lt;p&gt;There are other likely culprits (budgetary constraints, time pressure etc.) but the point of this article is that they're all surmountable once the fear is overcome.&lt;/p&gt;

&lt;p&gt;Of course, if you're incompetent then you &lt;em&gt;should&lt;/em&gt; feel fear - and you should expend all your efforts on trying to get better. Ironically, if you're not very good then you'll probably find that people will actively try to promote you according to the Dilbert Principle. Has an unsolicited promotion offer come your way recently just when you thought you were really struggling? Ouch. Sorry.&lt;/p&gt;

&lt;h2&gt;I want a promotion. Should I stay in my current company or look elsewhere?&lt;/h2&gt;

&lt;p&gt;The short answer to this is: go wherever your interests take you.&lt;/p&gt;

&lt;p&gt;The longer answer: if you like your company and want a particular position, ask for it. It's much easier to just tell people what you want and ask what you need to do in order to get it. You never know - they might not have realised that you're bored or unhappy where you are, especially if you're keeping things running smoothly and appear to have it all under control.&lt;/p&gt;

&lt;p&gt;If your current company can't or won't accommodate you then, by all means, look elsewhere. Before doing that, though, take a good, hard, honest look at yourself and ask whether &lt;em&gt;you'd&lt;/em&gt; promote you if you ran the company. If the answer's yes but the company won't then it's time to move on. If the answer's no then it's probably time to ask for help - and also to start making some serious efforts towards your own professional development.&lt;/p&gt;

&lt;h2&gt;Finally...&lt;/h2&gt;

&lt;p&gt;Finally, if your company's regularly appearing on &lt;a href="http://fuckedcompany.com/" target="_blank"&gt;FC&lt;/a&gt; or &lt;a href="http://notgoodenough.org/" target="_blank"&gt;NGE&lt;/a&gt; then it's time to jump ship no matter how good you are &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://lh3.ggpht.com/_-XUzf_kGi5I/Ta-SCrVlQkI/AAAAAAAAAKM/q82nqFo7d34/wlEmoticon-smile%5B2%5D.png?imgmax=800" /&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/8dHQ-ysVWb8" height="1" width="1"/&gt;</description><pubDate>Thu, 21 Apr 2011 12:10:00 +1000</pubDate><a10:updated>2011-04-21T12:10:00+10:00</a10:updated><a10:content type="xhtml"><p>I saw a <a href="http://news.slashdot.org/story/11/04/20/0823213/Promotion-Or-Job-Change-Which-Is-the-Best-Way-To-Advance-In-IT?utm_source=rss1.0&amp;utm_medium=feed" target="_blank">question on /.</a> this morning about exactly this and decided to blog it rather than comment as it's another one of those "I hear this question all the time" posts.</p>

<p>The question's usually along the lines of, "I'm really good at my job. How come I can't get promoted?"</p>

<p>The simple-yet-offensive answer is this: you haven't done a good enough job to be promoted.</p>

<p>Before everyone starts screaming, let's look at this from the perspective of a mythical manager who actually <em>wants</em> his/her employees to succeed. I know, I know, but they really are out there. So... what goes on?</p>

<p>Usually the internal monologue goes something like this:</p>

<ol>
<li><p>John's doing a really good job running X/Y/X.</p></li>
<li><p>I like John and want to promote him.</p></li>
<li><p>There's a position running a new project and I'd really like to offer it to him.</p></li>
<li><p>I have nobody to replace him with and would need to train a replacement.</p></li>
</ol>

<p>Oh, bollocks. John's just made it impossible for even the best-intentioned manager to promote him. Now imagine what a less-well-intentioned one would do.</p>

<p>At any one of these stages a promotion is easily killable. If John isn't doing a really good job running X/Y/ then there's no way that he's going to be promoted except under the Dilbert Principle. Similarly, if John isn't well-liked then there's no way he's going to get promoted simply because dealing with unpleasant people is unpleasant and a good manager isn't going to inflict an unpleasant person on other people if he/she can at all avoid it. The third one's obvious: if there's no promotion available then there's no promotion available.</p>

<p>The fourth point, though, is the one that almost invariably gets forgotten. I've <a href="http://www.codingforfunandprofit.com/2010/07/if-youre-so-smart-why-does-all-your.html">blogged about this before</a> but the gist of it is that if John's made himself indispensible then that's the end of it. Indispensible means that he cannot be done without; in other words, he's locked himself into his current position all by himself. John hasn't done a good enough job to get promoted because <em>he hasn't trained his own replacement</em>.</p>

<h2>Training your replacement is part of your job.</h2>

<p>So why don't people do it?</p>

<p>The most obvious answer is fear. Fear of being replaced by someone younger and cheaper; fear of being shown up by someone who ends up knowing more than you; fear that your management won't see this as a valuable use of your time. There's also fear of the unknown - it's much easier in many cases to perennially gripe about being really good but not getting promoted than it is to actually <em>get</em> promoted and run the risk of failing in your new position.</p>

<p>There are other likely culprits (budgetary constraints, time pressure etc.) but the point of this article is that they're all surmountable once the fear is overcome.</p>

<p>Of course, if you're incompetent then you <em>should</em> feel fear - and you should expend all your efforts on trying to get better. Ironically, if you're not very good then you'll probably find that people will actively try to promote you according to the Dilbert Principle. Has an unsolicited promotion offer come your way recently just when you thought you were really struggling? Ouch. Sorry.</p>

<h2>I want a promotion. Should I stay in my current company or look elsewhere?</h2>

<p>The short answer to this is: go wherever your interests take you.</p>

<p>The longer answer: if you like your company and want a particular position, ask for it. It's much easier to just tell people what you want and ask what you need to do in order to get it. You never know - they might not have realised that you're bored or unhappy where you are, especially if you're keeping things running smoothly and appear to have it all under control.</p>

<p>If your current company can't or won't accommodate you then, by all means, look elsewhere. Before doing that, though, take a good, hard, honest look at yourself and ask whether <em>you'd</em> promote you if you ran the company. If the answer's yes but the company won't then it's time to move on. If the answer's no then it's probably time to ask for help - and also to start making some serious efforts towards your own professional development.</p>

<h2>Finally...</h2>

<p>Finally, if your company's regularly appearing on <a href="http://fuckedcompany.com/" target="_blank">FC</a> or <a href="http://notgoodenough.org/" target="_blank">NGE</a> then it's time to jump ship no matter how good you are <img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://lh3.ggpht.com/_-XUzf_kGi5I/Ta-SCrVlQkI/AAAAAAAAAKM/q82nqFo7d34/wlEmoticon-smile%5B2%5D.png?imgmax=800" /></p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2011.04.21.1210</feedburner:origLink></item><item xml:base="Home/Post/2011.04.19.0427"><guid isPermaLink="false">2011.04.19.0427</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/v79KCtavbDo/2011.04.19.0427</link><author>andrewh@uglybugger.org</author><title>Fix what you know is broken</title><description>&lt;p&gt;As a consultant, there's a very common complaint that I hear from clients. The complaint is along the lines of, "It's all such a mess," or "We need to re-write it from scratch." They're almost always right in the first case, and almost invariably plain wrong in the second. A messy codebase is a pain, but learning the wrong lesson from it just means that they're going to experience the same pain all over again once they've done their re-write - if they're still in business when they finish.&lt;/p&gt;

&lt;p&gt;The first question to ask is simple: why is it all such a mess? If it's a mess because you made a completely wrong technology choice (e.g. classic ASP for a point-of-sale application, or a thick client where a web client was required) or the team that wrote it simply didn't have a clue and have all been fired, then perhaps a re-write is in order. Other than that, there's almost no good reason to do a complete re-write. Regardless, that's not the point of this post.&lt;/p&gt;

&lt;p&gt;The point of this post is that it's usually such a mess because people don't know how to fix it - or, more probably, people don't know how to even decide on a strategy to follow and are drowning in technical debt as a result. Here's a simple one:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix what you know is broken.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you honestly have no idea, go and &lt;a href="http://www.readify.net/" target="_blank"&gt;ask someone who has&lt;/a&gt;. Firstly, though, try this:&lt;/p&gt;

&lt;p&gt;Do you have source control? No? Then download Mercurial and fix that.&lt;br/&gt;
Do you have continuous integration? No? Then download &lt;a href="http://www.jetbrains.com/teamcity/" target="_blank"&gt;TeamCity&lt;/a&gt; and fix *that*.&lt;br/&gt;
Do you have unit tests? No? Then go and write at least a "Hello, world!" test to get yourself started.&lt;br/&gt;
Do you have an issue-tracking system? No? Then go to &lt;a href="http://agilezen.com/" target="_blank"&gt;AgileZen&lt;/a&gt; or similar and get one.&lt;br/&gt;
Do you have an automated deployment solution? No? Well... you know the drill.&lt;/p&gt;

&lt;p&gt;There's really no excuse for not having these sorts of tools. Moreover, there's no excuse for not having the agility that these sorts of tools offer.&lt;/p&gt;

&lt;p&gt;Once you have a build, a rudimentary test suite and a deployment solution, the next step is clear:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix what you know is broken.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What's at the top of your issue-tracking list? Does it make sense? If so, then that's what's broken. Go and fix it. If not, then its priority is what's broken. Fix it by re-prioritising it so that it *does* make sense.&lt;/p&gt;

&lt;p&gt;I visited one client recently that had a test automation task as a "drop everything and fix now" priority - but below that were cases that were costing parts of their business money &lt;em&gt;every single day&lt;/em&gt;. In this case, the prioritisation was broken. So... fix it and move on.&lt;/p&gt;

&lt;p&gt;Once you've fixed something that was broken, release it. That's right: release the thing. "Oh," you might say, "but it has to go through n levels of QA, UAT and sign-off first." Guess what: that's the next thing that's broken. So... given that you know what's broken, what now?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix what you know is broken.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'm starting to sound like a broken record here, but I'm also starting to sound like a broken record whenever I have to deliver this lesson in person :)&lt;/p&gt;

&lt;p&gt;You need to get your release cycles down to something manageable, and if you've had a messy codebase for a while then I guarantee that you're afraid of releasing to production because of what might have changed while you weren't looking. &lt;/p&gt;

&lt;p&gt;The solution is to start releasing earlier and more often. Get used to the idea that a production release is boring and routine, not unfamiliar and scary. Releasing to production should be scripted and ideally entirely automated (but that's the subject of a squillion other blog posts) so I'm not going to re-hash it here. Just accept that if you're afraid of releasing to production then that's the next thing that's broken. After all, if you haven't changed the code since your last release then what's likely to go wrong? If you *have* changed the code, then what you're really afraid of is your testing regime, not deployment per se.&lt;/p&gt;

&lt;p&gt;Once you have your releases automated and none of the above things are scary any more, you're down to the boring, menial task of just chipping away at your technical debt. Identify the highest-priority item to fix; fix it; release it.&lt;/p&gt;

&lt;p&gt;It really *is* that simple, ladies and gentlemen &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://lh4.ggpht.com/_-XUzf_kGi5I/Ta0rMrhkvjI/AAAAAAAAAKI/JlWHK2-yhzo/wlEmoticon-smile%5B2%5D.png?imgmax=800" /&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/v79KCtavbDo" height="1" width="1"/&gt;</description><pubDate>Tue, 19 Apr 2011 04:27:00 +1000</pubDate><a10:updated>2011-04-19T04:27:00+10:00</a10:updated><a10:content type="xhtml"><p>As a consultant, there's a very common complaint that I hear from clients. The complaint is along the lines of, "It's all such a mess," or "We need to re-write it from scratch." They're almost always right in the first case, and almost invariably plain wrong in the second. A messy codebase is a pain, but learning the wrong lesson from it just means that they're going to experience the same pain all over again once they've done their re-write - if they're still in business when they finish.</p>

<p>The first question to ask is simple: why is it all such a mess? If it's a mess because you made a completely wrong technology choice (e.g. classic ASP for a point-of-sale application, or a thick client where a web client was required) or the team that wrote it simply didn't have a clue and have all been fired, then perhaps a re-write is in order. Other than that, there's almost no good reason to do a complete re-write. Regardless, that's not the point of this post.</p>

<p>The point of this post is that it's usually such a mess because people don't know how to fix it - or, more probably, people don't know how to even decide on a strategy to follow and are drowning in technical debt as a result. Here's a simple one:</p>

<p><strong>Fix what you know is broken.</strong></p>

<p>If you honestly have no idea, go and <a href="http://www.readify.net/" target="_blank">ask someone who has</a>. Firstly, though, try this:</p>

<p>Do you have source control? No? Then download Mercurial and fix that.<br />
Do you have continuous integration? No? Then download <a href="http://www.jetbrains.com/teamcity/" target="_blank">TeamCity</a> and fix *that*.<br />
Do you have unit tests? No? Then go and write at least a "Hello, world!" test to get yourself started.<br />
Do you have an issue-tracking system? No? Then go to <a href="http://agilezen.com/" target="_blank">AgileZen</a> or similar and get one.<br />
Do you have an automated deployment solution? No? Well... you know the drill.</p>

<p>There's really no excuse for not having these sorts of tools. Moreover, there's no excuse for not having the agility that these sorts of tools offer.</p>

<p>Once you have a build, a rudimentary test suite and a deployment solution, the next step is clear:</p>

<p><strong>Fix what you know is broken.</strong></p>

<p>What's at the top of your issue-tracking list? Does it make sense? If so, then that's what's broken. Go and fix it. If not, then its priority is what's broken. Fix it by re-prioritising it so that it *does* make sense.</p>

<p>I visited one client recently that had a test automation task as a "drop everything and fix now" priority - but below that were cases that were costing parts of their business money <em>every single day</em>. In this case, the prioritisation was broken. So... fix it and move on.</p>

<p>Once you've fixed something that was broken, release it. That's right: release the thing. "Oh," you might say, "but it has to go through n levels of QA, UAT and sign-off first." Guess what: that's the next thing that's broken. So... given that you know what's broken, what now?</p>

<p><strong>Fix what you know is broken.</strong></p>

<p>I'm starting to sound like a broken record here, but I'm also starting to sound like a broken record whenever I have to deliver this lesson in person :)</p>

<p>You need to get your release cycles down to something manageable, and if you've had a messy codebase for a while then I guarantee that you're afraid of releasing to production because of what might have changed while you weren't looking. </p>

<p>The solution is to start releasing earlier and more often. Get used to the idea that a production release is boring and routine, not unfamiliar and scary. Releasing to production should be scripted and ideally entirely automated (but that's the subject of a squillion other blog posts) so I'm not going to re-hash it here. Just accept that if you're afraid of releasing to production then that's the next thing that's broken. After all, if you haven't changed the code since your last release then what's likely to go wrong? If you *have* changed the code, then what you're really afraid of is your testing regime, not deployment per se.</p>

<p>Once you have your releases automated and none of the above things are scary any more, you're down to the boring, menial task of just chipping away at your technical debt. Identify the highest-priority item to fix; fix it; release it.</p>

<p>It really *is* that simple, ladies and gentlemen <img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://lh4.ggpht.com/_-XUzf_kGi5I/Ta0rMrhkvjI/AAAAAAAAAKI/JlWHK2-yhzo/wlEmoticon-smile%5B2%5D.png?imgmax=800" /></p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2011.04.19.0427</feedburner:origLink></item><item xml:base="Home/Post/2011.03.08.0454"><guid isPermaLink="false">2011.03.08.0454</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/LJuqdaTr0nY/2011.03.08.0454</link><author>andrewh@uglybugger.org</author><title>MSTest throws System.AccessViolationException on build server</title><description>&lt;p&gt;I've just spent an entire day on this. Moreover, it's a day that I &lt;em&gt;really&lt;/em&gt; couldn't afford to waste right now. Hopefully this minor rant will save someone else the same pain.  &lt;/p&gt;

&lt;p&gt;The problem: the MS Test framework, QTTask.exe, sgen.exe and a bunch of others were throwing AccessViolationExceptions in all sorts of places, but most painfully during my CI build. This mean that our build server couldn't run our unit tests, which meant that TFS Deployer wouldn't deploy because it thought the build was bad.  &lt;/p&gt;

&lt;p&gt;A red herring presented itself in the form of SQL Server Management Studio also falling in a heap, which led us to believe that it was an issue with the server image.  &lt;/p&gt;

&lt;p&gt;After wasting an entire day re-provisioning VMs from images, the simple solution was to turn off Symantec's endpoint protection.  &lt;/p&gt;

&lt;p&gt;Corporate security policies be damned - if you're going to break my build at crunch-time on a time-critical project, you're part of the problem.  &lt;/p&gt;

&lt;p&gt;End rant.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/LJuqdaTr0nY" height="1" width="1"/&gt;</description><pubDate>Tue, 08 Mar 2011 04:54:00 +1000</pubDate><a10:updated>2011-03-08T04:54:00+10:00</a10:updated><a10:content type="xhtml"><p>I've just spent an entire day on this. Moreover, it's a day that I <em>really</em> couldn't afford to waste right now. Hopefully this minor rant will save someone else the same pain.  </p>

<p>The problem: the MS Test framework, QTTask.exe, sgen.exe and a bunch of others were throwing AccessViolationExceptions in all sorts of places, but most painfully during my CI build. This mean that our build server couldn't run our unit tests, which meant that TFS Deployer wouldn't deploy because it thought the build was bad.  </p>

<p>A red herring presented itself in the form of SQL Server Management Studio also falling in a heap, which led us to believe that it was an issue with the server image.  </p>

<p>After wasting an entire day re-provisioning VMs from images, the simple solution was to turn off Symantec's endpoint protection.  </p>

<p>Corporate security policies be damned - if you're going to break my build at crunch-time on a time-critical project, you're part of the problem.  </p>

<p>End rant.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2011.03.08.0454</feedburner:origLink></item><item xml:base="Home/Post/2011.02.06.0815"><guid isPermaLink="false">2011.02.06.0815</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/kyB9iCqWJ8A/2011.02.06.0815</link><author>andrewh@uglybugger.org</author><title>Correctly Creating and Using a WCF RIA Services Class Library</title><description>&lt;p&gt;I recently had a situation with a client who had a requirement to use Silverlight 4.0 with RIA Services for an application under development. I've used WCF RIA Services on and off and have a bit of a love-hate thing with them (they wreak havoc on ReSharper's &lt;em&gt;Adjust Namespaces&lt;/em&gt; feature, for instance, which is an OCD habit of mine), but using them really did make sense in this client's case.&lt;/p&gt;

&lt;p&gt;Anyway... The client's application had to interface with a legacy database and no schema changes are permitted (sound familiar?). The database was a monster, with over 300 tables, 255 columns per table in some cases, no referential integrity constraints and eight-character field and table names.&lt;/p&gt;

&lt;p&gt;If I'd had a month just to map it, I'd have suggested NHibernate for its ability to tie itself into knots to allow arbitrary key constraints and other cleverness. As I just don't have a month, however, the client's going with EF because it automatically builds &lt;strike&gt;a map that makes me cry&lt;/strike&gt; a beautiful map of the database schema as-is.&lt;/p&gt;

&lt;p&gt;Adding a Domain Service based on an EF data layer is also trivial - RIA Services has a magical code generator that builds the entire suite of CRUD WCF services for us and it's entirely possible that we'll never need to tweak them.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_-XUzf_kGi5I/TU5y-nxqtOI/AAAAAAAAAGc/JgMut4nGZ8g/s1600-h/image%5B7%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_-XUzf_kGi5I/TU5y__QoLuI/AAAAAAAAAGg/daAkfHnLxFQ/image_thumb%5B3%5D.png?imgmax=800" width="192" height="484" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have a look at the SilverlightApp project at the top, you'll see a "Generated_Code" directory that contains all of the generated proxy code for all the domain services advertised by the SilverlightApp.Web project.&lt;/p&gt;

&lt;p&gt;The catch is that it generates proxy code for &lt;em&gt;every single class advertised by EF&lt;/em&gt; (although it's selectable, in this case it's actually required), which in this case results in approximately 300,000 lines of code.&lt;/p&gt;

&lt;h2&gt;The Problem&lt;/h2&gt;

&lt;p&gt;It takes a &lt;em&gt;long&lt;/em&gt; time to compile 300,000 lines (about 10Mb) of code, especially every single time a completely unrelated change is made to the UI.&lt;/p&gt;

&lt;h2&gt;Enter RIA Services Class Libraries.&lt;/h2&gt;

&lt;p&gt;RIA class libraries are not your garden-variety of class library. They're not particularly well documented and are fairly unintuitive. If you follow the standard directions you'll miss the really clever part, which is the part that makes it worth-while to use them in the first place.&lt;/p&gt;

&lt;p&gt;The key is that we want all the generated code in a library that we don't compile every single time we make a UI change. So... how do we do that?&lt;/p&gt;

&lt;h2&gt;Creating and using a WCF RIA Services Class Library&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Create your Silverlight project (use the Business Application template if you don't have any pressing need not to - it's great).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Add a new "WCF RIA Services Class Library" to your solution. This will create two projects: the class library itself and another web project to host it in.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_-XUzf_kGi5I/TU5zAU3bxRI/AAAAAAAAAGk/lirNx381bNQ/s1600-h/image%5B14%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_-XUzf_kGi5I/TU5zBVJC22I/AAAAAAAAAGo/5WUVUezEw6A/image_thumb%5B8%5D.png?imgmax=800" width="404" height="119" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Add a reference from your existing web site to your new class library's web site.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Add your domain services into your class library's web site instead of your main web site. For the sake of an example I've added a domain service around pet ownership, with Pet and Owner entities.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You're not done yet!&lt;/strong&gt; This is the part where it will all actually work, so people tend to forget the next step. I'll show you that in a minute.&lt;/p&gt;

&lt;p&gt;Let's have a look in the Generated_Code folder in our main Silverlight app at this point. Firstly, make sure that you've checked the "Show All Files" button for the SilverlightApp project so that you can see the Generated_Code directory:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_-XUzf_kGi5I/TU5zB5BVZpI/AAAAAAAAAGs/f4cswwrdfZ0/s1600-h/image%5B17%5D.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://lh6.ggpht.com/_-XUzf_kGi5I/TU5zCblKuXI/AAAAAAAAAGw/_N2vDCF4H8U/image_thumb%5B9%5D.png?imgmax=800" width="244" height="127" /&gt;&lt;/a&gt; &lt;a href="http://lh6.ggpht.com/_-XUzf_kGi5I/TU5zC4BEHmI/AAAAAAAAAG0/gr8X-M7yHgs/s1600-h/image%5B20%5D.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://lh6.ggpht.com/_-XUzf_kGi5I/TU5zDVBen-I/AAAAAAAAAG4/sS_shl_bqsA/image_thumb%5B10%5D.png?imgmax=800" width="221" height="61" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open the SilverlightApp.Web.g.cs file and have a look. You should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_-XUzf_kGi5I/TU50lQYDMdI/AAAAAAAAAG8/WbazgWNPLrk/s1600-h/image%5B24%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_-XUzf_kGi5I/TU50mcoJkhI/AAAAAAAAAHA/fk9heu9CCuQ/image_thumb%5B12%5D.png?imgmax=800" width="644" height="292" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note the definition of a proxy class for the "Owner" entity. Hang on a minute, though - this class was supposed to be in the class library - we don't want it in our main application. The whole &lt;em&gt;point&lt;/em&gt; of this exercise was to &lt;em&gt;not&lt;/em&gt; have all this generated code in our main Silverlight application as it takes too long to compile. The next step then:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Add a reference from your Silverlight app to your Silverlight class library. This is the obvious step but it's the one that lots of people miss, hence this blog post.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The WCF RIA code generator is actually very clever and it works out which entities you have proxy code for already to and only generates code for the ones you're missing.&lt;/p&gt;

&lt;p&gt;Once you add the reference, if you leave the generated code file open, this is what you should see:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_-XUzf_kGi5I/TU50nLtyfpI/AAAAAAAAAHE/uKs8JAZMZMU/s1600-h/image%5B28%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_-XUzf_kGi5I/TU50oqkp5bI/AAAAAAAAAHY/1AVFrKp3Ups/image_thumb%5B14%5D.png?imgmax=800" width="644" height="465" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ooh! No proxy code for our entities! Our compilation times just plummeted &lt;img style="border-bottom-style: none; border-right-style: none; border-top-style: none; border-left-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://lh3.ggpht.com/_-XUzf_kGi5I/TU50pGu0TuI/AAAAAAAAAHc/SQvc6V5D4aM/wlEmoticon-smile%5B2%5D.png?imgmax=800" /&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/kyB9iCqWJ8A" height="1" width="1"/&gt;</description><pubDate>Sun, 06 Feb 2011 08:15:00 +1000</pubDate><a10:updated>2011-02-06T08:15:00+10:00</a10:updated><a10:content type="xhtml"><p>I recently had a situation with a client who had a requirement to use Silverlight 4.0 with RIA Services for an application under development. I've used WCF RIA Services on and off and have a bit of a love-hate thing with them (they wreak havoc on ReSharper's <em>Adjust Namespaces</em> feature, for instance, which is an OCD habit of mine), but using them really did make sense in this client's case.</p>

<p>Anyway... The client's application had to interface with a legacy database and no schema changes are permitted (sound familiar?). The database was a monster, with over 300 tables, 255 columns per table in some cases, no referential integrity constraints and eight-character field and table names.</p>

<p>If I'd had a month just to map it, I'd have suggested NHibernate for its ability to tie itself into knots to allow arbitrary key constraints and other cleverness. As I just don't have a month, however, the client's going with EF because it automatically builds <strike>a map that makes me cry</strike> a beautiful map of the database schema as-is.</p>

<p>Adding a Domain Service based on an EF data layer is also trivial - RIA Services has a magical code generator that builds the entire suite of CRUD WCF services for us and it's entirely possible that we'll never need to tweak them.</p>

<p><a href="http://lh3.ggpht.com/_-XUzf_kGi5I/TU5y-nxqtOI/AAAAAAAAAGc/JgMut4nGZ8g/s1600-h/image%5B7%5D.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_-XUzf_kGi5I/TU5y__QoLuI/AAAAAAAAAGg/daAkfHnLxFQ/image_thumb%5B3%5D.png?imgmax=800" width="192" height="484" /></a></p>

<p>If you have a look at the SilverlightApp project at the top, you'll see a "Generated_Code" directory that contains all of the generated proxy code for all the domain services advertised by the SilverlightApp.Web project.</p>

<p>The catch is that it generates proxy code for <em>every single class advertised by EF</em> (although it's selectable, in this case it's actually required), which in this case results in approximately 300,000 lines of code.</p>

<h2>The Problem</h2>

<p>It takes a <em>long</em> time to compile 300,000 lines (about 10Mb) of code, especially every single time a completely unrelated change is made to the UI.</p>

<h2>Enter RIA Services Class Libraries.</h2>

<p>RIA class libraries are not your garden-variety of class library. They're not particularly well documented and are fairly unintuitive. If you follow the standard directions you'll miss the really clever part, which is the part that makes it worth-while to use them in the first place.</p>

<p>The key is that we want all the generated code in a library that we don't compile every single time we make a UI change. So... how do we do that?</p>

<h2>Creating and using a WCF RIA Services Class Library</h2>

<p><strong>1. Create your Silverlight project (use the Business Application template if you don't have any pressing need not to - it's great).</strong></p>

<p><strong>2. Add a new "WCF RIA Services Class Library" to your solution. This will create two projects: the class library itself and another web project to host it in.</strong></p>

<p><a href="http://lh3.ggpht.com/_-XUzf_kGi5I/TU5zAU3bxRI/AAAAAAAAAGk/lirNx381bNQ/s1600-h/image%5B14%5D.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_-XUzf_kGi5I/TU5zBVJC22I/AAAAAAAAAGo/5WUVUezEw6A/image_thumb%5B8%5D.png?imgmax=800" width="404" height="119" /></a></p>

<p><strong>3. Add a reference from your existing web site to your new class library's web site.</strong></p>

<p><strong>4. Add your domain services into your class library's web site instead of your main web site. For the sake of an example I've added a domain service around pet ownership, with Pet and Owner entities.</strong></p>

<p><strong>You're not done yet!</strong> This is the part where it will all actually work, so people tend to forget the next step. I'll show you that in a minute.</p>

<p>Let's have a look in the Generated_Code folder in our main Silverlight app at this point. Firstly, make sure that you've checked the "Show All Files" button for the SilverlightApp project so that you can see the Generated_Code directory:</p>

<p><a href="http://lh3.ggpht.com/_-XUzf_kGi5I/TU5zB5BVZpI/AAAAAAAAAGs/f4cswwrdfZ0/s1600-h/image%5B17%5D.png"><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://lh6.ggpht.com/_-XUzf_kGi5I/TU5zCblKuXI/AAAAAAAAAGw/_N2vDCF4H8U/image_thumb%5B9%5D.png?imgmax=800" width="244" height="127" /></a> <a href="http://lh6.ggpht.com/_-XUzf_kGi5I/TU5zC4BEHmI/AAAAAAAAAG0/gr8X-M7yHgs/s1600-h/image%5B20%5D.png"><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://lh6.ggpht.com/_-XUzf_kGi5I/TU5zDVBen-I/AAAAAAAAAG4/sS_shl_bqsA/image_thumb%5B10%5D.png?imgmax=800" width="221" height="61" /></a></p>

<p>Open the SilverlightApp.Web.g.cs file and have a look. You should see something like this:</p>

<p><a href="http://lh3.ggpht.com/_-XUzf_kGi5I/TU50lQYDMdI/AAAAAAAAAG8/WbazgWNPLrk/s1600-h/image%5B24%5D.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_-XUzf_kGi5I/TU50mcoJkhI/AAAAAAAAAHA/fk9heu9CCuQ/image_thumb%5B12%5D.png?imgmax=800" width="644" height="292" /></a></p>

<p>Note the definition of a proxy class for the "Owner" entity. Hang on a minute, though - this class was supposed to be in the class library - we don't want it in our main application. The whole <em>point</em> of this exercise was to <em>not</em> have all this generated code in our main Silverlight application as it takes too long to compile. The next step then:</p>

<p><strong>5. Add a reference from your Silverlight app to your Silverlight class library. This is the obvious step but it's the one that lots of people miss, hence this blog post.</strong></p>

<p>The WCF RIA code generator is actually very clever and it works out which entities you have proxy code for already to and only generates code for the ones you're missing.</p>

<p>Once you add the reference, if you leave the generated code file open, this is what you should see:</p>

<p><a href="http://lh5.ggpht.com/_-XUzf_kGi5I/TU50nLtyfpI/AAAAAAAAAHE/uKs8JAZMZMU/s1600-h/image%5B28%5D.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_-XUzf_kGi5I/TU50oqkp5bI/AAAAAAAAAHY/1AVFrKp3Ups/image_thumb%5B14%5D.png?imgmax=800" width="644" height="465" /></a></p>

<p>Ooh! No proxy code for our entities! Our compilation times just plummeted <img style="border-bottom-style: none; border-right-style: none; border-top-style: none; border-left-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://lh3.ggpht.com/_-XUzf_kGi5I/TU50pGu0TuI/AAAAAAAAAHc/SQvc6V5D4aM/wlEmoticon-smile%5B2%5D.png?imgmax=800" /></p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2011.02.06.0815</feedburner:origLink></item><item xml:base="Home/Post/2010.07.09.0242"><guid isPermaLink="false">2010.07.09.0242</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/MWDzo-Mz55w/2010.07.09.0242</link><author>andrewh@uglybugger.org</author><title>"Unable to switch servers at this time. The Team Explorer is busy."</title><description>&lt;p&gt;This one's a very irritating gotcha. I guess it illustrates the value of good, descriptive and above all, &lt;em&gt;appropriate&lt;/em&gt;, error messages.&lt;/p&gt;

&lt;p&gt;One configuration below is obviously wrong and evil; one is all that is good and wholesome. You spot the difference &lt;img style="border-bottom-style: none; border-right-style: none; border-top-style: none; border-left-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://lh6.ggpht.com/_RlpLqbhdTdM/TDaopgOtNDI/AAAAAAABFj0/XnQJoQ--XDg/wlEmoticon-smile%5B2%5D.png?imgmax=800" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_RlpLqbhdTdM/TDao-MAGgZI/AAAAAAABFkI/8A0MzIyNxTA/s1600-h/image%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; margin: 0px; display: inline; border-top: 0px; border-right: 0px" class="wlDisabledImage" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_RlpLqbhdTdM/TDao-oYnx1I/AAAAAAABFkM/vJyXRidy_z4/image_thumb.png?imgmax=800" width="244" height="131" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hint: don't put a trailing slash on your TFS server name or you'll get the error that's in the title of this post.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/MWDzo-Mz55w" height="1" width="1"/&gt;</description><pubDate>Fri, 09 Jul 2010 02:42:00 +1000</pubDate><a10:updated>2010-07-09T02:42:00+10:00</a10:updated><a10:content type="xhtml"><p>This one's a very irritating gotcha. I guess it illustrates the value of good, descriptive and above all, <em>appropriate</em>, error messages.</p>

<p>One configuration below is obviously wrong and evil; one is all that is good and wholesome. You spot the difference <img style="border-bottom-style: none; border-right-style: none; border-top-style: none; border-left-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://lh6.ggpht.com/_RlpLqbhdTdM/TDaopgOtNDI/AAAAAAABFj0/XnQJoQ--XDg/wlEmoticon-smile%5B2%5D.png?imgmax=800" /></p>

<p><a href="http://lh5.ggpht.com/_RlpLqbhdTdM/TDao-MAGgZI/AAAAAAABFkI/8A0MzIyNxTA/s1600-h/image%5B2%5D.png"><img style="border-bottom: 0px; border-left: 0px; margin: 0px; display: inline; border-top: 0px; border-right: 0px" class="wlDisabledImage" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_RlpLqbhdTdM/TDao-oYnx1I/AAAAAAABFkM/vJyXRidy_z4/image_thumb.png?imgmax=800" width="244" height="131" /></a></p>

<p>Hint: don't put a trailing slash on your TFS server name or you'll get the error that's in the title of this post.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2010.07.09.0242</feedburner:origLink></item><item xml:base="Home/Post/2010.07.04.0958"><guid isPermaLink="false">2010.07.04.0958</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/jRIOsYoTN6A/2010.07.04.0958</link><author>andrewh@uglybugger.org</author><title>If you’re so smart, why does all your code look simple?</title><description>&lt;p&gt;I hear variations on the theme of this question all the time:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;"Oh, so that's all. That's really easy."&lt;/p&gt;
  
  &lt;p&gt;"Really? That's all it does?"&lt;/p&gt;
  
  &lt;p&gt;"So where's the hard part? I understood that straight away when I looked at it."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sometimes these questions are even asked of me, which is flattering ;) The flippant answer, of course, is "So that any idiot can come along and understand it." Disappointing though it might be, this answer is also quite correct.[1]&lt;/p&gt;

&lt;p&gt;If you only ever take one piece of advice from this blog, take this one: &lt;strong&gt;Code yourself out of your job.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Coding yourself out of a job doesn't mean you're going to get fired when you're done.[2] Coding yourself out of a job means that you don't end up responsible for the same chunk of a project forever, always fixing bugs in it because it's too complicated, too involved or just plain scary for newcomers.&lt;/p&gt;

&lt;p&gt;There's an art to having someone look at your code and understand it at a glance. It's a subtle display of skill, the result of which being that the person reading your code doesn't even &lt;em&gt;realise&lt;/em&gt; that you got inside their head before they ever arrived, understood what they'd be thinking when they looked at it and gave them subtle cues as to which parts of the code were the ones they were looking for.&lt;/p&gt;

&lt;p&gt;There's also a corresponding amount of confidence required in order to be able to choose a less optimal solution in terms of performance for the sake of comprehension. Why confidence? Because as part of having your code look simple, you have to be willing to have someone stroll along after the fact and ask within two seconds of looking at your solution, "Why did you choose this way? This &lt;em&gt;other&lt;/em&gt; way's almost twice as fast..." That, my friends, is the whole point: &lt;em&gt;they understood it within two seconds of looking at it&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One "I don't understand" question about a piece of code and unless it's a really, really fast and effective algorithm and the alternatives are awful, it's already cost more in real terms than its fast performance has saved.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Obviously in heavily-hit code paths this would not a good choice, but if I have a method that only gets executed a few times per second then I honestly don't care whether it takes 0.01s or 0.001s to execute. If there's no other real difference between the two then of course I'm going to pick the faster one, but if the screamingly fast one is horrendously complicated and I'm going to be the one who'll have to come back to it every time it needs modifying, then I'll take the quite fast one, thank you very much.&lt;/p&gt;

&lt;p&gt;At the point where someone asks why you made a sub-optimal performance decision, you have to be sufficiently confident in your own ability to explain to them that yes, you could have done it another way, but then it'd take longer for every single person who came after you to understand what was going on, you'd have to field more questions about it, and that it actually didn't matter[3]. You &lt;em&gt;also&lt;/em&gt; have to be sufficiently confident in yourself to evaluate their solution and confess on occasion, "Actually, I really do like your solution and it's better than mine. Let's do it your way instead."&lt;/p&gt;

&lt;p&gt;In a nutshell, the optimal solution is not necessarily the fastest, but the most effective in terms of the long-term maintenance of the application.&lt;/p&gt;

&lt;p&gt;Of course, the &lt;em&gt;really&lt;/em&gt; smart ones amongst us can write code that's simple, obvious &lt;em&gt;and&lt;/em&gt; extremely fast. And we're all that good, right? ;)&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;[1] Especially when that idiot might be yourself six months later...&lt;/p&gt;

&lt;p&gt;[2] Unless you work for a stupid company, in which case you need to leave now anyway.&lt;/p&gt;

&lt;p&gt;[3] Be correct about this, though. If it matters, do it better.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/jRIOsYoTN6A" height="1" width="1"/&gt;</description><pubDate>Sun, 04 Jul 2010 09:58:00 +1000</pubDate><a10:updated>2010-07-04T09:58:00+10:00</a10:updated><a10:content type="xhtml"><p>I hear variations on the theme of this question all the time:</p>

<blockquote>
  <p>"Oh, so that's all. That's really easy."</p>
  
  <p>"Really? That's all it does?"</p>
  
  <p>"So where's the hard part? I understood that straight away when I looked at it."</p>
</blockquote>

<p>Sometimes these questions are even asked of me, which is flattering ;) The flippant answer, of course, is "So that any idiot can come along and understand it." Disappointing though it might be, this answer is also quite correct.[1]</p>

<p>If you only ever take one piece of advice from this blog, take this one: <strong>Code yourself out of your job.</strong></p>

<p>Coding yourself out of a job doesn't mean you're going to get fired when you're done.[2] Coding yourself out of a job means that you don't end up responsible for the same chunk of a project forever, always fixing bugs in it because it's too complicated, too involved or just plain scary for newcomers.</p>

<p>There's an art to having someone look at your code and understand it at a glance. It's a subtle display of skill, the result of which being that the person reading your code doesn't even <em>realise</em> that you got inside their head before they ever arrived, understood what they'd be thinking when they looked at it and gave them subtle cues as to which parts of the code were the ones they were looking for.</p>

<p>There's also a corresponding amount of confidence required in order to be able to choose a less optimal solution in terms of performance for the sake of comprehension. Why confidence? Because as part of having your code look simple, you have to be willing to have someone stroll along after the fact and ask within two seconds of looking at your solution, "Why did you choose this way? This <em>other</em> way's almost twice as fast..." That, my friends, is the whole point: <em>they understood it within two seconds of looking at it</em>.</p>

<p><strong>One "I don't understand" question about a piece of code and unless it's a really, really fast and effective algorithm and the alternatives are awful, it's already cost more in real terms than its fast performance has saved.</strong></p>

<p>Obviously in heavily-hit code paths this would not a good choice, but if I have a method that only gets executed a few times per second then I honestly don't care whether it takes 0.01s or 0.001s to execute. If there's no other real difference between the two then of course I'm going to pick the faster one, but if the screamingly fast one is horrendously complicated and I'm going to be the one who'll have to come back to it every time it needs modifying, then I'll take the quite fast one, thank you very much.</p>

<p>At the point where someone asks why you made a sub-optimal performance decision, you have to be sufficiently confident in your own ability to explain to them that yes, you could have done it another way, but then it'd take longer for every single person who came after you to understand what was going on, you'd have to field more questions about it, and that it actually didn't matter[3]. You <em>also</em> have to be sufficiently confident in yourself to evaluate their solution and confess on occasion, "Actually, I really do like your solution and it's better than mine. Let's do it your way instead."</p>

<p>In a nutshell, the optimal solution is not necessarily the fastest, but the most effective in terms of the long-term maintenance of the application.</p>

<p>Of course, the <em>really</em> smart ones amongst us can write code that's simple, obvious <em>and</em> extremely fast. And we're all that good, right? ;)</p>

<p> </p>

<p>[1] Especially when that idiot might be yourself six months later...</p>

<p>[2] Unless you work for a stupid company, in which case you need to leave now anyway.</p>

<p>[3] Be correct about this, though. If it matters, do it better.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2010.07.04.0958</feedburner:origLink></item><item xml:base="Home/Post/2010.05.13.0657"><guid isPermaLink="false">2010.05.13.0657</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/rmCCXC-uTWI/2010.05.13.0657</link><author>andrewh@uglybugger.org</author><title>Introducing EasyTfs</title><description>&lt;p&gt;One of the most common tasks a software developer will perform is that of creating a bug or a task in an issue-tracking system. Before a task or a case is created, the developer should search for an existing case in the system so as to avoid duplicates. This should, then, according to Amdahl's Law&lt;a href="http://lh6.ggpht.com/_RlpLqbhdTdM/S-u-2MXqj1I/AAAAAAABFgs/b2GF_3JjA34/s1600-h/image%5B5%5D.png"&gt;1&lt;/a&gt;, be very fast and simple to do.&lt;/p&gt;

&lt;p&gt;Team Foundation Server, however, does &lt;em&gt;not&lt;/em&gt; make this simple and fast. Please excuse me for not having the energy to articulate the failings of TFS in this respect, and simply offer a solution instead.&lt;/p&gt;

&lt;p&gt;Enter &lt;a href="http://easytfs.codeplex.com/" target="_blank"&gt;EasyTfs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;EasyTfs will search your TFS database as you type, allows per-field matching, regular expressions and all sorts of other goodies that real issue tracking systems have had for years.&lt;/p&gt;

&lt;p&gt;Searching for "coffee" in our TFS database here results in this:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_RlpLqbhdTdM/S-u-2MXqj1I/AAAAAAABFgs/b2GF_3JjA34/s1600-h/image%5B5%5D.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://lh5.ggpht.com/_RlpLqbhdTdM/S-u-2_sGprI/AAAAAAABFgw/macYugWP1Hc/image_thumb%5B3%5D.png?imgmax=800" width="404" height="222" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;We could also search for "createdby:tullemans coffee", "cr:dan coffee" or simply "3165" (the work item number). Image attachments (.png and .jpg) are displayed as thumbnails by default and can be displayed full-screen just by clicking on them.&lt;/p&gt;

&lt;p&gt;Searches are quick, too :)&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_RlpLqbhdTdM/S-u-3cYnCFI/AAAAAAABFg0/kbMPNROMp-0/s1600-h/image%5B11%5D.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://lh6.ggpht.com/_RlpLqbhdTdM/S-u-4HEmwGI/AAAAAAABFg4/Ib5aJf47F0I/image_thumb%5B5%5D.png?imgmax=800" width="244" height="52" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;It's read-only and ignores work-item security for the present (early beta and all that), but it's fast and has already saved our team a huge amount of time, both in simply finding cases that we know exist, and also in avoiding raising duplicate cases because it's so much easier to search for them.&lt;/p&gt;

&lt;p&gt;It's open-source (GPLv2), and you can find both the source code and a Windows installer (.MSI) at &lt;a href="http://easytfs.codeplex.com/" target="_blank"&gt;easytfs.codeplex.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_RlpLqbhdTdM/S-u-2MXqj1I/AAAAAAABFgs/b2GF_3JjA34/s1600-h/image%5B5%5D.png"&gt;1&lt;/a&gt; which can be summarised as, "Make the common case fast, damn you!"&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/rmCCXC-uTWI" height="1" width="1"/&gt;</description><pubDate>Thu, 13 May 2010 06:57:00 +1000</pubDate><a10:updated>2010-05-13T06:57:00+10:00</a10:updated><a10:content type="xhtml"><p>One of the most common tasks a software developer will perform is that of creating a bug or a task in an issue-tracking system. Before a task or a case is created, the developer should search for an existing case in the system so as to avoid duplicates. This should, then, according to Amdahl's Law<a href="http://lh6.ggpht.com/_RlpLqbhdTdM/S-u-2MXqj1I/AAAAAAABFgs/b2GF_3JjA34/s1600-h/image%5B5%5D.png">1</a>, be very fast and simple to do.</p>

<p>Team Foundation Server, however, does <em>not</em> make this simple and fast. Please excuse me for not having the energy to articulate the failings of TFS in this respect, and simply offer a solution instead.</p>

<p>Enter <a href="http://easytfs.codeplex.com/" target="_blank">EasyTfs</a>.</p>

<p>EasyTfs will search your TFS database as you type, allows per-field matching, regular expressions and all sorts of other goodies that real issue tracking systems have had for years.</p>

<p>Searching for "coffee" in our TFS database here results in this:</p>

<p><a href="http://lh6.ggpht.com/_RlpLqbhdTdM/S-u-2MXqj1I/AAAAAAABFgs/b2GF_3JjA34/s1600-h/image%5B5%5D.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_RlpLqbhdTdM/S-u-2_sGprI/AAAAAAABFgw/macYugWP1Hc/image_thumb%5B3%5D.png?imgmax=800" width="404" height="222" /></a> </p>

<p>We could also search for "createdby:tullemans coffee", "cr:dan coffee" or simply "3165" (the work item number). Image attachments (.png and .jpg) are displayed as thumbnails by default and can be displayed full-screen just by clicking on them.</p>

<p>Searches are quick, too :)</p>

<p><a href="http://lh4.ggpht.com/_RlpLqbhdTdM/S-u-3cYnCFI/AAAAAAABFg0/kbMPNROMp-0/s1600-h/image%5B11%5D.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_RlpLqbhdTdM/S-u-4HEmwGI/AAAAAAABFg4/Ib5aJf47F0I/image_thumb%5B5%5D.png?imgmax=800" width="244" height="52" /></a> </p>

<p>It's read-only and ignores work-item security for the present (early beta and all that), but it's fast and has already saved our team a huge amount of time, both in simply finding cases that we know exist, and also in avoiding raising duplicate cases because it's so much easier to search for them.</p>

<p>It's open-source (GPLv2), and you can find both the source code and a Windows installer (.MSI) at <a href="http://easytfs.codeplex.com/" target="_blank">easytfs.codeplex.com</a>.</p>

<p><a href="http://lh6.ggpht.com/_RlpLqbhdTdM/S-u-2MXqj1I/AAAAAAABFgs/b2GF_3JjA34/s1600-h/image%5B5%5D.png">1</a> which can be summarised as, "Make the common case fast, damn you!"</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2010.05.13.0657</feedburner:origLink></item><item xml:base="Home/Post/2010.05.04.1133"><guid isPermaLink="false">2010.05.04.1133</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/gyyK9D3Hm4s/2010.05.04.1133</link><author>andrewh@uglybugger.org</author><title>Visual Studio: You're Doing it Wrong! Again!!</title><description>&lt;p&gt;Here's a hint to the Visual Studio team:&lt;/p&gt;

&lt;p&gt;If I have to wait so sodding long for a modal dialog box to just GTFO of my road that I can write an entire blog post about it, &lt;strong&gt;you're doing it wrong!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_RlpLqbhdTdM/S995TH4JysI/AAAAAAABFgE/nghapbolbEA/s1600-h/image%5B9%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_RlpLqbhdTdM/S995T42GaqI/AAAAAAABFgI/moY-P0DX2n8/image_thumb%5B5%5D.png?imgmax=800" width="400" height="150" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_RlpLqbhdTdM/S995UTKGIpI/AAAAAAABFgM/NTgO4B0l7I0/s1600-h/image%5B5%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_RlpLqbhdTdM/S995Vmc-7SI/AAAAAAABFgQ/QKgzDo9_d1Y/image_thumb%5B1%5D.png?imgmax=800" width="404" height="302" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Every VS developer knows about that &lt;em&gt;stupid&lt;/em&gt; sodding help popup, and we all hate it. It's of absolutely no help whatsoever and, just FYI, most of us just re-map F1 to a do-nothing macro.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/gyyK9D3Hm4s" height="1" width="1"/&gt;</description><pubDate>Tue, 04 May 2010 11:33:00 +1000</pubDate><a10:updated>2010-05-04T11:33:00+10:00</a10:updated><a10:content type="xhtml"><p>Here's a hint to the Visual Studio team:</p>

<p>If I have to wait so sodding long for a modal dialog box to just GTFO of my road that I can write an entire blog post about it, <strong>you're doing it wrong!</strong></p>

<p><a href="http://lh5.ggpht.com/_RlpLqbhdTdM/S995TH4JysI/AAAAAAABFgE/nghapbolbEA/s1600-h/image%5B9%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_RlpLqbhdTdM/S995T42GaqI/AAAAAAABFgI/moY-P0DX2n8/image_thumb%5B5%5D.png?imgmax=800" width="400" height="150" /></a></p>

<p><a href="http://lh3.ggpht.com/_RlpLqbhdTdM/S995UTKGIpI/AAAAAAABFgM/NTgO4B0l7I0/s1600-h/image%5B5%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_RlpLqbhdTdM/S995Vmc-7SI/AAAAAAABFgQ/QKgzDo9_d1Y/image_thumb%5B1%5D.png?imgmax=800" width="404" height="302" /></a> </p>

<p>Every VS developer knows about that <em>stupid</em> sodding help popup, and we all hate it. It's of absolutely no help whatsoever and, just FYI, most of us just re-map F1 to a do-nothing macro.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2010.05.04.1133</feedburner:origLink></item><item xml:base="Home/Post/2010.04.30.0659"><guid isPermaLink="false">2010.04.30.0659</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/BDkR1ByQyh4/2010.04.30.0659</link><author>andrewh@uglybugger.org</author><title>Code Review Watch List</title><description>&lt;p&gt;When reviewing code, everyone picks on different things. This is a good thing, provided that code reviewers move around frequently and everyone gets to benefit from the resulting sharing of knowledge.&lt;/p&gt;

&lt;p&gt;Here's a bunch of anti-patterns that have bitten teams and companies that I've worked with in the past, and some ways to avoid them. This is by no means a complete list; it's simply the ones that keep jumping out at me and, more so, the ones that tend to cause pain later rather than sooner with a corresponding degree of compound interest on the original technical debt.&lt;/p&gt;

&lt;h3&gt;Always picking the same code reviewer.&lt;/h3&gt;

&lt;p&gt;Asking the guy next to you for a code review is great; just don't do it all the time. That one guy next to you will always pick on the same things, and will likely miss (or simply not value) other points that another reviewer might pick up.&lt;/p&gt;

&lt;p&gt;The guy next to you is also probably going to become familiar with the code you're working on. Again, this is often a good thing but it also means that your code, while obvious to you and your favourite reviewer, might become impenetrable to others without your realising it.&lt;/p&gt;

&lt;h3&gt;Additional "using" Statements&lt;/h3&gt;

&lt;p&gt;"Using" statements, especially when highlighted by your favourite diff tool, are a good (and simple) indicator of increased class coupling. This isn't always a bad thing, but should always be studied rather than glossed over.&lt;/p&gt;

&lt;p&gt;This should also be your cue to check whether the new code has dependencies on concrete classes in the newly-used namespace, or whether someone's been clever and has coded to an interface.&lt;/p&gt;

&lt;div&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #0000ff"&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;using&lt;/span&gt; System.Text;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;using&lt;/span&gt; My.Useful.Namespace;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;using&lt;/span&gt; My.Specific.Namespace.That.I.Shouldnt.Know.About;  &lt;span style="color: #008000"&gt;// one of these things is not like the other...&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h3&gt;Pointless Safe Casts&lt;/h3&gt;

&lt;p&gt;This is a complete pet hate of mine, as many times I've spent ages tracking down some random NullReferenceException or Debug.Assert( ... != null) failure because someone's used a safe cast and then blithely assumed that the result will be non-null.&lt;/p&gt;

&lt;div&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #008000"&gt;// BAD!! This is a NullReferenceException waiting to happen!&lt;/span&gt;&lt;br /&gt;ISpecificThingy specificThingy = thingy &lt;span style="color: #0000ff"&gt;as&lt;/span&gt; ISpecificThingy;&lt;br /&gt;specificThingy.DoSomething();&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #008000"&gt;// GOOD.  This will (correctly) throw an InvalidCastException at the point of the error, rather&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #008000"&gt;// than allowing a null value to propagate along the code path and trip someone up later.&lt;/span&gt;&lt;br /&gt;ISpecificThingy specificThingy = (ISpecificThingy)thingy;&lt;br /&gt;specificThingy.DoSomething();&lt;/pre&gt;
&lt;/div&gt;

&lt;h3&gt;Non-thread-safe Collection Modification&lt;/h3&gt;

&lt;p&gt;This probably won't bite &lt;em&gt;you&lt;/em&gt;, but it &lt;em&gt;will&lt;/em&gt; bite someone else who has to come along three months later and figure out why there's some random, non-deterministic explosion. That person, however, will probably kick you, so it all balances out in the end.&lt;/p&gt;

&lt;div&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #008000"&gt;// BAD! This is not thread-safe, and is an ArgumentException (item with same key...) waiting to happen.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Remember(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; k, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; v)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!_strings.ContainsKey(k))&lt;br /&gt;    {&lt;br /&gt;        _strings[k] = v;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #008000"&gt;// BETTER. This is thread-safe and won't explode. What's missing, though?&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Remember(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; k, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; v)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!_strings.ContainsKey(k))&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;lock&lt;/span&gt; (_strings)&lt;br /&gt;        {&lt;br /&gt;            &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!_strings.ContainsKey(k))&lt;br /&gt;            {&lt;br /&gt;                _strings[k] = v;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #008000"&gt;// GOOD&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Remember(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; k, &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; v)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #cc6633"&gt;#region&lt;/span&gt; Argument Checking&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #008000"&gt;// ... actually check arguments, here :)&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span style="color: #cc6633"&gt;#endregion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!_strings.ContainsKey(k))&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;lock&lt;/span&gt; (_strings) &lt;span style="color: #008000"&gt;// careful, though - when locking on arbitrary objects, it's easy to create deadlocks.&lt;/span&gt;&lt;br /&gt;        {&lt;br /&gt;            &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!_strings.ContainsKey(k))&lt;br /&gt;            {&lt;br /&gt;                _strings[k] = v;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;h3&gt;Catching NullReferenceExceptions&lt;/h3&gt;

&lt;p&gt;It's just bad. Please don't do it - and never let your name be associated with a review of code that does.&lt;/p&gt;

&lt;div&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #0000ff"&gt;try&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;    myFoo.Bar.OtherProperty.DoSomething();&lt;br /&gt;}&lt;br /&gt;&lt;span style="color: #0000ff"&gt;catch&lt;/span&gt;(NullReferenceException)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #008000"&gt;// Hi. I'm so utterly lazy that I can't be bothered to null-check things, *or* to&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #008000"&gt;// de-couple my classes so that I don't *have* to null-check so many things.&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #008000"&gt;//&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #008000"&gt;// Please beat me around the head with a stick.&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;h3&gt;Mapping Symbol Names to Strings&lt;/h3&gt;

&lt;div&gt;
  &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &amp;#39;Courier New&amp;#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #008000"&gt;// BAD!&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; fooTypeName = foo.GetType().FullName;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (fooTypeName.Contains(&lt;span style="color: #006080"&gt;"Widget"&lt;/span&gt;))&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color: #008000"&gt;// we have a widget!&lt;/span&gt;&lt;br /&gt;    widgets.Add(foo);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #008000"&gt;// BETTER&lt;/span&gt;&lt;br /&gt;WidgetBase widget = foo &lt;span style="color: #0000ff"&gt;as&lt;/span&gt; WidgetBase;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (widget != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;br /&gt;{&lt;br /&gt;    widgets.Add(widget);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #008000"&gt;// GOOD&lt;/span&gt;&lt;br /&gt;IWidget widget = foo &lt;span style="color: #0000ff"&gt;as&lt;/span&gt; IWidget;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (widget != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;br /&gt;{&lt;br /&gt;    widgets.Add(widget);&lt;br /&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;div&gt;
  This is easy to avoid in the example above, but less easy to avoid when messing with types and type names without having an instance to safe-cast. Use Type.GetType("your_class_name") and .IsSubClassOf() instead.
&lt;/div&gt;

&lt;div&gt;
  Not an issue in C#? Fine, then. Wait until you have to inter-operate with JavaScript, and &lt;em&gt;then&lt;/em&gt; see how you go about retro-fitting subtype checks to your entire codebase :)
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/BDkR1ByQyh4" height="1" width="1"/&gt;</description><pubDate>Fri, 30 Apr 2010 06:59:00 +1000</pubDate><a10:updated>2010-04-30T06:59:00+10:00</a10:updated><a10:content type="xhtml"><p>When reviewing code, everyone picks on different things. This is a good thing, provided that code reviewers move around frequently and everyone gets to benefit from the resulting sharing of knowledge.</p>

<p>Here's a bunch of anti-patterns that have bitten teams and companies that I've worked with in the past, and some ways to avoid them. This is by no means a complete list; it's simply the ones that keep jumping out at me and, more so, the ones that tend to cause pain later rather than sooner with a corresponding degree of compound interest on the original technical debt.</p>

<h3>Always picking the same code reviewer.</h3>

<p>Asking the guy next to you for a code review is great; just don't do it all the time. That one guy next to you will always pick on the same things, and will likely miss (or simply not value) other points that another reviewer might pick up.</p>

<p>The guy next to you is also probably going to become familiar with the code you're working on. Again, this is often a good thing but it also means that your code, while obvious to you and your favourite reviewer, might become impenetrable to others without your realising it.</p>

<h3>Additional "using" Statements</h3>

<p>"Using" statements, especially when highlighted by your favourite diff tool, are a good (and simple) indicator of increased class coupling. This isn't always a bad thing, but should always be studied rather than glossed over.</p>

<p>This should also be your cue to check whether the new code has dependencies on concrete classes in the newly-used namespace, or whether someone's been clever and has coded to an interface.</p>

<div>
  <pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">using</span> System;<br /><span style="color: #0000ff">using</span> System.Text;<br /><span style="color: #0000ff">using</span> My.Useful.Namespace;<br /><span style="color: #0000ff">using</span> My.Specific.Namespace.That.I.Shouldnt.Know.About;  <span style="color: #008000">// one of these things is not like the other...</span></pre>
</div>

<h3>Pointless Safe Casts</h3>

<p>This is a complete pet hate of mine, as many times I've spent ages tracking down some random NullReferenceException or Debug.Assert( ... != null) failure because someone's used a safe cast and then blithely assumed that the result will be non-null.</p>

<div>
  <pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #008000">// BAD!! This is a NullReferenceException waiting to happen!</span><br />ISpecificThingy specificThingy = thingy <span style="color: #0000ff">as</span> ISpecificThingy;<br />specificThingy.DoSomething();<br /><br /><span style="color: #008000">// GOOD.  This will (correctly) throw an InvalidCastException at the point of the error, rather</span><br /><span style="color: #008000">// than allowing a null value to propagate along the code path and trip someone up later.</span><br />ISpecificThingy specificThingy = (ISpecificThingy)thingy;<br />specificThingy.DoSomething();</pre>
</div>

<h3>Non-thread-safe Collection Modification</h3>

<p>This probably won't bite <em>you</em>, but it <em>will</em> bite someone else who has to come along three months later and figure out why there's some random, non-deterministic explosion. That person, however, will probably kick you, so it all balances out in the end.</p>

<div>
  <pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #008000">// BAD! This is not thread-safe, and is an ArgumentException (item with same key...) waiting to happen.</span><br /><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> Remember(<span style="color: #0000ff">string</span> k, <span style="color: #0000ff">string</span> v)<br />{<br />    <span style="color: #0000ff">if</span> (!_strings.ContainsKey(k))<br />    {<br />        _strings[k] = v;<br />    }<br />}<br /><br /><span style="color: #008000">// BETTER. This is thread-safe and won't explode. What's missing, though?</span><br /><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> Remember(<span style="color: #0000ff">string</span> k, <span style="color: #0000ff">string</span> v)<br />{<br />    <span style="color: #0000ff">if</span> (!_strings.ContainsKey(k))<br />    {<br />        <span style="color: #0000ff">lock</span> (_strings)<br />        {<br />            <span style="color: #0000ff">if</span> (!_strings.ContainsKey(k))<br />            {<br />                _strings[k] = v;<br />            }<br />        }<br />    }<br />}<br /><br /><span style="color: #008000">// GOOD</span><br /><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> Remember(<span style="color: #0000ff">string</span> k, <span style="color: #0000ff">string</span> v)<br />{<br />    <span style="color: #cc6633">#region</span> Argument Checking<br /><br />    <span style="color: #008000">// ... actually check arguments, here :)</span><br />    <br />    <span style="color: #cc6633">#endregion</span><br /><br />    <span style="color: #0000ff">if</span> (!_strings.ContainsKey(k))<br />    {<br />        <span style="color: #0000ff">lock</span> (_strings) <span style="color: #008000">// careful, though - when locking on arbitrary objects, it's easy to create deadlocks.</span><br />        {<br />            <span style="color: #0000ff">if</span> (!_strings.ContainsKey(k))<br />            {<br />                _strings[k] = v;<br />            }<br />        }<br />    }<br />}</pre>
</div>

<h3>Catching NullReferenceExceptions</h3>

<p>It's just bad. Please don't do it - and never let your name be associated with a review of code that does.</p>

<div>
  <pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">try</span><br />{<br />    myFoo.Bar.OtherProperty.DoSomething();<br />}<br /><span style="color: #0000ff">catch</span>(NullReferenceException)<br />{<br />    <span style="color: #008000">// Hi. I'm so utterly lazy that I can't be bothered to null-check things, *or* to</span><br />    <span style="color: #008000">// de-couple my classes so that I don't *have* to null-check so many things.</span><br />    <span style="color: #008000">//</span><br />    <span style="color: #008000">// Please beat me around the head with a stick.</span><br />}</pre>
</div>

<h3>Mapping Symbol Names to Strings</h3>

<div>
  <pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #008000">// BAD!</span><br /><span style="color: #0000ff">string</span> fooTypeName = foo.GetType().FullName;<br /><span style="color: #0000ff">if</span> (fooTypeName.Contains(<span style="color: #006080">"Widget"</span>))<br />{<br />    <span style="color: #008000">// we have a widget!</span><br />    widgets.Add(foo);<br />}<br /><br /><span style="color: #008000">// BETTER</span><br />WidgetBase widget = foo <span style="color: #0000ff">as</span> WidgetBase;<br /><span style="color: #0000ff">if</span> (widget != <span style="color: #0000ff">null</span>)<br />{<br />    widgets.Add(widget);<br />}<br /><br /><span style="color: #008000">// GOOD</span><br />IWidget widget = foo <span style="color: #0000ff">as</span> IWidget;<br /><span style="color: #0000ff">if</span> (widget != <span style="color: #0000ff">null</span>)<br />{<br />    widgets.Add(widget);<br />}</pre>
</div>

<div>
  This is easy to avoid in the example above, but less easy to avoid when messing with types and type names without having an instance to safe-cast. Use Type.GetType("your_class_name") and .IsSubClassOf() instead.
</div>

<div>
  Not an issue in C#? Fine, then. Wait until you have to inter-operate with JavaScript, and <em>then</em> see how you go about retro-fitting subtype checks to your entire codebase :)
</div>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2010.04.30.0659</feedburner:origLink></item><item xml:base="Home/Post/2010.04.19.1123"><guid isPermaLink="false">2010.04.19.1123</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/FcPWildXF-4/2010.04.19.1123</link><author>andrewh@uglybugger.org</author><title>Automatic Updates? Bollocks.</title><description>&lt;p&gt;I'm an upgrade junkie. I really like having the latest and greatest of every piece of software on my workstation. That having been said, I absolutely hate with a passion having to update the whole lot of it manually.&lt;/p&gt;

&lt;p&gt;I just returned to work from a week's holiday. (It was a great holiday, by the way - I did almost entirely nothing - but that's not the point of this post.) Let's go through the list of software that pestered me to update it upon my return:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Firefox (Twice - once to 3.5.7 then another to 3.6! What happened there, guys?)&lt;/li&gt;
&lt;li&gt;Adobe Reader&lt;/li&gt;
&lt;li&gt;Opera&lt;/li&gt;
&lt;li&gt;Windows (surprise)&lt;/li&gt;
&lt;li&gt;Java&lt;/li&gt;
&lt;li&gt;Forefront&lt;/li&gt;
&lt;li&gt;Seesmic&lt;/li&gt;
&lt;li&gt;Firefox (Again!! ("Downloading and installing updates to your add-ons." WTF?)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_RlpLqbhdTdM/S8uwg9J7A-I/AAAAAAABFaA/aCKl2AwgwT4/s1600-h/image%5B9%5D.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://lh4.ggpht.com/_RlpLqbhdTdM/S8uwhioWHNI/AAAAAAABFaE/R8eeX3A0tEc/image_thumb%5B5%5D.png?imgmax=800" width="215" height="154" /&gt;&lt;/a&gt; &lt;a href="http://lh6.ggpht.com/_RlpLqbhdTdM/S8uwiSLRHCI/AAAAAAABFaI/TfefnNe9Ras/s1600-h/image%5B10%5D.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://lh6.ggpht.com/_RlpLqbhdTdM/S8uwi8TDacI/AAAAAAABFaM/V-jRDIuadak/image_thumb%5B6%5D.png?imgmax=800" width="193" height="154" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The list actually goes on, believe it or not, but I'm already fed up with the sight of little scrolly bars.&lt;/p&gt;

&lt;p&gt;A plea, then, to all software developers: make your software update itself automatically and silently.&lt;/p&gt;

&lt;p&gt;I've been walking around all morning asking people, "Does anyone know what version of Google Chrome we're up to now? Four! Chrome 4.0 and nobody's noticed, because it updates itself silently." As it turns out, we're actually up to version &lt;em&gt;five&lt;/em&gt;, and &lt;em&gt;I&lt;/em&gt; didn't notice - for the same reason. Chrome team, I take my hat off to you.&lt;/p&gt;

&lt;p&gt;Here are a couple of simple questions you should ask yourself as a developer:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Is my software life-, mission- or business-critical? That is, will people die or lose vast sums of money if my software fails?&lt;/li&gt;
&lt;li&gt;Are my unit and regression test suites up to date? Will I be able to tell if I've broken my software?&lt;/li&gt;
&lt;li&gt;Am I going to change my licence agreement?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you're writing, for example, an &lt;a href="http://www.zaptechnology.com/" target="_blank"&gt;enterprise-grade business intelligence suite&lt;/a&gt;, then perhaps you shouldn't auto-upgrade. By all means, make it &lt;em&gt;easy&lt;/em&gt; for people to upgrade, but don't do the whole ninja-update-sneak-it-in-at-midnight thing.&lt;/p&gt;

&lt;p&gt;If you're writing pretty much any other type of software, here's a tip: &lt;em&gt;users don't care about point releases&lt;/em&gt;. They don't care about bug fixes unless it directly impacts them. They don't even really care about major feature additions - they're obviously already using your software, so it must be fulfilling some need for them. By all means, add features, but do it in a way that isn't disruptive to your existing user base.&lt;/p&gt;

&lt;p&gt;Users, to be honest, really don't care about anything much, other than how to get their work done - and your stupid "Update Me! Now! Now!" dialog box is just getting in their way.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/FcPWildXF-4" height="1" width="1"/&gt;</description><pubDate>Mon, 19 Apr 2010 11:23:00 +1000</pubDate><a10:updated>2010-04-19T11:23:00+10:00</a10:updated><a10:content type="xhtml"><p>I'm an upgrade junkie. I really like having the latest and greatest of every piece of software on my workstation. That having been said, I absolutely hate with a passion having to update the whole lot of it manually.</p>

<p>I just returned to work from a week's holiday. (It was a great holiday, by the way - I did almost entirely nothing - but that's not the point of this post.) Let's go through the list of software that pestered me to update it upon my return:</p>

<ul>
<li>Firefox (Twice - once to 3.5.7 then another to 3.6! What happened there, guys?)</li>
<li>Adobe Reader</li>
<li>Opera</li>
<li>Windows (surprise)</li>
<li>Java</li>
<li>Forefront</li>
<li>Seesmic</li>
<li>Firefox (Again!! ("Downloading and installing updates to your add-ons." WTF?)</li>
</ul>

<p><a href="http://lh6.ggpht.com/_RlpLqbhdTdM/S8uwg9J7A-I/AAAAAAABFaA/aCKl2AwgwT4/s1600-h/image%5B9%5D.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_RlpLqbhdTdM/S8uwhioWHNI/AAAAAAABFaE/R8eeX3A0tEc/image_thumb%5B5%5D.png?imgmax=800" width="215" height="154" /></a> <a href="http://lh6.ggpht.com/_RlpLqbhdTdM/S8uwiSLRHCI/AAAAAAABFaI/TfefnNe9Ras/s1600-h/image%5B10%5D.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_RlpLqbhdTdM/S8uwi8TDacI/AAAAAAABFaM/V-jRDIuadak/image_thumb%5B6%5D.png?imgmax=800" width="193" height="154" /></a> </p>

<p>The list actually goes on, believe it or not, but I'm already fed up with the sight of little scrolly bars.</p>

<p>A plea, then, to all software developers: make your software update itself automatically and silently.</p>

<p>I've been walking around all morning asking people, "Does anyone know what version of Google Chrome we're up to now? Four! Chrome 4.0 and nobody's noticed, because it updates itself silently." As it turns out, we're actually up to version <em>five</em>, and <em>I</em> didn't notice - for the same reason. Chrome team, I take my hat off to you.</p>

<p>Here are a couple of simple questions you should ask yourself as a developer:</p>

<ol>
<li>Is my software life-, mission- or business-critical? That is, will people die or lose vast sums of money if my software fails?</li>
<li>Are my unit and regression test suites up to date? Will I be able to tell if I've broken my software?</li>
<li>Am I going to change my licence agreement?</li>
</ol>

<p>If you're writing, for example, an <a href="http://www.zaptechnology.com/" target="_blank">enterprise-grade business intelligence suite</a>, then perhaps you shouldn't auto-upgrade. By all means, make it <em>easy</em> for people to upgrade, but don't do the whole ninja-update-sneak-it-in-at-midnight thing.</p>

<p>If you're writing pretty much any other type of software, here's a tip: <em>users don't care about point releases</em>. They don't care about bug fixes unless it directly impacts them. They don't even really care about major feature additions - they're obviously already using your software, so it must be fulfilling some need for them. By all means, add features, but do it in a way that isn't disruptive to your existing user base.</p>

<p>Users, to be honest, really don't care about anything much, other than how to get their work done - and your stupid "Update Me! Now! Now!" dialog box is just getting in their way.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2010.04.19.1123</feedburner:origLink></item><item xml:base="Home/Post/2010.02.27.0138"><guid isPermaLink="false">2010.02.27.0138</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/UXQPbRJYm5Q/2010.02.27.0138</link><author>andrewh@uglybugger.org</author><title>Generic solution for testing flag enums in C#</title><description>&lt;p&gt;This is one that's irritated me just a little for ages, but never as much as this morning, when I needed to create a
whole swag of small-ish flags enums and then test for bits set in them.&lt;/p&gt;

&lt;p&gt;Here's a quick solution:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public static class FlagExtensions
{
    public static bool HasFlag&amp;lt;T&amp;gt;(this T target, T flag) where T: struct
    {
        if (!typeof(T).IsEnum) throw new InvalidOperationException("Only supported for enum types.");

        int targetInt = Convert.ToInt32(target);
        int flagInt = Convert.ToInt32(flag);

        return (targetInt &amp;amp; flagInt) == flagInt;
    }
} 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notably, while we can't use a where T: Enum constraint in our extension method, an enum (lower-case e) is actually
a struct, so we can at least constrain it to structs and then do a quick type-check.  &lt;/p&gt;

&lt;p&gt;To use it to test whether an enum value has a particular flag set, try this:  &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;MyFlagEnum flags = MyFlagEnum.Default;

if (flags.HasFlag&amp;lt;MyFlagEnum&amp;gt;(MyFlagEnum.Coffee))
{
    // our "Coffee" bit is set. Yum!
}
&lt;/code&gt;&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/UXQPbRJYm5Q" height="1" width="1"/&gt;</description><pubDate>Sat, 27 Feb 2010 01:38:00 +1000</pubDate><a10:updated>2010-02-27T01:38:00+10:00</a10:updated><a10:content type="xhtml"><p>This is one that's irritated me just a little for ages, but never as much as this morning, when I needed to create a
whole swag of small-ish flags enums and then test for bits set in them.</p>

<p>Here's a quick solution:</p>

<pre><code>public static class FlagExtensions
{
    public static bool HasFlag&lt;T&gt;(this T target, T flag) where T: struct
    {
        if (!typeof(T).IsEnum) throw new InvalidOperationException("Only supported for enum types.");

        int targetInt = Convert.ToInt32(target);
        int flagInt = Convert.ToInt32(flag);

        return (targetInt &amp; flagInt) == flagInt;
    }
} 
</code></pre>

<p>Notably, while we can't use a where T: Enum constraint in our extension method, an enum (lower-case e) is actually
a struct, so we can at least constrain it to structs and then do a quick type-check.  </p>

<p>To use it to test whether an enum value has a particular flag set, try this:  </p>

<pre><code>MyFlagEnum flags = MyFlagEnum.Default;

if (flags.HasFlag&lt;MyFlagEnum&gt;(MyFlagEnum.Coffee))
{
    // our "Coffee" bit is set. Yum!
}
</code></pre>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2010.02.27.0138</feedburner:origLink></item><item xml:base="Home/Post/2010.02.03.0231"><guid isPermaLink="false">2010.02.03.0231</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/ZoKoNCpr2ds/2010.02.03.0231</link><author>andrewh@uglybugger.org</author><title>Ugly Photos Screen Saver</title><description>&lt;p&gt;This is a very, very simple screen saver. I wrote it because I was fed up with not having one that did precisely what I wanted.&lt;/p&gt;

&lt;p&gt;There will probably be updates to it, but it does what I want for now. Hopefully it'll work for some others, too.&lt;/p&gt;

&lt;h3&gt;Features&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Displays photos from your My Pictures folder and/or any other folders that you configure.&lt;/li&gt;
&lt;li&gt;Performs a simple cross-fade between images.&lt;/li&gt;
&lt;li&gt;Navigate forward/backward between individual images and image galleries.&lt;/li&gt;
&lt;li&gt;Multiple monitor support.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Screenshots&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_RlpLqbhdTdM/S2j8CcZYcNI/AAAAAAABFAw/9XAKPKqmVDQ/s1600-h/image%5B5%5D.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://lh3.ggpht.com/_RlpLqbhdTdM/S2j8DV9FaKI/AAAAAAABFA0/KltXfXoUVG4/image_thumb%5B1%5D.png?imgmax=800" width="375" height="404" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_RlpLqbhdTdM/S2j8EPDfcPI/AAAAAAABFA4/Q2xNF_FZz_Q/s1600-h/image%5B2%5D.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://lh6.ggpht.com/_RlpLqbhdTdM/S2j8E8AiJ5I/AAAAAAABFA8/KbHxbuFDy8s/image_thumb.png?imgmax=800" width="404" height="213" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;What's it cost?&lt;/h3&gt;

&lt;p&gt;Nothing. It's free. If I update it to do some cool stuff that other screensavers don't do then I'll start asking a small price for it but, for now, it's free.&lt;/p&gt;

&lt;h3&gt;Licence Agreement&lt;/h3&gt;

&lt;p&gt;Permission is hereby granted, free of charge, to any person obtaining a copy of this software to use it without charge. All other rights, including those to modify, copy, merge, sell, license, sub-license, publish or otherwise distribute the software, are reserved by the author.&lt;/p&gt;

&lt;p&gt;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.&lt;/p&gt;

&lt;h3&gt;Download and Install&lt;/h3&gt;

&lt;p&gt;To install it under Windows Vista or Windows 7, save it to your Downloads folder, then right-click the saved file and select &lt;strong&gt;Install&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To install it under Windows XP, just save it to C:\Windows\System32 and you're done.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://dl.dropbox.com/u/1737721/Ugly%20Photos%20Screen%20Saver/Ugly.scr"&gt;I accept the licence agreement above. Download Ugly.scr.&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Please let the screen saver report errors to me&lt;/h3&gt;

&lt;p&gt;I neither want nor care about your bank account details, Facebook password or whether you tweet or not. I just want to know when my app crashes or experiences an unexpected failure. You can, of course, turn off error reporting, but by leaving it turned on you'll provide anonymous feedback to me so that I can fix things that go wrong.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/ZoKoNCpr2ds" height="1" width="1"/&gt;</description><pubDate>Wed, 03 Feb 2010 02:31:00 +1000</pubDate><a10:updated>2010-02-03T02:31:00+10:00</a10:updated><a10:content type="xhtml"><p>This is a very, very simple screen saver. I wrote it because I was fed up with not having one that did precisely what I wanted.</p>

<p>There will probably be updates to it, but it does what I want for now. Hopefully it'll work for some others, too.</p>

<h3>Features</h3>

<ul>
<li>Displays photos from your My Pictures folder and/or any other folders that you configure.</li>
<li>Performs a simple cross-fade between images.</li>
<li>Navigate forward/backward between individual images and image galleries.</li>
<li>Multiple monitor support.</li>
</ul>

<h3>Screenshots</h3>

<p><a href="http://lh6.ggpht.com/_RlpLqbhdTdM/S2j8CcZYcNI/AAAAAAABFAw/9XAKPKqmVDQ/s1600-h/image%5B5%5D.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/_RlpLqbhdTdM/S2j8DV9FaKI/AAAAAAABFA0/KltXfXoUVG4/image_thumb%5B1%5D.png?imgmax=800" width="375" height="404" /></a> </p>

<p><a href="http://lh4.ggpht.com/_RlpLqbhdTdM/S2j8EPDfcPI/AAAAAAABFA4/Q2xNF_FZz_Q/s1600-h/image%5B2%5D.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_RlpLqbhdTdM/S2j8E8AiJ5I/AAAAAAABFA8/KbHxbuFDy8s/image_thumb.png?imgmax=800" width="404" height="213" /></a> </p>

<h3>What's it cost?</h3>

<p>Nothing. It's free. If I update it to do some cool stuff that other screensavers don't do then I'll start asking a small price for it but, for now, it's free.</p>

<h3>Licence Agreement</h3>

<p>Permission is hereby granted, free of charge, to any person obtaining a copy of this software to use it without charge. All other rights, including those to modify, copy, merge, sell, license, sub-license, publish or otherwise distribute the software, are reserved by the author.</p>

<p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</p>

<h3>Download and Install</h3>

<p>To install it under Windows Vista or Windows 7, save it to your Downloads folder, then right-click the saved file and select <strong>Install</strong>.</p>

<p>To install it under Windows XP, just save it to C:\Windows\System32 and you're done.</p>

<p><a href="http://dl.dropbox.com/u/1737721/Ugly%20Photos%20Screen%20Saver/Ugly.scr">I accept the licence agreement above. Download Ugly.scr.</a></p>

<h3>Please let the screen saver report errors to me</h3>

<p>I neither want nor care about your bank account details, Facebook password or whether you tweet or not. I just want to know when my app crashes or experiences an unexpected failure. You can, of course, turn off error reporting, but by leaving it turned on you'll provide anonymous feedback to me so that I can fix things that go wrong.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2010.02.03.0231</feedburner:origLink></item><item xml:base="Home/Post/2009.12.07.1041"><guid isPermaLink="false">2009.12.07.1041</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/We0Fz2UOs08/2009.12.07.1041</link><author>andrewh@uglybugger.org</author><title>Quick JavaScript debugging: the browser’s address bar</title><description>&lt;p&gt;Okay, so I feel a bit stupid for not having noticed this before. I wanted to geo-tag my blog in FeedBurner and so flicked to Google Maps to work out the latitude and longitude of the head office of the company at which I work.&lt;/p&gt;

&lt;p&gt;I found a quick guide on &lt;a href="http://www.tech-recipes.com/rx/2403/google_maps_get_latitude_longitude_values/" target="_blank"&gt;how to extract lat/long information from Google Maps&lt;/a&gt; on the &lt;a href="http://www.tech-recipes.com/" target="_blank"&gt;Tech-Recipes&lt;/a&gt; site, which suggested centring[1] the map and then copying and pasting the following JavaScript code snippet into the browser's address bar:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;javascript:void(prompt('',gApplication.getMap().getCenter()));&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For the record, the code works, but that's not what caught my attention. The code runs, but the part that was new to me is that &lt;em&gt;the code runs in the context of the current browser window and has access to all its variables&lt;/em&gt;. I'd never realised that before, hence why I now feel stupid.&lt;/p&gt;

&lt;p&gt;Nonetheless, it means that I now have a quick way of executing arbitrary JavaScript when I want to poke around on a page but don't want to fire up a debugging tool.&lt;/p&gt;

&lt;p&gt;Oh, and yes, jQuery expressions do work, but watch out for characters requiring escaping in your selectors.&lt;/p&gt;

&lt;p&gt;[1] I'm Australian. That's correct spelling. So there :)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/We0Fz2UOs08" height="1" width="1"/&gt;</description><pubDate>Mon, 07 Dec 2009 10:41:00 +1000</pubDate><a10:updated>2009-12-07T10:41:00+10:00</a10:updated><a10:content type="xhtml"><p>Okay, so I feel a bit stupid for not having noticed this before. I wanted to geo-tag my blog in FeedBurner and so flicked to Google Maps to work out the latitude and longitude of the head office of the company at which I work.</p>

<p>I found a quick guide on <a href="http://www.tech-recipes.com/rx/2403/google_maps_get_latitude_longitude_values/" target="_blank">how to extract lat/long information from Google Maps</a> on the <a href="http://www.tech-recipes.com/" target="_blank">Tech-Recipes</a> site, which suggested centring[1] the map and then copying and pasting the following JavaScript code snippet into the browser's address bar:</p>

<blockquote>
  <p>javascript:void(prompt('',gApplication.getMap().getCenter()));</p>
</blockquote>

<p>For the record, the code works, but that's not what caught my attention. The code runs, but the part that was new to me is that <em>the code runs in the context of the current browser window and has access to all its variables</em>. I'd never realised that before, hence why I now feel stupid.</p>

<p>Nonetheless, it means that I now have a quick way of executing arbitrary JavaScript when I want to poke around on a page but don't want to fire up a debugging tool.</p>

<p>Oh, and yes, jQuery expressions do work, but watch out for characters requiring escaping in your selectors.</p>

<p>[1] I'm Australian. That's correct spelling. So there :)</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.12.07.1041</feedburner:origLink></item><item xml:base="Home/Post/2009.12.04.0223"><guid isPermaLink="false">2009.12.04.0223</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/sMFbolIXe48/2009.12.04.0223</link><author>andrewh@uglybugger.org</author><title>Never again will I forget the address of a DNS server...</title><description>&lt;p&gt;Google has just opened its &lt;a href="http://code.google.com/speed/public-dns/" target="_blank"&gt;Google Public DNS&lt;/a&gt; service to the public. It's very cool, but I'll come back to that. The coolest features of all, however, are the IP addresses at which the DNS servers live:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;8.8.8.8&lt;/p&gt;
  
  &lt;p&gt;8.8.4.4&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Odds are I'll never need to remember the IP address of another DNS server as long as I live :)&lt;/p&gt;

&lt;p&gt;Okay, the other cool stuff. Firstly, it pre-fetches a bunch of records; secondly, it handles recursive lookups; &lt;em&gt;very&lt;/em&gt; importantly, it doesn't do the dodgy resolve-to-ugly-spammer-sites that lots of other DNS services do when they can't resolve a particular hostname.&lt;/p&gt;

&lt;p&gt;It'd be nice to see localised versions of these so that those of us not in the United States of Litigation don't have to wait for packets to hop the pond and back, but I'm sure that will happen with time.&lt;/p&gt;

&lt;p&gt;Oh, and for all the tin-foil-hat-wearing conspiracy theorists out there: yes, this means that Google can tell whose hostname you're looking up. Face it, though, you're probably going to be going there as a result of a Google search anyway, so they &lt;em&gt;already&lt;/em&gt; know. I'd trust Google to "Do no evil" &lt;em&gt;way&lt;/em&gt; before I'd trust my local ISP.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/sMFbolIXe48" height="1" width="1"/&gt;</description><pubDate>Fri, 04 Dec 2009 02:23:00 +1000</pubDate><a10:updated>2009-12-04T02:23:00+10:00</a10:updated><a10:content type="xhtml"><p>Google has just opened its <a href="http://code.google.com/speed/public-dns/" target="_blank">Google Public DNS</a> service to the public. It's very cool, but I'll come back to that. The coolest features of all, however, are the IP addresses at which the DNS servers live:</p>

<blockquote>
  <p>8.8.8.8</p>
  
  <p>8.8.4.4</p>
</blockquote>

<p>Odds are I'll never need to remember the IP address of another DNS server as long as I live :)</p>

<p>Okay, the other cool stuff. Firstly, it pre-fetches a bunch of records; secondly, it handles recursive lookups; <em>very</em> importantly, it doesn't do the dodgy resolve-to-ugly-spammer-sites that lots of other DNS services do when they can't resolve a particular hostname.</p>

<p>It'd be nice to see localised versions of these so that those of us not in the United States of Litigation don't have to wait for packets to hop the pond and back, but I'm sure that will happen with time.</p>

<p>Oh, and for all the tin-foil-hat-wearing conspiracy theorists out there: yes, this means that Google can tell whose hostname you're looking up. Face it, though, you're probably going to be going there as a result of a Google search anyway, so they <em>already</em> know. I'd trust Google to "Do no evil" <em>way</em> before I'd trust my local ISP.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.12.04.0223</feedburner:origLink></item><item xml:base="Home/Post/2009.11.22.0515"><guid isPermaLink="false">2009.11.22.0515</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/xna7Is-Fxes/2009.11.22.0515</link><author>andrewh@uglybugger.org</author><title>"Your browsers are bad and you should feel bad."</title><description>&lt;p&gt;Microsoft &lt;a href="http://blogs.msdn.com/ie/archive/2009/11/18/an-early-look-at-ie9-for-developers.aspx" target="_blank"&gt;released a preview of Internet Explorer 9&lt;/a&gt; the other day. The world sniggered.&lt;/p&gt;

&lt;p&gt;My favourite comment of all of the ones on the IEBlog was by someone known only as Justin": "Your browsers are bad and you should feel bad." Justin, if you send me an email I'll send you a cookie for that quote.&lt;/p&gt;

&lt;p&gt;Don't get me wrong; I think it's great that Microsoft's finally staring to accept that their IE8 browser was obsolete before it even shipped. Their own graph shows that IE7 is around three times slower than IE8, which is in turn around five times slower than the next-slowest browser in circulation (Firefox), which is in turn at least twice as slow as Chrome. In other words, Microsoft's own graph shows an absolutely staggering performance difference between IE7 and the rest of the civilised world, and IE8 sitting all by itself in the middle. It's worth noting that while IE6 is also still a supported browser, Microsoft appears to have simply been too embarrassed to even include it.&lt;/p&gt;

&lt;p&gt;Microsoft claims that IE9 today is about as fast as the current version of Firefox. Oh, but wait - IE9 hasn't shipped yet, and won't for ages, whereas Firefox is out in the market, systematically eating away at IE's anti-trust-derived market share along with its younger, slimmer cousins like Opera, Chrome and Safari.&lt;/p&gt;

&lt;p&gt;Microsoft's next claim to fame is a massive improvement on their Acid3 test score, from 32/100 to... umm... 32/100. Hang on - what? You mean you've got an entirely new browser under development, guys, but you haven't fixed the core of what was broken with the previous one?&lt;/p&gt;

&lt;p&gt;For the record, IE's performance is awful. We as professional developers accept that and dislike it, but it's only a reason to &lt;em&gt;dislike&lt;/em&gt; Internet Explorer. The reason that anyone who's ever had to code for it hates the bloody thing with a passion is simple: &lt;em&gt;it doesn't support nearly enough of the web standards that every other browser in common use does&lt;/em&gt;. Oh, and &lt;a href="http://www.codingforfunandprofit.com/2009/07/microsoft-on-why-memory-leak-isn-really.html" target="_blank"&gt;it leaks memory like a bloody sieve, too&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Oh, but wonderful - I can now have 96-point Gabriola text render really quickly and without jaggies. I can honestly say that of all my complaints about having to write code for Internet Explorer, that's been number one on my all-time wish list. Wow. I can die happy, now.&lt;/p&gt;

&lt;p&gt;I'm not suggesting that Microsoft should stop development on IE. Far from it. Competition is good, right? If everyone were to adopt WebKit then we'd only be in a whole new world of hurt five years from now. What the entire development community would absolutely love to see, however, is this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fix the update mechanism. Has anyone noticed that we're up to Chrome 4.xx now? No? Why not? Because the thing updates itself, that's why. Make IE do the same, and ditch support for all legacy versions. If large corporate clients want to keep using IE6 for their intranet applications, fine. Let them. But if you continue to inflict IE6 and its misbegotten children on the world because of a few large corporate clients, the rest of the world is going to despise you for it. Rightly so.&lt;/li&gt;
&lt;li&gt;Just make it work. We honestly don't care how fast it runs as long as it's within cooee of the others. We do care about having to write custom code to deal with the broken rendering engine, memory leaks and other nasties.&lt;/li&gt;
&lt;li&gt;Stop bragging about until you've done it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To be civil (which is less than you're getting from most of the web community), but blunt nonetheless: put up or shut up.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/xna7Is-Fxes" height="1" width="1"/&gt;</description><pubDate>Sun, 22 Nov 2009 05:15:00 +1000</pubDate><a10:updated>2009-11-22T05:15:00+10:00</a10:updated><a10:content type="xhtml"><p>Microsoft <a href="http://blogs.msdn.com/ie/archive/2009/11/18/an-early-look-at-ie9-for-developers.aspx" target="_blank">released a preview of Internet Explorer 9</a> the other day. The world sniggered.</p>

<p>My favourite comment of all of the ones on the IEBlog was by someone known only as Justin": "Your browsers are bad and you should feel bad." Justin, if you send me an email I'll send you a cookie for that quote.</p>

<p>Don't get me wrong; I think it's great that Microsoft's finally staring to accept that their IE8 browser was obsolete before it even shipped. Their own graph shows that IE7 is around three times slower than IE8, which is in turn around five times slower than the next-slowest browser in circulation (Firefox), which is in turn at least twice as slow as Chrome. In other words, Microsoft's own graph shows an absolutely staggering performance difference between IE7 and the rest of the civilised world, and IE8 sitting all by itself in the middle. It's worth noting that while IE6 is also still a supported browser, Microsoft appears to have simply been too embarrassed to even include it.</p>

<p>Microsoft claims that IE9 today is about as fast as the current version of Firefox. Oh, but wait - IE9 hasn't shipped yet, and won't for ages, whereas Firefox is out in the market, systematically eating away at IE's anti-trust-derived market share along with its younger, slimmer cousins like Opera, Chrome and Safari.</p>

<p>Microsoft's next claim to fame is a massive improvement on their Acid3 test score, from 32/100 to... umm... 32/100. Hang on - what? You mean you've got an entirely new browser under development, guys, but you haven't fixed the core of what was broken with the previous one?</p>

<p>For the record, IE's performance is awful. We as professional developers accept that and dislike it, but it's only a reason to <em>dislike</em> Internet Explorer. The reason that anyone who's ever had to code for it hates the bloody thing with a passion is simple: <em>it doesn't support nearly enough of the web standards that every other browser in common use does</em>. Oh, and <a href="http://www.codingforfunandprofit.com/2009/07/microsoft-on-why-memory-leak-isn-really.html" target="_blank">it leaks memory like a bloody sieve, too</a>.</p>

<p>Oh, but wonderful - I can now have 96-point Gabriola text render really quickly and without jaggies. I can honestly say that of all my complaints about having to write code for Internet Explorer, that's been number one on my all-time wish list. Wow. I can die happy, now.</p>

<p>I'm not suggesting that Microsoft should stop development on IE. Far from it. Competition is good, right? If everyone were to adopt WebKit then we'd only be in a whole new world of hurt five years from now. What the entire development community would absolutely love to see, however, is this:</p>

<ol>
<li>Fix the update mechanism. Has anyone noticed that we're up to Chrome 4.xx now? No? Why not? Because the thing updates itself, that's why. Make IE do the same, and ditch support for all legacy versions. If large corporate clients want to keep using IE6 for their intranet applications, fine. Let them. But if you continue to inflict IE6 and its misbegotten children on the world because of a few large corporate clients, the rest of the world is going to despise you for it. Rightly so.</li>
<li>Just make it work. We honestly don't care how fast it runs as long as it's within cooee of the others. We do care about having to write custom code to deal with the broken rendering engine, memory leaks and other nasties.</li>
<li>Stop bragging about until you've done it.</li>
</ol>

<p>To be civil (which is less than you're getting from most of the web community), but blunt nonetheless: put up or shut up.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.11.22.0515</feedburner:origLink></item><item xml:base="Home/Post/2009.10.30.0142"><guid isPermaLink="false">2009.10.30.0142</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/1JP9yGl0y6c/2009.10.30.0142</link><author>andrewh@uglybugger.org</author><title>Google launches SideWiki for Chrome</title><description>&lt;p&gt;A while ago, I blogged about how it was amusing that Google had a new-ish product, SideWiki, that &lt;a href="http://www.codingforfunandprofit.com/2009/10/google-toolbar-requires-firefox.html" target="_blank"&gt;only worked in Firefox&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Google has just released a bookmarklet that will allow SideWiki to work in Chrome, Safari and others. &lt;a href="http://chrome.blogspot.com/2009/10/bringing-google-sidewiki-goodness-to.html" target="_blank"&gt;Read their official blog post about it here&lt;/a&gt;, or, if you already have it installed, perhaps even consider annotating this blog post :)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/1JP9yGl0y6c" height="1" width="1"/&gt;</description><pubDate>Fri, 30 Oct 2009 01:42:00 +1000</pubDate><a10:updated>2009-10-30T01:42:00+10:00</a10:updated><a10:content type="xhtml"><p>A while ago, I blogged about how it was amusing that Google had a new-ish product, SideWiki, that <a href="http://www.codingforfunandprofit.com/2009/10/google-toolbar-requires-firefox.html" target="_blank">only worked in Firefox</a>.</p>

<p>Google has just released a bookmarklet that will allow SideWiki to work in Chrome, Safari and others. <a href="http://chrome.blogspot.com/2009/10/bringing-google-sidewiki-goodness-to.html" target="_blank">Read their official blog post about it here</a>, or, if you already have it installed, perhaps even consider annotating this blog post :)</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.10.30.0142</feedburner:origLink></item><item xml:base="Home/Post/2009.10.25.1005"><guid isPermaLink="false">2009.10.25.1005</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/UvH8fDHhjQg/2009.10.25.1005</link><author>andrewh@uglybugger.org</author><title>UI Fail</title><description>&lt;p&gt;This morning I cancelled an old account with a DNS hosting provider. I'd been signed up to them involuntarily by a web hosting company, which is one of the reasons it's no longer my osting company. No hyperlinks - I can't really recommend either of them and that's not what this post is about.&lt;/p&gt;

&lt;p&gt;I clicked the "Account | Cancel" link and was presented with this dialogue box.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_RlpLqbhdTdM/SuOWJ6uDsWI/AAAAAAABEUM/IKxUAHgu1mc/s1600-h/image%5B5%5D.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://lh5.ggpht.com/_RlpLqbhdTdM/SuOWLdDAwkI/AAAAAAABEUU/fk7dtIJeZog/image_thumb%5B1%5D.png?imgmax=800" width="404" height="114" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Please, guys. If you don't have a UI designer, get one. If you &lt;em&gt;do&lt;/em&gt; have one, get another one instead.&lt;/p&gt;

&lt;p&gt;Fail.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/UvH8fDHhjQg" height="1" width="1"/&gt;</description><pubDate>Sun, 25 Oct 2009 10:05:00 +1000</pubDate><a10:updated>2009-10-25T10:05:00+10:00</a10:updated><a10:content type="xhtml"><p>This morning I cancelled an old account with a DNS hosting provider. I'd been signed up to them involuntarily by a web hosting company, which is one of the reasons it's no longer my osting company. No hyperlinks - I can't really recommend either of them and that's not what this post is about.</p>

<p>I clicked the "Account | Cancel" link and was presented with this dialogue box.</p>

<p><a href="http://lh6.ggpht.com/_RlpLqbhdTdM/SuOWJ6uDsWI/AAAAAAABEUM/IKxUAHgu1mc/s1600-h/image%5B5%5D.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_RlpLqbhdTdM/SuOWLdDAwkI/AAAAAAABEUU/fk7dtIJeZog/image_thumb%5B1%5D.png?imgmax=800" width="404" height="114" /></a> </p>

<p>Please, guys. If you don't have a UI designer, get one. If you <em>do</em> have one, get another one instead.</p>

<p>Fail.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.10.25.1005</feedburner:origLink></item><item xml:base="Home/Post/2009.10.13.1113"><guid isPermaLink="false">2009.10.13.1113</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/sxA_ob8hTKA/2009.10.13.1113</link><author>andrewh@uglybugger.org</author><title>On corporate blogging: corporate culture and personal ethics</title><description>&lt;p&gt;Let me start by demonstrating just a &lt;em&gt;tiny&lt;/em&gt; amount of corporate cynicism.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;"Blogging is &lt;em&gt;so&lt;/em&gt; Web two-point-oh."&lt;/p&gt;
  
  &lt;p&gt;"Oh, but everyone has a blog."&lt;/p&gt;
  
  &lt;p&gt;"If you're not on, like, Twitter an' Facebook 'n' stuff, then you're like, a dinosaur or IBM or something."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's now all pause for a moment to welcome those companies that aren't, strictly speaking, technological leaders any more, to the blogosphere[1]. Congratulations, you've finally arrived. But what are we doing, here? What, when you get down to it, is corporate blogging all about? What &lt;em&gt;should&lt;/em&gt; it be about? Why should a company do it? And when should it not?&lt;/p&gt;

&lt;p&gt;A company should blog, first and foremost, when it actually has something to contribute to the world at large. Rambling personal blogs are fine for... well... personal purposes[2], but corporate blogs should be useful to current and potential customers, partners, shareholders and so on. They should also allow people within the company who normally wouldn't be at the front line of public relations to provide their perspective on things - otherwise, why have a corporate blog at all? Why not just have a series of press releases from your marketing department?&lt;/p&gt;

&lt;p&gt;Having people within your company contribute to your corporate blog can be a two-edged sword. Unfortunately, it's one upon which many companies cut themselves. The pitfall should be obvious, but one damaging strategy that many companies employ is to sanitise or censor what their people say. I'm not arguing that you should permit people to blather your corporate secrets all over the web; merely that you should hire good people and then trust them to do their job well.&lt;/p&gt;

&lt;p&gt;If you have a trusted, valued employee who's worked on your business-critical systems or in client-facing roles where they've already represented the company, you should trust in their professionalism and let them post what they deem appropriate. &lt;/p&gt;

&lt;p&gt;If you have an irresponsible blogger who's publishing commercial-in-confidence information to the web at large, then you don't just have an irresponsible blogger. You have an irresponsible employee, who should be swiftly counselled or transformed into a former employee.&lt;/p&gt;

&lt;h3&gt;To Companies:&lt;/h3&gt;

&lt;p&gt;When asking your employees to blog on your behalf, you need to give them some guidelines about what they should and should not say, and you should &lt;em&gt;also&lt;/em&gt; give them some benefits from doing so. I suggest these as a minimum:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We won't edit your posts. Period. We reserve the right to pull them from the site if absolutely necessary, after which we'll explain to you why we did so, but &lt;em&gt;we will never edit anything that's been published under your name&lt;/em&gt;. Period. &lt;/li&gt;
&lt;li&gt;We won't require an approval process. Post as you will. The corollary to this: be responsible with what you publish, because you &lt;em&gt;will&lt;/em&gt; be held responsible for what you publish. We expect - and trust - you to do the right thing. &lt;/li&gt;
&lt;li&gt;It's infeasible to track whether it was personal or company time on which you wrote a blog post, so it must be accepted that if you publish a post on our corporate blog then we own the content. &lt;/li&gt;
&lt;li&gt;We grant you a perpetual and irrevocable (but non-exclusive) licence to use the content that you generate for our blog for your own purposes, including but not limited to syndication to your own personal blog, re-publishing as journal articles, or any other purpose you wish - specifically &lt;em&gt;including&lt;/em&gt; for personal profit - provided that such use does not harm the company's reputation. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you don't offer at least these guarantees, then your blogging-inclined employees will simply go off and publish their own content anyway, and you'll derive no benefit from their efforts whatsoever. Moreover, you'll have demonstrated a fundamental lack of trust in your employees that may well cause them to take their talents, not just their blogs, elsewhere.&lt;/p&gt;

&lt;p&gt;If you &lt;em&gt;can't&lt;/em&gt; offer at least these guarantees, then I respectfully suggest that a corporate blog is not for you.&lt;/p&gt;

&lt;h3&gt;To Individuals:&lt;/h3&gt;

&lt;p&gt;Carefully consider your personal reputation. If you haven't one, consider what you'd &lt;em&gt;like&lt;/em&gt; it to be in a year or so's time. If you have one, consider whether the opportunity to blog for your company is more likely to enhance or damage it.&lt;/p&gt;

&lt;p&gt;Consider whether you're likely to be permitted to express your real opinion on a matter, or whether you're going to be asked to be a corporate mouthpiece. If the former, great. Thank your employer and do the right thing by them. If the latter, I suggest that you respectfully and courteously decline the invitation to contribute.&lt;/p&gt;

&lt;p&gt;Never lie. You needn't (and shouldn't) air your corporate dirty linen in public - everyone has it, and nobody appreciates seeing someone else's - but your personal integrity is yours to defend. If you disagree with a tactical or strategic decision made by your company, &lt;em&gt;simply don't write about it&lt;/em&gt;. If you think Joe from Accounts is a cretin, &lt;em&gt;keep it to yourself&lt;/em&gt;. Write about your area of expertise or influence; ask for feedback from your audience; allow your readers to understand that your company is thinking about their issues and exploring ways and means of helping its stakeholders.&lt;/p&gt;

&lt;p&gt;Remember, if you blog as a corporate automaton, those of your readers who aren't very smart will probably take what you say at face value. Those of your readers who &lt;em&gt;are&lt;/em&gt; smart and observant (those whom you should hope are your peers) will see straight through it, and these are the people who won't be hiring you at your next job interview - or whom you'll be trying to hire yourself. Presumably your peers are the ones you want to respect and admire you.&lt;/p&gt;

&lt;h3&gt;In General:&lt;/h3&gt;

&lt;p&gt;I was recently asked to contribute to a corporate blog. When I responded asking for the guarantees suggested above, I was surprised to learn that nobody had actually considered it yet. On reflection, that shouldn't have been much of a surprise - blogging is, after all, a relatively new beastie in corporate land.&lt;/p&gt;

&lt;p&gt;The lessons to be learned from that, I guess, are to not be afraid to ask, and not be afraid to decline the opportunity if it isn't appropriate for you.&lt;/p&gt;

&lt;p&gt;Will you see my by-line on a corporate blog any time soon? We'll have to wait and see :)&lt;/p&gt;

&lt;p&gt;[1] Wow. Kudos to the Windows Live Writer team - their spell-checker actually recognises "blogosphere" as a word. Pity it didn't recognise "Facebook" :)&lt;/p&gt;

&lt;p&gt;[2]  See my personal blog at &lt;a href="http://www.uglybugger.org/" target="_blank"&gt;uglybugger.org&lt;/a&gt; for a perfect example of that - anyone want a trailer? :)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/sxA_ob8hTKA" height="1" width="1"/&gt;</description><pubDate>Tue, 13 Oct 2009 11:13:00 +1000</pubDate><a10:updated>2009-10-13T11:13:00+10:00</a10:updated><a10:content type="xhtml"><p>Let me start by demonstrating just a <em>tiny</em> amount of corporate cynicism.</p>

<blockquote>
  <p>"Blogging is <em>so</em> Web two-point-oh."</p>
  
  <p>"Oh, but everyone has a blog."</p>
  
  <p>"If you're not on, like, Twitter an' Facebook 'n' stuff, then you're like, a dinosaur or IBM or something."</p>
</blockquote>

<p>Let's now all pause for a moment to welcome those companies that aren't, strictly speaking, technological leaders any more, to the blogosphere[1]. Congratulations, you've finally arrived. But what are we doing, here? What, when you get down to it, is corporate blogging all about? What <em>should</em> it be about? Why should a company do it? And when should it not?</p>

<p>A company should blog, first and foremost, when it actually has something to contribute to the world at large. Rambling personal blogs are fine for... well... personal purposes[2], but corporate blogs should be useful to current and potential customers, partners, shareholders and so on. They should also allow people within the company who normally wouldn't be at the front line of public relations to provide their perspective on things - otherwise, why have a corporate blog at all? Why not just have a series of press releases from your marketing department?</p>

<p>Having people within your company contribute to your corporate blog can be a two-edged sword. Unfortunately, it's one upon which many companies cut themselves. The pitfall should be obvious, but one damaging strategy that many companies employ is to sanitise or censor what their people say. I'm not arguing that you should permit people to blather your corporate secrets all over the web; merely that you should hire good people and then trust them to do their job well.</p>

<p>If you have a trusted, valued employee who's worked on your business-critical systems or in client-facing roles where they've already represented the company, you should trust in their professionalism and let them post what they deem appropriate. </p>

<p>If you have an irresponsible blogger who's publishing commercial-in-confidence information to the web at large, then you don't just have an irresponsible blogger. You have an irresponsible employee, who should be swiftly counselled or transformed into a former employee.</p>

<h3>To Companies:</h3>

<p>When asking your employees to blog on your behalf, you need to give them some guidelines about what they should and should not say, and you should <em>also</em> give them some benefits from doing so. I suggest these as a minimum:</p>

<ol>
<li>We won't edit your posts. Period. We reserve the right to pull them from the site if absolutely necessary, after which we'll explain to you why we did so, but <em>we will never edit anything that's been published under your name</em>. Period. </li>
<li>We won't require an approval process. Post as you will. The corollary to this: be responsible with what you publish, because you <em>will</em> be held responsible for what you publish. We expect - and trust - you to do the right thing. </li>
<li>It's infeasible to track whether it was personal or company time on which you wrote a blog post, so it must be accepted that if you publish a post on our corporate blog then we own the content. </li>
<li>We grant you a perpetual and irrevocable (but non-exclusive) licence to use the content that you generate for our blog for your own purposes, including but not limited to syndication to your own personal blog, re-publishing as journal articles, or any other purpose you wish - specifically <em>including</em> for personal profit - provided that such use does not harm the company's reputation. </li>
</ol>

<p>If you don't offer at least these guarantees, then your blogging-inclined employees will simply go off and publish their own content anyway, and you'll derive no benefit from their efforts whatsoever. Moreover, you'll have demonstrated a fundamental lack of trust in your employees that may well cause them to take their talents, not just their blogs, elsewhere.</p>

<p>If you <em>can't</em> offer at least these guarantees, then I respectfully suggest that a corporate blog is not for you.</p>

<h3>To Individuals:</h3>

<p>Carefully consider your personal reputation. If you haven't one, consider what you'd <em>like</em> it to be in a year or so's time. If you have one, consider whether the opportunity to blog for your company is more likely to enhance or damage it.</p>

<p>Consider whether you're likely to be permitted to express your real opinion on a matter, or whether you're going to be asked to be a corporate mouthpiece. If the former, great. Thank your employer and do the right thing by them. If the latter, I suggest that you respectfully and courteously decline the invitation to contribute.</p>

<p>Never lie. You needn't (and shouldn't) air your corporate dirty linen in public - everyone has it, and nobody appreciates seeing someone else's - but your personal integrity is yours to defend. If you disagree with a tactical or strategic decision made by your company, <em>simply don't write about it</em>. If you think Joe from Accounts is a cretin, <em>keep it to yourself</em>. Write about your area of expertise or influence; ask for feedback from your audience; allow your readers to understand that your company is thinking about their issues and exploring ways and means of helping its stakeholders.</p>

<p>Remember, if you blog as a corporate automaton, those of your readers who aren't very smart will probably take what you say at face value. Those of your readers who <em>are</em> smart and observant (those whom you should hope are your peers) will see straight through it, and these are the people who won't be hiring you at your next job interview - or whom you'll be trying to hire yourself. Presumably your peers are the ones you want to respect and admire you.</p>

<h3>In General:</h3>

<p>I was recently asked to contribute to a corporate blog. When I responded asking for the guarantees suggested above, I was surprised to learn that nobody had actually considered it yet. On reflection, that shouldn't have been much of a surprise - blogging is, after all, a relatively new beastie in corporate land.</p>

<p>The lessons to be learned from that, I guess, are to not be afraid to ask, and not be afraid to decline the opportunity if it isn't appropriate for you.</p>

<p>Will you see my by-line on a corporate blog any time soon? We'll have to wait and see :)</p>

<p>[1] Wow. Kudos to the Windows Live Writer team - their spell-checker actually recognises "blogosphere" as a word. Pity it didn't recognise "Facebook" :)</p>

<p>[2]  See my personal blog at <a href="http://www.uglybugger.org/" target="_blank">uglybugger.org</a> for a perfect example of that - anyone want a trailer? :)</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.10.13.1113</feedburner:origLink></item><item xml:base="Home/Post/2009.10.12.1007"><guid isPermaLink="false">2009.10.12.1007</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/wKxepzb71Ao/2009.10.12.1007</link><author>andrewh@uglybugger.org</author><title>I am not trying to connect to the Internet, you stupid... oh, never mind...</title><description>&lt;p&gt;Sir Winston Churchill once said, "Those who fail to learn from history are doomed to repeat it."&lt;/p&gt;

&lt;p&gt;Cast your memory back to this particular gem: &lt;a href="http://www.youtube.com/watch?v=gS0vZFPnksk"&gt;http://www.youtube.com/watch?v=gS0vZFPnksk&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That stupid paperclip was one of the worst UI bungles in history, and one would think that Microsoft's UI
designers would have done their absolute best to &lt;em&gt;never&lt;/em&gt; irritate their users so much again. The lesson to
learn is simple:&lt;/p&gt;

&lt;h1&gt;Never, ever steal the focus when your user is doing something unless it's absolutely critical that you do so.&lt;/h1&gt;

&lt;p&gt;Short on battery? Flash an icon in the notification area. (Hint to UI designers: in Windows, the system tray is
generally at the bottom-right of the display. It has all these little notification-ish thingies in it. It's really
remarkably useful.)&lt;/p&gt;

&lt;p&gt;I have new email? That's nice, but I'm busy right now. Flash an icon in the notification area.&lt;/p&gt;

&lt;p&gt;Someone's unplugged my headphones? Oh, that's right - that'd be &lt;em&gt;me!&lt;/em&gt; Don't even bother flashing an icon - I &lt;em&gt;know&lt;/em&gt;
I unplugged the things. It'd be nice if your media player didn't stop when I did it, though.&lt;/p&gt;

&lt;p&gt;Can't connect to the Internet? That's okay, too - you're already taking up &lt;em&gt;two&lt;/em&gt; icons' worth of space in the
notification area for no good reason, so perhaps you could re-use some of that.&lt;/p&gt;

&lt;p&gt;Just about the only reason I can think of off the cuff to steal focus is if the device is critically low on power
and is going to fail within the next thirty seconds or so. That's it. And even then, only do so once you've saved my
work.&lt;/p&gt;

&lt;p&gt;Everything else can be done by - you guessed it! - sticking a notification in the area reserved for them.&lt;/p&gt;

&lt;h1&gt;Enter Windows Mobile.&lt;/h1&gt;

&lt;p&gt;Windows Mobile has the extremely annoying habit of popping stupid notification balloons up over whatever I'm doing,
just to tell me about something completely unrelated. I finally got so incredibly fed up with this that I decided
to photograph it before I fed the device to the Kreepy Krauly. This behaviour is remarkably like Clippit, and even
more annoying. What's worse is that this behaviour comes in a small, easy-to-fling-at-the-wall-when-you're-infuriated
package.&lt;/p&gt;

&lt;p&gt;Seriously, if you haven't taken the time to watch the Salmon Days clip above, now's the time: &lt;a href="http://www.youtube.com/watch?v=gS0vZFPnksk"&gt;http://www.youtube.com/watch?v=gS0vZFPnksk&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;"Hey, it looks like you're writing a text message!"&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.codingforfunandprofit.com/Posts/2009/2009.10.12.1007/Screenshot1.jpg" alt="Screenshot"/&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.codingforfunandprofit.com/Posts/2009/2009.10.12.1007/Screenshot2.jpg" alt="Screenshot"/&gt;&lt;/p&gt;

&lt;p&gt;F***| off.&lt;/p&gt;

&lt;p&gt;"Hey, it looks like you're driving somewhere and really can't afford to be interrupted!"&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.codingforfunandprofit.com/Posts/2009/2009.10.12.1007/Screenshot3.jpg" alt="Screenshot"/&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.codingforfunandprofit.com/Posts/2009/2009.10.12.1007/Screenshot4.jpg" alt="Screenshot"/&gt;&lt;/p&gt;

&lt;p&gt;F***| off.&lt;/p&gt;

&lt;p&gt;"Hey, it looks like you're trying to tell me where you want to go today!"&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.codingforfunandprofit.com/Posts/2009/2009.10.12.1007/Screenshot5.jpg" alt="Screenshot"/&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.codingforfunandprofit.com/Posts/2009/2009.10.12.1007/Screenshot6.jpg" alt="Screenshot"/&gt;&lt;/p&gt;

&lt;p&gt;F*&lt;strong&gt;| off! I am not trying to connect to the f*&lt;/strong&gt;|ing Internet, you stupid, f***|ing papercl.. oh, never mind.&lt;/p&gt;

&lt;p&gt;Where do I want to go today? Well, I'm off to a dealership to replace this awful contraption. The only question is
this: Android or iPhone?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/wKxepzb71Ao" height="1" width="1"/&gt;</description><pubDate>Mon, 12 Oct 2009 10:07:00 +1000</pubDate><a10:updated>2009-10-12T10:07:00+10:00</a10:updated><a10:content type="xhtml"><p>Sir Winston Churchill once said, "Those who fail to learn from history are doomed to repeat it."</p>

<p>Cast your memory back to this particular gem: <a href="http://www.youtube.com/watch?v=gS0vZFPnksk">http://www.youtube.com/watch?v=gS0vZFPnksk</a></p>

<p>That stupid paperclip was one of the worst UI bungles in history, and one would think that Microsoft's UI
designers would have done their absolute best to <em>never</em> irritate their users so much again. The lesson to
learn is simple:</p>

<h1>Never, ever steal the focus when your user is doing something unless it's absolutely critical that you do so.</h1>

<p>Short on battery? Flash an icon in the notification area. (Hint to UI designers: in Windows, the system tray is
generally at the bottom-right of the display. It has all these little notification-ish thingies in it. It's really
remarkably useful.)</p>

<p>I have new email? That's nice, but I'm busy right now. Flash an icon in the notification area.</p>

<p>Someone's unplugged my headphones? Oh, that's right - that'd be <em>me!</em> Don't even bother flashing an icon - I <em>know</em>
I unplugged the things. It'd be nice if your media player didn't stop when I did it, though.</p>

<p>Can't connect to the Internet? That's okay, too - you're already taking up <em>two</em> icons' worth of space in the
notification area for no good reason, so perhaps you could re-use some of that.</p>

<p>Just about the only reason I can think of off the cuff to steal focus is if the device is critically low on power
and is going to fail within the next thirty seconds or so. That's it. And even then, only do so once you've saved my
work.</p>

<p>Everything else can be done by - you guessed it! - sticking a notification in the area reserved for them.</p>

<h1>Enter Windows Mobile.</h1>

<p>Windows Mobile has the extremely annoying habit of popping stupid notification balloons up over whatever I'm doing,
just to tell me about something completely unrelated. I finally got so incredibly fed up with this that I decided
to photograph it before I fed the device to the Kreepy Krauly. This behaviour is remarkably like Clippit, and even
more annoying. What's worse is that this behaviour comes in a small, easy-to-fling-at-the-wall-when-you're-infuriated
package.</p>

<p>Seriously, if you haven't taken the time to watch the Salmon Days clip above, now's the time: <a href="http://www.youtube.com/watch?v=gS0vZFPnksk">http://www.youtube.com/watch?v=gS0vZFPnksk</a>.</p>

<p>"Hey, it looks like you're writing a text message!"</p>

<p><img src="http://www.codingforfunandprofit.com/Posts/2009/2009.10.12.1007/Screenshot1.jpg" alt="Screenshot" /></p>

<p><img src="http://www.codingforfunandprofit.com/Posts/2009/2009.10.12.1007/Screenshot2.jpg" alt="Screenshot" /></p>

<p>F***| off.</p>

<p>"Hey, it looks like you're driving somewhere and really can't afford to be interrupted!"</p>

<p><img src="http://www.codingforfunandprofit.com/Posts/2009/2009.10.12.1007/Screenshot3.jpg" alt="Screenshot" /></p>

<p><img src="http://www.codingforfunandprofit.com/Posts/2009/2009.10.12.1007/Screenshot4.jpg" alt="Screenshot" /></p>

<p>F***| off.</p>

<p>"Hey, it looks like you're trying to tell me where you want to go today!"</p>

<p><img src="http://www.codingforfunandprofit.com/Posts/2009/2009.10.12.1007/Screenshot5.jpg" alt="Screenshot" /></p>

<p><img src="http://www.codingforfunandprofit.com/Posts/2009/2009.10.12.1007/Screenshot6.jpg" alt="Screenshot" /></p>

<p>F*<strong>| off! I am not trying to connect to the f*</strong>|ing Internet, you stupid, f***|ing papercl.. oh, never mind.</p>

<p>Where do I want to go today? Well, I'm off to a dealership to replace this awful contraption. The only question is
this: Android or iPhone?</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.10.12.1007</feedburner:origLink></item><item xml:base="Home/Post/2009.10.07.0734"><guid isPermaLink="false">2009.10.07.0734</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/tI5lwRO7GUo/2009.10.07.0734</link><author>andrewh@uglybugger.org</author><title>Google "why is..."</title><description>&lt;p&gt;A friend just dropped around and suggested that I have a look at Google's suggested searches for "why is".&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_RlpLqbhdTdM/Ssxgj9QCQNI/AAAAAAABD9U/s6prlIPk1pE/s1600-h/image%5B3%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_RlpLqbhdTdM/Ssxglapq7MI/AAAAAAABD9c/1Jw8PsQVTHo/image_thumb%5B1%5D.png?imgmax=800" width="404" height="284" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Enough said?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/tI5lwRO7GUo" height="1" width="1"/&gt;</description><pubDate>Wed, 07 Oct 2009 07:34:00 +1000</pubDate><a10:updated>2009-10-07T07:34:00+10:00</a10:updated><a10:content type="xhtml"><p>A friend just dropped around and suggested that I have a look at Google's suggested searches for "why is".</p>

<p><a href="http://lh6.ggpht.com/_RlpLqbhdTdM/Ssxgj9QCQNI/AAAAAAABD9U/s6prlIPk1pE/s1600-h/image%5B3%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_RlpLqbhdTdM/Ssxglapq7MI/AAAAAAABD9c/1Jw8PsQVTHo/image_thumb%5B1%5D.png?imgmax=800" width="404" height="284" /></a> </p>

<p>Enough said?</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.10.07.0734</feedburner:origLink></item><item xml:base="Home/Post/2009.10.05.1010"><guid isPermaLink="false">2009.10.05.1010</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/sNfiayqQDxE/2009.10.05.1010</link><author>andrewh@uglybugger.org</author><title>Google Toolbar requires Firefox?</title><description>&lt;p&gt;Umm... what? Guys, didn't you realise that you have a browser all of your own? :)&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_RlpLqbhdTdM/SsniOpsxIbI/AAAAAAABD8s/vDJ9C84Q2b4/s1600-h/image%5B4%5D.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://lh6.ggpht.com/_RlpLqbhdTdM/SsniQRczmTI/AAAAAAABD84/wrf1OxfHEXk/image_thumb%5B2%5D.png?imgmax=800" width="404" height="172" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;I'm sure &lt;a href="http://www.google.com/sidewiki" target="_blank"&gt;SideWiki&lt;/a&gt;'s very cute, but I'm not willing to go back to Firefox to use it.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/sNfiayqQDxE" height="1" width="1"/&gt;</description><pubDate>Mon, 05 Oct 2009 10:10:00 +1000</pubDate><a10:updated>2009-10-05T10:10:00+10:00</a10:updated><a10:content type="xhtml"><p>Umm... what? Guys, didn't you realise that you have a browser all of your own? :)</p>

<p><a href="http://lh5.ggpht.com/_RlpLqbhdTdM/SsniOpsxIbI/AAAAAAABD8s/vDJ9C84Q2b4/s1600-h/image%5B4%5D.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_RlpLqbhdTdM/SsniQRczmTI/AAAAAAABD84/wrf1OxfHEXk/image_thumb%5B2%5D.png?imgmax=800" width="404" height="172" /></a> </p>

<p>I'm sure <a href="http://www.google.com/sidewiki" target="_blank">SideWiki</a>'s very cute, but I'm not willing to go back to Firefox to use it.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.10.05.1010</feedburner:origLink></item><item xml:base="Home/Post/2009.08.14.0521"><guid isPermaLink="false">2009.08.14.0521</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/cYyF1Kw2RTY/2009.08.14.0521</link><author>andrewh@uglybugger.org</author><title>Live Mesh, I'm breaking up with you</title><description>&lt;p&gt;I'll be honest, Live Mesh: It's not me, it's you.  &lt;/p&gt;

&lt;p&gt;You're too slow.  &lt;/p&gt;

&lt;p&gt;You're unresponsive.  &lt;/p&gt;

&lt;p&gt;I need something larger, faster and more flexible.  &lt;/p&gt;

&lt;p&gt;I'm in love with &lt;a title="Dropbox" href="https://www.getdropbox.com/referrals/NTE3Mzc3MjE5" target="_blank"&gt;Dropbox&lt;/a&gt;. (Disclosure: that's a referrer link from my user ID; I get free space if you sign up.)  &lt;/p&gt;

&lt;p&gt;To be fair, Live Mesh was (and is) a great idea. Unfortunately, it's been in its "Tech Preview" state for far too long. I can live with technical preview status, but what comes &lt;em&gt;with&lt;/em&gt; that status is a 5Gb limit, which I just can't survive any more.  &lt;/p&gt;

&lt;p&gt;I want my data to be on someone's cloud, somewhere. I'm perfectly comfortable that I can encrypt my own stuff as I need to, before handing it over to somebody else. And Dropbox appears to fit the "someone else" bill pretty much perfectly.  &lt;/p&gt;

&lt;p&gt;It works across platforms; it has a browser interface; it does everything that Mesh does (that I want, anyway), but does it faster and more transparently.  &lt;/p&gt;

&lt;p&gt;Oh, and it does photo sharing as well. Picasa's going to get a run for its money, here - this is so incredibly easy to store and arrange files on that I'm seriously considering ditching my (paid-for) Picasa web albums.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/cYyF1Kw2RTY" height="1" width="1"/&gt;</description><pubDate>Fri, 14 Aug 2009 05:21:00 +1000</pubDate><a10:updated>2009-08-14T05:21:00+10:00</a10:updated><a10:content type="xhtml"><p>I'll be honest, Live Mesh: It's not me, it's you.  </p>

<p>You're too slow.  </p>

<p>You're unresponsive.  </p>

<p>I need something larger, faster and more flexible.  </p>

<p>I'm in love with <a title="Dropbox" href="https://www.getdropbox.com/referrals/NTE3Mzc3MjE5" target="_blank">Dropbox</a>. (Disclosure: that's a referrer link from my user ID; I get free space if you sign up.)  </p>

<p>To be fair, Live Mesh was (and is) a great idea. Unfortunately, it's been in its "Tech Preview" state for far too long. I can live with technical preview status, but what comes <em>with</em> that status is a 5Gb limit, which I just can't survive any more.  </p>

<p>I want my data to be on someone's cloud, somewhere. I'm perfectly comfortable that I can encrypt my own stuff as I need to, before handing it over to somebody else. And Dropbox appears to fit the "someone else" bill pretty much perfectly.  </p>

<p>It works across platforms; it has a browser interface; it does everything that Mesh does (that I want, anyway), but does it faster and more transparently.  </p>

<p>Oh, and it does photo sharing as well. Picasa's going to get a run for its money, here - this is so incredibly easy to store and arrange files on that I'm seriously considering ditching my (paid-for) Picasa web albums.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.08.14.0521</feedburner:origLink></item><item xml:base="Home/Post/2009.08.07.0824"><guid isPermaLink="false">2009.08.07.0824</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/EoYUDClWqqY/2009.08.07.0824</link><author>andrewh@uglybugger.org</author><title>Worth Reading: Automate, else Enforce otherwise Path of Least Resistance</title><description>&lt;p&gt;A friend and colleague, Matthew Rowan, has just spent some time formalising some of the knowledge that many developers will have grasped intuitively with respect to process management - but that many won't have.  &lt;/p&gt;

&lt;p&gt;&lt;a href="http://matthewrowan.spaces.live.com/blog/cns!CCB05A30BCA0FF01!2229.entry"&gt;Automate, else Enforce otherwise Path of Least Resistance&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;This is well worth a read as far too many companies get burdened with process documentation over actual workable process.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/EoYUDClWqqY" height="1" width="1"/&gt;</description><pubDate>Fri, 07 Aug 2009 08:24:00 +1000</pubDate><a10:updated>2009-08-07T08:24:00+10:00</a10:updated><a10:content type="xhtml"><p>A friend and colleague, Matthew Rowan, has just spent some time formalising some of the knowledge that many developers will have grasped intuitively with respect to process management - but that many won't have.  </p>

<p><a href="http://matthewrowan.spaces.live.com/blog/cns!CCB05A30BCA0FF01!2229.entry">Automate, else Enforce otherwise Path of Least Resistance</a>.  </p>

<p>This is well worth a read as far too many companies get burdened with process documentation over actual workable process.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.08.07.0824</feedburner:origLink></item><item xml:base="Home/Post/2009.08.01.0320"><guid isPermaLink="false">2009.08.01.0320</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/m4hIkcOK3Og/2009.08.01.0320</link><author>andrewh@uglybugger.org</author><title>Automatically rejecting appointments in Microsoft Outlook 2007</title><description>&lt;p&gt;There's a nice feature in Outlook that allows users to automatically accept appointments, and even decline
conflicting appointments. Unfortunately, what it &lt;em&gt;can't&lt;/em&gt; do is allow you to specify specific reasons for
rejecting meeting invitations.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.codingforfunandprofit.com/Posts/2009/2009.08.01.0320/Screenshot1.png" alt="Screenshot"/&gt;&lt;/p&gt;

&lt;p&gt;A particular pet hate of mine is when people send a meeting invitation entitled "Foo Discussions" or some such,
and fail to specify a location or any content. It's even more irritating when I'm trying to be a good little
corporate citizen and have my calendar auto-accept appointments, but they send it ten minutes before the thing
actually starts. They're going to receive an acceptance notice (of course) but my phone's not going to synch for
a good half-hour, and there's just no way I'm going to be there. Funnily enough, I'm not just sitting around on
my backside, waiting for someone to invite me to a meeting.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Oh, a meeting! How &lt;em&gt;exciting!&lt;/em&gt; I've been waiting for one of these &lt;em&gt;all day!&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Of course, if you simply decline offending appointments manually, people tend to get offended. (Which may or may
not be a good thing, depending on who it is.) A better way, however, is to automate the process.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Nothing personal, old chap - my calendar just has automation rules that apply to everyone.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The rules for getting into my calendar are simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tell me everything I need to know about the meeting.&lt;/strong&gt; This includes, specifically, its location.
Outlook enforces pretty much everything else, but fails to enforce this one.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Please do me the courtesy of checking my free/busy information and *do not *attempt to trump something
that's already been organised.&lt;/strong&gt; It shows a complete and utter disregard for my time and that of anyone with
whom I've already agreed to meet.   &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Do me the courtesy of giving me at least 24 hours' notice.&lt;/strong&gt; Don't send me a meeting request at 7pm on Monday
evening for 7:30am on Tuesday morning. I'm not going to read it, and I'm not going to be there.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I finally snapped today, after another imbecilic meeting request, and wrote these two quick methods. They enforce
the three rules above, automatically accept the request if it passes and automatically decline otherwise. They
appear to work for me; your mileage may vary. No warranties, express or implied, etc. &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Sub AutoProcessMeetingRequest(oRequest As MeetingItem)

    ' bail if this isn't a meeting request
    If oRequest.MessageClass &amp;lt;&amp;gt; "IPM.Schedule.Meeting.Request" Then Exit Sub

    Dim oAppt As AppointmentItem
    Set oAppt = oRequest.GetAssociatedAppointment(True)

    Dim declinedReasons As String
    declinedReasons = ""

    If (oAppt.Location = "") Then
        declinedReasons = declinedReasons &amp;amp; " * No location specified." &amp;amp; vbCrLf
    End If

    If (HasConflicts(oAppt)) Then
        declinedReasons = declinedReasons &amp;amp; " * It conflicts with an existing appointment." &amp;amp; vbCrLf
    End If

    If (DateTime.DateDiff("h", DateTime.Now, oAppt.Start) &amp;lt; 24) Then
        declinedReasons = declinedReasons &amp;amp; " * The meeting's start time is too close to the current time. " &amp;amp; vbCrLf
    End If

    Dim oResponse As MeetingItem
    If (declinedReasons = "") Then
        Set oResponse = oAppt.Respond(olMeetingAccepted, True)
    Else
        Set oResponse = oAppt.Respond(olMeetingDeclined, True)
        oResponse.Body = _
            "This meeting request has been automatically declined for the following reasons:" &amp;amp; vbCrLf &amp;amp; _
            declinedReasons
    End If

    oResponse.Send
    oRequest.Delete

End Sub

Function HasConflicts(oAppt As AppointmentItem) As Boolean
    Dim oCalendarFolder As Folder
    Set oCalendarFolder = ThisOutlookSession.Session.GetDefaultFolder(olFolderCalendar)

    Dim apptItem As AppointmentItem

    For Each apptItem In oCalendarFolder.Items
        If ((apptItem.BusyStatus &amp;lt;&amp;gt; olFree) And (oAppt &amp;lt;&amp;gt; apptItem)) Then
            If (apptItem.Start &amp;lt; oAppt.End) Then
                ' if this item starts before the given item ends, it must end before the given item starts
                If (apptItem.End &amp;gt; oAppt.Start) Then
                    HasConflicts = True
                    Exit Function
                End If
            End If
        End If
    Next

    HasConflicts = False
End Function
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Just open the VBA editor from within Outlook (Alt-F11) and paste the subroutines into the ThisOutlookSession project.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.codingforfunandprofit.com/Posts/2009/2009.08.01.0320/Screenshot2.png" alt="Screenshot"/&gt;&lt;/p&gt;

&lt;p&gt;Then go and create an Outlook rule that calls the AutoProcessMeetingRequest subroutine for every meeting request you receive:   &lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.codingforfunandprofit.com/Posts/2009/2009.08.01.0320/Screenshot3.png" alt="Screenshot"/&gt;&lt;/p&gt;

&lt;p&gt;Those of your colleagues who persistently refuse to learn how to use email (an essential business tool!) will receive
responses along the following lines:   &lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.codingforfunandprofit.com/Posts/2009/2009.08.01.0320/Screenshot4.png" alt="Screenshot"/&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/m4hIkcOK3Og" height="1" width="1"/&gt;</description><pubDate>Sat, 01 Aug 2009 03:20:00 +1000</pubDate><a10:updated>2009-08-01T03:20:00+10:00</a10:updated><a10:content type="xhtml"><p>There's a nice feature in Outlook that allows users to automatically accept appointments, and even decline
conflicting appointments. Unfortunately, what it <em>can't</em> do is allow you to specify specific reasons for
rejecting meeting invitations.</p>

<p><img src="http://www.codingforfunandprofit.com/Posts/2009/2009.08.01.0320/Screenshot1.png" alt="Screenshot" /></p>

<p>A particular pet hate of mine is when people send a meeting invitation entitled "Foo Discussions" or some such,
and fail to specify a location or any content. It's even more irritating when I'm trying to be a good little
corporate citizen and have my calendar auto-accept appointments, but they send it ten minutes before the thing
actually starts. They're going to receive an acceptance notice (of course) but my phone's not going to synch for
a good half-hour, and there's just no way I'm going to be there. Funnily enough, I'm not just sitting around on
my backside, waiting for someone to invite me to a meeting.</p>

<blockquote>
  <p>Oh, a meeting! How <em>exciting!</em> I've been waiting for one of these <em>all day!</em></p>
</blockquote>

<p>Of course, if you simply decline offending appointments manually, people tend to get offended. (Which may or may
not be a good thing, depending on who it is.) A better way, however, is to automate the process.</p>

<blockquote>
  <p>Nothing personal, old chap - my calendar just has automation rules that apply to everyone.</p>
</blockquote>

<p>The rules for getting into my calendar are simple:</p>

<ol>
<li><p><strong>Tell me everything I need to know about the meeting.</strong> This includes, specifically, its location.
Outlook enforces pretty much everything else, but fails to enforce this one.</p></li>
<li><p><strong>Please do me the courtesy of checking my free/busy information and *do not *attempt to trump something
that's already been organised.</strong> It shows a complete and utter disregard for my time and that of anyone with
whom I've already agreed to meet.   </p></li>
<li><p><strong>Do me the courtesy of giving me at least 24 hours' notice.</strong> Don't send me a meeting request at 7pm on Monday
evening for 7:30am on Tuesday morning. I'm not going to read it, and I'm not going to be there.</p></li>
</ol>

<p>I finally snapped today, after another imbecilic meeting request, and wrote these two quick methods. They enforce
the three rules above, automatically accept the request if it passes and automatically decline otherwise. They
appear to work for me; your mileage may vary. No warranties, express or implied, etc. </p>

<pre><code>Sub AutoProcessMeetingRequest(oRequest As MeetingItem)

    ' bail if this isn't a meeting request
    If oRequest.MessageClass &lt;&gt; "IPM.Schedule.Meeting.Request" Then Exit Sub

    Dim oAppt As AppointmentItem
    Set oAppt = oRequest.GetAssociatedAppointment(True)

    Dim declinedReasons As String
    declinedReasons = ""

    If (oAppt.Location = "") Then
        declinedReasons = declinedReasons &amp; " * No location specified." &amp; vbCrLf
    End If

    If (HasConflicts(oAppt)) Then
        declinedReasons = declinedReasons &amp; " * It conflicts with an existing appointment." &amp; vbCrLf
    End If

    If (DateTime.DateDiff("h", DateTime.Now, oAppt.Start) &lt; 24) Then
        declinedReasons = declinedReasons &amp; " * The meeting's start time is too close to the current time. " &amp; vbCrLf
    End If

    Dim oResponse As MeetingItem
    If (declinedReasons = "") Then
        Set oResponse = oAppt.Respond(olMeetingAccepted, True)
    Else
        Set oResponse = oAppt.Respond(olMeetingDeclined, True)
        oResponse.Body = _
            "This meeting request has been automatically declined for the following reasons:" &amp; vbCrLf &amp; _
            declinedReasons
    End If

    oResponse.Send
    oRequest.Delete

End Sub

Function HasConflicts(oAppt As AppointmentItem) As Boolean
    Dim oCalendarFolder As Folder
    Set oCalendarFolder = ThisOutlookSession.Session.GetDefaultFolder(olFolderCalendar)

    Dim apptItem As AppointmentItem

    For Each apptItem In oCalendarFolder.Items
        If ((apptItem.BusyStatus &lt;&gt; olFree) And (oAppt &lt;&gt; apptItem)) Then
            If (apptItem.Start &lt; oAppt.End) Then
                ' if this item starts before the given item ends, it must end before the given item starts
                If (apptItem.End &gt; oAppt.Start) Then
                    HasConflicts = True
                    Exit Function
                End If
            End If
        End If
    Next

    HasConflicts = False
End Function
</code></pre>

<p>Just open the VBA editor from within Outlook (Alt-F11) and paste the subroutines into the ThisOutlookSession project.</p>

<p><img src="http://www.codingforfunandprofit.com/Posts/2009/2009.08.01.0320/Screenshot2.png" alt="Screenshot" /></p>

<p>Then go and create an Outlook rule that calls the AutoProcessMeetingRequest subroutine for every meeting request you receive:   </p>

<p><img src="http://www.codingforfunandprofit.com/Posts/2009/2009.08.01.0320/Screenshot3.png" alt="Screenshot" /></p>

<p>Those of your colleagues who persistently refuse to learn how to use email (an essential business tool!) will receive
responses along the following lines:   </p>

<p><img src="http://www.codingforfunandprofit.com/Posts/2009/2009.08.01.0320/Screenshot4.png" alt="Screenshot" /></p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.08.01.0320</feedburner:origLink></item><item xml:base="Home/Post/2009.07.30.1249"><guid isPermaLink="false">2009.07.30.1249</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/9ggyEdqFl3Y/2009.07.30.1249</link><author>andrewh@uglybugger.org</author><title>I'm really bloody sick of this, guys.</title><description>&lt;p&gt;&lt;a href="http://codingforfunandprofit.files.wordpress.com/2009/07/image5.png"&gt;&lt;img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="image" border="0" alt="image" src="http://codingforfunandprofit.files.wordpress.com/2009/07/image_thumb5.png" width="646" height="518" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/9ggyEdqFl3Y" height="1" width="1"/&gt;</description><pubDate>Thu, 30 Jul 2009 12:49:00 +1000</pubDate><a10:updated>2009-07-30T12:49:00+10:00</a10:updated><a10:content type="xhtml"><p><a href="http://codingforfunandprofit.files.wordpress.com/2009/07/image5.png"><img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="image" border="0" alt="image" src="http://codingforfunandprofit.files.wordpress.com/2009/07/image_thumb5.png" width="646" height="518" /></a></p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.07.30.1249</feedburner:origLink></item><item xml:base="Home/Post/2009.07.30.1214"><guid isPermaLink="false">2009.07.30.1214</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/SwmFG9_8-cg/2009.07.30.1214</link><author>andrewh@uglybugger.org</author><title /><description>&lt;p&gt;I'm starting to get a little cranky about this. Perhaps you could use your own debugger to have a look at it, guys?&lt;/p&gt;

&lt;p&gt;&lt;a href="http://codingforfunandprofit.files.wordpress.com/2009/07/image4.png"&gt;&lt;img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="image" border="0" alt="image" src="http://codingforfunandprofit.files.wordpress.com/2009/07/image_thumb4.png" width="546" height="465" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/SwmFG9_8-cg" height="1" width="1"/&gt;</description><pubDate>Thu, 30 Jul 2009 12:14:00 +1000</pubDate><a10:updated>2009-07-30T12:14:00+10:00</a10:updated><a10:content type="xhtml"><p>I'm starting to get a little cranky about this. Perhaps you could use your own debugger to have a look at it, guys?</p>

<p><a href="http://codingforfunandprofit.files.wordpress.com/2009/07/image4.png"><img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="image" border="0" alt="image" src="http://codingforfunandprofit.files.wordpress.com/2009/07/image_thumb4.png" width="546" height="465" /></a></p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.07.30.1214</feedburner:origLink></item><item xml:base="Home/Post/2009.07.17.0742"><guid isPermaLink="false">2009.07.17.0742</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/i0ydk9fqquk/2009.07.17.0742</link><author>andrewh@uglybugger.org</author><title>Don't be spamming me, Windows Live</title><description>&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_RlpLqbhdTdM/SsnVZRQ1kjI/AAAAAAABD4Q/OWtGNxYBHUQ/s1600-h/image%5B3%5D.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://lh3.ggpht.com/_RlpLqbhdTdM/SsnVbHZVktI/AAAAAAABD4Y/p_-in24MheQ/image_thumb%5B1%5D.png?imgmax=800" width="404" height="346" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;New features are all very nice, guys, but:&lt;/p&gt;

&lt;p&gt;a) that feature's been around for ages;&lt;/p&gt;

&lt;p&gt;b) I hate it, as does everyone I know;&lt;/p&gt;

&lt;p&gt;c) I've already told Messenger not to pop up the today box when I launch it, and this looks remarkably like you're ignoring your users' wishes for your own marketing purposes.&lt;/p&gt;

&lt;p&gt;Back to Pidgin, methinks.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/i0ydk9fqquk" height="1" width="1"/&gt;</description><pubDate>Fri, 17 Jul 2009 07:42:00 +1000</pubDate><a10:updated>2009-07-17T07:42:00+10:00</a10:updated><a10:content type="xhtml"><p><a href="http://lh4.ggpht.com/_RlpLqbhdTdM/SsnVZRQ1kjI/AAAAAAABD4Q/OWtGNxYBHUQ/s1600-h/image%5B3%5D.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/_RlpLqbhdTdM/SsnVbHZVktI/AAAAAAABD4Y/p_-in24MheQ/image_thumb%5B1%5D.png?imgmax=800" width="404" height="346" /></a> </p>

<p>New features are all very nice, guys, but:</p>

<p>a) that feature's been around for ages;</p>

<p>b) I hate it, as does everyone I know;</p>

<p>c) I've already told Messenger not to pop up the today box when I launch it, and this looks remarkably like you're ignoring your users' wishes for your own marketing purposes.</p>

<p>Back to Pidgin, methinks.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.07.17.0742</feedburner:origLink></item><item xml:base="Home/Post/2009.07.17.0438"><guid isPermaLink="false">2009.07.17.0438</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/LXf3PjiVzV8/2009.07.17.0438</link><author>andrewh@uglybugger.org</author><title>What’s wrong with this sequence? A message to the VSTS guys:</title><description>&lt;h4&gt;Stupid Question #1: What actually constitutes a conflict?&lt;/h4&gt;

&lt;p&gt;Is a conflict when two people have changed a file, or is it when two people have changed the same &lt;em&gt;part&lt;/em&gt; of a file and VSTS needs assistance to resolve it? Every other (sane) version control system in the world interprets a conflict as the latter.   &lt;/p&gt;

&lt;p&gt; &lt;a href="http://lh4.ggpht.com/_RlpLqbhdTdM/SsnXEIRS2_I/AAAAAAABD5g/XUK03iBe9Fc/s1600-h/image%5B15%5D.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://lh6.ggpht.com/_RlpLqbhdTdM/SsnXF1E545I/AAAAAAABD5o/ZnmqP1y3gEA/image_thumb%5B7%5D.png?imgmax=800" width="404" height="239" /&gt;&lt;/a&gt;   &lt;/p&gt;

&lt;h4&gt;Stupid Question #2: How is it "Auto Merge" when I have to &lt;em&gt;tell&lt;/em&gt; VSTS to merge?&lt;/h4&gt;

&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_RlpLqbhdTdM/SsnV6u1UllI/AAAAAAABD4w/_bk44YjRWKI/s1600-h/image%5B7%5D.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://lh4.ggpht.com/_RlpLqbhdTdM/SsnV8ZLhXyI/AAAAAAABD44/Vfg7ebuB-lA/image_thumb%5B3%5D.png?imgmax=800" width="404" height="244" /&gt;&lt;/a&gt;   &lt;/p&gt;

&lt;h4&gt;Stupid Question #3: If VSTS could not-quite-auto-but-with-the-press-of-a-button merge, and it managed to resolve everything all by itself, &lt;strong&gt;&lt;em&gt;why on earth does it pester me about non-existent conflicts all the time?!?!?&lt;/em&gt;&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_RlpLqbhdTdM/SsnV-TiVanI/AAAAAAABD5A/6G2E1WhQEM8/s1600-h/image%5B11%5D.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://lh4.ggpht.com/_RlpLqbhdTdM/SsnV_8OPtOI/AAAAAAABD5I/I5A5tfQ2Mwk/image_thumb%5B5%5D.png?imgmax=800" width="404" height="239" /&gt;&lt;/a&gt;   &lt;/p&gt;

&lt;p&gt;Perhaps these questions are stupid, but I most respectfully submit that the answers are stupider.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/LXf3PjiVzV8" height="1" width="1"/&gt;</description><pubDate>Fri, 17 Jul 2009 04:38:00 +1000</pubDate><a10:updated>2009-07-17T04:38:00+10:00</a10:updated><a10:content type="xhtml"><h4>Stupid Question #1: What actually constitutes a conflict?</h4>

<p>Is a conflict when two people have changed a file, or is it when two people have changed the same <em>part</em> of a file and VSTS needs assistance to resolve it? Every other (sane) version control system in the world interprets a conflict as the latter.   </p>

<p> <a href="http://lh4.ggpht.com/_RlpLqbhdTdM/SsnXEIRS2_I/AAAAAAABD5g/XUK03iBe9Fc/s1600-h/image%5B15%5D.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_RlpLqbhdTdM/SsnXF1E545I/AAAAAAABD5o/ZnmqP1y3gEA/image_thumb%5B7%5D.png?imgmax=800" width="404" height="239" /></a>   </p>

<h4>Stupid Question #2: How is it "Auto Merge" when I have to <em>tell</em> VSTS to merge?</h4>

<p><a href="http://lh4.ggpht.com/_RlpLqbhdTdM/SsnV6u1UllI/AAAAAAABD4w/_bk44YjRWKI/s1600-h/image%5B7%5D.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_RlpLqbhdTdM/SsnV8ZLhXyI/AAAAAAABD44/Vfg7ebuB-lA/image_thumb%5B3%5D.png?imgmax=800" width="404" height="244" /></a>   </p>

<h4>Stupid Question #3: If VSTS could not-quite-auto-but-with-the-press-of-a-button merge, and it managed to resolve everything all by itself, <strong><em>why on earth does it pester me about non-existent conflicts all the time?!?!?</em></strong></h4>

<p><a href="http://lh4.ggpht.com/_RlpLqbhdTdM/SsnV-TiVanI/AAAAAAABD5A/6G2E1WhQEM8/s1600-h/image%5B11%5D.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_RlpLqbhdTdM/SsnV_8OPtOI/AAAAAAABD5I/I5A5tfQ2Mwk/image_thumb%5B5%5D.png?imgmax=800" width="404" height="239" /></a>   </p>

<p>Perhaps these questions are stupid, but I most respectfully submit that the answers are stupider.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.07.17.0438</feedburner:origLink></item><item xml:base="Home/Post/2009.07.10.0257"><guid isPermaLink="false">2009.07.10.0257</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/5oWuL8L24pY/2009.07.10.0257</link><author>andrewh@uglybugger.org</author><title>Microsoft on why a memory leak isn't really a leak</title><description>&lt;p&gt;The genesis of this rant is that a colleague and I have just spent a couple of days diagnosing and fixing memory leaks (sorry, "pseudo-leaks"," according to Microsoft, which presumably means that the memory explosion we were seeing wasn't actually real) caused by awful, awful garbage collection in Internet Explorer.  &lt;/p&gt;

&lt;p&gt;The icing on the cake was finding this article: &lt;a href="http://msdn.microsoft.com/en-us/library/bb250448%28VS.85%29.aspx"&gt;Understanding and Solving Internet Explorer Leak Patterns.&lt;/a&gt; The markworthy text is this:  &lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Pseudo-leaks almost always appear on the same page during dynamic scripting operations and should rarely be visible after navigation away from the page to a blank page.&lt;br/&gt;
  In other words, Microsoft Word doesn't leak memory either. All you have to do is close it, open it again and miraculously all the memory that it allocated and failed to release (but that somehow fails to meet the definition of "leaked") is released.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The whole &lt;em&gt;point&lt;/em&gt; of Internet Exploder 8 was to build an AJAX-friendly browser. The subtext went along the lines of, "Well, all those AJAX-heavy sites like GMail, Google Maps, Hotmail etc don't perform well under IE7 and we're losing browser market share, so let's make a browser that &lt;em&gt;is&lt;/em&gt; AJAX-friendly. But, at the same time, let's make developers require people to navigate away from that application before any of its memory is released."  &lt;/p&gt;

&lt;p&gt;We've just spent &lt;em&gt;days&lt;/em&gt; diagnosing as many of the various ways that IE leaks memory (ways, incidentally, with which none of the other browsers seem to have problems), patching the jQuery core to cope with its idiocy and writing our own DOM garbage collection handlers to deal with it. The jQuery and GWT discussion forums reveal that these guys are having just as much pain, and for similar reasons.  &lt;/p&gt;

&lt;p&gt;To the IE development team: Please, please, please, guys, fix your sodding .removeChild method and everything that has &lt;em&gt;anything&lt;/em&gt; to do with it. And don't talk to me about setting .innerHTML properties either until you have a browser that doesn't seg-fault when I do that to a table element, or when I manually break the relationship between a node and its parent. Finally, at least have the courage to confess that your browser &lt;em&gt;does&lt;/em&gt; leak memory in these scenarios rather than some pathetic attempt at explaining why a leak isn't a leak. Grr!!  &lt;/p&gt;

&lt;p&gt;If you want to cringe, grab the sIEve tool (see &lt;a href="http://codingforfunandprofit.uglybugger.org/2009/07/09/memory-leak-detector-for-internet-explorer/" title="http://codingforfunandprofit.uglybugger.org/2009/07/09/memory-leak-detector-for-internet-explorer/"&gt;Memory leak detector for Internet Explorer&lt;/a&gt; for a link) and point it at &lt;a href="http://msdn.microsoft.com" title="http://msdn.microsoft.com"&gt;http://msdn.microsoft.com&lt;/a&gt;. Navigate around a bit and then have a look at the number of orphan DOM nodes. Consider how many full-page reloads MSDN causes, and compare this to your own AJAX application. Weep.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/5oWuL8L24pY" height="1" width="1"/&gt;</description><pubDate>Fri, 10 Jul 2009 02:57:00 +1000</pubDate><a10:updated>2009-07-10T02:57:00+10:00</a10:updated><a10:content type="xhtml"><p>The genesis of this rant is that a colleague and I have just spent a couple of days diagnosing and fixing memory leaks (sorry, "pseudo-leaks"," according to Microsoft, which presumably means that the memory explosion we were seeing wasn't actually real) caused by awful, awful garbage collection in Internet Explorer.  </p>

<p>The icing on the cake was finding this article: <a href="http://msdn.microsoft.com/en-us/library/bb250448%28VS.85%29.aspx">Understanding and Solving Internet Explorer Leak Patterns.</a> The markworthy text is this:  </p>

<blockquote>
  <p>Pseudo-leaks almost always appear on the same page during dynamic scripting operations and should rarely be visible after navigation away from the page to a blank page.<br />
  In other words, Microsoft Word doesn't leak memory either. All you have to do is close it, open it again and miraculously all the memory that it allocated and failed to release (but that somehow fails to meet the definition of "leaked") is released.  </p>
</blockquote>

<p>The whole <em>point</em> of Internet Exploder 8 was to build an AJAX-friendly browser. The subtext went along the lines of, "Well, all those AJAX-heavy sites like GMail, Google Maps, Hotmail etc don't perform well under IE7 and we're losing browser market share, so let's make a browser that <em>is</em> AJAX-friendly. But, at the same time, let's make developers require people to navigate away from that application before any of its memory is released."  </p>

<p>We've just spent <em>days</em> diagnosing as many of the various ways that IE leaks memory (ways, incidentally, with which none of the other browsers seem to have problems), patching the jQuery core to cope with its idiocy and writing our own DOM garbage collection handlers to deal with it. The jQuery and GWT discussion forums reveal that these guys are having just as much pain, and for similar reasons.  </p>

<p>To the IE development team: Please, please, please, guys, fix your sodding .removeChild method and everything that has <em>anything</em> to do with it. And don't talk to me about setting .innerHTML properties either until you have a browser that doesn't seg-fault when I do that to a table element, or when I manually break the relationship between a node and its parent. Finally, at least have the courage to confess that your browser <em>does</em> leak memory in these scenarios rather than some pathetic attempt at explaining why a leak isn't a leak. Grr!!  </p>

<p>If you want to cringe, grab the sIEve tool (see <a href="http://codingforfunandprofit.uglybugger.org/2009/07/09/memory-leak-detector-for-internet-explorer/" title="http://codingforfunandprofit.uglybugger.org/2009/07/09/memory-leak-detector-for-internet-explorer/">Memory leak detector for Internet Explorer</a> for a link) and point it at <a href="http://msdn.microsoft.com" title="http://msdn.microsoft.com">http://msdn.microsoft.com</a>. Navigate around a bit and then have a look at the number of orphan DOM nodes. Consider how many full-page reloads MSDN causes, and compare this to your own AJAX application. Weep.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.07.10.0257</feedburner:origLink></item><item xml:base="Home/Post/2009.07.09.0957"><guid isPermaLink="false">2009.07.09.0957</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/lZ_mYYdFrBA/2009.07.09.0957</link><author>andrewh@uglybugger.org</author><title>Memory leak detector for Internet Explorer</title><description>&lt;p&gt;I've been playing with Drip and sIEve in order to find some memory leaks that we've been encountering under Internet Exploder.  &lt;/p&gt;

&lt;p&gt;&lt;a href="http://home.wanadoo.nl/jsrosman/"&gt;Drip / IESieve, Memory leak detector for IE Internet Explorer &lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;If you haven't looked at your application with sIEve, you really should.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/lZ_mYYdFrBA" height="1" width="1"/&gt;</description><pubDate>Thu, 09 Jul 2009 09:57:00 +1000</pubDate><a10:updated>2009-07-09T09:57:00+10:00</a10:updated><a10:content type="xhtml"><p>I've been playing with Drip and sIEve in order to find some memory leaks that we've been encountering under Internet Exploder.  </p>

<p><a href="http://home.wanadoo.nl/jsrosman/">Drip / IESieve, Memory leak detector for IE Internet Explorer </a>.  </p>

<p>If you haven't looked at your application with sIEve, you really should.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.07.09.0957</feedburner:origLink></item><item xml:base="Home/Post/2009.04.21.0835"><guid isPermaLink="false">2009.04.21.0835</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/3WFM9svhYo4/2009.04.21.0835</link><author>andrewh@uglybugger.org</author><title>"The control collection cannot be modified during DataBind, Init, Load, PreRender or Unload phases."</title><description>&lt;p&gt;Garbage. Of course it can. What a stupid error message.  &lt;/p&gt;

&lt;p&gt;What it &lt;em&gt;should&lt;/em&gt; say is, "Ancestors' control collections cannot be modified..." or "Control collections in a base server control class where a derived class uses markup cannot be modified..."  &lt;/p&gt;

&lt;p&gt;You'll see this error for a bunch of reasons to do with modifying control collections, and by and large it's probably because you're messing with someone else's collection. (Hint: don't do that. It's a bad practice. Clean up your code and don't mess around with other classes' internals. It's like reaching into someone else's trousers and adjusting things. You just don't do it. Ugh.)  &lt;/p&gt;

&lt;p&gt;Consider this scenario, though:  &lt;/p&gt;

&lt;div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;"&gt;
  &lt;br /&gt;&lt;pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; FooControl: UserControl&lt;br /&gt;{&lt;br /&gt;    HiddenField _hiddenFoo;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; CreateChildControls()&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;base&lt;/span&gt;.CreateChildControls();&lt;br /&gt;&lt;br /&gt;        _hiddenFoo = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; HiddenField { ID = &lt;span style="color:#006080;"&gt;"hiddenFoo"&lt;/span&gt; };&lt;br /&gt;        Controls.Add(_hiddenFoo);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;// Presumably we'll also actually *do* something with hiddenFoo, but&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;// that's neither here nor there.&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;

  &lt;br /&gt;
&lt;/div&gt;

&lt;p&gt;Remarkably boring. Until, that is, someone creates a control using markup (a .ascx control) and uses FooControl as the base class. All of a sudden, the exception above is going to be thrown, and you're going to be scratching your head, wondering what on earth's going on.  &lt;/p&gt;

&lt;p&gt;The most common scenario for this is where there's post data for your hiddenFoo field, and the page's ProcessPostData method indirectly calls EnsureChildControls() on everything it needs to in order to re-populate the control tree to where it was last time and then stuff the post data into the relevant field. This can sometimes (and don't ask me about "sometimes") lead to the above exception.  &lt;/p&gt;

&lt;p&gt;Calling EnsureChildControls() in your OnInit handler won't work, as your control's events won't reliably have started firing yet. (It &lt;em&gt;might&lt;/em&gt; work, but it won't guarantee it.) Inspecting your Controls property at a breakpoint in CreateChildControls method will give you a clue, though: &lt;em&gt;your child controls that are declared in markup already exist at this point&lt;/em&gt;.  &lt;/p&gt;

&lt;p&gt;What you want to do instead is the following:  &lt;/p&gt;

&lt;div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;"&gt;
  &lt;br /&gt;&lt;pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; FooControl: UserControl&lt;br /&gt;{&lt;br /&gt;    HiddenField _hiddenFoo;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; AddParsedSubObject(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; obj)&lt;br /&gt;    {&lt;br /&gt;        EnsureChildControls();&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;base&lt;/span&gt;.AddParsedSubObject(obj);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;protected&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; CreateChildControls()&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;base&lt;/span&gt;.CreateChildControls();&lt;br /&gt;&lt;br /&gt;        _hiddenFoo = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; HiddenField { ID = &lt;span style="color:#006080;"&gt;"hiddenFoo"&lt;/span&gt; };&lt;br /&gt;        Controls.Add(_hiddenFoo);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;// Presumably we'll also actually *do* something with hiddenFoo, but&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;// that's neither here nor there.&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;

  &lt;br /&gt;
&lt;/div&gt;

&lt;p&gt;The AddParsedSubObject method is what's called to add controls that were parsed from markup to your control tree. As we already know that our parsed controls are happily ensconced in our control tree, all we have to do is demand that all of our other controls get loaded first.  &lt;/p&gt;

&lt;p&gt;Bear in mind that this won't work if you're doing silly things with your control collection, and it &lt;em&gt;will&lt;/em&gt; incur a slight performance hit: AddParsedSubObject is called once per markup element (including for whitespace literals) and calling EnsureChildControls will result in a check against ChildControlsCreated, so you're going to have a lot of those hits. Still', it's better than an unhandled exception, right?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/3WFM9svhYo4" height="1" width="1"/&gt;</description><pubDate>Tue, 21 Apr 2009 08:35:00 +1000</pubDate><a10:updated>2009-04-21T08:35:00+10:00</a10:updated><a10:content type="xhtml"><p>Garbage. Of course it can. What a stupid error message.  </p>

<p>What it <em>should</em> say is, "Ancestors' control collections cannot be modified..." or "Control collections in a base server control class where a derived class uses markup cannot be modified..."  </p>

<p>You'll see this error for a bunch of reasons to do with modifying control collections, and by and large it's probably because you're messing with someone else's collection. (Hint: don't do that. It's a bad practice. Clean up your code and don't mess around with other classes' internals. It's like reaching into someone else's trousers and adjusting things. You just don't do it. Ugh.)  </p>

<p>Consider this scenario, though:  </p>

<div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;">
  <br /><pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">class</span> FooControl: UserControl<br />{<br />    HiddenField _hiddenFoo;<br /><br />    <span style="color:#0000ff;">protected</span> <span style="color:#0000ff;">override</span> <span style="color:#0000ff;">void</span> CreateChildControls()<br />    {<br />        <span style="color:#0000ff;">base</span>.CreateChildControls();<br /><br />        _hiddenFoo = <span style="color:#0000ff;">new</span> HiddenField { ID = <span style="color:#006080;">"hiddenFoo"</span> };<br />        Controls.Add(_hiddenFoo);<br />    }<br /><br />    <span style="color:#008000;">// Presumably we'll also actually *do* something with hiddenFoo, but</span><br />    <span style="color:#008000;">// that's neither here nor there.</span><br />}</pre>

  <br />
</div>

<p>Remarkably boring. Until, that is, someone creates a control using markup (a .ascx control) and uses FooControl as the base class. All of a sudden, the exception above is going to be thrown, and you're going to be scratching your head, wondering what on earth's going on.  </p>

<p>The most common scenario for this is where there's post data for your hiddenFoo field, and the page's ProcessPostData method indirectly calls EnsureChildControls() on everything it needs to in order to re-populate the control tree to where it was last time and then stuff the post data into the relevant field. This can sometimes (and don't ask me about "sometimes") lead to the above exception.  </p>

<p>Calling EnsureChildControls() in your OnInit handler won't work, as your control's events won't reliably have started firing yet. (It <em>might</em> work, but it won't guarantee it.) Inspecting your Controls property at a breakpoint in CreateChildControls method will give you a clue, though: <em>your child controls that are declared in markup already exist at this point</em>.  </p>

<p>What you want to do instead is the following:  </p>

<div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;">
  <br /><pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">class</span> FooControl: UserControl<br />{<br />    HiddenField _hiddenFoo;<br /><br />    <span style="color:#0000ff;">protected</span> <span style="color:#0000ff;">override</span> <span style="color:#0000ff;">void</span> AddParsedSubObject(<span style="color:#0000ff;">object</span> obj)<br />    {<br />        EnsureChildControls();<br />        <span style="color:#0000ff;">base</span>.AddParsedSubObject(obj);<br />    }<br /><br />    <span style="color:#0000ff;">protected</span> <span style="color:#0000ff;">override</span> <span style="color:#0000ff;">void</span> CreateChildControls()<br />    {<br />        <span style="color:#0000ff;">base</span>.CreateChildControls();<br /><br />        _hiddenFoo = <span style="color:#0000ff;">new</span> HiddenField { ID = <span style="color:#006080;">"hiddenFoo"</span> };<br />        Controls.Add(_hiddenFoo);<br />    }<br /><br />    <span style="color:#008000;">// Presumably we'll also actually *do* something with hiddenFoo, but</span><br />    <span style="color:#008000;">// that's neither here nor there.</span><br />}</pre>

  <br />
</div>

<p>The AddParsedSubObject method is what's called to add controls that were parsed from markup to your control tree. As we already know that our parsed controls are happily ensconced in our control tree, all we have to do is demand that all of our other controls get loaded first.  </p>

<p>Bear in mind that this won't work if you're doing silly things with your control collection, and it <em>will</em> incur a slight performance hit: AddParsedSubObject is called once per markup element (including for whitespace literals) and calling EnsureChildControls will result in a check against ChildControlsCreated, so you're going to have a lot of those hits. Still', it's better than an unhandled exception, right?</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.04.21.0835</feedburner:origLink></item><item xml:base="Home/Post/2009.04.06.1203"><guid isPermaLink="false">2009.04.06.1203</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/xjYwgPbhyTU/2009.04.06.1203</link><author>andrewh@uglybugger.org</author><title>My Life is Debugging</title><description>&lt;p&gt;Hmm. I spent today at work, optimising JavaScript and re-jigging chunks of Microsoft's scripting framework. It's a Sunday, by the way.  &lt;/p&gt;

&lt;p&gt;I then came home and spent the rest of the evening debugging WordPress XMLRPC.  &lt;/p&gt;

&lt;p&gt;My life is debugging.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/xjYwgPbhyTU" height="1" width="1"/&gt;</description><pubDate>Mon, 06 Apr 2009 12:03:00 +1000</pubDate><a10:updated>2009-04-06T12:03:00+10:00</a10:updated><a10:content type="xhtml"><p>Hmm. I spent today at work, optimising JavaScript and re-jigging chunks of Microsoft's scripting framework. It's a Sunday, by the way.  </p>

<p>I then came home and spent the rest of the evening debugging WordPress XMLRPC.  </p>

<p>My life is debugging.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.04.06.1203</feedburner:origLink></item><item xml:base="Home/Post/2009.03.20.0859"><guid isPermaLink="false">2009.03.20.0859</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/Eql8Psbjez4/2009.03.20.0859</link><author>andrewh@uglybugger.org</author><title>Official Gmail Blog: New in Labs: Undo Send</title><description>&lt;p&gt;Here's a cute new feature from Google: "Undo Send" in Gmail.  &lt;/p&gt;

&lt;p&gt;&lt;a href="http://gmailblog.blogspot.com/2009/03/new-in-labs-undo-send.html"&gt;Official Gmail Blog: New in Labs: Undo Send&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;Cool :)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/Eql8Psbjez4" height="1" width="1"/&gt;</description><pubDate>Fri, 20 Mar 2009 08:59:00 +1000</pubDate><a10:updated>2009-03-20T08:59:00+10:00</a10:updated><a10:content type="xhtml"><p>Here's a cute new feature from Google: "Undo Send" in Gmail.  </p>

<p><a href="http://gmailblog.blogspot.com/2009/03/new-in-labs-undo-send.html">Official Gmail Blog: New in Labs: Undo Send</a>.  </p>

<p>Cool :)</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.03.20.0859</feedburner:origLink></item><item xml:base="Home/Post/2009.03.20.0849"><guid isPermaLink="false">2009.03.20.0849</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/i4BSaVW-WWE/2009.03.20.0849</link><author>andrewh@uglybugger.org</author><title>Scripting Gotchas</title><description>&lt;p&gt;Microsoft JScript runtime error: Sys.ArgumentUndefinedException: Value cannot be undefined.&lt;br/&gt;
Parameter name: type 
 &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="http://codingforfunandprofit.files.wordpress.com/2009/03/image1.png"&gt;&lt;img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="image" border="0" alt="image" src="http://codingforfunandprofit.files.wordpress.com/2009/03/image-thumb1.png" width="508" height="242" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Type name defined in .js does not match GetType().FullName in .cs.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/i4BSaVW-WWE" height="1" width="1"/&gt;</description><pubDate>Fri, 20 Mar 2009 08:49:00 +1000</pubDate><a10:updated>2009-03-20T08:49:00+10:00</a10:updated><a10:content type="xhtml"><p>Microsoft JScript runtime error: Sys.ArgumentUndefinedException: Value cannot be undefined.<br />
Parameter name: type 
 </p>

<p> </p>

<p><a href="http://codingforfunandprofit.files.wordpress.com/2009/03/image1.png"><img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="image" border="0" alt="image" src="http://codingforfunandprofit.files.wordpress.com/2009/03/image-thumb1.png" width="508" height="242" /></a> </p>

<p>Type name defined in .js does not match GetType().FullName in .cs.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.03.20.0849</feedburner:origLink></item><item xml:base="Home/Post/2009.03.12.0147"><guid isPermaLink="false">2009.03.12.0147</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/_sExEsdfR9w/2009.03.12.0147</link><author>andrewh@uglybugger.org</author><title>console.log() Equivalent for Internet Explorer</title><description>&lt;p&gt;There are a bunch of people out there who are fed up with the lack of a console.log() equivalent in Internet Explorer. It shouldn't come as any surprise that I'm one of them.&lt;/p&gt;

&lt;p&gt;For anyone who's ever tried to debug a whole bunch of JavaScript code and ended up with myriad alert('here') and alert('here2') calls just so they could see what was happening, console.log() became our friend very, very quickly. No surprise, however, that IE didn't have it.&lt;/p&gt;

&lt;p&gt;It becomes significantly more painful, however, when you're trying to clean up JS code for the sake of
performance. The usefulness of any metrics collected goes out the window once there's user activity involved.
(Besides, clicking "OK" for all those alert boxes is a royal &lt;em&gt;pain&lt;/em&gt;.)&lt;/p&gt;

&lt;p&gt;(Hint to the IE8 team: Your product is still in beta. You &lt;em&gt;must&lt;/em&gt; have a logging call somewhere. Publish it,
please. &lt;em&gt;Please.&lt;/em&gt; All the other browsers of note do.)&lt;/p&gt;

&lt;p&gt;There are quite a few good console.log() equivalents out there, not the least of which are &lt;a href="http://icant.co.uk/sandbox/fauxconsole/"&gt;Faux Console&lt;/a&gt;
and the &lt;a href="http://developer.yahoo.com/yui/logger/"&gt;Yahoo User Interface Logger Widget&lt;/a&gt;. For extremely light-weight
applications, though, there was nothing that did just what I wanted, so I wrote one. You'll be depressed
at how simple it is, and how easy it would have been for the IE team to have included this functionality at
almost any point in IE's development cycle.&lt;/p&gt;

&lt;p&gt;The JavaScript code:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// rudimentary javascript logging to emulate console.log(). If there
// already exists an object named "console" (defined by most *useful*
// browsers :p) then we won't do anything here at all.
if (typeof (console) === 'undefined') {

    // define "console" namespace
    console = new function() {
        // this is the Id of the console div. It doesn't actually need
        // to be a div, as long as it has an innerHTML property.
        this.ConsoleDivId = "JavaScriptConsole";

        // maintains a reference to the console output div, so that we
        // don't have to call document.getElementById a bunch of times.
        this.ConsoleDiv = null;

        // allows us to cache whether or not the console div exists, so
        // that we can just do an early exit from the console.log method
        // and similar if we're not going to put any useful output anywhere.
        this.ConsoleDivExists = null;
    };

    // this is an expensive (really quite expensive) string padding function.
    // Don't use it for large strings.
    console.padString = function(s, padToLength, padCharacter) {
        var response = "" + s;
        while (response.length &amp;lt; padToLength) {
            response = padCharacter + response;
        }

        return response;
    }

    console.log = function(message) {

        // this will be executed once, on first method invocation, to
        // get a reference to the output div if it exists
        if (console.ConsoleDivExists == null) {
            console.ConsoleDiv = document.getElementById(console.ConsoleDivId);
            console.ConsoleDivExists = (console.ConsoleDiv != null);
        }

        // only do any logging if we actually have an output div.
        // (Check using the cached variable so that we don't end up
        // with a bunch of failed calls to document.getElementById).
        if (console.ConsoleDivExists) {
            var date = new Date();
            var entireMessage =
                console.padString(date.getHours(), 2, "0") + ":" +
                console.padString(date.getMinutes(), 2, "0") + ":" +
                console.padString(date.getSeconds(), 2, "0") + "." +
                console.padString(date.getMilliseconds(), 3, "0") + " " + message;
            delete date;

            // append the message
            console.ConsoleDiv.innerHTML = console.ConsoleDiv.innerHTML + "&amp;lt;br /&amp;gt;" + entireMessage;

            // scroll the div to the bottom
            console.ConsoleDiv.scrollTop = console.ConsoleDiv.scrollHeight;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ideally you'd drop this into an included script file, but it's more likely that you'll paste it into a &amp;lt;script&amp;gt; tag in the header of your HTML document.&lt;/p&gt;

&lt;p&gt;The HTML that creates the DIV to contain the output:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;!--
    This is here for JavaScript debugging. Please use calls to
    console.log(message) to log to this console, as we're emulating
    the console.log() function that real browsers provide.
--&amp;gt;
&amp;lt;div id="JavaScriptConsole" style="position: absolute; bottom: 30px; left: 30px; width: 600px; height: 200px; overflow: scroll; background-color: Yellow; color: Red;"&amp;gt;
    &amp;lt;a href="javascript:document.getElementById('JavascriptConsole').style.visibility = 'hidden';" style="float: right;"&amp;gt;Close&amp;lt;/a&amp;gt; &amp;lt;span style="font-weight: bold;"&amp;gt;JavaScript Console&amp;lt;/span&amp;gt;&amp;lt;br /&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that this div also contains a hyperlink with JavaScript code in it to hide it.&lt;/p&gt;

&lt;p&gt;A simple hello world script to log to it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;script type="text/javascript"&amp;gt;
    console.log("Hello, world!");
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;... and finally, the output:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.codingforfunandprofit.com/Posts/2009/2009.03.12.0147/Screenshot.png" alt="Screenshot"/&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/_sExEsdfR9w" height="1" width="1"/&gt;</description><pubDate>Thu, 12 Mar 2009 01:47:00 +1000</pubDate><a10:updated>2009-03-12T01:47:00+10:00</a10:updated><a10:content type="xhtml"><p>There are a bunch of people out there who are fed up with the lack of a console.log() equivalent in Internet Explorer. It shouldn't come as any surprise that I'm one of them.</p>

<p>For anyone who's ever tried to debug a whole bunch of JavaScript code and ended up with myriad alert('here') and alert('here2') calls just so they could see what was happening, console.log() became our friend very, very quickly. No surprise, however, that IE didn't have it.</p>

<p>It becomes significantly more painful, however, when you're trying to clean up JS code for the sake of
performance. The usefulness of any metrics collected goes out the window once there's user activity involved.
(Besides, clicking "OK" for all those alert boxes is a royal <em>pain</em>.)</p>

<p>(Hint to the IE8 team: Your product is still in beta. You <em>must</em> have a logging call somewhere. Publish it,
please. <em>Please.</em> All the other browsers of note do.)</p>

<p>There are quite a few good console.log() equivalents out there, not the least of which are <a href="http://icant.co.uk/sandbox/fauxconsole/">Faux Console</a>
and the <a href="http://developer.yahoo.com/yui/logger/">Yahoo User Interface Logger Widget</a>. For extremely light-weight
applications, though, there was nothing that did just what I wanted, so I wrote one. You'll be depressed
at how simple it is, and how easy it would have been for the IE team to have included this functionality at
almost any point in IE's development cycle.</p>

<p>The JavaScript code:</p>

<pre><code>// rudimentary javascript logging to emulate console.log(). If there
// already exists an object named "console" (defined by most *useful*
// browsers :p) then we won't do anything here at all.
if (typeof (console) === 'undefined') {

    // define "console" namespace
    console = new function() {
        // this is the Id of the console div. It doesn't actually need
        // to be a div, as long as it has an innerHTML property.
        this.ConsoleDivId = "JavaScriptConsole";

        // maintains a reference to the console output div, so that we
        // don't have to call document.getElementById a bunch of times.
        this.ConsoleDiv = null;

        // allows us to cache whether or not the console div exists, so
        // that we can just do an early exit from the console.log method
        // and similar if we're not going to put any useful output anywhere.
        this.ConsoleDivExists = null;
    };

    // this is an expensive (really quite expensive) string padding function.
    // Don't use it for large strings.
    console.padString = function(s, padToLength, padCharacter) {
        var response = "" + s;
        while (response.length &lt; padToLength) {
            response = padCharacter + response;
        }

        return response;
    }

    console.log = function(message) {

        // this will be executed once, on first method invocation, to
        // get a reference to the output div if it exists
        if (console.ConsoleDivExists == null) {
            console.ConsoleDiv = document.getElementById(console.ConsoleDivId);
            console.ConsoleDivExists = (console.ConsoleDiv != null);
        }

        // only do any logging if we actually have an output div.
        // (Check using the cached variable so that we don't end up
        // with a bunch of failed calls to document.getElementById).
        if (console.ConsoleDivExists) {
            var date = new Date();
            var entireMessage =
                console.padString(date.getHours(), 2, "0") + ":" +
                console.padString(date.getMinutes(), 2, "0") + ":" +
                console.padString(date.getSeconds(), 2, "0") + "." +
                console.padString(date.getMilliseconds(), 3, "0") + " " + message;
            delete date;

            // append the message
            console.ConsoleDiv.innerHTML = console.ConsoleDiv.innerHTML + "&lt;br /&gt;" + entireMessage;

            // scroll the div to the bottom
            console.ConsoleDiv.scrollTop = console.ConsoleDiv.scrollHeight;
        }
    }
}
</code></pre>

<p>Ideally you'd drop this into an included script file, but it's more likely that you'll paste it into a &lt;script&gt; tag in the header of your HTML document.</p>

<p>The HTML that creates the DIV to contain the output:</p>

<pre><code>&lt;!--
    This is here for JavaScript debugging. Please use calls to
    console.log(message) to log to this console, as we're emulating
    the console.log() function that real browsers provide.
--&gt;
&lt;div id="JavaScriptConsole" style="position: absolute; bottom: 30px; left: 30px; width: 600px; height: 200px; overflow: scroll; background-color: Yellow; color: Red;"&gt;
    &lt;a href="javascript:document.getElementById('JavascriptConsole').style.visibility = 'hidden';" style="float: right;"&gt;Close&lt;/a&gt; &lt;span style="font-weight: bold;"&gt;JavaScript Console&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
</code></pre>

<p>Note that this div also contains a hyperlink with JavaScript code in it to hide it.</p>

<p>A simple hello world script to log to it:</p>

<pre><code>&lt;script type="text/javascript"&gt;
    console.log("Hello, world!");
&lt;/script&gt;
</code></pre>

<p>... and finally, the output:</p>

<p><img src="http://www.codingforfunandprofit.com/Posts/2009/2009.03.12.0147/Screenshot.png" alt="Screenshot" /></p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.03.12.0147</feedburner:origLink></item><item xml:base="Home/Post/2009.02.18.0613"><guid isPermaLink="false">2009.02.18.0613</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/vYXCha0IPjs/2009.02.18.0613</link><author>andrewh@uglybugger.org</author><title>Microsoft's Azure Services Platform</title><description>&lt;p&gt;... and why you really should care.  &lt;/p&gt;

&lt;p&gt;I'm sitting in a Microsoft user group meeting right now, and I am, to be honest, pretty unimpressed. Not with the presenters - they're doing a good job - or with the presentation, which is on what should be a fascinating topic, but with the people. Sorry, Microsoft, but the greatest problem you face right now is not your technology; it's pretty damn good[1]. It's the people who are afraid of using it - who, sadly, aren't very.  &lt;/p&gt;

&lt;p&gt;OK, I'm home now, so I can type properly.  &lt;/p&gt;

&lt;p&gt;The presentation topic was the� &lt;a href="http://www.microsoft.com/azure" target="_blank"&gt;Azure Services Platform&lt;/a&gt;, which is� Microsoft's� � answer to the Google cloud. Azure is a fascinating topic, both technically and strategically. The technical merits I'll discuss in a minute. Strategically, however, this platform shows that Microsoft is quaking in its boots over what Google's been doing with cloud computing, and is now trying to play catch-up. The degree of success a) remains to be seen; and b) depends upon the aforementioned people who are going to have to want to learn to use and exploit its strengths.  &lt;/p&gt;

&lt;p&gt;This platform gives immeasurable advantages to whomever wants them: almost infinite scalability, massive parallelism and redundancy, no more worries about server provisioning or downtime... the list goes on.  &lt;/p&gt;

&lt;p&gt;One of the reasons I'm so irritated is that instead of asking intelligent questions like, "How much can we scale a single computational task?" or even "How does this compare to the Google cloud in terms of speed, flexibility and response time?" people asked questions around keeping their own servers ("Can I still be woken up at 3am when a server falls over, please?") and security ("Can I host my own database and have the platform talk to it?" or, in other words, "Can I still trust Microsoft with my unencrypted data, but nonetheless re-introduce my own single point of failure into an otherwise-well-designed system?"). Honestly.  &lt;/p&gt;

&lt;p&gt;I don't want to rant, so suffice it to say this:  &lt;/p&gt;

&lt;p&gt;Learn about your craft. Go and sign up for the Azure CTP. Go and get your &lt;a href="http://code.google.com/appengine/" target="_blank"&gt;Google App Engine&lt;/a&gt; key. Read about the &lt;a href="http://labs.google.com/papers/gfs.html" target="_blank"&gt;Google file-system&lt;/a&gt; and &lt;a href="http://aws.amazon.com/s3/" target="_blank"&gt;Amazon's S3&lt;/a&gt;. And, while you're at it, go and re-read some Knuth and some Fowler[2], just because you should, and probably haven't.  &lt;/p&gt;

&lt;p&gt;Get some enthusiasm about what you're seeing, people. It's brilliant. Go and learn about it. For what it's worth, if you haven't been hanging out for a cloud computing solution from Microsoft for a very long time, I most respectfully suggest that you might be in the wrong profession.  &lt;/p&gt;

&lt;p&gt;�   &lt;/p&gt;

&lt;p&gt;[1] Except for Live Writer. What were you &lt;em&gt;thinking&lt;/em&gt;, guys? Writing this post has been &lt;em&gt;painful&lt;/em&gt;. I tried to screenshot the crash messages and embed them into another blog post (also in Live Writer) and it crashed, too. Fail.  &lt;/p&gt;

&lt;p&gt;[2] Who are they? Shame on you.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/vYXCha0IPjs" height="1" width="1"/&gt;</description><pubDate>Wed, 18 Feb 2009 06:13:00 +1000</pubDate><a10:updated>2009-02-18T06:13:00+10:00</a10:updated><a10:content type="xhtml"><p>... and why you really should care.  </p>

<p>I'm sitting in a Microsoft user group meeting right now, and I am, to be honest, pretty unimpressed. Not with the presenters - they're doing a good job - or with the presentation, which is on what should be a fascinating topic, but with the people. Sorry, Microsoft, but the greatest problem you face right now is not your technology; it's pretty damn good[1]. It's the people who are afraid of using it - who, sadly, aren't very.  </p>

<p>OK, I'm home now, so I can type properly.  </p>

<p>The presentation topic was the� <a href="http://www.microsoft.com/azure" target="_blank">Azure Services Platform</a>, which is� Microsoft's� � answer to the Google cloud. Azure is a fascinating topic, both technically and strategically. The technical merits I'll discuss in a minute. Strategically, however, this platform shows that Microsoft is quaking in its boots over what Google's been doing with cloud computing, and is now trying to play catch-up. The degree of success a) remains to be seen; and b) depends upon the aforementioned people who are going to have to want to learn to use and exploit its strengths.  </p>

<p>This platform gives immeasurable advantages to whomever wants them: almost infinite scalability, massive parallelism and redundancy, no more worries about server provisioning or downtime... the list goes on.  </p>

<p>One of the reasons I'm so irritated is that instead of asking intelligent questions like, "How much can we scale a single computational task?" or even "How does this compare to the Google cloud in terms of speed, flexibility and response time?" people asked questions around keeping their own servers ("Can I still be woken up at 3am when a server falls over, please?") and security ("Can I host my own database and have the platform talk to it?" or, in other words, "Can I still trust Microsoft with my unencrypted data, but nonetheless re-introduce my own single point of failure into an otherwise-well-designed system?"). Honestly.  </p>

<p>I don't want to rant, so suffice it to say this:  </p>

<p>Learn about your craft. Go and sign up for the Azure CTP. Go and get your <a href="http://code.google.com/appengine/" target="_blank">Google App Engine</a> key. Read about the <a href="http://labs.google.com/papers/gfs.html" target="_blank">Google file-system</a> and <a href="http://aws.amazon.com/s3/" target="_blank">Amazon's S3</a>. And, while you're at it, go and re-read some Knuth and some Fowler[2], just because you should, and probably haven't.  </p>

<p>Get some enthusiasm about what you're seeing, people. It's brilliant. Go and learn about it. For what it's worth, if you haven't been hanging out for a cloud computing solution from Microsoft for a very long time, I most respectfully suggest that you might be in the wrong profession.  </p>

<p>�   </p>

<p>[1] Except for Live Writer. What were you <em>thinking</em>, guys? Writing this post has been <em>painful</em>. I tried to screenshot the crash messages and embed them into another blog post (also in Live Writer) and it crashed, too. Fail.  </p>

<p>[2] Who are they? Shame on you.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.02.18.0613</feedburner:origLink></item><item xml:base="Home/Post/2009.01.16.0305"><guid isPermaLink="false">2009.01.16.0305</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/eXwgFlz-aBk/2009.01.16.0305</link><author>andrewh@uglybugger.org</author><title>#if DEBUG Considered Harmful</title><description>&lt;p&gt;I know, I know. Lots of people have written about this one, but nonetheless it still gets used and I feel I should add my $0.02. (That's Australian money, by the way, so it probably works out at not very much in your own currency.)&lt;/p&gt;

&lt;p&gt;This post is specific to C#, as .NET has the very nice feature of code attributes, specifically the ConditionalAttribute class which allows methods to be compiled and invoked by the JIT compiler only if there's a particular compilation variable set.&lt;/p&gt;

&lt;p&gt;Consider the code below:&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:310px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;margin:20px 0 10px;padding:4px;"&gt;
  &lt;pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;height:346px;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; Hello()&lt;br /&gt;{&lt;br /&gt;    Console.WriteLine(&lt;span style="color:#006080;"&gt;"Hello, world!"&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; Goodbye()&lt;br /&gt;{&lt;br /&gt;    Console.WriteLine(&lt;span style="color:#006080;"&gt;"Goodbye, cruel world!"&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; GreetTheWorld()&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:#cc6633;"&gt;#if&lt;/span&gt; DEBUG&lt;br /&gt;    Hello();&lt;br /&gt;    &lt;span style="color:#cc6633;"&gt;#endif&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    Goodbye();&lt;br /&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Let's say that we compile this in Debug mode with code analysis turned on and warnings set to errors. (We all compile with warnings == errors, right?) All is well.&lt;/p&gt;

&lt;p&gt;We go to run our unit tests again in Release mode prior to check-in, so we recompile in Release mode. (Or, if we're lazy, we just check in from our Debug build and let our build server compile and run the tests in Release mode.)&lt;/p&gt;

&lt;p&gt;Oops. CA1811 violation: you have uncalled private methods in your code. Please call them if you meant to call them, or remove them if not. The FxCop engine will never notice that our #if DEBUG directive has compiled out the call to our Hello() method, so code analysis throws an error.&lt;/p&gt;

&lt;p&gt;Use this one instead:&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:310px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;margin:20px 0 10px;padding:4px;"&gt;
  &lt;pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"&gt;[Conditional(&lt;span style="color:#006080;"&gt;"DEBUG"&lt;/span&gt;)]&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; Hello()&lt;br /&gt;{&lt;br /&gt;    Console.WriteLine(&lt;span style="color:#006080;"&gt;"Hello, world!"&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; Goodbye()&lt;br /&gt;{&lt;br /&gt;    Console.WriteLine(&lt;span style="color:#006080;"&gt;"Goodbye, cruel world!"&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; GreetTheWorld()&lt;br /&gt;{&lt;br /&gt;    Hello();&lt;br /&gt;    Goodbye();&lt;br /&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This makes the compiler &lt;em&gt;much&lt;/em&gt; happier.&lt;/p&gt;

&lt;p&gt;Let's consider the first piece of code again, though, and edit it in Release mode. Perhaps we'd like to rename our methods to something more descriptive of what they do: PrintHello() and PrintGoodbye(). So, we whip out our trusty refactoring tool (^R ^R in Visual Studio) and tell it to rename our methods.&lt;/p&gt;

&lt;p&gt;Here's what we end up with (remembering that we're in Release mode):&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:310px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;margin:20px 0 10px;padding:4px;"&gt;
  &lt;pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; PrintHello()&lt;br /&gt;{&lt;br /&gt;    Console.WriteLine(&lt;span style="color:#006080;"&gt;"Hello, world!"&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; PrintGoodbye()&lt;br /&gt;{&lt;br /&gt;    Console.WriteLine(&lt;span style="color:#006080;"&gt;"Goodbye, cruel world!"&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; GreetTheWorld()&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:#cc6633;"&gt;#if&lt;/span&gt; DEBUG&lt;br /&gt;    Hello();&lt;br /&gt;    &lt;span style="color:#cc6633;"&gt;#endif&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    PrintGoodbye();&lt;br /&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Oh, sod. We've introduced a compilation error because the refactor/rename operation uses the compiled version of the code to check for symbol usage, and our call to the former Hello() method doesn't appear in the compiled assembly because the #if DEBUG check caused it to not be compiled. We've left the old call to Hello() unchanged.&lt;/p&gt;

&lt;p&gt;If we'd performed the same operation on the second piece of code instead, we'd be laughing.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/eXwgFlz-aBk" height="1" width="1"/&gt;</description><pubDate>Fri, 16 Jan 2009 03:05:00 +1000</pubDate><a10:updated>2009-01-16T03:05:00+10:00</a10:updated><a10:content type="xhtml"><p>I know, I know. Lots of people have written about this one, but nonetheless it still gets used and I feel I should add my $0.02. (That's Australian money, by the way, so it probably works out at not very much in your own currency.)</p>

<p>This post is specific to C#, as .NET has the very nice feature of code attributes, specifically the ConditionalAttribute class which allows methods to be compiled and invoked by the JIT compiler only if there's a particular compilation variable set.</p>

<p>Consider the code below:</p>

<div style="border-bottom:gray 1px solid;border-left:gray 1px solid;line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:310px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;margin:20px 0 10px;padding:4px;">
  <pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;height:346px;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">private</span> <span style="color:#0000ff;">static</span> <span style="color:#0000ff;">void</span> Hello()<br />{<br />    Console.WriteLine(<span style="color:#006080;">"Hello, world!"</span>);<br />}<br /><br /><span style="color:#0000ff;">private</span> <span style="color:#0000ff;">static</span> <span style="color:#0000ff;">void</span> Goodbye()<br />{<br />    Console.WriteLine(<span style="color:#006080;">"Goodbye, cruel world!"</span>);<br />}<br /><br /><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">static</span> <span style="color:#0000ff;">void</span> GreetTheWorld()<br />{<br />    <span style="color:#cc6633;">#if</span> DEBUG<br />    Hello();<br />    <span style="color:#cc6633;">#endif</span><br /><br />    Goodbye();<br />}</pre>
</div>

<p>Let's say that we compile this in Debug mode with code analysis turned on and warnings set to errors. (We all compile with warnings == errors, right?) All is well.</p>

<p>We go to run our unit tests again in Release mode prior to check-in, so we recompile in Release mode. (Or, if we're lazy, we just check in from our Debug build and let our build server compile and run the tests in Release mode.)</p>

<p>Oops. CA1811 violation: you have uncalled private methods in your code. Please call them if you meant to call them, or remove them if not. The FxCop engine will never notice that our #if DEBUG directive has compiled out the call to our Hello() method, so code analysis throws an error.</p>

<p>Use this one instead:</p>

<div style="border-bottom:gray 1px solid;border-left:gray 1px solid;line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:310px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;margin:20px 0 10px;padding:4px;">
  <pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;">[Conditional(<span style="color:#006080;">"DEBUG"</span>)]<br /><span style="color:#0000ff;">private</span> <span style="color:#0000ff;">static</span> <span style="color:#0000ff;">void</span> Hello()<br />{<br />    Console.WriteLine(<span style="color:#006080;">"Hello, world!"</span>);<br />}<br /><br /><span style="color:#0000ff;">private</span> <span style="color:#0000ff;">static</span> <span style="color:#0000ff;">void</span> Goodbye()<br />{<br />    Console.WriteLine(<span style="color:#006080;">"Goodbye, cruel world!"</span>);<br />}<br /><br /><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">static</span> <span style="color:#0000ff;">void</span> GreetTheWorld()<br />{<br />    Hello();<br />    Goodbye();<br />}</pre>
</div>

<p>This makes the compiler <em>much</em> happier.</p>

<p>Let's consider the first piece of code again, though, and edit it in Release mode. Perhaps we'd like to rename our methods to something more descriptive of what they do: PrintHello() and PrintGoodbye(). So, we whip out our trusty refactoring tool (^R ^R in Visual Studio) and tell it to rename our methods.</p>

<p>Here's what we end up with (remembering that we're in Release mode):</p>

<div style="border-bottom:gray 1px solid;border-left:gray 1px solid;line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:310px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;margin:20px 0 10px;padding:4px;">
  <pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">private</span> <span style="color:#0000ff;">static</span> <span style="color:#0000ff;">void</span> PrintHello()<br />{<br />    Console.WriteLine(<span style="color:#006080;">"Hello, world!"</span>);<br />}<br /><br /><span style="color:#0000ff;">private</span> <span style="color:#0000ff;">static</span> <span style="color:#0000ff;">void</span> PrintGoodbye()<br />{<br />    Console.WriteLine(<span style="color:#006080;">"Goodbye, cruel world!"</span>);<br />}<br /><br /><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">static</span> <span style="color:#0000ff;">void</span> GreetTheWorld()<br />{<br />    <span style="color:#cc6633;">#if</span> DEBUG<br />    Hello();<br />    <span style="color:#cc6633;">#endif</span><br /><br />    PrintGoodbye();<br />}</pre>
</div>

<p>Oh, sod. We've introduced a compilation error because the refactor/rename operation uses the compiled version of the code to check for symbol usage, and our call to the former Hello() method doesn't appear in the compiled assembly because the #if DEBUG check caused it to not be compiled. We've left the old call to Hello() unchanged.</p>

<p>If we'd performed the same operation on the second piece of code instead, we'd be laughing.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.01.16.0305</feedburner:origLink></item><item xml:base="Home/Post/2009.01.14.1048"><guid isPermaLink="false">2009.01.14.1048</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/glNNV4W9mlo/2009.01.14.1048</link><author>andrewh@uglybugger.org</author><title>Brisbane Alt.Net User Group Launched</title><description>&lt;p&gt;The Brisbane Alt.Net User Group has launched. Check it out at &lt;a href="http://brisbane.ozalt.net/"&gt;Brisbane Alt.Net&lt;/a&gt; or, even better, turn up to the first meeting in February.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/glNNV4W9mlo" height="1" width="1"/&gt;</description><pubDate>Wed, 14 Jan 2009 10:48:00 +1000</pubDate><a10:updated>2009-01-14T10:48:00+10:00</a10:updated><a10:content type="xhtml"><p>The Brisbane Alt.Net User Group has launched. Check it out at <a href="http://brisbane.ozalt.net/">Brisbane Alt.Net</a> or, even better, turn up to the first meeting in February.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.01.14.1048</feedburner:origLink></item><item xml:base="Home/Post/2009.01.12.0453"><guid isPermaLink="false">2009.01.12.0453</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/BuVugB8RHgg/2009.01.12.0453</link><author>andrewh@uglybugger.org</author><title>The Windows 7 Beta Kicks Off This Week - Windows 7 Team Blog - The Windows Blog</title><description>&lt;p&gt;Just in case you missed it, the Windows 7 Beta is now available.  &lt;/p&gt;

&lt;p&gt;&lt;a href="http://windowsteamblog.com/blogs/windows7/archive/2009/01/07/the-windows-7-beta-kicks-off-this-week.aspx"&gt;The Windows 7 Beta Kicks Off This Week - Windows 7 Team Blog - The Windows Blog &lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;As I've been officially on holidays for the last four days (yes, four days includes two days of weekend; /sigh) I haven't fetched it yet so I have no wisdom for anyone about what's good and what's not. Why not try it and see?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/BuVugB8RHgg" height="1" width="1"/&gt;</description><pubDate>Mon, 12 Jan 2009 04:53:00 +1000</pubDate><a10:updated>2009-01-12T04:53:00+10:00</a10:updated><a10:content type="xhtml"><p>Just in case you missed it, the Windows 7 Beta is now available.  </p>

<p><a href="http://windowsteamblog.com/blogs/windows7/archive/2009/01/07/the-windows-7-beta-kicks-off-this-week.aspx">The Windows 7 Beta Kicks Off This Week - Windows 7 Team Blog - The Windows Blog </a>.  </p>

<p>As I've been officially on holidays for the last four days (yes, four days includes two days of weekend; /sigh) I haven't fetched it yet so I have no wisdom for anyone about what's good and what's not. Why not try it and see?</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2009.01.12.0453</feedburner:origLink></item><item xml:base="Home/Post/2008.12.02.0906"><guid isPermaLink="false">2008.12.02.0906</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/8jv7cAGaa1o/2008.12.02.0906</link><author>andrewh@uglybugger.org</author><title>More Messenger Bugs</title><description>&lt;p&gt;This tells me that I'm signed in in two places, even though a) I'm not, as I signed out on my laptop &lt;em&gt;before&lt;/em&gt; I came in to work, and b) the first thing it's supposed to to if I &lt;em&gt;am&lt;/em&gt; signed in somewhere else is sign me out.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://uglybugger.files.wordpress.com/2008/12/image.png"&gt;&lt;img style="display:inline;border-width:0;" title="image" border="0" alt="image" src="http://uglybugger.files.wordpress.com/2008/12/image-thumb.png" width="205" height="121" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;This option still exists, but apparently isn't honoured.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://uglybugger.files.wordpress.com/2008/12/image1.png"&gt;&lt;img style="display:inline;border-width:0;" title="image" border="0" alt="image" src="http://uglybugger.files.wordpress.com/2008/12/image-thumb1.png" width="244" height="29" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/8jv7cAGaa1o" height="1" width="1"/&gt;</description><pubDate>Tue, 02 Dec 2008 09:06:00 +1000</pubDate><a10:updated>2008-12-02T09:06:00+10:00</a10:updated><a10:content type="xhtml"><p>This tells me that I'm signed in in two places, even though a) I'm not, as I signed out on my laptop <em>before</em> I came in to work, and b) the first thing it's supposed to to if I <em>am</em> signed in somewhere else is sign me out.</p>

<p><a href="http://uglybugger.files.wordpress.com/2008/12/image.png"><img style="display:inline;border-width:0;" title="image" border="0" alt="image" src="http://uglybugger.files.wordpress.com/2008/12/image-thumb.png" width="205" height="121" /></a> </p>

<p>This option still exists, but apparently isn't honoured.</p>

<p><a href="http://uglybugger.files.wordpress.com/2008/12/image1.png"><img style="display:inline;border-width:0;" title="image" border="0" alt="image" src="http://uglybugger.files.wordpress.com/2008/12/image-thumb1.png" width="244" height="29" /></a></p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2008.12.02.0906</feedburner:origLink></item><item xml:base="Home/Post/2008.12.02.0733"><guid isPermaLink="false">2008.12.02.0733</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/FBacFHZV5r0/2008.12.02.0733</link><author>andrewh@uglybugger.org</author><title>Braces in string.Format()</title><description>&lt;p&gt;I'm really quite surprised that I've never needed this before, but today I wanted to embed some JavaScript within a string contained in a C# class and format it using string.Format().&lt;/p&gt;

&lt;p&gt;The problem? My JavaScript was a function declaration and therefore contained braces, but the placeholder delimiters in string.Format also use braces.&lt;/p&gt;

&lt;p&gt;The solution: braces get escaped using another brace of the same sort.&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;margin:20px 0 10px;padding:4px;"&gt;
  &lt;pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"&gt;&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; jsConditionalHelloWorldTemplate =&lt;br /&gt;    &lt;span style="color:#006080;"&gt;"if ({0}) {{\r\n"&lt;/span&gt; +&lt;br /&gt;    &lt;span style="color:#006080;"&gt;"    alert('Hello, world!');"&lt;/span&gt; +&lt;br /&gt;    &lt;span style="color:#006080;"&gt;"}}"&lt;/span&gt; +&lt;br /&gt;    &lt;span style="color:#006080;"&gt;""&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; sendToBrowser = &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Format(jsConditionalHelloWorldTemplate, &lt;span style="color:#006080;"&gt;"true"&lt;/span&gt;)&lt;br /&gt;writer.Write(sendToBrowser);&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Simple, really, but not intuitive - most civilized formatters use a backslash to escape characters. Hmm.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/FBacFHZV5r0" height="1" width="1"/&gt;</description><pubDate>Tue, 02 Dec 2008 07:33:00 +1000</pubDate><a10:updated>2008-12-02T07:33:00+10:00</a10:updated><a10:content type="xhtml"><p>I'm really quite surprised that I've never needed this before, but today I wanted to embed some JavaScript within a string contained in a C# class and format it using string.Format().</p>

<p>The problem? My JavaScript was a function declaration and therefore contained braces, but the placeholder delimiters in string.Format also use braces.</p>

<p>The solution: braces get escaped using another brace of the same sort.</p>

<div style="border-bottom:gray 1px solid;border-left:gray 1px solid;line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;margin:20px 0 10px;padding:4px;">
  <pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">string</span> jsConditionalHelloWorldTemplate =<br />    <span style="color:#006080;">"if ({0}) {{\r\n"</span> +<br />    <span style="color:#006080;">"    alert('Hello, world!');"</span> +<br />    <span style="color:#006080;">"}}"</span> +<br />    <span style="color:#006080;">""</span>;<br /><br /><span style="color:#0000ff;">string</span> sendToBrowser = <span style="color:#0000ff;">string</span>.Format(jsConditionalHelloWorldTemplate, <span style="color:#006080;">"true"</span>)<br />writer.Write(sendToBrowser);</pre>
</div>

<p>Simple, really, but not intuitive - most civilized formatters use a backslash to escape characters. Hmm.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2008.12.02.0733</feedburner:origLink></item><item xml:base="Home/Post/2008.11.29.0125"><guid isPermaLink="false">2008.11.29.0125</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/bxY8kqZWy2E/2008.11.29.0125</link><author>andrewh@uglybugger.org</author><title>Windows Live Messenger Beta</title><description>&lt;p&gt;If you read this post, please download the new beta of &lt;a target="_blank" href="http://download.live.com/"&gt;Windows Live Messenger&lt;/a&gt;, install it and turn on the Customer Experience Improvement Program feature.&lt;/p&gt;

&lt;p&gt;Why? Because if enough of us do it, perhaps Microsoft will fix some of the issues before we're lumped with the thing for real.&lt;/p&gt;

&lt;p&gt;There are a couple of things about the new beta (build 14.0.5027.908), however, that are driving me completely insane. &lt;/p&gt;

&lt;p&gt;Firstly, Microsoft, could you &lt;em&gt;please&lt;/em&gt; remove the stupid warning bar telling me that "Clicking this link might open your computer to security risks." For one thing, funnily enough, &lt;em&gt;I know that&lt;/em&gt;. I should at least be able to make it go away after it's been displayed once. For another thing, &lt;em&gt;it's warning me about a link that I sent&lt;/em&gt;, that just happens to be in my message history. &lt;/p&gt;

&lt;p&gt;Secondly, the sign-on in multiple places feature is an absolute pain, even when it's supposedly turned off. It still keeps telling me that I've signed in in multiple places, even when the very next thing it does is sign me out. It also means that if I turn the feature on and then sign out of one machine for a few minutes, messages to me aren't presented as offline messages; they just never seen at all until I happen to move to the other one. That strikes me as a bit silly. &lt;/p&gt;

&lt;p&gt;Finally, although it's petty: The whole point of having an adjustable profile picture size is to provide more screen real estate for messages. In the new Messenger, if I make my profile picture smaller, that's all that happens. That's kind of silly... &lt;/p&gt;

&lt;p&gt;All in all, IMHO the new Messenger "beta" should really have been called an early alpha. Good ideas, but awful implementation.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/bxY8kqZWy2E" height="1" width="1"/&gt;</description><pubDate>Sat, 29 Nov 2008 01:25:00 +1000</pubDate><a10:updated>2008-11-29T01:25:00+10:00</a10:updated><a10:content type="xhtml"><p>If you read this post, please download the new beta of <a target="_blank" href="http://download.live.com/">Windows Live Messenger</a>, install it and turn on the Customer Experience Improvement Program feature.</p>

<p>Why? Because if enough of us do it, perhaps Microsoft will fix some of the issues before we're lumped with the thing for real.</p>

<p>There are a couple of things about the new beta (build 14.0.5027.908), however, that are driving me completely insane. </p>

<p>Firstly, Microsoft, could you <em>please</em> remove the stupid warning bar telling me that "Clicking this link might open your computer to security risks." For one thing, funnily enough, <em>I know that</em>. I should at least be able to make it go away after it's been displayed once. For another thing, <em>it's warning me about a link that I sent</em>, that just happens to be in my message history. </p>

<p>Secondly, the sign-on in multiple places feature is an absolute pain, even when it's supposedly turned off. It still keeps telling me that I've signed in in multiple places, even when the very next thing it does is sign me out. It also means that if I turn the feature on and then sign out of one machine for a few minutes, messages to me aren't presented as offline messages; they just never seen at all until I happen to move to the other one. That strikes me as a bit silly. </p>

<p>Finally, although it's petty: The whole point of having an adjustable profile picture size is to provide more screen real estate for messages. In the new Messenger, if I make my profile picture smaller, that's all that happens. That's kind of silly... </p>

<p>All in all, IMHO the new Messenger "beta" should really have been called an early alpha. Good ideas, but awful implementation.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2008.11.29.0125</feedburner:origLink></item><item xml:base="Home/Post/2008.11.28.1254"><guid isPermaLink="false">2008.11.28.1254</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/cojpVX8Yw_M/2008.11.28.1254</link><author>andrewh@uglybugger.org</author><title>JavaScript .cloneNode() doesn't clone event handlers</title><description>&lt;p&gt;Just for the record, I hate JavaScript. It makes me feel dirty. Nonetheless, if you're going to use a tool - even one that you hate - use it well.  &lt;/p&gt;

&lt;p&gt;Here's one that will one day bite you. Consider this code:  &lt;/p&gt;

&lt;div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;"&gt;
  &lt;br /&gt;&lt;pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"&gt;&amp;lt;html&amp;gt;&lt;br /&gt;    &amp;lt;head&amp;gt;&lt;br /&gt;        &amp;lt;script type=&lt;span style="color:#006080;"&gt;"text/javascript"&lt;/span&gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;var&lt;/span&gt; OnLoad = &lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;() {&lt;br /&gt;                document.getElementById(&lt;span style="color:#006080;"&gt;"cloneme"&lt;/span&gt;).onclick = &lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;() { alert(&lt;span style="color:#006080;"&gt;"onload"&lt;/span&gt;);};&lt;br /&gt;                document.body.appendChild(document.getElementById(&lt;span style="color:#006080;"&gt;"cloneme"&lt;/span&gt;).cloneNode(&lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;));&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            window.attachEvent(&lt;span style="color:#006080;"&gt;"onload"&lt;/span&gt;, OnLoad);&lt;br /&gt;        &amp;lt;/script&amp;gt;&lt;br /&gt;    &amp;lt;/head&amp;gt;&lt;br /&gt;    &amp;lt;body&amp;gt;&lt;br /&gt;        &amp;lt;a id=&lt;span style="color:#006080;"&gt;"cloneme"&lt;/span&gt; href=&lt;span style="color:#006080;"&gt;"javascript:alert('href');"&lt;/span&gt;&amp;gt;Test Hyperlink&amp;lt;/a&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;        &amp;lt;br /&amp;gt;&lt;br /&gt;    &amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;/pre&gt;

  &lt;br /&gt;
&lt;/div&gt;

&lt;p&gt;If you drop it into a local .html file and point a browser at it, it'll look something like this:  &lt;/p&gt;

&lt;p&gt;&lt;a href="http://codingforfunandprofit.files.wordpress.com/2008/11/image1.png"&gt;&lt;img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="Yes, I know, I used Internet Exploder for this example. I'm sorry. I'm a bad human." src="http://codingforfunandprofit.files.wordpress.com/2008/11/image-thumb1.png" border="0" alt="Yes, I know, I used Internet Exploder for this example. I'm sorry. I'm a bad human." width="354" height="157" /&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;There &lt;em&gt;is&lt;/em&gt; a catch, however: although one hyperlink is a direct clone of the other, they're not identical.  &lt;/p&gt;

&lt;p&gt;If you click the first one, you'll see the order in which the events should fire represented by two alert boxes, the first one shouting "onload" and the second "href".  &lt;/p&gt;

&lt;p&gt;If you click the second one, you'll only see the "href" message.  &lt;/p&gt;

&lt;p&gt;Why is this?  &lt;/p&gt;

&lt;p&gt;The key point to remember is that the DOM object is being cloned from its textual representation. In other words, .clone() does &lt;em&gt;not&lt;/em&gt; do a deep copy; rather, it effectively just creates a new node based on the .outerHtml property of the old node. Notably, that does &lt;em&gt;not&lt;/em&gt; include any event handlers that have been attached programmatically.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/cojpVX8Yw_M" height="1" width="1"/&gt;</description><pubDate>Fri, 28 Nov 2008 12:54:00 +1000</pubDate><a10:updated>2008-11-28T12:54:00+10:00</a10:updated><a10:content type="xhtml"><p>Just for the record, I hate JavaScript. It makes me feel dirty. Nonetheless, if you're going to use a tool - even one that you hate - use it well.  </p>

<p>Here's one that will one day bite you. Consider this code:  </p>

<div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;">
  <br /><pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;">&lt;html&gt;<br />    &lt;head&gt;<br />        &lt;script type=<span style="color:#006080;">"text/javascript"</span>&gt;<br /><br />            <span style="color:#0000ff;">var</span> OnLoad = <span style="color:#0000ff;">function</span>() {<br />                document.getElementById(<span style="color:#006080;">"cloneme"</span>).onclick = <span style="color:#0000ff;">function</span>() { alert(<span style="color:#006080;">"onload"</span>);};<br />                document.body.appendChild(document.getElementById(<span style="color:#006080;">"cloneme"</span>).cloneNode(<span style="color:#0000ff;">true</span>));<br />            }<br /><br />            window.attachEvent(<span style="color:#006080;">"onload"</span>, OnLoad);<br />        &lt;/script&gt;<br />    &lt;/head&gt;<br />    &lt;body&gt;<br />        &lt;a id=<span style="color:#006080;">"cloneme"</span> href=<span style="color:#006080;">"javascript:alert('href');"</span>&gt;Test Hyperlink&lt;/a&gt;&lt;br /&gt;<br />        &lt;br /&gt;<br />    &lt;/body&gt;<br />&lt;/html&gt;</pre>

  <br />
</div>

<p>If you drop it into a local .html file and point a browser at it, it'll look something like this:  </p>

<p><a href="http://codingforfunandprofit.files.wordpress.com/2008/11/image1.png"><img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="Yes, I know, I used Internet Exploder for this example. I'm sorry. I'm a bad human." src="http://codingforfunandprofit.files.wordpress.com/2008/11/image-thumb1.png" border="0" alt="Yes, I know, I used Internet Exploder for this example. I'm sorry. I'm a bad human." width="354" height="157" /></a>  </p>

<p>There <em>is</em> a catch, however: although one hyperlink is a direct clone of the other, they're not identical.  </p>

<p>If you click the first one, you'll see the order in which the events should fire represented by two alert boxes, the first one shouting "onload" and the second "href".  </p>

<p>If you click the second one, you'll only see the "href" message.  </p>

<p>Why is this?  </p>

<p>The key point to remember is that the DOM object is being cloned from its textual representation. In other words, .clone() does <em>not</em> do a deep copy; rather, it effectively just creates a new node based on the .outerHtml property of the old node. Notably, that does <em>not</em> include any event handlers that have been attached programmatically.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2008.11.28.1254</feedburner:origLink></item><item xml:base="Home/Post/2008.11.25.1040"><guid isPermaLink="false">2008.11.25.1040</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/i1xSQSxKjVo/2008.11.25.1040</link><author>andrewh@uglybugger.org</author><title>.NET Provider Model and Code Snippet</title><description>&lt;p&gt;While I think the .NET provider model is great as a means of codifying dependency inversion, it really irritates me that we have to create so many peripheral classes in order to use it.  &lt;/p&gt;

&lt;p&gt;For example, we need to create a strongly-typed collection class that contains them all (presumably a left-over from the .NET 1.x days where there were no generic types), we need a configuration section class just to support an addition to the (web|app).config file, we need the provider class itself (effectively a factory class) and we need the class(es) of which it provides instances. Oh, and the interface that our provider stuff actually provides.  &lt;/p&gt;

&lt;p&gt;Here's a code snippet (&lt;a href="http://www.google.com.au/search?hl=en&amp;amp;rlz=1C1GGLS_enAU291&amp;amp;q=&amp;quot;code+snippet&amp;quot;+&amp;quot;visual+studio&amp;quot;&amp;amp;btnG=Search&amp;amp;meta=" target="_blank"&gt;what's a code snippet?&lt;/a&gt;) for creating a .NET provider and all the associated paraphernalia. Unfortunately it dumps all the classes into one .cs file, but AFAIK there's no way to get a single snippet to create multiple files. You can (and should) do that yourself, though.  &lt;/p&gt;

&lt;p&gt;Handily, the snippet will also generate XML for you that can be copied/pasted directly into your (web|app).config file.  &lt;/p&gt;

&lt;div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;"&gt;
  &lt;br /&gt;&lt;pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#800000;"&gt;xml&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;version&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;="1.0"&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;encoding&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;="utf-8"&lt;/span&gt; ?&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;CodeSnippets&lt;/span&gt;  &lt;span style="color:#ff0000;"&gt;xmlns&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;CodeSnippet&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Format&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;="1.0.0"&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Header&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Title&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;provider&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Title&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Shortcut&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;provider&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Shortcut&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Description&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;Code snippet for a .NET Provider implementation&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Description&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Author&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;Andrew Harcourt&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Author&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;SnippetTypes&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;SnippetType&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;Expansion&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;SnippetType&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;SnippetTypes&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Header&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Snippet&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Declarations&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Literal&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;          &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ID&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;providerName&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;ID&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;          &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ToolTip&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;The name of the provider (e.g. "Cache", "Licence").&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;ToolTip&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;          &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Default&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;Stupid&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Default&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Literal&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Literal&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;          &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ID&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;interfaceName&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;ID&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ToolTip&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;The name of the interface that the provider will return (e.g. "ICache", "ILicence").&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;ToolTip&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Default&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;IStupid&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Default&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Literal&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Literal&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;          &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ID&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;defaultProvider&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;ID&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;          &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ToolTip&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;The name of the default provider instance to use (e.g. "Web", "File"). The suffix "$providerName$Provider" will be added automatically.&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;ToolTip&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;          &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Default&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;Default&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Default&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Literal&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Literal&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Editable&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;="false"&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;          &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ID&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;className&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;ID&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;          &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ToolTip&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;The type of the owning class.&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;ToolTip&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;          &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Function&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;ClassName()&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Function&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;          &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Default&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;StupidClass&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Default&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Literal&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Declarations&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Code&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Language&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;="csharp"&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;&amp;lt;!&lt;/span&gt;[CDATA[using System;&lt;br /&gt;using System.Collections.Specialized;&lt;br /&gt;using System.Configuration;&lt;br /&gt;using System.Configuration.Provider;&lt;br /&gt;using System.Diagnostics;&lt;br /&gt;using System.Reflection;&lt;br /&gt;using System.Web.Configuration;&lt;br /&gt;&lt;br /&gt;#region $providerName$Provider&lt;br /&gt;&lt;br /&gt;    [Serializable]&lt;br /&gt;    public abstract class $providerName$Provider : ProviderBase&lt;br /&gt;    {&lt;br /&gt;&lt;br /&gt;        protected abstract string DefaultName { get; }&lt;br /&gt;        protected abstract string DefaultDescription { get; }&lt;br /&gt;&lt;br /&gt;        public abstract $interfaceName$ Get$providerName$();&lt;br /&gt;&lt;br /&gt;        protected static void CheckForUnrecognizedAttributes(NameValueCollection config)&lt;br /&gt;        {&lt;br /&gt;            if (null == config)&lt;br /&gt;            {&lt;br /&gt;                throw new ArgumentNullException("config");&lt;br /&gt;            }&lt;br /&gt;            if (config.Count &lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt; 0)&lt;br /&gt;            {&lt;br /&gt;                string attr = config.GetKey(0);&lt;br /&gt;                if (!string.IsNullOrEmpty(attr))&lt;br /&gt;                {&lt;br /&gt;                    throw new ProviderException("Unrecognized attribute: " + attr);&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        protected string VerifyInitParams(NameValueCollection config, string name)&lt;br /&gt;        {&lt;br /&gt;            if (null == config)&lt;br /&gt;            {&lt;br /&gt;                throw new ArgumentNullException("config");&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            if (string.IsNullOrEmpty(name))&lt;br /&gt;            {&lt;br /&gt;                name = DefaultName;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            if (string.IsNullOrEmpty(config["description"]))&lt;br /&gt;            {&lt;br /&gt;                config.Remove("description");&lt;br /&gt;                config.Add("description", DefaultDescription);&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            return name;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;#endregion&lt;br /&gt;&lt;br /&gt;#region $defaultProvider$$providerName$Provider&lt;br /&gt;&lt;br /&gt;    public class $defaultProvider$$providerName$Provider : $providerName$$end$Provider  //TODO Implement abstract class "$providerName$$end$Provider"&lt;br /&gt;    {&lt;br /&gt;        //TODO Add or merge the following into your (web|app).config file.&lt;br /&gt;        /*&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;configuration&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;          &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;configSections&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;section&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;="$providerName$ProviderService"&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;type&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;="FULL_NAMESPACE_HERE.$providerName$ProviderSection, ASSEMBLY_NAME_HERE"&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;          &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;configSections&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;          &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;$providerName$ProviderService defaultProvider="$defaultProvider$$providerName$Provider"&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;providers&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;              &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;clear&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;              &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;add&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;="$defaultProvider$$providerName$Provider"&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;type&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;="FULL_NAMESPACE_HERE.$defaultProvider$$providerName$Provider, ASSEMBLY_NAME_HERE"&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;providers&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;          &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;$providerName$ProviderService&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;configuration&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        */&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;#endregion&lt;br /&gt;&lt;br /&gt;// The code below here is auto-generated and shouldn't need any manual&lt;br /&gt;// editing unless you want to do interesting stuff.  -andrewh 18/9/08&lt;br /&gt;&lt;br /&gt;#region $providerName$ProviderSection&lt;br /&gt;&lt;br /&gt;    [Obfuscation(Feature = "renaming", Exclude = true, ApplyToMembers = false)]&lt;br /&gt;    public class $providerName$ProviderSection : ConfigurationSection&lt;br /&gt;    {&lt;br /&gt;        [ConfigurationProperty("providers")]&lt;br /&gt;        public ProviderSettingsCollection Providers&lt;br /&gt;        {&lt;br /&gt;            get { return (ProviderSettingsCollection)base["providers"]; }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [StringValidator(MinLength = 1)]&lt;br /&gt;        [ConfigurationProperty("defaultProvider", DefaultValue = "$defaultProvider$$providerName$Provider")]&lt;br /&gt;        public string DefaultProvider&lt;br /&gt;        {&lt;br /&gt;            get { return (string)base["defaultProvider"]; }&lt;br /&gt;            set { base["defaultProvider"] = value; }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;#endregion&lt;br /&gt;&lt;br /&gt;#region $providerName$ProviderService&lt;br /&gt;&lt;br /&gt;    [Serializable]&lt;br /&gt;    public class $providerName$ProviderService&lt;br /&gt;    {&lt;br /&gt;        private static $interfaceName$ _instance;&lt;br /&gt;        private static $providerName$Provider _provider;&lt;br /&gt;        private static $providerName$ProviderCollection _providers;&lt;br /&gt;        private static object _lock = new object();&lt;br /&gt;&lt;br /&gt;        public static $providerName$Provider Provider&lt;br /&gt;        {&lt;br /&gt;            get { return _provider; }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public static $providerName$ProviderCollection Providers&lt;br /&gt;        {&lt;br /&gt;            get {&lt;br /&gt;              LoadProviders();&lt;br /&gt;              return _providers;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public static $interfaceName$ $providerName$&lt;br /&gt;        {&lt;br /&gt;            get&lt;br /&gt;            {&lt;br /&gt;                if (_instance == null)&lt;br /&gt;                {&lt;br /&gt;                    _instance = LoadInstance();&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                return _instance;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private static $interfaceName$ LoadInstance()&lt;br /&gt;        {&lt;br /&gt;            LoadProviders();&lt;br /&gt;            $interfaceName$ instance = _provider.Get$providerName$();&lt;br /&gt;&lt;br /&gt;            // if the default provider fails, try the others&lt;br /&gt;            if (instance == null)&lt;br /&gt;            {&lt;br /&gt;                foreach ($providerName$Provider p in _providers)&lt;br /&gt;                {&lt;br /&gt;                    if (p != _provider) // don't retry the default one&lt;br /&gt;                    {&lt;br /&gt;                        instance = p.Get$providerName$();&lt;br /&gt;                        if (instance != null) // success?&lt;br /&gt;                        {&lt;br /&gt;                            _provider = p;&lt;br /&gt;                            break;&lt;br /&gt;                        }&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            Debug.Assert(instance != null);&lt;br /&gt;            return instance;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private static void LoadProviders()&lt;br /&gt;        {&lt;br /&gt;            if (null == _provider)&lt;br /&gt;            {&lt;br /&gt;                lock (_lock)&lt;br /&gt;                {&lt;br /&gt;                    // do this again to make sure _provider is still null&lt;br /&gt;                    if (null == _provider)&lt;br /&gt;                    {&lt;br /&gt;                        $providerName$ProviderSection section = LoadAndVerifyProviderSection();&lt;br /&gt;                        BuildProviderCollection(section);&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private static void BuildProviderCollection($providerName$ProviderSection section)&lt;br /&gt;        {&lt;br /&gt;            _providers = new $providerName$ProviderCollection();&lt;br /&gt;            ProvidersHelper.InstantiateProviders(section.Providers, _providers, typeof($providerName$Provider));&lt;br /&gt;&lt;br /&gt;            if (_providers.Count == 0)&lt;br /&gt;            {&lt;br /&gt;                throw new ProviderException("No providers instantiated");&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            _provider = _providers[section.DefaultProvider];&lt;br /&gt;            if (null == _provider)&lt;br /&gt;            {&lt;br /&gt;                throw new ProviderException("Unable to load provider");&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private static $providerName$ProviderSection LoadAndVerifyProviderSection()&lt;br /&gt;        {&lt;br /&gt;            // fetch the section from the application's configuration file&lt;br /&gt;            $providerName$ProviderSection section = ($providerName$ProviderSection)ConfigurationManager.GetSection("$providerName$ProviderService");&lt;br /&gt;            if (section == null)&lt;br /&gt;            {&lt;br /&gt;                throw new ProviderException("$providerName$ProviderService section missing from (web|app).config");&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            return section;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;#endregion&lt;br /&gt;&lt;br /&gt;#region $providerName$ProviderCollection&lt;br /&gt;&lt;br /&gt;    [Serializable]&lt;br /&gt;    public class $providerName$ProviderCollection : ProviderCollection&lt;br /&gt;    {&lt;br /&gt;        public new $providerName$Provider this[string name]&lt;br /&gt;        {&lt;br /&gt;            get { return ($providerName$Provider)base[name]; }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public override void Add(ProviderBase provider)&lt;br /&gt;        {&lt;br /&gt;            if (null == provider)&lt;br /&gt;            {&lt;br /&gt;                throw new ArgumentNullException("provider");&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            if (!(provider is $providerName$Provider))&lt;br /&gt;            {&lt;br /&gt;                throw new ArgumentException("Invalid provider type", "provider");&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            base.Add(provider);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;#endregion&lt;br /&gt;]]&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Code&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Snippet&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;CodeSnippet&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;CodeSnippets&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;br /&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/i1xSQSxKjVo" height="1" width="1"/&gt;</description><pubDate>Tue, 25 Nov 2008 10:40:00 +1000</pubDate><a10:updated>2008-11-25T10:40:00+10:00</a10:updated><a10:content type="xhtml"><p>While I think the .NET provider model is great as a means of codifying dependency inversion, it really irritates me that we have to create so many peripheral classes in order to use it.  </p>

<p>For example, we need to create a strongly-typed collection class that contains them all (presumably a left-over from the .NET 1.x days where there were no generic types), we need a configuration section class just to support an addition to the (web|app).config file, we need the provider class itself (effectively a factory class) and we need the class(es) of which it provides instances. Oh, and the interface that our provider stuff actually provides.  </p>

<p>Here's a code snippet (<a href="http://www.google.com.au/search?hl=en&amp;rlz=1C1GGLS_enAU291&amp;q=&quot;code+snippet&quot;+&quot;visual+studio&quot;&amp;btnG=Search&amp;meta=" target="_blank">what's a code snippet?</a>) for creating a .NET provider and all the associated paraphernalia. Unfortunately it dumps all the classes into one .cs file, but AFAIK there's no way to get a single snippet to create multiple files. You can (and should) do that yourself, though.  </p>

<p>Handily, the snippet will also generate XML for you that can be copied/pasted directly into your (web|app).config file.  </p>

<div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;">
  <br /><pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">&lt;?</span><span style="color:#800000;">xml</span> <span style="color:#ff0000;">version</span><span style="color:#0000ff;">="1.0"</span> <span style="color:#ff0000;">encoding</span><span style="color:#0000ff;">="utf-8"</span> ?<span style="color:#0000ff;">&gt;</span><br /><span style="color:#0000ff;">&lt;</span><span style="color:#800000;">CodeSnippets</span>  <span style="color:#ff0000;">xmlns</span><span style="color:#0000ff;">="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"</span><span style="color:#0000ff;">&gt;</span><br />  <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">CodeSnippet</span> <span style="color:#ff0000;">Format</span><span style="color:#0000ff;">="1.0.0"</span><span style="color:#0000ff;">&gt;</span><br />    <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">Header</span><span style="color:#0000ff;">&gt;</span><br />      <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">Title</span><span style="color:#0000ff;">&gt;</span>provider<span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">Title</span><span style="color:#0000ff;">&gt;</span><br />      <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">Shortcut</span><span style="color:#0000ff;">&gt;</span>provider<span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">Shortcut</span><span style="color:#0000ff;">&gt;</span><br />      <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">Description</span><span style="color:#0000ff;">&gt;</span>Code snippet for a .NET Provider implementation<span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">Description</span><span style="color:#0000ff;">&gt;</span><br />      <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">Author</span><span style="color:#0000ff;">&gt;</span>Andrew Harcourt<span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">Author</span><span style="color:#0000ff;">&gt;</span><br />      <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">SnippetTypes</span><span style="color:#0000ff;">&gt;</span><br />        <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">SnippetType</span><span style="color:#0000ff;">&gt;</span>Expansion<span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">SnippetType</span><span style="color:#0000ff;">&gt;</span><br />      <span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">SnippetTypes</span><span style="color:#0000ff;">&gt;</span><br />    <span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">Header</span><span style="color:#0000ff;">&gt;</span><br />    <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">Snippet</span><span style="color:#0000ff;">&gt;</span><br />      <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">Declarations</span><span style="color:#0000ff;">&gt;</span><br />        <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">Literal</span><span style="color:#0000ff;">&gt;</span><br />          <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">ID</span><span style="color:#0000ff;">&gt;</span>providerName<span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">ID</span><span style="color:#0000ff;">&gt;</span><br />          <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">ToolTip</span><span style="color:#0000ff;">&gt;</span>The name of the provider (e.g. "Cache", "Licence").<span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">ToolTip</span><span style="color:#0000ff;">&gt;</span><br />          <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">Default</span><span style="color:#0000ff;">&gt;</span>Stupid<span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">Default</span><span style="color:#0000ff;">&gt;</span><br />        <span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">Literal</span><span style="color:#0000ff;">&gt;</span><br />        <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">Literal</span><span style="color:#0000ff;">&gt;</span><br />          <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">ID</span><span style="color:#0000ff;">&gt;</span>interfaceName<span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">ID</span><span style="color:#0000ff;">&gt;</span><br />            <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">ToolTip</span><span style="color:#0000ff;">&gt;</span>The name of the interface that the provider will return (e.g. "ICache", "ILicence").<span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">ToolTip</span><span style="color:#0000ff;">&gt;</span><br />            <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">Default</span><span style="color:#0000ff;">&gt;</span>IStupid<span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">Default</span><span style="color:#0000ff;">&gt;</span><br />        <span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">Literal</span><span style="color:#0000ff;">&gt;</span><br />        <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">Literal</span><span style="color:#0000ff;">&gt;</span><br />          <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">ID</span><span style="color:#0000ff;">&gt;</span>defaultProvider<span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">ID</span><span style="color:#0000ff;">&gt;</span><br />          <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">ToolTip</span><span style="color:#0000ff;">&gt;</span>The name of the default provider instance to use (e.g. "Web", "File"). The suffix "$providerName$Provider" will be added automatically.<span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">ToolTip</span><span style="color:#0000ff;">&gt;</span><br />          <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">Default</span><span style="color:#0000ff;">&gt;</span>Default<span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">Default</span><span style="color:#0000ff;">&gt;</span><br />        <span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">Literal</span><span style="color:#0000ff;">&gt;</span><br /><br />        <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">Literal</span> <span style="color:#ff0000;">Editable</span><span style="color:#0000ff;">="false"</span><span style="color:#0000ff;">&gt;</span><br />          <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">ID</span><span style="color:#0000ff;">&gt;</span>className<span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">ID</span><span style="color:#0000ff;">&gt;</span><br />          <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">ToolTip</span><span style="color:#0000ff;">&gt;</span>The type of the owning class.<span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">ToolTip</span><span style="color:#0000ff;">&gt;</span><br />          <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">Function</span><span style="color:#0000ff;">&gt;</span>ClassName()<span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">Function</span><span style="color:#0000ff;">&gt;</span><br />          <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">Default</span><span style="color:#0000ff;">&gt;</span>StupidClass<span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">Default</span><span style="color:#0000ff;">&gt;</span><br />        <span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">Literal</span><span style="color:#0000ff;">&gt;</span><br /><br />      <span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">Declarations</span><span style="color:#0000ff;">&gt;</span><br />      <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">Code</span> <span style="color:#ff0000;">Language</span><span style="color:#0000ff;">="csharp"</span><span style="color:#0000ff;">&gt;</span><br />        <span style="color:#0000ff;">&lt;!</span>[CDATA[using System;<br />using System.Collections.Specialized;<br />using System.Configuration;<br />using System.Configuration.Provider;<br />using System.Diagnostics;<br />using System.Reflection;<br />using System.Web.Configuration;<br /><br />#region $providerName$Provider<br /><br />    [Serializable]<br />    public abstract class $providerName$Provider : ProviderBase<br />    {<br /><br />        protected abstract string DefaultName { get; }<br />        protected abstract string DefaultDescription { get; }<br /><br />        public abstract $interfaceName$ Get$providerName$();<br /><br />        protected static void CheckForUnrecognizedAttributes(NameValueCollection config)<br />        {<br />            if (null == config)<br />            {<br />                throw new ArgumentNullException("config");<br />            }<br />            if (config.Count <span style="color:#0000ff;">&gt;</span> 0)<br />            {<br />                string attr = config.GetKey(0);<br />                if (!string.IsNullOrEmpty(attr))<br />                {<br />                    throw new ProviderException("Unrecognized attribute: " + attr);<br />                }<br />            }<br />        }<br /><br />        protected string VerifyInitParams(NameValueCollection config, string name)<br />        {<br />            if (null == config)<br />            {<br />                throw new ArgumentNullException("config");<br />            }<br /><br />            if (string.IsNullOrEmpty(name))<br />            {<br />                name = DefaultName;<br />            }<br /><br />            if (string.IsNullOrEmpty(config["description"]))<br />            {<br />                config.Remove("description");<br />                config.Add("description", DefaultDescription);<br />            }<br /><br />            return name;<br />        }<br />    }<br /><br />#endregion<br /><br />#region $defaultProvider$$providerName$Provider<br /><br />    public class $defaultProvider$$providerName$Provider : $providerName$$end$Provider  //TODO Implement abstract class "$providerName$$end$Provider"<br />    {<br />        //TODO Add or merge the following into your (web|app).config file.<br />        /*<br />        <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">configuration</span><span style="color:#0000ff;">&gt;</span><br />          <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">configSections</span><span style="color:#0000ff;">&gt;</span><br />            <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">section</span> <span style="color:#ff0000;">name</span><span style="color:#0000ff;">="$providerName$ProviderService"</span> <span style="color:#ff0000;">type</span><span style="color:#0000ff;">="FULL_NAMESPACE_HERE.$providerName$ProviderSection, ASSEMBLY_NAME_HERE"</span> <span style="color:#0000ff;">/&gt;</span><br />          <span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">configSections</span><span style="color:#0000ff;">&gt;</span><br /><br />          <span style="color:#0000ff;">&lt;</span>$providerName$ProviderService defaultProvider="$defaultProvider$$providerName$Provider"<span style="color:#0000ff;">&gt;</span><br />            <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">providers</span><span style="color:#0000ff;">&gt;</span><br />              <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">clear</span> <span style="color:#0000ff;">/&gt;</span><br />              <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">add</span> <span style="color:#ff0000;">name</span><span style="color:#0000ff;">="$defaultProvider$$providerName$Provider"</span> <span style="color:#ff0000;">type</span><span style="color:#0000ff;">="FULL_NAMESPACE_HERE.$defaultProvider$$providerName$Provider, ASSEMBLY_NAME_HERE"</span> <span style="color:#0000ff;">/&gt;</span><br />            <span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">providers</span><span style="color:#0000ff;">&gt;</span><br />          <span style="color:#0000ff;">&lt;/</span>$providerName$ProviderService<span style="color:#0000ff;">&gt;</span><br /><br />        <span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">configuration</span><span style="color:#0000ff;">&gt;</span><br />        */<br />    }<br /><br />#endregion<br /><br />// The code below here is auto-generated and shouldn't need any manual<br />// editing unless you want to do interesting stuff.  -andrewh 18/9/08<br /><br />#region $providerName$ProviderSection<br /><br />    [Obfuscation(Feature = "renaming", Exclude = true, ApplyToMembers = false)]<br />    public class $providerName$ProviderSection : ConfigurationSection<br />    {<br />        [ConfigurationProperty("providers")]<br />        public ProviderSettingsCollection Providers<br />        {<br />            get { return (ProviderSettingsCollection)base["providers"]; }<br />        }<br /><br />        [StringValidator(MinLength = 1)]<br />        [ConfigurationProperty("defaultProvider", DefaultValue = "$defaultProvider$$providerName$Provider")]<br />        public string DefaultProvider<br />        {<br />            get { return (string)base["defaultProvider"]; }<br />            set { base["defaultProvider"] = value; }<br />        }<br />    }<br /><br />#endregion<br /><br />#region $providerName$ProviderService<br /><br />    [Serializable]<br />    public class $providerName$ProviderService<br />    {<br />        private static $interfaceName$ _instance;<br />        private static $providerName$Provider _provider;<br />        private static $providerName$ProviderCollection _providers;<br />        private static object _lock = new object();<br /><br />        public static $providerName$Provider Provider<br />        {<br />            get { return _provider; }<br />        }<br /><br />        public static $providerName$ProviderCollection Providers<br />        {<br />            get {<br />              LoadProviders();<br />              return _providers;<br />            }<br />        }<br /><br />        public static $interfaceName$ $providerName$<br />        {<br />            get<br />            {<br />                if (_instance == null)<br />                {<br />                    _instance = LoadInstance();<br />                }<br /><br />                return _instance;<br />            }<br />        }<br /><br />        private static $interfaceName$ LoadInstance()<br />        {<br />            LoadProviders();<br />            $interfaceName$ instance = _provider.Get$providerName$();<br /><br />            // if the default provider fails, try the others<br />            if (instance == null)<br />            {<br />                foreach ($providerName$Provider p in _providers)<br />                {<br />                    if (p != _provider) // don't retry the default one<br />                    {<br />                        instance = p.Get$providerName$();<br />                        if (instance != null) // success?<br />                        {<br />                            _provider = p;<br />                            break;<br />                        }<br />                    }<br />                }<br />            }<br /><br />            Debug.Assert(instance != null);<br />            return instance;<br />        }<br /><br />        private static void LoadProviders()<br />        {<br />            if (null == _provider)<br />            {<br />                lock (_lock)<br />                {<br />                    // do this again to make sure _provider is still null<br />                    if (null == _provider)<br />                    {<br />                        $providerName$ProviderSection section = LoadAndVerifyProviderSection();<br />                        BuildProviderCollection(section);<br />                    }<br />                }<br />            }<br />        }<br /><br />        private static void BuildProviderCollection($providerName$ProviderSection section)<br />        {<br />            _providers = new $providerName$ProviderCollection();<br />            ProvidersHelper.InstantiateProviders(section.Providers, _providers, typeof($providerName$Provider));<br /><br />            if (_providers.Count == 0)<br />            {<br />                throw new ProviderException("No providers instantiated");<br />            }<br /><br />            _provider = _providers[section.DefaultProvider];<br />            if (null == _provider)<br />            {<br />                throw new ProviderException("Unable to load provider");<br />            }<br />        }<br /><br />        private static $providerName$ProviderSection LoadAndVerifyProviderSection()<br />        {<br />            // fetch the section from the application's configuration file<br />            $providerName$ProviderSection section = ($providerName$ProviderSection)ConfigurationManager.GetSection("$providerName$ProviderService");<br />            if (section == null)<br />            {<br />                throw new ProviderException("$providerName$ProviderService section missing from (web|app).config");<br />            }<br /><br />            return section;<br />        }<br />    }<br /><br />#endregion<br /><br />#region $providerName$ProviderCollection<br /><br />    [Serializable]<br />    public class $providerName$ProviderCollection : ProviderCollection<br />    {<br />        public new $providerName$Provider this[string name]<br />        {<br />            get { return ($providerName$Provider)base[name]; }<br />        }<br /><br />        public override void Add(ProviderBase provider)<br />        {<br />            if (null == provider)<br />            {<br />                throw new ArgumentNullException("provider");<br />            }<br /><br />            if (!(provider is $providerName$Provider))<br />            {<br />                throw new ArgumentException("Invalid provider type", "provider");<br />            }<br /><br />            base.Add(provider);<br />        }<br />    }<br /><br />#endregion<br />]]<span style="color:#0000ff;">&gt;</span><br />      <span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">Code</span><span style="color:#0000ff;">&gt;</span><br />    <span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">Snippet</span><span style="color:#0000ff;">&gt;</span><br />  <span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">CodeSnippet</span><span style="color:#0000ff;">&gt;</span><br /><span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">CodeSnippets</span><span style="color:#0000ff;">&gt;</span></pre>

  <br />
</div>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2008.11.25.1040</feedburner:origLink></item><item xml:base="Home/Post/2008.11.25.1028"><guid isPermaLink="false">2008.11.25.1028</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/NOL4aHjNors/2008.11.25.1028</link><author>andrewh@uglybugger.org</author><title>I'm in love with jQuery</title><description>&lt;p&gt;What more need I say? jQuery is making my life bearable.  &lt;/p&gt;

&lt;p&gt;From &lt;a href="http://simonwillison.net/2007/Aug/15/jquery/" target="_blank"&gt;Simon Willison's blog&lt;/a&gt;:  &lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_RlpLqbhdTdM/SStGrxtLUQI/AAAAAAAAZ8M/i_JpfhVstTs/s1600-h/image%5B5%5D.png"&gt;&lt;img style="display:inline;border-width:0;" title="image" src="http://lh4.ggpht.com/_RlpLqbhdTdM/SStGtnp6vZI/AAAAAAAAZ8U/v6MQlUSzHZQ/image_thumb%5B1%5D.png?imgmax=800" border="0" alt="image" width="244" height="212" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/NOL4aHjNors" height="1" width="1"/&gt;</description><pubDate>Tue, 25 Nov 2008 10:28:00 +1000</pubDate><a10:updated>2008-11-25T10:28:00+10:00</a10:updated><a10:content type="xhtml"><p>What more need I say? jQuery is making my life bearable.  </p>

<p>From <a href="http://simonwillison.net/2007/Aug/15/jquery/" target="_blank">Simon Willison's blog</a>:  </p>

<p><a href="http://lh6.ggpht.com/_RlpLqbhdTdM/SStGrxtLUQI/AAAAAAAAZ8M/i_JpfhVstTs/s1600-h/image%5B5%5D.png"><img style="display:inline;border-width:0;" title="image" src="http://lh4.ggpht.com/_RlpLqbhdTdM/SStGtnp6vZI/AAAAAAAAZ8U/v6MQlUSzHZQ/image_thumb%5B1%5D.png?imgmax=800" border="0" alt="image" width="244" height="212" /></a></p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2008.11.25.1028</feedburner:origLink></item><item xml:base="Home/Post/2008.11.25.0546"><guid isPermaLink="false">2008.11.25.0546</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/Q1gJaqM-foo/2008.11.25.0546</link><author>andrewh@uglybugger.org</author><title>Microsoft JScript compilation error: 'return' statement outside of function</title><description>&lt;p&gt;I feel dirty. Oh, so dirty.  &lt;/p&gt;

&lt;p&gt;Internet Exploder runs script evaluated using the JavaScript eval() function in the global scope.  &lt;/p&gt;

&lt;p&gt;So what?  &lt;/p&gt;

&lt;p&gt;Well, if you're doing something silly, as I'm being obliged to do right now, such as dynamically adding and removing click handlers based on CSS attributes, fake HtmlTextWriter objects and third-party controls (over which I have no control), you're eventually going to run into the error above.  &lt;/p&gt;

&lt;p&gt;Your code might look, in a very simplified form, something like this:  &lt;/p&gt;

&lt;div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;"&gt;
  &lt;br /&gt;&lt;pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"&gt;&lt;span style="color:#0000ff;"&gt;var&lt;/span&gt; RunCrazyUnsafeScript = &lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;(scriptToEval) {&lt;br /&gt;    eval(scriptToEval);&lt;br /&gt;}&lt;/pre&gt;

  &lt;br /&gt;
&lt;/div&gt;

&lt;p&gt;... and you're probably invoking it something like this:  &lt;/p&gt;

&lt;div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;"&gt;
  &lt;br /&gt;&lt;pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"&gt;RunCrazyUnsafeScript(&lt;span style="color:#006080;"&gt;"alert('Hello, world!');"&lt;/span&gt;);&lt;/pre&gt;

  &lt;br /&gt;
&lt;/div&gt;

&lt;p&gt;... and by and large, this all works perfectly well. Occasionally, however, you'll see the error above. The odds are that you're probably doing something like this:  &lt;/p&gt;

&lt;div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;"&gt;
  &lt;br /&gt;&lt;pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"&gt;RunCrazyUnsafeScript(&lt;span style="color:#006080;"&gt;"alert('Hello, world!'); return false;"&lt;/span&gt;);&lt;/pre&gt;

  &lt;br /&gt;
&lt;/div&gt;

&lt;p&gt;This is perfectly legitimate in an event handler, and there are plenty of cases in which you actually &lt;em&gt;want&lt;/em&gt; to return a value from evaluated code. I can't understand why the JavaScript implementation of eval() doesn't function more along the lines of perl, where eval() can be used to return all sorts of things, including - gasp! - the return value of the evaluated code. Wow.  &lt;/p&gt;

&lt;p&gt;Anyway... I'll come to the code snippet that you can copy and paste so that you can leave this blog and go back to your own code.  &lt;/p&gt;

&lt;p&gt;�   &lt;/p&gt;

&lt;div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;"&gt;
  &lt;br /&gt;&lt;pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"&gt;&lt;span style="color:#0000ff;"&gt;var&lt;/span&gt; ScriptHelpers = &lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;() {&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;var&lt;/span&gt; _this = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;;    &lt;span style="color:#008000;"&gt;// don't trust "this" in JS unless you *really* know what you're doing&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;// IMPORTANT: This function is NOT thread safe. If you want to use it in a&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;// multi-threaded application, you need to make it so. Or, preferably, fix&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;// the code that's forcing you do use this approach at all.&lt;/span&gt;&lt;br /&gt;    _this.EvalWithReturnValue = &lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;(scriptToEval) {&lt;br /&gt;        returnValue = undefined;&lt;br /&gt;        scriptToEval = expToEval.replace(&lt;span style="color:#006080;"&gt;" return "&lt;/span&gt;, &lt;span style="color:#006080;"&gt;" returnValue= "&lt;/span&gt;);    &lt;span style="color:#008000;"&gt;// euww.. global. icky, icky, icky.  -andrewh 25/11/08&lt;/span&gt;&lt;br /&gt;        eval(scriptToEval);&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; returnValue;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;var&lt;/span&gt; scriptWotWeGotFromSomeBlokeInAPub = &lt;span style="color:#006080;"&gt;"alert('Hello, world!'); return false;"&lt;/span&gt;;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;var&lt;/span&gt; scriptReturnValue = ScriptHelpers.EvalWithReturnValue(scriptWotWeGotFromSomeBlokeInAPub);&lt;/pre&gt;

  &lt;br /&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/Q1gJaqM-foo" height="1" width="1"/&gt;</description><pubDate>Tue, 25 Nov 2008 05:46:00 +1000</pubDate><a10:updated>2008-11-25T05:46:00+10:00</a10:updated><a10:content type="xhtml"><p>I feel dirty. Oh, so dirty.  </p>

<p>Internet Exploder runs script evaluated using the JavaScript eval() function in the global scope.  </p>

<p>So what?  </p>

<p>Well, if you're doing something silly, as I'm being obliged to do right now, such as dynamically adding and removing click handlers based on CSS attributes, fake HtmlTextWriter objects and third-party controls (over which I have no control), you're eventually going to run into the error above.  </p>

<p>Your code might look, in a very simplified form, something like this:  </p>

<div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;">
  <br /><pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">var</span> RunCrazyUnsafeScript = <span style="color:#0000ff;">function</span>(scriptToEval) {<br />    eval(scriptToEval);<br />}</pre>

  <br />
</div>

<p>... and you're probably invoking it something like this:  </p>

<div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;">
  <br /><pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;">RunCrazyUnsafeScript(<span style="color:#006080;">"alert('Hello, world!');"</span>);</pre>

  <br />
</div>

<p>... and by and large, this all works perfectly well. Occasionally, however, you'll see the error above. The odds are that you're probably doing something like this:  </p>

<div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;">
  <br /><pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;">RunCrazyUnsafeScript(<span style="color:#006080;">"alert('Hello, world!'); return false;"</span>);</pre>

  <br />
</div>

<p>This is perfectly legitimate in an event handler, and there are plenty of cases in which you actually <em>want</em> to return a value from evaluated code. I can't understand why the JavaScript implementation of eval() doesn't function more along the lines of perl, where eval() can be used to return all sorts of things, including - gasp! - the return value of the evaluated code. Wow.  </p>

<p>Anyway... I'll come to the code snippet that you can copy and paste so that you can leave this blog and go back to your own code.  </p>

<p>�   </p>

<div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;">
  <br /><pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">var</span> ScriptHelpers = <span style="color:#0000ff;">function</span>() {<br />    <span style="color:#0000ff;">var</span> _this = <span style="color:#0000ff;">this</span>;    <span style="color:#008000;">// don't trust "this" in JS unless you *really* know what you're doing</span><br /><br />    <span style="color:#008000;">// IMPORTANT: This function is NOT thread safe. If you want to use it in a</span><br />    <span style="color:#008000;">// multi-threaded application, you need to make it so. Or, preferably, fix</span><br />    <span style="color:#008000;">// the code that's forcing you do use this approach at all.</span><br />    _this.EvalWithReturnValue = <span style="color:#0000ff;">function</span>(scriptToEval) {<br />        returnValue = undefined;<br />        scriptToEval = expToEval.replace(<span style="color:#006080;">" return "</span>, <span style="color:#006080;">" returnValue= "</span>);    <span style="color:#008000;">// euww.. global. icky, icky, icky.  -andrewh 25/11/08</span><br />        eval(scriptToEval);<br />        <span style="color:#0000ff;">return</span> returnValue;<br />    }<br />}<br /><br /><span style="color:#0000ff;">var</span> scriptWotWeGotFromSomeBlokeInAPub = <span style="color:#006080;">"alert('Hello, world!'); return false;"</span>;<br /><span style="color:#0000ff;">var</span> scriptReturnValue = ScriptHelpers.EvalWithReturnValue(scriptWotWeGotFromSomeBlokeInAPub);</pre>

  <br />
</div>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2008.11.25.0546</feedburner:origLink></item><item xml:base="Home/Post/2008.11.21.1122"><guid isPermaLink="false">2008.11.21.1122</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/79k2C5aabgo/2008.11.21.1122</link><author>andrewh@uglybugger.org</author><title>IE8 JavaScript Profiling</title><description>&lt;p&gt;If you haven't played with it yet, IE8's JS profiling is awesome. Happy, happy, joy, joy and all that.&lt;/p&gt;

&lt;p&gt;Just don't look at the actual execution times below, or you'll cry (as I am :'( ).&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.codingforfunandprofit.com/Posts/2008/2008.11.21.1122/Screenshot.jpg" alt="Screenshot"/&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/79k2C5aabgo" height="1" width="1"/&gt;</description><pubDate>Fri, 21 Nov 2008 11:22:00 +1000</pubDate><a10:updated>2008-11-21T11:22:00+10:00</a10:updated><a10:content type="xhtml"><p>If you haven't played with it yet, IE8's JS profiling is awesome. Happy, happy, joy, joy and all that.</p>

<p>Just don't look at the actual execution times below, or you'll cry (as I am :'( ).</p>

<p><img src="http://www.codingforfunandprofit.com/Posts/2008/2008.11.21.1122/Screenshot.jpg" alt="Screenshot" /></p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2008.11.21.1122</feedburner:origLink></item><item xml:base="Home/Post/2008.11.12.0515"><guid isPermaLink="false">2008.11.12.0515</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/vponporiYiw/2008.11.12.0515</link><author>andrewh@uglybugger.org</author><title>Code Analysis Rule for Parameter Checking</title><description>&lt;p&gt;I know, I know. Everyone's a gun coder, and nobody ever forgets to check the inputs to their public methods - in the same way as no coder ever makes a mistake, right? Which suggests that all bugs are deliberate...  &lt;/p&gt;

&lt;p&gt;Anyway, to the point. Below is a code analysis rule (don't ask me what a CA rule is; &lt;a href="http://www.google.com.au/search?hl=en&amp;amp;rlz=1C1GGLS_enAU291&amp;amp;q=code+analysis+rules&amp;amp;btnG=Search&amp;amp;meta=" target="_blank"&gt;ask Google&lt;/a&gt;) to encourage developers to check all parameters to their public methods.  &lt;/p&gt;

&lt;p&gt;It's not the complete rule; you'll need your own BaseRule class and XML rule definition file, but if you're competent enough to write these rules in general then you're competent enough to find examples of those elsewhere.  &lt;/p&gt;

&lt;div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;"&gt;
  &lt;br /&gt;&lt;pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"&gt;&lt;span style="color:#0000ff;"&gt;internal&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; EnforceArgumentChecking : BaseRule&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:#cc6633;"&gt;#region&lt;/span&gt; Constructors&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; EnforceArgumentChecking()&lt;br /&gt;        : &lt;span style="color:#0000ff;"&gt;base&lt;/span&gt;(&lt;span style="color:#0000ff;"&gt;typeof&lt;/span&gt;(EnforceArgumentChecking).Name) { }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#cc6633;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#cc6633;"&gt;#region&lt;/span&gt; Public Properties&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; Microsoft.FxCop.Sdk.TargetVisibilities TargetVisibility&lt;br /&gt;    {&lt;br /&gt;        get&lt;br /&gt;        {&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; TargetVisibilities.All;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#cc6633;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#cc6633;"&gt;#region&lt;/span&gt; Public Methods&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; ProblemCollection Check(Member member)&lt;br /&gt;    {&lt;br /&gt;        ProblemCollection problems = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ProblemCollection();&lt;br /&gt;&lt;br /&gt;        Method method = member &lt;span style="color:#0000ff;"&gt;as&lt;/span&gt; Method;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (ShouldCheck(method))&lt;br /&gt;        {&lt;br /&gt;            Dictionary&amp;lt;&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;, &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;&amp;gt; parameterExceptions = GetParameterExceptionCounts(method);&lt;br /&gt;&lt;br /&gt;            &lt;span style="color:#008000;"&gt;// require that each parameter have at least one /Argument.*Exception/ associated with it&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; parameterName &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; GetParametersToCheck(method))&lt;br /&gt;            {&lt;br /&gt;                &lt;span style="color:#008000;"&gt;// if there's no count for this parameter name, or the count's less than one, we have a problem.&lt;/span&gt;&lt;br /&gt;                &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; ((!parameterExceptions.ContainsKey(parameterName)) || ((parameterExceptions[parameterName] &amp;lt; 1)))&lt;br /&gt;                {&lt;br /&gt;                    Resolution resolution = GetNamedResolution(&lt;span style="color:#006080;"&gt;"ArgumentNotChecked"&lt;/span&gt;, parameterName, method.Name.ToString());&lt;br /&gt;                    problems.Add(&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Problem(resolution));&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; problems;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#cc6633;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#cc6633;"&gt;#region&lt;/span&gt; Helper Methods&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// Gets a list of the parameter names to check. This will return all parameter names except those&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// that have a Zap.Attributes.SuspressParameterCheck entry for that individual parameter.&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// &amp;lt;param name="method"&amp;gt;The method whose parameter collection to scan.&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; IEnumerable&amp;lt;&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;&amp;gt; GetParametersToCheck(Method method)&lt;br /&gt;    {&lt;br /&gt;        List&amp;lt;&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;&amp;gt; parametersToIgnore = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; List&amp;lt;&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;&amp;gt;();&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (AttributeNode attr &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; method.Attributes)&lt;br /&gt;        {&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (attr.Type.FullName.Equals(&lt;span style="color:#006080;"&gt;"Zap.Attributes.SuppressParameterCheck"&lt;/span&gt;))&lt;br /&gt;            {&lt;br /&gt;                Expression paramName = attr.GetPositionalArgument(0);&lt;br /&gt;                Expression justification = attr.GetPositionalArgument(1);&lt;br /&gt;&lt;br /&gt;                &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (!&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.IsNullOrEmpty(justification.ToString()))&lt;br /&gt;                {&lt;br /&gt;                    parametersToIgnore.Add(paramName.ToString());&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (Parameter p &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; method.Parameters)&lt;br /&gt;        {&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; paramName = p.Name.ToString();&lt;br /&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (parametersToIgnore.Contains(paramName))&lt;br /&gt;            {&lt;br /&gt;                &lt;span style="color:#0000ff;"&gt;continue&lt;/span&gt;;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;yield&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; paramName;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// Decides whether we should apply this rule to the given method.&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// &amp;lt;param name="method"&amp;gt;The method.&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// &amp;lt;returns&amp;gt;False if the method is null, non-public, an interface or abstract method, a public property setter; true otherwise.&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt; ShouldCheck(Method method)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (method == &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;) { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;false&lt;/span&gt;; }&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (!method.IsPublic) { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;false&lt;/span&gt;; }&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#008000;"&gt;// this will catch methods that are defined as either abstract or interface methods&lt;/span&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (method.IsAbstract) { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;false&lt;/span&gt;; }&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (method.IsAccessor) { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;false&lt;/span&gt;; }&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#008000;"&gt;// we don't check operators - they all generally call the AreEqual, Add, Append or other named methods anyway - and they're almost&lt;/span&gt;&lt;br /&gt;        &lt;span style="color:#008000;"&gt;// always overloads.&lt;/span&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (method.Name.ToString().StartsWith(&lt;span style="color:#006080;"&gt;"op_"&lt;/span&gt;, StringComparison.Ordinal)) { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;false&lt;/span&gt;; }&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// Looks for the creation of instances of /Argument.*Exception/ and counts them for each parameter on the method.&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;/// &amp;lt;returns&amp;gt;A dictionary mapping the parameter name to the number of /Argument.*Exception/ thrown against that parameter.&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; Dictionary&amp;lt;&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;, &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;&amp;gt; GetParameterExceptionCounts(Method method)&lt;br /&gt;    {&lt;br /&gt;        Dictionary&amp;lt;&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;, &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;&amp;gt; exceptionsThrownOnParameters = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;, &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;&amp;gt;();&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#008000;"&gt;// count the exceptions thrown on each parameter.&lt;/span&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;for&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; i = 2; i &amp;lt; method.Instructions.Count; i++) &lt;span style="color:#008000;"&gt;// start from 2 because it's pretty much impossible to throw a useful exception before this.&lt;/span&gt;&lt;br /&gt;        {&lt;br /&gt;            Instruction instruction = method.Instructions[i];&lt;br /&gt;&lt;br /&gt;            &lt;span style="color:#008000;"&gt;// are creating a new Argument*.Exception object?&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (instruction.OpCode == OpCode.Newobj)&lt;br /&gt;            {&lt;br /&gt;                InstanceInitializer initializer = (InstanceInitializer)instruction.Value;&lt;br /&gt;                &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (Regex.IsMatch(initializer.FullName, &lt;span style="color:#006080;"&gt;"Argument.*Exception"&lt;/span&gt;))&lt;br /&gt;                {&lt;br /&gt;                    &lt;span style="color:#0000ff;"&gt;for&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; paramIdx = 0; paramIdx &amp;lt; initializer.Parameters.Count; paramIdx++)&lt;br /&gt;                    {&lt;br /&gt;                        Parameter p = initializer.Parameters[paramIdx];&lt;br /&gt;                        &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (p.Name.ToString().Equals(&lt;span style="color:#006080;"&gt;"paramName"&lt;/span&gt;))&lt;br /&gt;                        {&lt;br /&gt;                            &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; paramOffset = initializer.Parameters.Count - paramIdx;&lt;br /&gt;&lt;br /&gt;                            Instruction loadStringInstruction = method.Instructions[i - paramOffset];&lt;br /&gt;                            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (loadStringInstruction.OpCode == OpCode.Ldstr)&lt;br /&gt;                            {&lt;br /&gt;                                &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; parameterValue = loadStringInstruction.Value.ToString();&lt;br /&gt;&lt;br /&gt;                                &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (!exceptionsThrownOnParameters.ContainsKey(parameterValue))&lt;br /&gt;                                {&lt;br /&gt;                                    exceptionsThrownOnParameters[parameterValue] = 1;&lt;br /&gt;                                }&lt;br /&gt;                                &lt;span style="color:#0000ff;"&gt;else&lt;/span&gt;&lt;br /&gt;                                {&lt;br /&gt;                                    exceptionsThrownOnParameters[parameterValue]++;&lt;br /&gt;                                }&lt;br /&gt;                            }&lt;br /&gt;                        }&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; exceptionsThrownOnParameters;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#cc6633;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;

  &lt;br /&gt;
&lt;/div&gt;

&lt;p&gt;Hand in hand with this rule is a code attribute that allows the programmer to suppress warnings on individual method parameters, rather than just suppressing the entire rule for a particular method:  &lt;/p&gt;

&lt;div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;"&gt;
  &lt;br /&gt;&lt;pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"&gt;[AttributeUsage(AttributeTargets.Method, Inherited = &lt;span style="color:#0000ff;"&gt;false&lt;/span&gt;, AllowMultiple = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;)]&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;sealed&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; SuppressParameterCheck : Attribute&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; _parameterName;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; _justification;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; SuppressParameterCheck(&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; parameterName, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; justification)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; ((&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.IsNullOrEmpty(justification)) || (justification.Length &amp;lt; 10))&lt;br /&gt;        {&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;throw&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ArgumentNullException(&lt;span style="color:#006080;"&gt;"justification"&lt;/span&gt;, &lt;span style="color:#006080;"&gt;"If you're going to suppress a parameter check, you MUST MUST MUST give a reason."&lt;/span&gt;);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        _parameterName = parameterName;&lt;br /&gt;        _justification = justification;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; ParameterName&lt;br /&gt;    {&lt;br /&gt;        get { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; _parameterName; }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; Justification&lt;br /&gt;    {&lt;br /&gt;        get { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; _justification; }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;

  &lt;br /&gt;
&lt;/div&gt;

&lt;p&gt;And an example of how to use the SuppressParameterCheck attribute:  &lt;/p&gt;

&lt;div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;"&gt;
  &lt;br /&gt;&lt;pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; Insert(&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; key, &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:#cc6633;"&gt;#region&lt;/span&gt; Argument Checking&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#cc6633;"&gt;#region&lt;/span&gt; Argument Check &lt;span style="color:#0000ff;"&gt;for&lt;/span&gt; &lt;span style="color:#006080;"&gt;"key"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.IsNullOrEmpty(key))&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;throw&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ArgumentNullException(&lt;span style="color:#006080;"&gt;"key"&lt;/span&gt;);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#cc6633;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#cc6633;"&gt;#region&lt;/span&gt; Argument Check &lt;span style="color:#0000ff;"&gt;for&lt;/span&gt; &lt;span style="color:#006080;"&gt;"value"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;value&lt;/span&gt; == &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;throw&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ArgumentNullException(&lt;span style="color:#006080;"&gt;"value"&lt;/span&gt;);&lt;br /&gt;    }&lt;br /&gt;    &lt;span style="color:#cc6633;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#cc6633;"&gt;#endregion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;// Accept the object, but don't cache it.&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[SuppressParameterCheck(&lt;span style="color:#006080;"&gt;"key"&lt;/span&gt;, &lt;span style="color:#006080;"&gt;"This will be checked in a called method."&lt;/span&gt;)]&lt;br /&gt;[SuppressParameterCheck(&lt;span style="color:#006080;"&gt;"value"&lt;/span&gt;, &lt;span style="color:#006080;"&gt;"This will be checked in a called method."&lt;/span&gt;)]&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; Insert(&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; key, &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;, CacheExpireType expireType)&lt;br /&gt;{&lt;br /&gt;    Insert(key, &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;);    &lt;span style="color:#008000;"&gt;// Accept the object, but don't cache it.&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;

  &lt;br /&gt;
&lt;/div&gt;

&lt;p&gt;Of course, it goes without saying that you're compiling with warnings == errors, right? :)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/vponporiYiw" height="1" width="1"/&gt;</description><pubDate>Wed, 12 Nov 2008 05:15:00 +1000</pubDate><a10:updated>2008-11-12T05:15:00+10:00</a10:updated><a10:content type="xhtml"><p>I know, I know. Everyone's a gun coder, and nobody ever forgets to check the inputs to their public methods - in the same way as no coder ever makes a mistake, right? Which suggests that all bugs are deliberate...  </p>

<p>Anyway, to the point. Below is a code analysis rule (don't ask me what a CA rule is; <a href="http://www.google.com.au/search?hl=en&amp;rlz=1C1GGLS_enAU291&amp;q=code+analysis+rules&amp;btnG=Search&amp;meta=" target="_blank">ask Google</a>) to encourage developers to check all parameters to their public methods.  </p>

<p>It's not the complete rule; you'll need your own BaseRule class and XML rule definition file, but if you're competent enough to write these rules in general then you're competent enough to find examples of those elsewhere.  </p>

<div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;">
  <br /><pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">internal</span> <span style="color:#0000ff;">class</span> EnforceArgumentChecking : BaseRule<br />{<br />    <span style="color:#cc6633;">#region</span> Constructors<br /><br />    <span style="color:#0000ff;">public</span> EnforceArgumentChecking()<br />        : <span style="color:#0000ff;">base</span>(<span style="color:#0000ff;">typeof</span>(EnforceArgumentChecking).Name) { }<br /><br />    <span style="color:#cc6633;">#endregion</span><br /><br />    <span style="color:#cc6633;">#region</span> Public Properties<br /><br />    <span style="color:#0000ff;">public</span> <span style="color:#0000ff;">override</span> Microsoft.FxCop.Sdk.TargetVisibilities TargetVisibility<br />    {<br />        get<br />        {<br />            <span style="color:#0000ff;">return</span> TargetVisibilities.All;<br />        }<br />    }<br /><br />    <span style="color:#cc6633;">#endregion</span><br /><br />    <span style="color:#cc6633;">#region</span> Public Methods<br /><br />    <span style="color:#0000ff;">public</span> <span style="color:#0000ff;">override</span> ProblemCollection Check(Member member)<br />    {<br />        ProblemCollection problems = <span style="color:#0000ff;">new</span> ProblemCollection();<br /><br />        Method method = member <span style="color:#0000ff;">as</span> Method;<br />        <span style="color:#0000ff;">if</span> (ShouldCheck(method))<br />        {<br />            Dictionary&lt;<span style="color:#0000ff;">string</span>, <span style="color:#0000ff;">int</span>&gt; parameterExceptions = GetParameterExceptionCounts(method);<br /><br />            <span style="color:#008000;">// require that each parameter have at least one /Argument.*Exception/ associated with it</span><br />            <span style="color:#0000ff;">foreach</span> (<span style="color:#0000ff;">string</span> parameterName <span style="color:#0000ff;">in</span> GetParametersToCheck(method))<br />            {<br />                <span style="color:#008000;">// if there's no count for this parameter name, or the count's less than one, we have a problem.</span><br />                <span style="color:#0000ff;">if</span> ((!parameterExceptions.ContainsKey(parameterName)) || ((parameterExceptions[parameterName] &lt; 1)))<br />                {<br />                    Resolution resolution = GetNamedResolution(<span style="color:#006080;">"ArgumentNotChecked"</span>, parameterName, method.Name.ToString());<br />                    problems.Add(<span style="color:#0000ff;">new</span> Problem(resolution));<br />                }<br />            }<br />        }<br /><br />        <span style="color:#0000ff;">return</span> problems;<br />    }<br /><br />    <span style="color:#cc6633;">#endregion</span><br /><br />    <span style="color:#cc6633;">#region</span> Helper Methods<br /><br />    <span style="color:#008000;">/// &lt;summary&gt;</span><br />    <span style="color:#008000;">/// Gets a list of the parameter names to check. This will return all parameter names except those</span><br />    <span style="color:#008000;">/// that have a Zap.Attributes.SuspressParameterCheck entry for that individual parameter.</span><br />    <span style="color:#008000;">/// &lt;/summary&gt;</span><br />    <span style="color:#008000;">/// &lt;param name="method"&gt;The method whose parameter collection to scan.&lt;/param&gt;</span><br />    <span style="color:#0000ff;">private</span> IEnumerable&lt;<span style="color:#0000ff;">string</span>&gt; GetParametersToCheck(Method method)<br />    {<br />        List&lt;<span style="color:#0000ff;">string</span>&gt; parametersToIgnore = <span style="color:#0000ff;">new</span> List&lt;<span style="color:#0000ff;">string</span>&gt;();<br /><br />        <span style="color:#0000ff;">foreach</span> (AttributeNode attr <span style="color:#0000ff;">in</span> method.Attributes)<br />        {<br />            <span style="color:#0000ff;">if</span> (attr.Type.FullName.Equals(<span style="color:#006080;">"Zap.Attributes.SuppressParameterCheck"</span>))<br />            {<br />                Expression paramName = attr.GetPositionalArgument(0);<br />                Expression justification = attr.GetPositionalArgument(1);<br /><br />                <span style="color:#0000ff;">if</span> (!<span style="color:#0000ff;">string</span>.IsNullOrEmpty(justification.ToString()))<br />                {<br />                    parametersToIgnore.Add(paramName.ToString());<br />                }<br />            }<br />        }<br /><br />        <span style="color:#0000ff;">foreach</span> (Parameter p <span style="color:#0000ff;">in</span> method.Parameters)<br />        {<br />            <span style="color:#0000ff;">string</span> paramName = p.Name.ToString();<br /><br />            <span style="color:#0000ff;">if</span> (parametersToIgnore.Contains(paramName))<br />            {<br />                <span style="color:#0000ff;">continue</span>;<br />            }<br /><br />            <span style="color:#0000ff;">yield</span> <span style="color:#0000ff;">return</span> paramName;<br />        }<br />    }<br /><br />    <span style="color:#008000;">/// &lt;summary&gt;</span><br />    <span style="color:#008000;">/// Decides whether we should apply this rule to the given method.</span><br />    <span style="color:#008000;">/// &lt;/summary&gt;</span><br />    <span style="color:#008000;">/// &lt;param name="method"&gt;The method.&lt;/param&gt;</span><br />    <span style="color:#008000;">/// &lt;returns&gt;False if the method is null, non-public, an interface or abstract method, a public property setter; true otherwise.&lt;/returns&gt;</span><br />    <span style="color:#0000ff;">private</span> <span style="color:#0000ff;">static</span> <span style="color:#0000ff;">bool</span> ShouldCheck(Method method)<br />    {<br />        <span style="color:#0000ff;">if</span> (method == <span style="color:#0000ff;">null</span>) { <span style="color:#0000ff;">return</span> <span style="color:#0000ff;">false</span>; }<br /><br />        <span style="color:#0000ff;">if</span> (!method.IsPublic) { <span style="color:#0000ff;">return</span> <span style="color:#0000ff;">false</span>; }<br /><br />        <span style="color:#008000;">// this will catch methods that are defined as either abstract or interface methods</span><br />        <span style="color:#0000ff;">if</span> (method.IsAbstract) { <span style="color:#0000ff;">return</span> <span style="color:#0000ff;">false</span>; }<br /><br />        <span style="color:#0000ff;">if</span> (method.IsAccessor) { <span style="color:#0000ff;">return</span> <span style="color:#0000ff;">false</span>; }<br /><br />        <span style="color:#008000;">// we don't check operators - they all generally call the AreEqual, Add, Append or other named methods anyway - and they're almost</span><br />        <span style="color:#008000;">// always overloads.</span><br />        <span style="color:#0000ff;">if</span> (method.Name.ToString().StartsWith(<span style="color:#006080;">"op_"</span>, StringComparison.Ordinal)) { <span style="color:#0000ff;">return</span> <span style="color:#0000ff;">false</span>; }<br /><br />        <span style="color:#0000ff;">return</span> <span style="color:#0000ff;">true</span>;<br />    }<br /><br />    <span style="color:#008000;">/// &lt;summary&gt;</span><br />    <span style="color:#008000;">/// Looks for the creation of instances of /Argument.*Exception/ and counts them for each parameter on the method.</span><br />    <span style="color:#008000;">/// &lt;/summary&gt;</span><br />    <span style="color:#008000;">/// &lt;returns&gt;A dictionary mapping the parameter name to the number of /Argument.*Exception/ thrown against that parameter.&lt;/returns&gt;</span><br />    <span style="color:#0000ff;">private</span> <span style="color:#0000ff;">static</span> Dictionary&lt;<span style="color:#0000ff;">string</span>, <span style="color:#0000ff;">int</span>&gt; GetParameterExceptionCounts(Method method)<br />    {<br />        Dictionary&lt;<span style="color:#0000ff;">string</span>, <span style="color:#0000ff;">int</span>&gt; exceptionsThrownOnParameters = <span style="color:#0000ff;">new</span> Dictionary&lt;<span style="color:#0000ff;">string</span>, <span style="color:#0000ff;">int</span>&gt;();<br /><br />        <span style="color:#008000;">// count the exceptions thrown on each parameter.</span><br />        <span style="color:#0000ff;">for</span> (<span style="color:#0000ff;">int</span> i = 2; i &lt; method.Instructions.Count; i++) <span style="color:#008000;">// start from 2 because it's pretty much impossible to throw a useful exception before this.</span><br />        {<br />            Instruction instruction = method.Instructions[i];<br /><br />            <span style="color:#008000;">// are creating a new Argument*.Exception object?</span><br />            <span style="color:#0000ff;">if</span> (instruction.OpCode == OpCode.Newobj)<br />            {<br />                InstanceInitializer initializer = (InstanceInitializer)instruction.Value;<br />                <span style="color:#0000ff;">if</span> (Regex.IsMatch(initializer.FullName, <span style="color:#006080;">"Argument.*Exception"</span>))<br />                {<br />                    <span style="color:#0000ff;">for</span> (<span style="color:#0000ff;">int</span> paramIdx = 0; paramIdx &lt; initializer.Parameters.Count; paramIdx++)<br />                    {<br />                        Parameter p = initializer.Parameters[paramIdx];<br />                        <span style="color:#0000ff;">if</span> (p.Name.ToString().Equals(<span style="color:#006080;">"paramName"</span>))<br />                        {<br />                            <span style="color:#0000ff;">int</span> paramOffset = initializer.Parameters.Count - paramIdx;<br /><br />                            Instruction loadStringInstruction = method.Instructions[i - paramOffset];<br />                            <span style="color:#0000ff;">if</span> (loadStringInstruction.OpCode == OpCode.Ldstr)<br />                            {<br />                                <span style="color:#0000ff;">string</span> parameterValue = loadStringInstruction.Value.ToString();<br /><br />                                <span style="color:#0000ff;">if</span> (!exceptionsThrownOnParameters.ContainsKey(parameterValue))<br />                                {<br />                                    exceptionsThrownOnParameters[parameterValue] = 1;<br />                                }<br />                                <span style="color:#0000ff;">else</span><br />                                {<br />                                    exceptionsThrownOnParameters[parameterValue]++;<br />                                }<br />                            }<br />                        }<br />                    }<br />                }<br />            }<br />        }<br /><br />        <span style="color:#0000ff;">return</span> exceptionsThrownOnParameters;<br />    }<br /><br />    <span style="color:#cc6633;">#endregion</span><br /><br />}</pre>

  <br />
</div>

<p>Hand in hand with this rule is a code attribute that allows the programmer to suppress warnings on individual method parameters, rather than just suppressing the entire rule for a particular method:  </p>

<div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;">
  <br /><pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;">[AttributeUsage(AttributeTargets.Method, Inherited = <span style="color:#0000ff;">false</span>, AllowMultiple = <span style="color:#0000ff;">true</span>)]<br /><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">sealed</span> <span style="color:#0000ff;">class</span> SuppressParameterCheck : Attribute<br />{<br />    <span style="color:#0000ff;">private</span> <span style="color:#0000ff;">string</span> _parameterName;<br />    <span style="color:#0000ff;">private</span> <span style="color:#0000ff;">string</span> _justification;<br /><br />    <span style="color:#0000ff;">public</span> SuppressParameterCheck(<span style="color:#0000ff;">string</span> parameterName, <span style="color:#0000ff;">string</span> justification)<br />    {<br />        <span style="color:#0000ff;">if</span> ((<span style="color:#0000ff;">string</span>.IsNullOrEmpty(justification)) || (justification.Length &lt; 10))<br />        {<br />            <span style="color:#0000ff;">throw</span> <span style="color:#0000ff;">new</span> ArgumentNullException(<span style="color:#006080;">"justification"</span>, <span style="color:#006080;">"If you're going to suppress a parameter check, you MUST MUST MUST give a reason."</span>);<br />        }<br /><br />        _parameterName = parameterName;<br />        _justification = justification;<br />    }<br /><br />    <span style="color:#0000ff;">public</span> <span style="color:#0000ff;">string</span> ParameterName<br />    {<br />        get { <span style="color:#0000ff;">return</span> _parameterName; }<br />    }<br /><br />    <span style="color:#0000ff;">public</span> <span style="color:#0000ff;">string</span> Justification<br />    {<br />        get { <span style="color:#0000ff;">return</span> _justification; }<br />    }<br />}</pre>

  <br />
</div>

<p>And an example of how to use the SuppressParameterCheck attribute:  </p>

<div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;">
  <br /><pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">void</span> Insert(<span style="color:#0000ff;">string</span> key, <span style="color:#0000ff;">object</span> <span style="color:#0000ff;">value</span>)<br />{<br />    <span style="color:#cc6633;">#region</span> Argument Checking<br /><br />    <span style="color:#cc6633;">#region</span> Argument Check <span style="color:#0000ff;">for</span> <span style="color:#006080;">"key"</span><br /><br />    <span style="color:#0000ff;">if</span> (<span style="color:#0000ff;">string</span>.IsNullOrEmpty(key))<br />    {<br />        <span style="color:#0000ff;">throw</span> <span style="color:#0000ff;">new</span> ArgumentNullException(<span style="color:#006080;">"key"</span>);<br />    }<br /><br />    <span style="color:#cc6633;">#endregion</span><br /><br />    <span style="color:#cc6633;">#region</span> Argument Check <span style="color:#0000ff;">for</span> <span style="color:#006080;">"value"</span><br /><br />    <span style="color:#0000ff;">if</span> (<span style="color:#0000ff;">value</span> == <span style="color:#0000ff;">null</span>)<br />    {<br />        <span style="color:#0000ff;">throw</span> <span style="color:#0000ff;">new</span> ArgumentNullException(<span style="color:#006080;">"value"</span>);<br />    }<br />    <span style="color:#cc6633;">#endregion</span><br /><br />    <span style="color:#cc6633;">#endregion</span><br /><br />    <span style="color:#008000;">// Accept the object, but don't cache it.</span><br />}<br /><br />[SuppressParameterCheck(<span style="color:#006080;">"key"</span>, <span style="color:#006080;">"This will be checked in a called method."</span>)]<br />[SuppressParameterCheck(<span style="color:#006080;">"value"</span>, <span style="color:#006080;">"This will be checked in a called method."</span>)]<br /><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">void</span> Insert(<span style="color:#0000ff;">string</span> key, <span style="color:#0000ff;">object</span> <span style="color:#0000ff;">value</span>, CacheExpireType expireType)<br />{<br />    Insert(key, <span style="color:#0000ff;">value</span>);    <span style="color:#008000;">// Accept the object, but don't cache it.</span><br />}</pre>

  <br />
</div>

<p>Of course, it goes without saying that you're compiling with warnings == errors, right? :)</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2008.11.12.0515</feedburner:origLink></item><item xml:base="Home/Post/2008.11.07.0800"><guid isPermaLink="false">2008.11.07.0800</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/kx9ydfuVuow/2008.11.07.0800</link><author>andrewh@uglybugger.org</author><title>Way to End an Interview...</title><description>&lt;p&gt;Todd's quote for the day:  &lt;/p&gt;

&lt;p&gt;"I tried to explain to him why these things were important, but then I gave up, and just said, 'You should probably go now.'"  &lt;/p&gt;

&lt;p&gt;Not the way you'd want your interview to end...&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/kx9ydfuVuow" height="1" width="1"/&gt;</description><pubDate>Fri, 07 Nov 2008 08:00:00 +1000</pubDate><a10:updated>2008-11-07T08:00:00+10:00</a10:updated><a10:content type="xhtml"><p>Todd's quote for the day:  </p>

<p>"I tried to explain to him why these things were important, but then I gave up, and just said, 'You should probably go now.'"  </p>

<p>Not the way you'd want your interview to end...</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2008.11.07.0800</feedburner:origLink></item><item xml:base="Home/Post/2008.10.09.1125"><guid isPermaLink="false">2008.10.09.1125</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/-jmnU7ut0Kk/2008.10.09.1125</link><author>andrewh@uglybugger.org</author><title>Windows Mobile Error 0x8503001c</title><description>&lt;p&gt;OK, the entire point of this blog post is to save some other poor sod from the pain that I've just been through.  &lt;/p&gt;

&lt;p&gt;If you have a Windows Mobile device and get synchronization error 0x8503001c, your life is close to over. Trust me.  &lt;/p&gt;

&lt;p&gt;You can delete and re-create the sync partnerships between your PC and your Windows Mobile device as many times as you want, with whatever permutations of synchronization settings you choose, but it's not likely to help. Try it anyway, but don't waste too much time on it.  &lt;/p&gt;

&lt;p&gt;What you're going to do, at some point after you've realized that it's all hopeless, is reset everything to factory defaults and start over.  &lt;/p&gt;

&lt;p&gt;The first tool you'll want is Dotfred's PIM Backup tool, available at &lt;a href="http://www.dotfred.net/" target="_blank"&gt;http://www.dotfred.net/&lt;/a&gt;. Get it and back your device up (NOT to your device memory!).  &lt;/p&gt;

&lt;p&gt;Reset your device to factory defaults. On my Dopod you hold both of the multi-function buttons (the "-" buttons) while poking the reset button with your stylus. Press the Send button when it prompts you to confirm. Yours is probably different.  &lt;/p&gt;

&lt;p&gt;Re-create the sync relationship between your phone and your PC.  &lt;/p&gt;

&lt;p&gt;Re-sync everything.  &lt;/p&gt;

&lt;p&gt;Restore your backup.  &lt;/p&gt;

&lt;p&gt;Cry.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/-jmnU7ut0Kk" height="1" width="1"/&gt;</description><pubDate>Thu, 09 Oct 2008 11:25:00 +1000</pubDate><a10:updated>2008-10-09T11:25:00+10:00</a10:updated><a10:content type="xhtml"><p>OK, the entire point of this blog post is to save some other poor sod from the pain that I've just been through.  </p>

<p>If you have a Windows Mobile device and get synchronization error 0x8503001c, your life is close to over. Trust me.  </p>

<p>You can delete and re-create the sync partnerships between your PC and your Windows Mobile device as many times as you want, with whatever permutations of synchronization settings you choose, but it's not likely to help. Try it anyway, but don't waste too much time on it.  </p>

<p>What you're going to do, at some point after you've realized that it's all hopeless, is reset everything to factory defaults and start over.  </p>

<p>The first tool you'll want is Dotfred's PIM Backup tool, available at <a href="http://www.dotfred.net/" target="_blank">http://www.dotfred.net/</a>. Get it and back your device up (NOT to your device memory!).  </p>

<p>Reset your device to factory defaults. On my Dopod you hold both of the multi-function buttons (the "-" buttons) while poking the reset button with your stylus. Press the Send button when it prompts you to confirm. Yours is probably different.  </p>

<p>Re-create the sync relationship between your phone and your PC.  </p>

<p>Re-sync everything.  </p>

<p>Restore your backup.  </p>

<p>Cry.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2008.10.09.1125</feedburner:origLink></item><item xml:base="Home/Post/2008.08.29.0410"><guid isPermaLink="false">2008.08.29.0410</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/PhQWbe84-yo/2008.08.29.0410</link><author>andrewh@uglybugger.org</author><title>The Value of Check-In Policies</title><description>&lt;p&gt;See? Now isn't everyone glad that we have check-in policies that search for words like this? :)  &lt;/p&gt;

&lt;p&gt;&lt;a href="http://thedailywtf.com/Articles/We-Burned-the-Poop.aspx" target="_blank"&gt;http://thedailywtf.com/Articles/We-Burned-the-Poop.aspx&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/PhQWbe84-yo" height="1" width="1"/&gt;</description><pubDate>Fri, 29 Aug 2008 04:10:00 +1000</pubDate><a10:updated>2008-08-29T04:10:00+10:00</a10:updated><a10:content type="xhtml"><p>See? Now isn't everyone glad that we have check-in policies that search for words like this? :)  </p>

<p><a href="http://thedailywtf.com/Articles/We-Burned-the-Poop.aspx" target="_blank">http://thedailywtf.com/Articles/We-Burned-the-Poop.aspx</a></p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2008.08.29.0410</feedburner:origLink></item><item xml:base="Home/Post/2008.08.27.0429"><guid isPermaLink="false">2008.08.27.0429</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/0qVNuXdCRuw/2008.08.27.0429</link><author>andrewh@uglybugger.org</author><title>public property != public variable</title><description>&lt;p&gt;Here's a particularly nasty gotcha that new .NET developers should be aware of. It &lt;em&gt;should *go without saying, but nonetheless it appears that it *does&lt;/em&gt; need to be said. Hmph.  &lt;/p&gt;

&lt;p&gt;The sordid details are not included here to preserve the dignity of the guilty parties, but basically it boils down to: a property getter/setter is NOT the same as a public instance variable.  &lt;/p&gt;

&lt;p&gt;In other words, you are never &lt;em&gt;guaranteed&lt;/em&gt; that the value you put in will be the value you get back. Consider the following:  &lt;/p&gt;

&lt;div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;"&gt;
  &lt;br /&gt;&lt;pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"&gt;&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Foo = &lt;span style="color:#006080;"&gt;"Hello, world!"&lt;/span&gt;;&lt;br /&gt;Debug.Assert(&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Foo.Equals(&lt;span style="color:#006080;"&gt;"Hello, world!"&lt;/span&gt;);&lt;/pre&gt;

  &lt;br /&gt;
&lt;/div&gt;

&lt;p&gt;If I were evil (or just incompetent, as the developers of certain pieces of code I've had to deal with recently were), my definition of Foo could be as below:  &lt;/p&gt;

&lt;div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;"&gt;
  &lt;br /&gt;&lt;pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; _foo;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; Foo&lt;br /&gt;{&lt;br /&gt;    get&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; _foo;&lt;br /&gt;    }&lt;br /&gt;    set&lt;br /&gt;    {&lt;br /&gt;        Trace.WriteLine(&lt;span style="color:#006080;"&gt;"The caller asked me to store '{0}', but I'm going to drop it on the floor instead. &amp;lt;snigger /&amp;gt;"&lt;/span&gt;.FormatWith(&lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;));&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;

  &lt;br /&gt;
&lt;/div&gt;

&lt;p&gt;As I said, this is an elementary distinction (and a trivial example) but do &lt;em&gt;not not not&lt;/em&gt; assume that just because you've asked a setter to store a value that you'll get the same value back from the getter. You &lt;em&gt;should&lt;/em&gt;, but "should" is the most over-used word in this industry.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/0qVNuXdCRuw" height="1" width="1"/&gt;</description><pubDate>Wed, 27 Aug 2008 04:29:00 +1000</pubDate><a10:updated>2008-08-27T04:29:00+10:00</a10:updated><a10:content type="xhtml"><p>Here's a particularly nasty gotcha that new .NET developers should be aware of. It <em>should *go without saying, but nonetheless it appears that it *does</em> need to be said. Hmph.  </p>

<p>The sordid details are not included here to preserve the dignity of the guilty parties, but basically it boils down to: a property getter/setter is NOT the same as a public instance variable.  </p>

<p>In other words, you are never <em>guaranteed</em> that the value you put in will be the value you get back. Consider the following:  </p>

<div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;">
  <br /><pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">this</span>.Foo = <span style="color:#006080;">"Hello, world!"</span>;<br />Debug.Assert(<span style="color:#0000ff;">this</span>.Foo.Equals(<span style="color:#006080;">"Hello, world!"</span>);</pre>

  <br />
</div>

<p>If I were evil (or just incompetent, as the developers of certain pieces of code I've had to deal with recently were), my definition of Foo could be as below:  </p>

<div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;">
  <br /><pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">private</span> <span style="color:#0000ff;">string</span> _foo;<br /><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">string</span> Foo<br />{<br />    get<br />    {<br />        <span style="color:#0000ff;">return</span> _foo;<br />    }<br />    set<br />    {<br />        Trace.WriteLine(<span style="color:#006080;">"The caller asked me to store '{0}', but I'm going to drop it on the floor instead. &lt;snigger /&gt;"</span>.FormatWith(<span style="color:#0000ff;">value</span>));<br />    }<br />}</pre>

  <br />
</div>

<p>As I said, this is an elementary distinction (and a trivial example) but do <em>not not not</em> assume that just because you've asked a setter to store a value that you'll get the same value back from the getter. You <em>should</em>, but "should" is the most over-used word in this industry.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2008.08.27.0429</feedburner:origLink></item><item xml:base="Home/Post/2008.07.25.0422"><guid isPermaLink="false">2008.07.25.0422</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/-UUUVN8W3FU/2008.07.25.0422</link><author>andrewh@uglybugger.org</author><title>JavaScript Code Re-Use in Microsoft CRM</title><description>&lt;p&gt;Microsoft's CRM tool offers some pretty powerful JavaScript event hooks. One thing it doesn't appear to offer, however, is a way to import a library of JS functions and re-use them across different event handlers.  &lt;/p&gt;

&lt;p&gt;For example, if one wanted to display a "Hello, world!" message whenever several different attributes were changed, the conventional approach would be to embed the call to alert() in each of the event handlers. Obviously, for such a simple example, this isn't such a big deal, but for more sophisticated logic it becomes unwieldy very, very rapidly.  &lt;/p&gt;

&lt;p&gt;One common approach is to use externally-referenced script files. Great, but imagine the horror when you suddenly discover that your system administrator has been religiously backing up your CRM server for the last six years, but hasn't backed up the web server from which you were serving your scripts... We still have the problem of how to reference them, too.  &lt;/p&gt;

&lt;p&gt;Variable declarations in JavaScript (evilly) default to global. What you can do to exploit this, however, is to declare a global function pointer from within an OnLoad event handler as follows:  &lt;/p&gt;

&lt;div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;"&gt;
  &lt;br /&gt;&lt;pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"&gt;&lt;span style="color:#008000;"&gt;// This is the OnLoad event handler provided by CRM&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;function&lt;/span&gt; OnLoad() {&lt;br /&gt;    &lt;span style="color:#008000;"&gt;// This is the function that we want to make&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;// available globally. Note the lack of a&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;// "var" declaration.&lt;/span&gt;&lt;br /&gt;    helloWorldFunction = &lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;() {&lt;br /&gt;        alert(&lt;span style="color:#006080;"&gt;"Hello, world!"&lt;/span&gt;);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;

  &lt;br /&gt;
&lt;/div&gt;

&lt;p&gt;Then, in your event handler for other controls on the page, you can re-use that global variable:  &lt;/p&gt;

&lt;div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;"&gt;
  &lt;br /&gt;&lt;pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"&gt;&lt;span style="color:#008000;"&gt;// This is the OnChange event handler provided by CRM&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;function&lt;/span&gt; OnChange() {&lt;br /&gt;    &lt;span style="color:#008000;"&gt;// ... and here's the one we prepared earlier.&lt;/span&gt;&lt;br /&gt;    helloWorldFunction();&lt;br /&gt;}&lt;/pre&gt;

  &lt;br /&gt;
&lt;/div&gt;

&lt;p&gt;... and Bob's your father's creepy brother, you have code reuse with no external dependencies.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/-UUUVN8W3FU" height="1" width="1"/&gt;</description><pubDate>Fri, 25 Jul 2008 04:22:00 +1000</pubDate><a10:updated>2008-07-25T04:22:00+10:00</a10:updated><a10:content type="xhtml"><p>Microsoft's CRM tool offers some pretty powerful JavaScript event hooks. One thing it doesn't appear to offer, however, is a way to import a library of JS functions and re-use them across different event handlers.  </p>

<p>For example, if one wanted to display a "Hello, world!" message whenever several different attributes were changed, the conventional approach would be to embed the call to alert() in each of the event handlers. Obviously, for such a simple example, this isn't such a big deal, but for more sophisticated logic it becomes unwieldy very, very rapidly.  </p>

<p>One common approach is to use externally-referenced script files. Great, but imagine the horror when you suddenly discover that your system administrator has been religiously backing up your CRM server for the last six years, but hasn't backed up the web server from which you were serving your scripts... We still have the problem of how to reference them, too.  </p>

<p>Variable declarations in JavaScript (evilly) default to global. What you can do to exploit this, however, is to declare a global function pointer from within an OnLoad event handler as follows:  </p>

<div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;">
  <br /><pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"><span style="color:#008000;">// This is the OnLoad event handler provided by CRM</span><br /><span style="color:#0000ff;">function</span> OnLoad() {<br />    <span style="color:#008000;">// This is the function that we want to make</span><br />    <span style="color:#008000;">// available globally. Note the lack of a</span><br />    <span style="color:#008000;">// "var" declaration.</span><br />    helloWorldFunction = <span style="color:#0000ff;">function</span>() {<br />        alert(<span style="color:#006080;">"Hello, world!"</span>);<br />    }<br />}</pre>

  <br />
</div>

<p>Then, in your event handler for other controls on the page, you can re-use that global variable:  </p>

<div style="line-height:12pt;background-color:#f4f4f4;width:97.5%;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;cursor:text;border:gray 1px solid;margin:20px 0 10px;padding:4px;">
  <br /><pre style="line-height:12pt;background-color:#f4f4f4;width:100%;font-family:consolas, 'Courier New', courier, monospace;color:black;font-size:8pt;overflow:visible;border-style:none;margin:0;padding:0;"><span style="color:#008000;">// This is the OnChange event handler provided by CRM</span><br /><span style="color:#0000ff;">function</span> OnChange() {<br />    <span style="color:#008000;">// ... and here's the one we prepared earlier.</span><br />    helloWorldFunction();<br />}</pre>

  <br />
</div>

<p>... and Bob's your father's creepy brother, you have code reuse with no external dependencies.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2008.07.25.0422</feedburner:origLink></item><item xml:base="Home/Post/2008.07.04.0942"><guid isPermaLink="false">2008.07.04.0942</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/X7z2X8bTplo/2008.07.04.0942</link><author>andrewh@uglybugger.org</author><title>Writing Good Unit Tests</title><description>&lt;p&gt;&lt;strong&gt;Writing Unit Tests&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Why do we write unit tests?  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Improve code quality&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fewer reported defects&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make checking code faster&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tell us when we've broken something&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tell us when our work is done&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Allow others to check our code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Encourage modular design&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Keep behaviour constant during refactoring Functions as a spec (think TDD)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The law of diminishing returns most definitely applies here  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Testing everything is infeasible. Don't be unrealistic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;70% code coverage is actually pretty decent for most classes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;First, test the common stuff.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next, test the common exception-case stuff.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Then test the critical stuff.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add other tests as appropriate.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When to write a unit test  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use a unit test to provide a framework for writing your code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you find yourself running up an entire application more than once or twice to test a particular&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;method you've written, wrap it in a unit test and use that test to invoke it directly&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;^R ^T is your friend&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When someone comes to you with a bug report, write a test to reproduce the bug.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key Principles for Unit Tests&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Each and every test must be able to be run in isolation  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Tests should the environment up for themselves and clean up afterwards  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use your ClassInitialize, ClassCleanup, TestInitialize and TestCleanup attributes&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tests should never rely on being executed in any particular order (that's part of the meaning of "unit")&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tests should not rely overmuch on their environment  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Don't depend on files' being anywhere&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;span style="color:#ff0000;"&gt;Never, ever, ever hard-code a path. Find a better way.&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;span style="color:#ff0000;"&gt;For the Zap crowd: anyone who codes "C:\Projects" into a unit test (again!) is going to get a swift kicking. Politely, of course :)&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If a class depends on another class that depends on another class that you can't easily instantiate in your unit test, this suggests that your classes need refactoring. Writing tests should be easy. If your classes make it hard, fix your classes first.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tests should be cheap to write  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Don't worry about exception-handling - if an unexpected exception is thrown, the test fails. Don't bother catching it and manually asserting failure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Be as explicit as you can  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Don't allow for variations in your output unless you absolutely have to.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If there are going to be different outputs, ideally there should be different tests&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tests should be numerous and cheap to maintain  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Each test should test one (perhaps two or three, but generally just one) behaviour&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It's much better to have lots of small tests that check individual functionality rather than fewer, complex tests that test many things.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When a test breaks, we want to know exactly where the problem is, not just that there's a problem somewhere in a call stack seven classes deep.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tests should be disposable  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;When the code it tests is gone, the test should be dropped on the floor.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If it's a simple, obvious test, it will be simple and obvious to identify when this should happen.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tests need not be efficient&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cool Stuff&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Private Accessors  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;These allow you to call private methods and access private variables from another class&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This deliberately breaks OO principles&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use it for testing implementation-specific stuff, but depend on concrete types when you do.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_RlpLqbhdTdM/SSunuUIDvDI/AAAAAAAAZ-s/c92dCUHBpVA/s1600-h/clip_image001%5B3%5D.png"&gt;&lt;img style="display:inline;border-width:0;" title="clip_image001" src="http://lh3.ggpht.com/_RlpLqbhdTdM/SSunxVMmKvI/AAAAAAAAZ-0/CtRQDDsh4JY/clip_image001_thumb.png?imgmax=800" border="0" alt="clip_image001" width="244" height="84" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ASPX page testing  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You can automate all sorts of stuff with respect to ASPX pages&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Button clicks&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Form inputs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_RlpLqbhdTdM/SSunzCKsgZI/AAAAAAAAZ-8/jJI7YY5cXj0/s1600-h/clip_image002%5B3%5D.png"&gt;&lt;img style="display:inline;border-width:0;" title="clip_image002" src="http://lh4.ggpht.com/_RlpLqbhdTdM/SSun06bdiFI/AAAAAAAAZ_E/mfL-MMEJYnI/clip_image002_thumb.png?imgmax=800" border="0" alt="clip_image002" width="244" height="59" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This does not replace regression test automation (e.g. Mercury et al), but should be used by individual developers when writing new ASPX pages and ASCX controls.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don't run the application and click stuff manually&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Write a unit test and tell it to click stuff automatically&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Testing web service methods  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The unit test framework will get confused&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use either a wrapper (think Adapter or Façade pattern) and/or a Strategy-pattern.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using the unit testing framework for integration testing  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have a couple of common-case "unit" tests that actually represent an end-to-end use case of your application.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note for young players: if you get an invalid cast exception such as...  &lt;/p&gt;

&lt;p&gt;Test method Test.Zap.CubeModel.DigitalSearchTreeTest.TestInsert threw exception: System.InvalidCastException: Unable to cast object of type 'Node`1[System.Char,System.Char]' to type 'Node`1[System.Char,System.Char]'..  &lt;/p&gt;

&lt;p&gt;...it may be that your type is a nested class or similar and does not have public visibility.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/X7z2X8bTplo" height="1" width="1"/&gt;</description><pubDate>Fri, 04 Jul 2008 09:42:00 +1000</pubDate><a10:updated>2008-07-04T09:42:00+10:00</a10:updated><a10:content type="xhtml"><p><strong>Writing Unit Tests</strong>  </p>

<ul>
<li><p>Why do we write unit tests?  </p>

<ul>
<li><p>Improve code quality</p></li>
<li><p>Fewer reported defects</p></li>
<li><p>Make checking code faster</p></li>
<li><p>Tell us when we've broken something</p></li>
<li><p>Tell us when our work is done</p></li>
<li><p>Allow others to check our code</p></li>
<li><p>Encourage modular design</p></li>
<li><p>Keep behaviour constant during refactoring Functions as a spec (think TDD)</p></li>
</ul></li>
<li><p>The law of diminishing returns most definitely applies here  </p>

<ul>
<li><p>Testing everything is infeasible. Don't be unrealistic.</p></li>
<li><p>70% code coverage is actually pretty decent for most classes.</p></li>
<li><p>First, test the common stuff.</p></li>
<li><p>Next, test the common exception-case stuff.</p></li>
<li><p>Then test the critical stuff.</p></li>
<li><p>Add other tests as appropriate.</p></li>
</ul></li>
<li><p>When to write a unit test  </p>

<ul>
<li><p>Use a unit test to provide a framework for writing your code</p></li>
<li><p>If you find yourself running up an entire application more than once or twice to test a particular</p></li>
<li><p>method you've written, wrap it in a unit test and use that test to invoke it directly</p></li>
<li><p>^R ^T is your friend</p></li>
<li><p>When someone comes to you with a bug report, write a test to reproduce the bug.</p></li>
</ul></li>
</ul>

<p><strong>Key Principles for Unit Tests</strong>  </p>

<ul>
<li><p>Each and every test must be able to be run in isolation  </p>

<ul>
<li><p>Tests should the environment up for themselves and clean up afterwards  </p>

<ul>
<li>Use your ClassInitialize, ClassCleanup, TestInitialize and TestCleanup attributes</li>
</ul></li>
<li><p>Tests should never rely on being executed in any particular order (that's part of the meaning of "unit")</p></li>
<li><p>Tests should not rely overmuch on their environment  </p>

<ul>
<li><p>Don't depend on files' being anywhere</p></li>
<li><p><span style="color:#ff0000;">Never, ever, ever hard-code a path. Find a better way.</span></p></li>
<li><p><span style="color:#ff0000;">For the Zap crowd: anyone who codes "C:\Projects" into a unit test (again!) is going to get a swift kicking. Politely, of course :)</span></p></li>
</ul></li>
<li><p>If a class depends on another class that depends on another class that you can't easily instantiate in your unit test, this suggests that your classes need refactoring. Writing tests should be easy. If your classes make it hard, fix your classes first.</p></li>
</ul></li>
<li><p>Tests should be cheap to write  </p>

<ul>
<li><p>Don't worry about exception-handling - if an unexpected exception is thrown, the test fails. Don't bother catching it and manually asserting failure.</p></li>
<li><p>Be as explicit as you can  </p>

<ul>
<li><p>Don't allow for variations in your output unless you absolutely have to.</p></li>
<li><p>If there are going to be different outputs, ideally there should be different tests</p></li>
</ul></li>
</ul></li>
<li><p>Tests should be numerous and cheap to maintain  </p>

<ul>
<li><p>Each test should test one (perhaps two or three, but generally just one) behaviour</p></li>
<li><p>It's much better to have lots of small tests that check individual functionality rather than fewer, complex tests that test many things.</p></li>
<li><p>When a test breaks, we want to know exactly where the problem is, not just that there's a problem somewhere in a call stack seven classes deep.</p></li>
</ul></li>
<li><p>Tests should be disposable  </p>

<ul>
<li><p>When the code it tests is gone, the test should be dropped on the floor.</p></li>
<li><p>If it's a simple, obvious test, it will be simple and obvious to identify when this should happen.</p></li>
</ul></li>
<li><p>Tests need not be efficient</p></li>
</ul>

<p><strong>Cool Stuff</strong>  </p>

<ul>
<li><p>Private Accessors  </p>

<ul>
<li><p>These allow you to call private methods and access private variables from another class</p></li>
<li><p>This deliberately breaks OO principles</p></li>
<li><p>Use it for testing implementation-specific stuff, but depend on concrete types when you do.</p></li>
</ul></li>
<li><p><a href="http://lh4.ggpht.com/_RlpLqbhdTdM/SSunuUIDvDI/AAAAAAAAZ-s/c92dCUHBpVA/s1600-h/clip_image001%5B3%5D.png"><img style="display:inline;border-width:0;" title="clip_image001" src="http://lh3.ggpht.com/_RlpLqbhdTdM/SSunxVMmKvI/AAAAAAAAZ-0/CtRQDDsh4JY/clip_image001_thumb.png?imgmax=800" border="0" alt="clip_image001" width="244" height="84" /></a></p></li>
<li><p>ASPX page testing  </p>

<ul>
<li><p>You can automate all sorts of stuff with respect to ASPX pages</p></li>
<li><p>Button clicks</p></li>
<li><p>Form inputs</p></li>
<li><p><a href="http://lh4.ggpht.com/_RlpLqbhdTdM/SSunzCKsgZI/AAAAAAAAZ-8/jJI7YY5cXj0/s1600-h/clip_image002%5B3%5D.png"><img style="display:inline;border-width:0;" title="clip_image002" src="http://lh4.ggpht.com/_RlpLqbhdTdM/SSun06bdiFI/AAAAAAAAZ_E/mfL-MMEJYnI/clip_image002_thumb.png?imgmax=800" border="0" alt="clip_image002" width="244" height="59" /></a></p></li>
<li><p>This does not replace regression test automation (e.g. Mercury et al), but should be used by individual developers when writing new ASPX pages and ASCX controls.</p></li>
<li><p>Don't run the application and click stuff manually</p></li>
<li><p>Write a unit test and tell it to click stuff automatically</p></li>
</ul></li>
<li><p>Testing web service methods  </p>

<ul>
<li><p>The unit test framework will get confused</p></li>
<li><p>Use either a wrapper (think Adapter or Façade pattern) and/or a Strategy-pattern.</p></li>
</ul></li>
<li><p>Using the unit testing framework for integration testing  </p>

<ul>
<li>Have a couple of common-case "unit" tests that actually represent an end-to-end use case of your application.</li>
</ul></li>
</ul>

<p>Note for young players: if you get an invalid cast exception such as...  </p>

<p>Test method Test.Zap.CubeModel.DigitalSearchTreeTest.TestInsert threw exception: System.InvalidCastException: Unable to cast object of type 'Node`1[System.Char,System.Char]' to type 'Node`1[System.Char,System.Char]'..  </p>

<p>...it may be that your type is a nested class or similar and does not have public visibility.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2008.07.04.0942</feedburner:origLink></item><item xml:base="Home/Post/2008.06.13.0814"><guid isPermaLink="false">2008.06.13.0814</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/uBZMtZY4NYw/2008.06.13.0814</link><author>andrewh@uglybugger.org</author><title>Code Snippet for WPF Routed Event</title><description>&lt;p&gt;It's useful for me. Your mileage may vary. I wouldn't mind knowing if it's useful for anyone else, though :)&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8" ?&amp;gt;
&amp;lt;CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"&amp;gt;
  &amp;lt;CodeSnippet Format="1.0.0"&amp;gt;
    &amp;lt;Header&amp;gt;
      &amp;lt;Title&amp;gt;eventr&amp;lt;/Title&amp;gt;
      &amp;lt;Shortcut&amp;gt;eventr&amp;lt;/Shortcut&amp;gt;
      &amp;lt;Description&amp;gt;Code snippet for a WPF Routed Event&amp;lt;/Description&amp;gt;
      &amp;lt;Author&amp;gt;Andrew Harcourt&amp;lt;/Author&amp;gt;
      &amp;lt;SnippetTypes&amp;gt;
        &amp;lt;SnippetType&amp;gt;Expansion&amp;lt;/SnippetType&amp;gt;
        &amp;lt;SnippetType&amp;gt;SurroundsWith&amp;lt;/SnippetType&amp;gt;
      &amp;lt;/SnippetTypes&amp;gt;
    &amp;lt;/Header&amp;gt;
    &amp;lt;Snippet&amp;gt;
      &amp;lt;Declarations&amp;gt;
        &amp;lt;Literal&amp;gt;
          &amp;lt;ID&amp;gt;eventName&amp;lt;/ID&amp;gt;
          &amp;lt;ToolTip&amp;gt;The name of the routed property (should *end* in ...Event).&amp;lt;/ToolTip&amp;gt;
          &amp;lt;Default&amp;gt;Stupid&amp;lt;/Default&amp;gt;
        &amp;lt;/Literal&amp;gt;
        &amp;lt;Literal Editable="false"&amp;gt;
          &amp;lt;ID&amp;gt;className&amp;lt;/ID&amp;gt;
          &amp;lt;ToolTip&amp;gt;The type of the owning class.&amp;lt;/ToolTip&amp;gt;
          &amp;lt;Function&amp;gt;ClassName()&amp;lt;/Function&amp;gt;
          &amp;lt;Default&amp;gt;StupidClass&amp;lt;/Default&amp;gt;
        &amp;lt;/Literal&amp;gt;
      &amp;lt;/Declarations&amp;gt;
      &amp;lt;Code Language="csharp"&amp;gt;
        &amp;lt;![CDATA[#region $eventName$ Routed Event

        public static readonly RoutedEvent $eventName$Event = EventManager.RegisterRoutedEvent(
            "$eventName$",
            RoutingStrategy.Bubble,
            typeof(RoutedEventHandler),
            typeof($className$));

        public event RoutedEventHandler $eventName$
        {
            add { AddHandler($eventName$Event, value); }
            remove { RemoveHandler($eventName$Event, value); }
        }

        /// &amp;lt;summary&amp;gt;
        /// Invoke this method when you wish to raise a(n) $eventName$ event
        /// &amp;lt;/summary&amp;gt;
        private void Raise$eventName$Event()
        {
            RoutedEventArgs newEventArgs = new RoutedEventArgs($className$.$eventName$Event);
            RaiseEvent(newEventArgs);
        }

        #endregion]]&amp;gt;
      &amp;lt;/Code&amp;gt;
    &amp;lt;/Snippet&amp;gt;
  &amp;lt;/CodeSnippet&amp;gt;
&amp;lt;/CodeSnippets&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/uBZMtZY4NYw" height="1" width="1"/&gt;</description><pubDate>Fri, 13 Jun 2008 08:14:00 +1000</pubDate><a10:updated>2008-06-13T08:14:00+10:00</a10:updated><a10:content type="xhtml"><p>It's useful for me. Your mileage may vary. I wouldn't mind knowing if it's useful for anyone else, though :)</p>

<pre><code>&lt;?xml version="1.0" encoding="utf-8" ?&gt;
&lt;CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"&gt;
  &lt;CodeSnippet Format="1.0.0"&gt;
    &lt;Header&gt;
      &lt;Title&gt;eventr&lt;/Title&gt;
      &lt;Shortcut&gt;eventr&lt;/Shortcut&gt;
      &lt;Description&gt;Code snippet for a WPF Routed Event&lt;/Description&gt;
      &lt;Author&gt;Andrew Harcourt&lt;/Author&gt;
      &lt;SnippetTypes&gt;
        &lt;SnippetType&gt;Expansion&lt;/SnippetType&gt;
        &lt;SnippetType&gt;SurroundsWith&lt;/SnippetType&gt;
      &lt;/SnippetTypes&gt;
    &lt;/Header&gt;
    &lt;Snippet&gt;
      &lt;Declarations&gt;
        &lt;Literal&gt;
          &lt;ID&gt;eventName&lt;/ID&gt;
          &lt;ToolTip&gt;The name of the routed property (should *end* in ...Event).&lt;/ToolTip&gt;
          &lt;Default&gt;Stupid&lt;/Default&gt;
        &lt;/Literal&gt;
        &lt;Literal Editable="false"&gt;
          &lt;ID&gt;className&lt;/ID&gt;
          &lt;ToolTip&gt;The type of the owning class.&lt;/ToolTip&gt;
          &lt;Function&gt;ClassName()&lt;/Function&gt;
          &lt;Default&gt;StupidClass&lt;/Default&gt;
        &lt;/Literal&gt;
      &lt;/Declarations&gt;
      &lt;Code Language="csharp"&gt;
        &lt;![CDATA[#region $eventName$ Routed Event

        public static readonly RoutedEvent $eventName$Event = EventManager.RegisterRoutedEvent(
            "$eventName$",
            RoutingStrategy.Bubble,
            typeof(RoutedEventHandler),
            typeof($className$));

        public event RoutedEventHandler $eventName$
        {
            add { AddHandler($eventName$Event, value); }
            remove { RemoveHandler($eventName$Event, value); }
        }

        /// &lt;summary&gt;
        /// Invoke this method when you wish to raise a(n) $eventName$ event
        /// &lt;/summary&gt;
        private void Raise$eventName$Event()
        {
            RoutedEventArgs newEventArgs = new RoutedEventArgs($className$.$eventName$Event);
            RaiseEvent(newEventArgs);
        }

        #endregion]]&gt;
      &lt;/Code&gt;
    &lt;/Snippet&gt;
  &lt;/CodeSnippet&gt;
&lt;/CodeSnippets&gt;
</code></pre>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2008.06.13.0814</feedburner:origLink></item><item xml:base="Home/Post/2008.05.01.0254"><guid isPermaLink="false">2008.05.01.0254</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/N5yFy6satHk/2008.05.01.0254</link><author>andrewh@uglybugger.org</author><title>Windows Communication Foundation Introduction</title><description>&lt;p&gt;Here's a very (very!) quick WCF overview I prepared the other day for the team at Zap. It's intended as a soldier's five on the topic; no more and no less.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Service Contracts and Operation Contracts&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;This is what your WCF service promises faithfully to do for its callers.  &lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_RlpLqbhdTdM/SSulbNwKMOI/AAAAAAAAZ8s/Zra9QhK6BvQ/s1600-h/image%5B4%5D.png"&gt;&lt;img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="image" src="http://lh6.ggpht.com/_RlpLqbhdTdM/SSulcv2cZtI/AAAAAAAAZ80/q-o8PoOK6XE/image_thumb%5B2%5D.png?imgmax=800" border="0" alt="image" width="404" height="350" /&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data Contracts&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;These are the data types that your WCF service expects its callers to understand. Thankfully, it will happily explain these data types to its callers.  &lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_RlpLqbhdTdM/SSuleHAgyHI/AAAAAAAAZ88/3x6u-x_Lh-I/s1600-h/clip_image002%5B4%5D.png"&gt;&lt;img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="clip_image002" src="http://lh3.ggpht.com/_RlpLqbhdTdM/SSulfthFnUI/AAAAAAAAZ9E/Ap03SAa5xFE/clip_image002_thumb%5B1%5D.png?imgmax=800" border="0" alt="clip_image002" width="404" height="312" /&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Events (... or "Duplex Contracts")&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;Out of scope for this presentation, but see &lt;a href="http://msdn.microsoft.com/en-us/library/ms731184.aspx"&gt;http://msdn.microsoft.com/en-us/library/ms731184.aspx&lt;/a&gt; for a pretty decent explanation.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hosting Your WCF Service&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_RlpLqbhdTdM/SSulhEZNMDI/AAAAAAAAZ9M/gnJFpljlFqo/s1600-h/clip_image003%5B4%5D.png"&gt;&lt;img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="clip_image003" src="http://lh4.ggpht.com/_RlpLqbhdTdM/SSulilE6DdI/AAAAAAAAZ9U/7alL9hwcuFo/clip_image003_thumb%5B1%5D.png?imgmax=800" border="0" alt="clip_image003" width="404" height="124" /&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Note the endpoint address:  &lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_RlpLqbhdTdM/SSulkaQ1jKI/AAAAAAAAZ9c/ObFgkzEroEM/s1600-h/clip_image004%5B4%5D.png"&gt;&lt;img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="clip_image004" src="http://lh4.ggpht.com/_RlpLqbhdTdM/SSull2mZjTI/AAAAAAAAZ9k/H_7NPuWyb6Q/clip_image004_thumb%5B1%5D.png?imgmax=800" border="0" alt="clip_image004" width="404" height="257" /&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adding a service reference to your project&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;The metadata exchange address is the equivalent of the old Web Service Definition Language (WSDL) address.  &lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_RlpLqbhdTdM/SSuln1sGsqI/AAAAAAAAZ9s/T9AkhVT-D-U/s1600-h/clip_image005%5B4%5D.png"&gt;&lt;img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="clip_image005" src="http://lh4.ggpht.com/_RlpLqbhdTdM/SSulplHm8CI/AAAAAAAAZ90/jNq9dt5P9Ds/clip_image005_thumb%5B1%5D.png?imgmax=800" border="0" alt="clip_image005" width="404" height="329" /&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Calling the WCF Service&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;Call it just as you would your local methods.  &lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_RlpLqbhdTdM/SSulrMHss2I/AAAAAAAAZ98/I1IYrTYxocY/s1600-h/clip_image006%5B4%5D.png"&gt;&lt;img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="clip_image006" src="http://lh6.ggpht.com/_RlpLqbhdTdM/SSultF9muuI/AAAAAAAAZ-E/5yAcOkUD6iU/clip_image006_thumb%5B1%5D.png?imgmax=800" border="0" alt="clip_image006" width="404" height="366" /&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;It's that easy.  &lt;/p&gt;

&lt;p&gt;Purely for edification, this is what some of the generated code looks like:  &lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_RlpLqbhdTdM/SSuluyOm4XI/AAAAAAAAZ-M/GeyLgNvMqJw/s1600-h/clip_image007%5B4%5D.png"&gt;&lt;img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="clip_image007" src="http://lh5.ggpht.com/_RlpLqbhdTdM/SSulwQQYZAI/AAAAAAAAZ-U/RHh3wjYMP4g/clip_image007_thumb%5B1%5D.png?imgmax=800" border="0" alt="clip_image007" width="404" height="306" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/N5yFy6satHk" height="1" width="1"/&gt;</description><pubDate>Thu, 01 May 2008 02:54:00 +1000</pubDate><a10:updated>2008-05-01T02:54:00+10:00</a10:updated><a10:content type="xhtml"><p>Here's a very (very!) quick WCF overview I prepared the other day for the team at Zap. It's intended as a soldier's five on the topic; no more and no less.  </p>

<p><strong>Service Contracts and Operation Contracts</strong>  </p>

<p>This is what your WCF service promises faithfully to do for its callers.  </p>

<p><a href="http://lh6.ggpht.com/_RlpLqbhdTdM/SSulbNwKMOI/AAAAAAAAZ8s/Zra9QhK6BvQ/s1600-h/image%5B4%5D.png"><img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="image" src="http://lh6.ggpht.com/_RlpLqbhdTdM/SSulcv2cZtI/AAAAAAAAZ80/q-o8PoOK6XE/image_thumb%5B2%5D.png?imgmax=800" border="0" alt="image" width="404" height="350" /></a>  </p>

<p><strong>Data Contracts</strong>  </p>

<p>These are the data types that your WCF service expects its callers to understand. Thankfully, it will happily explain these data types to its callers.  </p>

<p><a href="http://lh4.ggpht.com/_RlpLqbhdTdM/SSuleHAgyHI/AAAAAAAAZ88/3x6u-x_Lh-I/s1600-h/clip_image002%5B4%5D.png"><img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="clip_image002" src="http://lh3.ggpht.com/_RlpLqbhdTdM/SSulfthFnUI/AAAAAAAAZ9E/Ap03SAa5xFE/clip_image002_thumb%5B1%5D.png?imgmax=800" border="0" alt="clip_image002" width="404" height="312" /></a>  </p>

<p><strong>Events (... or "Duplex Contracts")</strong>  </p>

<p>Out of scope for this presentation, but see <a href="http://msdn.microsoft.com/en-us/library/ms731184.aspx">http://msdn.microsoft.com/en-us/library/ms731184.aspx</a> for a pretty decent explanation.  </p>

<p><strong>Hosting Your WCF Service</strong>  </p>

<p><a href="http://lh5.ggpht.com/_RlpLqbhdTdM/SSulhEZNMDI/AAAAAAAAZ9M/gnJFpljlFqo/s1600-h/clip_image003%5B4%5D.png"><img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="clip_image003" src="http://lh4.ggpht.com/_RlpLqbhdTdM/SSulilE6DdI/AAAAAAAAZ9U/7alL9hwcuFo/clip_image003_thumb%5B1%5D.png?imgmax=800" border="0" alt="clip_image003" width="404" height="124" /></a>  </p>

<p>Note the endpoint address:  </p>

<p><a href="http://lh6.ggpht.com/_RlpLqbhdTdM/SSulkaQ1jKI/AAAAAAAAZ9c/ObFgkzEroEM/s1600-h/clip_image004%5B4%5D.png"><img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="clip_image004" src="http://lh4.ggpht.com/_RlpLqbhdTdM/SSull2mZjTI/AAAAAAAAZ9k/H_7NPuWyb6Q/clip_image004_thumb%5B1%5D.png?imgmax=800" border="0" alt="clip_image004" width="404" height="257" /></a>  </p>

<p><strong>Adding a service reference to your project</strong>  </p>

<p>The metadata exchange address is the equivalent of the old Web Service Definition Language (WSDL) address.  </p>

<p><a href="http://lh5.ggpht.com/_RlpLqbhdTdM/SSuln1sGsqI/AAAAAAAAZ9s/T9AkhVT-D-U/s1600-h/clip_image005%5B4%5D.png"><img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="clip_image005" src="http://lh4.ggpht.com/_RlpLqbhdTdM/SSulplHm8CI/AAAAAAAAZ90/jNq9dt5P9Ds/clip_image005_thumb%5B1%5D.png?imgmax=800" border="0" alt="clip_image005" width="404" height="329" /></a>  </p>

<p><strong>Calling the WCF Service</strong>  </p>

<p>Call it just as you would your local methods.  </p>

<p><a href="http://lh4.ggpht.com/_RlpLqbhdTdM/SSulrMHss2I/AAAAAAAAZ98/I1IYrTYxocY/s1600-h/clip_image006%5B4%5D.png"><img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="clip_image006" src="http://lh6.ggpht.com/_RlpLqbhdTdM/SSultF9muuI/AAAAAAAAZ-E/5yAcOkUD6iU/clip_image006_thumb%5B1%5D.png?imgmax=800" border="0" alt="clip_image006" width="404" height="366" /></a>  </p>

<p>It's that easy.  </p>

<p>Purely for edification, this is what some of the generated code looks like:  </p>

<p><a href="http://lh5.ggpht.com/_RlpLqbhdTdM/SSuluyOm4XI/AAAAAAAAZ-M/GeyLgNvMqJw/s1600-h/clip_image007%5B4%5D.png"><img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="clip_image007" src="http://lh5.ggpht.com/_RlpLqbhdTdM/SSulwQQYZAI/AAAAAAAAZ-U/RHh3wjYMP4g/clip_image007_thumb%5B1%5D.png?imgmax=800" border="0" alt="clip_image007" width="404" height="306" /></a></p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2008.05.01.0254</feedburner:origLink></item><item xml:base="Home/Post/2008.03.25.0449"><guid isPermaLink="false">2008.03.25.0449</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/lLOUgdGzmwE/2008.03.25.0449</link><author>andrewh@uglybugger.org</author><title>Common Assembly Attributes</title><description>&lt;p&gt;... or, "What's that SolutionInfo.cs thingy for?"  &lt;/p&gt;

&lt;p&gt;&lt;a href="http://bloggingabout.net/blogs/jschreuder/archive/2006/11/02/Centralizing-AssemblyInfo-settings_2C00_-or-simplify-versioning-of-solutions.aspx"&gt;http://bloggingabout.net/blogs/jschreuder/archive/2006/11/02/Centralizing-AssemblyInfo-settings_2C00_-or-simplify-versioning-of-solutions.aspx&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/lLOUgdGzmwE" height="1" width="1"/&gt;</description><pubDate>Tue, 25 Mar 2008 04:49:00 +1000</pubDate><a10:updated>2008-03-25T04:49:00+10:00</a10:updated><a10:content type="xhtml"><p>... or, "What's that SolutionInfo.cs thingy for?"  </p>

<p><a href="http://bloggingabout.net/blogs/jschreuder/archive/2006/11/02/Centralizing-AssemblyInfo-settings_2C00_-or-simplify-versioning-of-solutions.aspx">http://bloggingabout.net/blogs/jschreuder/archive/2006/11/02/Centralizing-AssemblyInfo-settings_2C00_-or-simplify-versioning-of-solutions.aspx</a></p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2008.03.25.0449</feedburner:origLink></item><item xml:base="Home/Post/2008.03.25.0446"><guid isPermaLink="false">2008.03.25.0446</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/FQ2vVEZpQjo/2008.03.25.0446</link><author>andrewh@uglybugger.org</author><title>“The trust relationship between the primary domain and the trusted domain failed.”</title><description>&lt;p&gt;This error will occur for many reasons. If you've arrived at this blog, however, the odds are that you're searching for something .NET-related, possibly even a provider-related issue.  &lt;/p&gt;

&lt;p&gt;A .NET provider specified in a web.config file has its status set to enabled=false by default. Don't ask me why.  &lt;/p&gt;

&lt;p&gt;This problem, when using a custom role provider, might manifest as the above error. Very frustrating, as none of the Google results I've seen will mention this particular cause of this error, anything about how to actually fix it.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/FQ2vVEZpQjo" height="1" width="1"/&gt;</description><pubDate>Tue, 25 Mar 2008 04:46:00 +1000</pubDate><a10:updated>2008-03-25T04:46:00+10:00</a10:updated><a10:content type="xhtml"><p>This error will occur for many reasons. If you've arrived at this blog, however, the odds are that you're searching for something .NET-related, possibly even a provider-related issue.  </p>

<p>A .NET provider specified in a web.config file has its status set to enabled=false by default. Don't ask me why.  </p>

<p>This problem, when using a custom role provider, might manifest as the above error. Very frustrating, as none of the Google results I've seen will mention this particular cause of this error, anything about how to actually fix it.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2008.03.25.0446</feedburner:origLink></item><item xml:base="Home/Post/2008.03.24.0449"><guid isPermaLink="false">2008.03.24.0449</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/1joUmOBC470/2008.03.24.0449</link><author>andrewh@uglybugger.org</author><title>Using DBML/LINQ to Generate WCF DataContracts</title><description>&lt;p&gt;Yes, you can actually use the DBML editor to generate classes tagged with the WCF DataContract attribute.  &lt;/p&gt;

&lt;p&gt;.NET 3.5 rocks.  &lt;/p&gt;

&lt;p&gt;&lt;a href="http://blogs.msdn.com/wriju/archive/2007/11/27/linq-to-sql-enabling-dbml-file-for-wcf.aspx"&gt;http://blogs.msdn.com/wriju/archive/2007/11/27/linq-to-sql-enabling-dbml-file-for-wcf.aspx&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/1joUmOBC470" height="1" width="1"/&gt;</description><pubDate>Mon, 24 Mar 2008 04:49:00 +1000</pubDate><a10:updated>2008-03-24T04:49:00+10:00</a10:updated><a10:content type="xhtml"><p>Yes, you can actually use the DBML editor to generate classes tagged with the WCF DataContract attribute.  </p>

<p>.NET 3.5 rocks.  </p>

<p><a href="http://blogs.msdn.com/wriju/archive/2007/11/27/linq-to-sql-enabling-dbml-file-for-wcf.aspx">http://blogs.msdn.com/wriju/archive/2007/11/27/linq-to-sql-enabling-dbml-file-for-wcf.aspx</a></p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2008.03.24.0449</feedburner:origLink></item><item xml:base="Home/Post/2008.02.14.0452"><guid isPermaLink="false">2008.02.14.0452</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/Y1H79BkpAbc/2008.02.14.0452</link><author>andrewh@uglybugger.org</author><title>WPF Context Menu Doesn't Display on First Load</title><description>&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;When using WPF OnContextMenuOpening, ContextMenu doesn't display on first load.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The reason:&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;The OnContextMenuOpening routed event is used for dynamically creating a ContextMenu object for a particular UIElement.  &lt;/p&gt;

&lt;p&gt;Each UIElement has a ContextMenu property which dictates what gets displayed when a user right-clicks on it. If the property is null, nothing will be displayed. If the property is not null, the context menu that it references will be displayed.  &lt;/p&gt;

&lt;p&gt;The catch? The ContextMenu property must not be null before the event handler first fires, or the menu won't load. This appears to be a WPF bug, but it's a pain either way.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The solution:&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;Create an empty ContextMenu object and assign it to each UIElement that's going to have any context menu displayed. In the OnContextMenuOpening event, either Clear() the existing context menu or just create a new one and assign the property to the object reference. Either will work.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/Y1H79BkpAbc" height="1" width="1"/&gt;</description><pubDate>Thu, 14 Feb 2008 04:52:00 +1000</pubDate><a10:updated>2008-02-14T04:52:00+10:00</a10:updated><a10:content type="xhtml"><p><strong>The problem:</strong>  </p>

<p>When using WPF OnContextMenuOpening, ContextMenu doesn't display on first load.  </p>

<p><strong>The reason:</strong>  </p>

<p>The OnContextMenuOpening routed event is used for dynamically creating a ContextMenu object for a particular UIElement.  </p>

<p>Each UIElement has a ContextMenu property which dictates what gets displayed when a user right-clicks on it. If the property is null, nothing will be displayed. If the property is not null, the context menu that it references will be displayed.  </p>

<p>The catch? The ContextMenu property must not be null before the event handler first fires, or the menu won't load. This appears to be a WPF bug, but it's a pain either way.  </p>

<p><strong>The solution:</strong>  </p>

<p>Create an empty ContextMenu object and assign it to each UIElement that's going to have any context menu displayed. In the OnContextMenuOpening event, either Clear() the existing context menu or just create a new one and assign the property to the object reference. Either will work.</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2008.02.14.0452</feedburner:origLink></item><item xml:base="Home/Post/2001.04.02.0732"><guid isPermaLink="false">2001.04.02.0732</guid><link>http://feedproxy.google.com/~r/CodingForFunAndProfit/~3/QUN0gWfjzHo/2001.04.02.0732</link><author>andrewh@uglybugger.org</author><title>Fetchmail Multidrop</title><description>&lt;h1&gt;Disclaimer: This is an OLD, OLD blog post.&lt;/h1&gt;

&lt;h1&gt;I shudder to think how much this PERL code looks like it was written by a C programmer...&lt;/h1&gt;

&lt;p&gt;If you still find it useful, great. If you'd like to mess with the code, great too. If you're really
annoyed with fetchmail and it doesn't already have this feature built in, why not change the fetchmail
code yourself and submit it to the maintainers? :)  &lt;/p&gt;

&lt;p&gt;Why don't I? Because I wanted to learn PERL...  &lt;/p&gt;

&lt;p&gt;I recently had some trouble with fetchmail and multidrop mailboxes. fetchmail handles mail well when a
local address is found in the To: field of an email, but badly when it has to extract address information
from the other headers of an email. In particular, people on the BCC list of an email (and who never
appear in "official" mail headers) are likely to never receive emails addressed to them when handled via
fetchmail with a multidrop mailbox.  &lt;/p&gt;

&lt;p&gt;I was also looking for an excuse to learn PERL (08/2004 update: wow, this page really &lt;em&gt;is&lt;/em&gt; old...).  &lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.qmail.org"&gt;qmail&lt;/a&gt; has a nice solution where it inserts an &lt;strong&gt;Delivered-To:&lt;/strong&gt; line into the mail headers. For
virtual hosts, it prepends the domain name to the email account it was delivered to. My domain is
uglybugger.org, so when the MX host for mail.uglybugger.org accepts mail for me, it dumps it into a
single account. The headers it inserts look like this:  &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Return-Path: Andrew.Harcourt@team.telstra.com
Delivered-To: uglybugger.org%uglybugger@uglybugger.org
Received: (cpmta 5066 invoked from network); 2 Apr 2001 21:59:52 -0700
Delivered-To: uglybugger.org%andrewh@uglybugger.org
Received: (cpmta 5062 invoked from network); 2 Apr 2001 21:59:51 -0700
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Read this from the bottom up. You'll see that the first &lt;strong&gt;Delivered-To:&lt;/strong&gt; line reads &lt;strong&gt;uglybugger.org%andrewh@uglybugger.org&lt;/strong&gt;
and the second &lt;strong&gt;Delivered-To:&lt;/strong&gt; line reads &lt;strong&gt;uglybugger.org%uglybugger@uglybugger.org&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;fetchmail can be configured to read &lt;em&gt;envelope addresses&lt;/em&gt;. These are the addresses (such as the
&lt;strong&gt;Delivered-To:&lt;/strong&gt; line) that mail servers include in mail headers to record which &lt;em&gt;account&lt;/em&gt; the
mail was delivered to. This is an important distinction from which &lt;em&gt;address&lt;/em&gt; the mail was intended for.
You can tell fetchmail to use these headers by specifying the following in your .fetchmailrc file:  &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;envelope "Delivered-To:"
qvirtual "uglybugger.org%"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Obviously, please change the qvirtual line to read your domain :)  &lt;/p&gt;

&lt;p&gt;The problem here is that fetchmail will only read headers top-down, and it matches the first one it finds. This
breaks the &lt;em&gt;envelope&lt;/em&gt;/&lt;em&gt;qvirtual&lt;/em&gt; delivery process completely as fetchmail is unable to ignore the first line it
receives. So if the &lt;em&gt;envelope&lt;/em&gt;/&lt;em&gt;qvirtual&lt;/em&gt; settings do not solve your problem, read on.&lt;/p&gt;

&lt;p&gt;What we need to do is specify an alternate delivery agent, so that we can handle our processing ourselves. You
can do this by specifying an external Mail Delivery Agent for fetchmail. Use the &lt;em&gt;mda&lt;/em&gt; keyword to point mail to
a script that you can copy and paste from here:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;----- /usr/sbin/fetchmail-inject ----------
#!/usr/bin/perl
# fetchmail-inject
# Andrew Harcourt, 1 May, 2001
#
# this script removes a nasty header that fetchmail can't handle
# from incoming mail and then passes the mail to sendmail to
# deliver locally

# write the mail to a temp file on disk
# as we do, parse it for the address
# lines
local($outputName, $fromAddress, $toAddress, $cmd);

$outputName = "/tmp/message.".$$;
open(OUTFILE,"&amp;gt; ".$outputName)
        || die "could not open $outputName!";

while (&amp;amp;ltSTDIN&amp;amp;gt) {
        if (/^Delivered-To: uglybugger\.org\%uglybugger\@uglybugger\.org/) {
                # just ignore this line - it's ugly
        }
        elsif (/^Delivered-To: uglybugger\.org\%(.*)\@uglybugger.org/) {
                $toAddress = $1."\@uglybugger.org";
        }
        elsif (/^From: .* /) {
                $fromAddress = $1;
        }
        elsif (/^From: /) {
                $fromAddress = $1;
        }
        elsif (/^From: .*/) {
                $fromAddress = $1
        }
        print OUTFILE $_;
}

close(OUTFILE);

# check that we have our addresses correct
if ($toAddress eq "") {
        $toAddress = "postmaster\@uglybugger.org";
}
if ($fromAddress eq "") {
        $fromAddress = "postmaster\@uglybugger.org";
}

# now call sendmail to deliver the message
$cmd = "/usr/sbin/sendmail -f $fromAddress $toAddress &amp;lt; $outputName";
system($cmd);
-------------------------------------------
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Good luck :)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CodingForFunAndProfit/~4/QUN0gWfjzHo" height="1" width="1"/&gt;</description><pubDate>Mon, 02 Apr 2001 07:32:00 +1000</pubDate><a10:updated>2001-04-02T07:32:00+10:00</a10:updated><a10:content type="xhtml"><h1>Disclaimer: This is an OLD, OLD blog post.</h1>

<h1>I shudder to think how much this PERL code looks like it was written by a C programmer...</h1>

<p>If you still find it useful, great. If you'd like to mess with the code, great too. If you're really
annoyed with fetchmail and it doesn't already have this feature built in, why not change the fetchmail
code yourself and submit it to the maintainers? :)  </p>

<p>Why don't I? Because I wanted to learn PERL...  </p>

<p>I recently had some trouble with fetchmail and multidrop mailboxes. fetchmail handles mail well when a
local address is found in the To: field of an email, but badly when it has to extract address information
from the other headers of an email. In particular, people on the BCC list of an email (and who never
appear in "official" mail headers) are likely to never receive emails addressed to them when handled via
fetchmail with a multidrop mailbox.  </p>

<p>I was also looking for an excuse to learn PERL (08/2004 update: wow, this page really <em>is</em> old...).  </p>

<p><a href="http://www.qmail.org">qmail</a> has a nice solution where it inserts an <strong>Delivered-To:</strong> line into the mail headers. For
virtual hosts, it prepends the domain name to the email account it was delivered to. My domain is
uglybugger.org, so when the MX host for mail.uglybugger.org accepts mail for me, it dumps it into a
single account. The headers it inserts look like this:  </p>

<pre><code>Return-Path: Andrew.Harcourt@team.telstra.com
Delivered-To: uglybugger.org%uglybugger@uglybugger.org
Received: (cpmta 5066 invoked from network); 2 Apr 2001 21:59:52 -0700
Delivered-To: uglybugger.org%andrewh@uglybugger.org
Received: (cpmta 5062 invoked from network); 2 Apr 2001 21:59:51 -0700
</code></pre>

<p>Read this from the bottom up. You'll see that the first <strong>Delivered-To:</strong> line reads <strong>uglybugger.org%andrewh@uglybugger.org</strong>
and the second <strong>Delivered-To:</strong> line reads <strong>uglybugger.org%uglybugger@uglybugger.org</strong>.  </p>

<p>fetchmail can be configured to read <em>envelope addresses</em>. These are the addresses (such as the
<strong>Delivered-To:</strong> line) that mail servers include in mail headers to record which <em>account</em> the
mail was delivered to. This is an important distinction from which <em>address</em> the mail was intended for.
You can tell fetchmail to use these headers by specifying the following in your .fetchmailrc file:  </p>

<pre><code>envelope "Delivered-To:"
qvirtual "uglybugger.org%"
</code></pre>

<p>Obviously, please change the qvirtual line to read your domain :)  </p>

<p>The problem here is that fetchmail will only read headers top-down, and it matches the first one it finds. This
breaks the <em>envelope</em>/<em>qvirtual</em> delivery process completely as fetchmail is unable to ignore the first line it
receives. So if the <em>envelope</em>/<em>qvirtual</em> settings do not solve your problem, read on.</p>

<p>What we need to do is specify an alternate delivery agent, so that we can handle our processing ourselves. You
can do this by specifying an external Mail Delivery Agent for fetchmail. Use the <em>mda</em> keyword to point mail to
a script that you can copy and paste from here:</p>

<pre><code>----- /usr/sbin/fetchmail-inject ----------
#!/usr/bin/perl
# fetchmail-inject
# Andrew Harcourt, 1 May, 2001
#
# this script removes a nasty header that fetchmail can't handle
# from incoming mail and then passes the mail to sendmail to
# deliver locally

# write the mail to a temp file on disk
# as we do, parse it for the address
# lines
local($outputName, $fromAddress, $toAddress, $cmd);

$outputName = "/tmp/message.".$$;
open(OUTFILE,"&gt; ".$outputName)
        || die "could not open $outputName!";

while (&amp;ltSTDIN&amp;gt) {
        if (/^Delivered-To: uglybugger\.org\%uglybugger\@uglybugger\.org/) {
                # just ignore this line - it's ugly
        }
        elsif (/^Delivered-To: uglybugger\.org\%(.*)\@uglybugger.org/) {
                $toAddress = $1."\@uglybugger.org";
        }
        elsif (/^From: .* /) {
                $fromAddress = $1;
        }
        elsif (/^From: /) {
                $fromAddress = $1;
        }
        elsif (/^From: .*/) {
                $fromAddress = $1
        }
        print OUTFILE $_;
}

close(OUTFILE);

# check that we have our addresses correct
if ($toAddress eq "") {
        $toAddress = "postmaster\@uglybugger.org";
}
if ($fromAddress eq "") {
        $fromAddress = "postmaster\@uglybugger.org";
}

# now call sendmail to deliver the message
$cmd = "/usr/sbin/sendmail -f $fromAddress $toAddress &lt; $outputName";
system($cmd);
-------------------------------------------
</code></pre>

<p>Good luck :)</p>
</a10:content><feedburner:origLink>http://www.codingforfunandprofit.com/Home/Post/2001.04.02.0732</feedburner:origLink></item></channel></rss>

