<?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:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Richard Dingwall</title>
	
	<link>http://richarddingwall.name</link>
	<description>Adventures of a young kiwi software developer in London</description>
	<lastBuildDate>Thu, 04 Mar 2010 13:11:43 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/RichardDingwall" /><feedburner:info uri="richarddingwall" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Pair programming: Keyboard ninja? Maybe you should drive</title>
		<link>http://feedproxy.google.com/~r/RichardDingwall/~3/Jzhu17yZhs0/</link>
		<comments>http://richarddingwall.name/2010/03/04/pair-programming-keyboard-ninja-maybe-you-should-drive/#comments</comments>
		<pubDate>Thu, 04 Mar 2010 12:55:54 +0000</pubDate>
		<dc:creator>Richard</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[General Development]]></category>
		<category><![CDATA[Refactoring insights]]></category>
		<category><![CDATA[Agile]]></category>
		<category><![CDATA[ReSharper]]></category>

		<guid isPermaLink="false">http://richarddingwall.name/?p=2843</guid>
		<description><![CDATA[As you may know, I&#8217;ve recently started at a new position here in London. Last week I was pair programming all day, every day, with a couple of the other developers, learning the ins and outs of the system. It reminded me of an important tip for beginners: good pair programming requires both driver and [...]]]></description>
			<content:encoded><![CDATA[<p>As you may know, I&#8217;ve recently started at a new position here in London. Last week I was pair programming all day, every day, with a couple of the other developers, learning the ins and outs of the system. It reminded me of an important tip for beginners: good pair programming requires both driver and observer to maintain focus between making a decision and implementing that change.</p>
<p.When you're working alone, or the driver in a pair, it's easy to stay focused because you're making the changes yourself. There is a continuous flow between discussing a change and moving your fingers and hitting the keys that make it happen. But for the other person in the pair, there can be big gaps waiting for the driver to implement the change, depending the size of the refactoring.</p>
<p>Renaming a class or a method can be done throughout your code in a fraction of a second with built-in IDE shortcuts. But something like <em>promoting a static method to an injected service</em> (still a pretty common refactoring) can easily take a couple of minutes to actually do. In this time, there&#8217;s not much going on for the observer, except listening to the sound of typing. And waiting. And trying not to get bored.</p>
<p>(If you&#8217;re unlucky enough to be paired with me, I&#8217;ll probably be completely distracted and playing with all the things on your desk by this point.)</p>
<p>Now, I am no stranger to pair programming, and have used it many times before for small tasks. But this is the first time I&#8217;ve ever done it solidly for several days at a time. This past week has been a real eye-opener for me in terms of quickly making code changes; although I have been using ReSharper for a while now, I have a new found appreciation for its keyboard shortcuts, and people who can use them effectively. Which sadly doesn&#8217;t include me yet.</p>
<p>Using your mouse to navigate code and poke through menus is just too slow, and it really shows when you are refactoring code in front of someone else. A good driver minimises the lag between agreeing on a change and effecting it with lighting-fast typing skills. So unplug your mouse, and go learn your tools&#8217; keyboard shortcuts!</p>
<img src="http://feeds.feedburner.com/~r/RichardDingwall/~4/Jzhu17yZhs0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://richarddingwall.name/2010/03/04/pair-programming-keyboard-ninja-maybe-you-should-drive/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://richarddingwall.name/2010/03/04/pair-programming-keyboard-ninja-maybe-you-should-drive/</feedburner:origLink></item>
		<item>
		<title>Correctness vs Robustness</title>
		<link>http://feedproxy.google.com/~r/RichardDingwall/~3/VB55dTRQVdw/</link>
		<comments>http://richarddingwall.name/2010/02/10/correctness-vs-robustness/#comments</comments>
		<pubDate>Wed, 10 Feb 2010 14:49:46 +0000</pubDate>
		<dc:creator>Richard</dc:creator>
				<category><![CDATA[General Development]]></category>
		<category><![CDATA[Refactoring insights]]></category>
		<category><![CDATA[Domain Driven Design]]></category>
		<category><![CDATA[Robustness]]></category>

		<guid isPermaLink="false">http://richarddingwall.name/?p=1552</guid>
		<description><![CDATA[In programming, correctness and robustness are two high-level principles from which a number of other principles can be traced back to.



Correctness
Robustness




Design by Contract
Defensive programming
Assertions
Invariants
Fail Fast
Populating missing parameters
Sensible defaults
Getting out of the users way
Anticorruption Layer
Backwards-compatible APIs



Robustness adds built-in tolerance for common and non-critical mistakes, while correctness throws an error when it encounters anything less than perfect [...]]]></description>
			<content:encoded><![CDATA[<p>In programming, <strong>correctness</strong> and <strong>robustness</strong> are two high-level principles from which a number of other principles can be traced back to.</p>
<table style="width: 550px; text-align: center">
<thead style="font-weight: bold">
<tr>
<td style="width: 50%">Correctness</td>
<td style="width: 50%">Robustness</td>
</tr>
</thead>
<tbody>
<tr>
<td><a href="http://c2.com/cgi/wiki?DesignByContract">Design by Contract</a><br />
<a href="http://en.wikipedia.org/wiki/Defensive_programming">Defensive programming</a><br />
<a href="http://www.stanford.edu/~pgbovine/programming-with-asserts.htm">Assertions</a><br />
<a href="http://www.pragprog.com/articles/semantic-invariants">Invariants</a><br />
<a href="http://dthain.blogspot.com/2009/02/fail-fast-fail-often.html">Fail Fast</a></td>
<td>Populating missing parameters<br />
Sensible defaults<br />
Getting out of the users way<br />
<a href="http://www.markhneedham.com/blog/2009/07/07/domain-driven-design-anti-corruption-layer/">Anticorruption Layer</a><br />
Backwards-compatible APIs</td>
</tr>
</tbody>
</table>
<p>Robustness adds built-in tolerance for common and non-critical mistakes, while correctness throws an error when it encounters anything less than perfect input. Although they are contradictory, both principles play an important role in most software, so it&#8217;s important to know when each is appropriate, and why.</p>
<h4>Robustness</h4>
<p>&#8220;Robustness&#8221; is well known as one of the founding principles of the internet, and is probably one of the major contributing factors to its success. <a href="http://en.wikipedia.org/wiki/Robustness_principle">Postel&#8217;s Law</a> summarizes it simply:</p>
<blockquote><p>Be conservative in what you do; be liberal in what you accept from others.</p></blockquote>
<p>Postel&#8217;s Law originally referred to other computers on a network, but these days, it can be applied to files, configuration, third party code, other developers, and even users themselves. For example:</p>
<style type="text/css">
table.robustness-examples { font-size: 80%; }
table.robustness-examples td { border-bottom: solid 1px #ccc; vertical-align: top; }
table.robustness-examples tbody td { padding-top: 0.5em; padding-bottom: 0.5em; }
</style>
<table class="robustness-examples">
<thead style="text-align: center; font-weight: bold">
<tr>
<td width="33%">Problem</td>
<td width="33%">Robust approach</td>
<td width="33%">Correct approach</td>
</tr>
</thead>
<tbody>
<tr>
<td>A rogue web browser that adds trailing whitespace to HTTP headers.</td>
<td>Strip whitespace, process request as normal.</td>
<td>Return HTTP 400 Bad Request error status to client.</td>
</tr>
<tr>
<td>A video file with corrupt frames.</td>
<td>Skip over corrupt area to next playable section.</td>
<td>Stop playback, raise &#8220;Corrupt video file&#8221; error.</td>
</tr>
<tr>
<td>A config file with lines commented out using the wrong character.</td>
<td>Internally recognize most common comment prefixes, ignore them.</td>
<td>Terminate on startup with &#8220;bad configuration&#8221; error.</td>
</tr>
<tr>
<td>A user who enters dates in a strange format.</td>
<td>Try parsing the string against a number of different date formats. Render the correct format back to the user.</td>
<td>Invalid date error.</td>
</tr>
</tbody>
</table>
<p>(<strong>Important side note:</strong> Postel&#8217;s law doesn&#8217;t suggest skipping validation entirely, but that errors in non-essential items simply be logged and/or warned about instead of throwing fatal exceptions.)</p>
<p>In many cases, relentless pursuit of correctness results in a pretty bad user experience. One recent annoyance of mine is <a href="http://unixwiz.net/ndos-shame.html">companies that can&#8217;t handle spaces in credit card numbers</a>. Computers are pretty good at text processing, so wasting the user&#8217;s time by forcing them to retype their credit card numbers in strange formats is pure laziness on behalf of the developer. Especially if you consider the validation error probably took more code than simply stripping the spaces out.</p>
<p>Compare this to Google Maps, where you can enter just about <em>anything</em> in the search box and it will figure out a street address. I know which I prefer using.</p>
<p><strong>Robustness makes users&#8217; lives easier</strong>, and by doing so promotes uptake. Not only amongst end users, but also developers &#8212; if you&#8217;re developing a standard/library/service/whatever, and can build in a bit of well thought-out flexibility, it&#8217;s going to grant a second chance for users with clients that aren&#8217;t quite compliant, instead of kicking them out cold.</p>
<p>Adam Bosworth noted a couple of examples of this in a recent post <a href="http://adambosworth.net/2009/10/29/talking-to-dc/">what makes successful standards</a>:</p>
<blockquote><p>If there is something in HTTP that the receiver doesn’t understand it ignores it. It doesn’t break. If there is something in HTML that the browser doesn’t understand, it ignores it. It doesn’t break. <a href="http://en.wikipedia.org/wiki/Robustness_principle">See Postel’s law</a>.  Assume the unexpected. False precision is the graveyard of successful standards. XML Schema did very badly in this regard.</p></blockquote>
<p>HTTP and HTML are displaying robustness here; if they see anything they don&#8217;t recognize they simply skip past it. XML Schema on the other hand fails validation if there are any extra elements/attributes present other than precisely those specified in the XSD.</p>
<h4>Correctness</h4>
<p>So robustness makes life easier for users and third-party developers. But correctness, on the other hand, <strong>makes life easier for <em>your</em> developers</strong> &#8212; instead of bogging down checking/fixing parameters and working around strange edge cases, they can focus on the one single model where all assumptions are guaranteed. Any states outside the main success path can thus be ignored (by failing noisily) &#8212; producing code that is briefer, easier to understand, and easier to maintain.</p>
<p>For example, consider parsing <a href="http://wiki.whatwg.org/wiki/HTML_vs._XHTML#Syntax_and_Parsing">XHTML vs regular HTML</a>. If XHTML isn&#8217;t well formed, you can simply throw a parser error and give up. HTML on the other hand has thoroughly documented graceful error handling and recovery procedures that you need to implement &#8212; much harder than simply validating it as XML.</p>
<h4>Which should you use then?</h4>
<p>We have a conflict here between robustness or correctness as a guiding principle. I remember one paralyzing moment of indecision I had when I was a bit younger with this very question. The specific details aren&#8217;t important, but the 50/50 problem basically boiled down to this: <strong>If my code doesn&#8217;t technically <em>require</em> this value to be provided, should I check it anyway?</strong></p>
<p>To answer this question, you need to be aware of where you are in the code base, and who it is serving.</p>
<ul>
<li>External interfaces (UI, input files, configuration, API etc) exist primarily to serve users and third parties. Make them robust, and as accommodating as possible, with the expectation that people will input garbage.</li>
<li>An application&#8217;s internal model (i.e. domain model) should be as simple as possible, and always be in a 100% valid state. Use invariants and assertions to make safe assumptions, and just throw a big fat exception whenever you encounter anything that isn&#8217;t right.</li>
<li>Protect the internal model from external interfaces with an anti-corruption layer which maps and corrects invalid input where possible, before passing it to the internal model.</li>
</ul>
<p>Remember if you ignore users&#8217; needs, no one will want to use your software. And if you ignore programmers&#8217; needs, there won&#8217;t <em>be</em> any software. So make your external interfaces robust. Make your internal model correct.</p>
<p>Or in other words: <strong>internally, seek correctness; externally, seek robustness.</strong> A successful application needs both.</p>
<img src="http://feeds.feedburner.com/~r/RichardDingwall/~4/VB55dTRQVdw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://richarddingwall.name/2010/02/10/correctness-vs-robustness/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		<feedburner:origLink>http://richarddingwall.name/2010/02/10/correctness-vs-robustness/</feedburner:origLink></item>
		<item>
		<title>Announcement: I’m moving to London!</title>
		<link>http://feedproxy.google.com/~r/RichardDingwall/~3/qxexUtK7rGY/</link>
		<comments>http://richarddingwall.name/2010/01/18/announcement-im-moving-to-london/#comments</comments>
		<pubDate>Mon, 18 Jan 2010 09:46:28 +0000</pubDate>
		<dc:creator>Richard</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://richarddingwall.name/?p=2748</guid>
		<description><![CDATA[Announcement: in just over a fortnight I&#8217;ll be packing my bags to go chase the kiwi dream &#8211; I&#8217;m moving to London!
Provoke has been a wonderful home for the past two years, and I thank all my workmates and clients who made my time there so special. Working here has really been an unforgettable experience, [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Announcement</strong>: in just over a fortnight I&#8217;ll be packing my bags to go chase the kiwi dream &#8211; I&#8217;m moving to London!</p>
<p><a href="http://provoke.co.nz">Provoke</a> has been a wonderful home for the past two years, and I thank all my workmates and clients who made my time there so special. Working here has really been an unforgettable experience, and I hope to take a little bit of that magic onto future jobs and organisations.</p>
<p>So far, my immediate plan for the next few months involves .NET architecture/development work in London, probably on contract basis so I can fit in some travel around Europe between projects. I&#8217;m also keen to check out the various developer conferences like QCon and Oredev. But first, I need to start packing!</p>
<img src="http://feeds.feedburner.com/~r/RichardDingwall/~4/qxexUtK7rGY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://richarddingwall.name/2010/01/18/announcement-im-moving-to-london/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://richarddingwall.name/2010/01/18/announcement-im-moving-to-london/</feedburner:origLink></item>
		<item>
		<title>Semantic CSS grid layout with LESS</title>
		<link>http://feedproxy.google.com/~r/RichardDingwall/~3/JxxL9sZePig/</link>
		<comments>http://richarddingwall.name/2009/12/28/semantic-css-grid-layout-with-less/#comments</comments>
		<pubDate>Mon, 28 Dec 2009 01:53:44 +0000</pubDate>
		<dc:creator>Richard</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[General Development]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[LESS]]></category>

		<guid isPermaLink="false">http://richarddingwall.name/?p=2684</guid>
		<description><![CDATA[I have a confession to make. After eight years since we first met, I still don&#8217;t quite get CSS.
Sure, I can do typography, sprite backgrounds and understand the basics of the box model. I even know about browser-specific CSS extensions for CSS3 effects. But when it comes to clearing floats, vertically-aligning form elements or figuring [...]]]></description>
			<content:encoded><![CDATA[<p>I have a confession to make. After eight years since we first met, I still don&#8217;t quite <em>get</em> CSS.</p>
<p>Sure, I can do typography, sprite backgrounds and understand the basics of the box model. I even know about browser-specific CSS extensions for CSS3 effects. But when it comes to clearing floats, vertically-aligning form elements or figuring out inline parents with block children, I go to a very dark place and start cursing.</p>
<p>I freely admit my CSS layout and positioning skills are lacking, and I probably shouldn&#8217;t even be blogging about it. But when I discovered CSS grid frameworks, I was naturally interested &#8212; anything that helps me get up and running quicker in a foreign language is a win.</p>
<h4>Grid frameworks: CSS for dummies</h4>
<p>For those that don&#8217;t know, grid frameworks like <a href="http://960.gs/">960gs</a>, <a href="http://developer.yahoo.com/yui/grids/">YUI grids</a> and <a href="http://blueprintcss.org/">Blueprint CSS</a> provide a simple 12, 16 or 24 column grid that abstracts away complicated CSS layout and positioning rules.</p>
<p>For example, using the Blueprint CSS framework, this markup produces the following layout, neatly centered in the middle of the browser window:</p>
<pre class="brush: xml;">&lt;html&gt;
&lt;head&gt;
    &lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;blueprint/screen.css&quot; /&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div class=&quot;container&quot;&gt;
		&lt;div class=&quot;push-4 span-15&quot;&gt;header&lt;/div&gt;
		&lt;div class=&quot;push-4 span-4&quot;&gt;menu&lt;/div&gt;
		&lt;div class=&quot;span-7&quot;&gt;main&lt;/div&gt;
		&lt;div class=&quot;span-4&quot;&gt;ad space?&lt;/div&gt;
		&lt;div class=&quot;push-4 span-15&quot;&gt;footer&lt;/div&gt;
    &lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p><img src="http://richarddingwall.name/wp-content/uploads/2009/12/easy-column-layout.png" alt="" title="3-column grid layout" width="593" height="91" class="aligncenter size-full wp-image-2701" /></p>
<p>How easy was that? As a CSS newbie, not having to worry about floats, clears, negative margings and other positioning tricks is a <em>very</em> attractive proposition.</p>
<p>So CSS grids are very powerful for quickly laying out elements. But there is a trade off you should consider &#8212; HTML marked up with grids is not at all semantic. Peppering your HTML with classes like .span-12 or .yui-t3 for layout is no better than specifying table widths and heights everywhere.</p>
<p>Wouldn&#8217;t it be great if you could keep using these grid classes, but somehow mask them behind semantic class names?</p>
<h4>LESS: CSS preprocessor</h4>
<p>About the same time I discovered grids, I stumbled upon <a href="http://lesscss.org/">LESS</a>: a &#8216;leaner&#8217; CSS command-line preprocessor that extends CSS with its own syntax and features. The .NET port, <a href="http://www.dotlesscss.com/">.Less</a>, has a smaller feature set than the rails version, but it lets you do stuff like this:</p>
<pre class="brush: css;">.rounded_corners {
	@radius: 8px; /* variables */
	-moz-border-radius: @radius;
	-webkit-border-radius: @radius;
	border-radius: @radius;
}

#header {
	.rounded_corners; /* mix-ins */

	img.logo { /* nested styles */
		margin: (@radius * 2) + 1px; /* expressions */
	}
}

#footer {
	.rounded_corners;
}</pre>
<p>I have .Less is setup as an HttpModule in my web.config. It intercepts any requests to *.less files, translates them to real CSS, and optionally minifies (compresses) them. So you can you can simply reference the .less file directly in your markup, with no extra compilation step required:</p>
<pre class="brush: xml;">&lt;head&gt;
    &lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;site.less&quot; /&gt;
&lt;/head&gt;</pre>
<h4>Grid CSS frameworks + LESS = semantic grids</h4>
<p>I&#8217;ve been using LESS for a few weeks now, and to be honest, I never want to go back to writing &#8216;raw&#8217; CSS again. So what happens when you combine the CSS grid framework with LESS? Here&#8217;s the new stylesheet:</p>
<pre class="brush: css;">@import blueprint/screen.css;

div.container {

	div.header {
		.push-4;
		.span-15;
	}

	div.menu {
		.push-4;
		.span-4;
	}

	div.main {
		.span-7;
	}

	div.ads {
		.push-4;
	}

	div.footer {
		.push-4;
		.span-15;
	}
}</pre>
<p>All that&#8217;s left is semantic class names using grids styles as mix-ins. Now the markup is looking acceptable again:</p>
<pre class="brush: xml;">&lt;html&gt;
&lt;head&gt;
    &lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;site.less&quot; /&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div class=&quot;container&quot;&gt;
		&lt;div class=&quot;header&quot;&gt;header&lt;/div&gt;
		&lt;div class=&quot;menu&quot;&gt;menu&lt;/div&gt;
		&lt;div class=&quot;main&quot;&gt;main&lt;/div&gt;
		&lt;div class=&quot;ads&quot;&gt;ad space?&lt;/div&gt;
		&lt;div class=&quot;footer&quot;&gt;footer&lt;/div&gt;
    &lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Using grid classes as mix-ins gives us the best of both worlds &#8212; you get the power of the grid CSS framework, but without introducing layout concerns to your markup.</p>
<img src="http://feeds.feedburner.com/~r/RichardDingwall/~4/JxxL9sZePig" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://richarddingwall.name/2009/12/28/semantic-css-grid-layout-with-less/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://richarddingwall.name/2009/12/28/semantic-css-grid-layout-with-less/</feedburner:origLink></item>
		<item>
		<title>Domain-Driven Documentation</title>
		<link>http://feedproxy.google.com/~r/RichardDingwall/~3/WDkHTdAtX90/</link>
		<comments>http://richarddingwall.name/2009/12/10/domain-driven-documentation/#comments</comments>
		<pubDate>Thu, 10 Dec 2009 08:39:44 +0000</pubDate>
		<dc:creator>Richard</dc:creator>
				<category><![CDATA[General Development]]></category>

		<guid isPermaLink="false">http://richarddingwall.name/?p=2603</guid>
		<description><![CDATA[Here&#8217;s a couple of real-life documentation examples from a system I&#8217;ve been building for a client:
A Monitored Individual is a role played by certain Employees. Each Monitored Individual is required to be proficient in a number of Competencies, according to [among other things] what District they&#8217;re stationed in.

A Training Programme is comprised of Skills, arranged [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a couple of real-life documentation examples from a system I&#8217;ve been building for a client:</p>
<blockquote><p>A <strong>Monitored Individual</strong> is a role played by certain <strong>Employees</strong>. Each <strong>Monitored Individual</strong> is required to be proficient in a number of <strong>Competencies</strong>, according to [among other things] what <strong>District</strong> they&#8217;re stationed in.</p></blockquote>
<p><span/></p>
<blockquote><p>A <strong>Training Programme</strong> is comprised of <strong>Skills</strong>, arranged in <strong>Skill Groups</strong>. <strong>Skill Groups</strong> can contain <strong>Sub Groups</strong> with as many levels deep as you like. <strong>Skills</strong> can be used for multiple <strong>Training Programmes</strong>, but you can&#8217;t have the same <strong>Skill</strong> twice under the same <strong>Training Programme</strong>. When a <strong>Skill</strong> is removed from a <strong>Training Programme</strong>, <strong>Individuals</strong> should no longer have to practice it.</p></blockquote>
<p>This is the same style Evans uses himself in the <a href="http://books.google.co.nz/books?id=7dlaMs0SECsC&#038;lpg=PP1&#038;dq=domain%20driven%20design&#038;pg=PA177#v=onepage&#038;q=&#038;f=false">blue DDD book</a>. A colleague jokingly called it <em>Domain-Driven Documentation</em>.</p>
<p>I adopted it after noticing a couple of problems with my documentation:</p>
<ul>
<li>I was using synonyms &#8212; different words with the same meaning &#8212; interchangeably to refer to the same thing in different places.</li>
<li>Sentences talking about the code itself looked messy and inconsistent when mixing class names with higher-level concepts.</li>
</ul>
<p>It&#8217;s a pretty simple system. There are only three rules to remember: when referring to domain concepts, use capital letters, write them in full, and write them in <strong>bold</strong>.</p>
<p>Highlighting the names of domain concepts like this is a fantastic way to hammer down the ubiquitous language &#8212; the vocabulary shared between business and developers.</p>
<p>Since adopting it, I&#8217;ve noticed improvements in both the quality of my documentation, and of the communication in our project meetings &#8212; non-technical business stakeholders are starting to stick to the ubiquitous language now, where in the past they would fall back to talking about purely UI artifacts. This is really encouraging to see &#8212; definitely a success for DDD.</p>
<img src="http://feeds.feedburner.com/~r/RichardDingwall/~4/WDkHTdAtX90" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://richarddingwall.name/2009/12/10/domain-driven-documentation/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://richarddingwall.name/2009/12/10/domain-driven-documentation/</feedburner:origLink></item>
		<item>
		<title>jQuery: checkboxes that remember their original state</title>
		<link>http://feedproxy.google.com/~r/RichardDingwall/~3/yb0x_fOoudw/</link>
		<comments>http://richarddingwall.name/2009/12/06/jquery-checkboxes-that-remember-their-original-state/#comments</comments>
		<pubDate>Sun, 06 Dec 2009 10:35:18 +0000</pubDate>
		<dc:creator>Richard</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://richarddingwall.name/?p=2645</guid>
		<description><![CDATA[Last week I had to write a little javascript for a form that involved a long list of check boxes. To save time, the application only processes rows where the checkbox value actually changed away from its original state.
For example, if a checkbox was checked to begin with, then the user unchecks it then re-checks [...]]]></description>
			<content:encoded><![CDATA[<p>Last week I had to write a little javascript for a form that involved a long list of check boxes. To save time, the application only processes rows where the checkbox value actually changed away from its original state.</p>
<p>For example, if a checkbox was checked to begin with, then the user unchecks it then re-checks it, we don&#8217;t have to do anything because although it did change, it ended up back at the same original state.</p>
<p>This is pretty easy to achieve by remembering the original state of the checkbox using jQuery <a href="http://docs.jquery.com/Core/data">data</a> &#8212; library methods for storing arbitrary javascript objects in DOM elements &#8212; then comparing against the original value when toggled.</p>
<pre class="brush: xml;">&lt;script type=&quot;text/javascript&quot;&gt;
	$(document).ready(function() {

		// Set aside the original state of each checkbox.
		$(&quot;input.toggle&quot;).each(function() {
			$(this).data(&quot;originallyChecked&quot;, $(this).is(&quot;:checked&quot;));
		});

		// Check whether it really changed on click.
		$(&quot;input.toggle&quot;).change(function() {
			var action = $(this).siblings(&quot;span&quot;);

			if ($(this).data(&quot;originallyChecked&quot;) == $(this).is(&quot;:checked&quot;))
				action.text(&quot;(no change)&quot;);
			else
				action.text($(this).is(&quot;:checked&quot;) ? &quot;added&quot; : &quot;removed&quot;);
		});
	});
&lt;/script&gt;
&lt;ol&gt;
	&lt;li&gt;Apple &lt;input type=&quot;checkbox&quot; class=&quot;toggle&quot; /&gt; &lt;span/&gt;&lt;/li&gt;
	&lt;li&gt;Banana &lt;input type=&quot;checkbox&quot; class=&quot;toggle&quot; checked /&gt; &lt;span/&gt;&lt;/li&gt;
	&lt;li&gt;Carrot &lt;input type=&quot;checkbox&quot; class=&quot;toggle&quot; /&gt; &lt;span/&gt;&lt;/li&gt;
	&lt;li&gt;Zucchini &lt;input type=&quot;checkbox&quot; class=&quot;toggle&quot; checked /&gt; &lt;span/&gt;&lt;/li&gt;
&lt;/ol&gt;</pre>
<p>The next requirement was adding a <em>select/deselect all</em> button. This proved a little bit more difficult, because of the way jQuery deals with events and the checked attribute. To cut a <a href="http://briancray.com/2009/08/06/check-all-jquery-javascript/">long story short</a>, I ended up with an event handler that manually sets the checked attribute and then fires the <a href="http://docs.jquery.com/Events/change">change</a> event on all the checkboxes (I tried the <a href="http://docs.jquery.com/Events/click">click</a> event first, but it didn&#8217;t seem to pick up the new state).</p>
<pre class="brush: jscript;">$(document).ready(function() {
	$(&quot;input#select-all&quot;).click(function() {
		$(&quot;input.toggle&quot;).attr('checked', this.checked);
		$(&quot;input.toggle&quot;).change();
	});
});</pre>
<p>Altogether, it works very nicely in only a few lines of javascript. You can <a href='http://richarddingwall.name/wp-content/uploads/2009/12/jquery-select-all.html'>see the whole thing in action here</a>.</p>
<img src="http://feeds.feedburner.com/~r/RichardDingwall/~4/yb0x_fOoudw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://richarddingwall.name/2009/12/06/jquery-checkboxes-that-remember-their-original-state/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://richarddingwall.name/2009/12/06/jquery-checkboxes-that-remember-their-original-state/</feedburner:origLink></item>
		<item>
		<title>Why most software projects fail</title>
		<link>http://feedproxy.google.com/~r/RichardDingwall/~3/SrqXAALTCnw/</link>
		<comments>http://richarddingwall.name/2009/12/03/why-most-software-projects-fail/#comments</comments>
		<pubDate>Wed, 02 Dec 2009 19:03:23 +0000</pubDate>
		<dc:creator>Richard</dc:creator>
				<category><![CDATA[General Development]]></category>

		<guid isPermaLink="false">http://richarddingwall.name/?p=2640</guid>
		<description><![CDATA[This is a really good article I came across yesterday with some scary truths about IT projects in general: Roger Sessions &#8211; The IT Complexity Crisis: Danger and Opportunity (Nov 2009, PDF)

Worldwide, the annual cost of IT failure is around USD $6.18 trillion
66% of IT projects in the US govt were considered ‘at risk’ of [...]]]></description>
			<content:encoded><![CDATA[<p>This is a really good article I came across yesterday with some scary truths about IT projects in general: <a href="http://www.objectwatch.com/whitepapers/ITComplexityWhitePaper.pdf">Roger Sessions &#8211; The IT Complexity Crisis: Danger and Opportunity</a> (Nov 2009, PDF)</p>
<ul>
<li>Worldwide, the annual cost of IT failure is around USD $6.18 trillion</li>
<li>66% of IT projects in the US govt were considered ‘at risk’ of failure in 2009 (growing 15% each year)</li>
</ul>
<p>There’s a bit of maths, but basically it suggests that the whole reason for this is increasing complexity in projects, and presents an equation where the chance of failure in a project grows logarithmically with the number of business functions and the number of connections to other systems.</p>
<p>The answer is to identify these functions and connections and split them out into simpler isolated systems &#8212; one per bounded context! &#8212; that can be delivered independently of each other (and independently between vendors), instead of trying to smush them all into one humungous ball-of-mud application.</p>
<p>Definitely worth a read if you’re on the architecture side of things!</p>
<img src="http://feeds.feedburner.com/~r/RichardDingwall/~4/SrqXAALTCnw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://richarddingwall.name/2009/12/03/why-most-software-projects-fail/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://richarddingwall.name/2009/12/03/why-most-software-projects-fail/</feedburner:origLink></item>
		<item>
		<title>Stick to the paradigm (even if it sucks)</title>
		<link>http://feedproxy.google.com/~r/RichardDingwall/~3/cozGdvtb4rc/</link>
		<comments>http://richarddingwall.name/2009/11/26/stick-to-the-paradigm-even-if-it-sucks/#comments</comments>
		<pubDate>Thu, 26 Nov 2009 08:58:06 +0000</pubDate>
		<dc:creator>Richard</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Refactoring insights]]></category>

		<guid isPermaLink="false">http://richarddingwall.name/?p=2624</guid>
		<description><![CDATA[Today I had the pleasure of fixing a bug in an unashamedly-procedural ASP.NET application, comprised almost entirely of static methods with anywhere from 5-20 parameters each (yuck yuck yuck).
After locating the bug and devising a fix, I hit a wall. I needed some additional information that wasn&#8217;t in scope. There were three places I could [...]]]></description>
			<content:encoded><![CDATA[<p>Today I had the pleasure of fixing a bug in an unashamedly-procedural ASP.NET application, comprised almost entirely of static methods with anywhere from 5-20 parameters each (yuck yuck yuck).</p>
<p>After locating the bug and devising a fix, I hit a wall. I needed some additional information that wasn&#8217;t in scope. There were three places I could get it from:</p>
<ul>
<li>The database</li>
<li>Form variables</li>
<li>The query string</li>
</ul>
<p>The problem was knowing which to choose, because it depended on the lifecycle of the page &#8212; is it the first hit, a reopened item, or a post back? Of course <em>that</em> information wasn&#8217;t in scope either.</p>
<p>As I contemplated how to figure the state of the page using HttpContext.Current, my spidey sense told me to stop and reconsider.</p>
<p>Let&#8217;s go right back to basics. How did we use to manage this problem in procedural languages like C? There is a simple rule &#8212; always pass everything you need into the function. Global variables and hidden state may be convenient in the short-term, but only serve to confuse later on.</p>
<p>To fix the problem, I had to forget about &#8220;this page&#8221; as an object instance. I had to forget about private class state. I had to forget that C# was an object-oriented language. Those concepts were totally incompatible with this procedural code base, and any implementation would likely result in a big mess.</p>
<p>In fact, it turns out to avoid a DRY violation working out the page state again, and adding hidden dependencies on HttpContext, the most elegant solution was simply to add an extra parameter to every method in the stack. So wrong from a OO/.NET standpoint, but so right for procedural paradigm in place.</p>
<img src="http://feeds.feedburner.com/~r/RichardDingwall/~4/cozGdvtb4rc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://richarddingwall.name/2009/11/26/stick-to-the-paradigm-even-if-it-sucks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://richarddingwall.name/2009/11/26/stick-to-the-paradigm-even-if-it-sucks/</feedburner:origLink></item>
		<item>
		<title>DDD: making the Time Period concept explicit</title>
		<link>http://feedproxy.google.com/~r/RichardDingwall/~3/DVzMfKs2v70/</link>
		<comments>http://richarddingwall.name/2009/11/25/ddd-making-the-time-period-concept-explicit/#comments</comments>
		<pubDate>Tue, 24 Nov 2009 23:40:14 +0000</pubDate>
		<dc:creator>Richard</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Refactoring insights]]></category>
		<category><![CDATA[Domain Driven Design]]></category>

		<guid isPermaLink="false">http://richarddingwall.name/?p=2563</guid>
		<description><![CDATA[One of the applications I work on is a planning system, used for managing the operations of the business over the next week, month and financial year.
Almost every entity in this application has a fixed &#8216;applicable period&#8217; &#8212; a lifetime that begins and ends at certain dates. For example:

An employee&#8217;s applicable period lasts as long [...]]]></description>
			<content:encoded><![CDATA[<p>One of the applications I work on is a planning system, used for managing the operations of the business over the next week, month and financial year.</p>
<p>Almost every entity in this application has a fixed &#8216;applicable period&#8217; &#8212; a lifetime that begins and ends at certain dates. For example:</p>
<ul>
<li>An employee&#8217;s applicable period lasts as long as they are employed</li>
<li>A business unit&#8217;s lifetime lasts from the day it&#8217;s formed, to the day it disbands</li>
<li>A policy lasts from the day it comes into effect to the day it ends</li>
<li>A shift starts at 8am and finishes at 6pm</li>
</ul>
<p>Previous incarnations of the application simply added StartDate and EndDate properties to every object, and evaluated them ad-hoc as required. This resulted in a lot of code duplication &#8212; date and time logic around overlaps, contiguous blocks etc were repeated all over the place.</p>
<p>As we&#8217;ve been carving off bounded contexts and reimplementing them using DDD, I&#8217;m proud to say this concept has been identified and separated out into an explicit value type with encapsulated behaviour. We call it a <strong>Time Period</strong>:</p>
<p><img src="http://yuml.me/diagram/scruffy/class/%5BPolicy%5D++-ApplicablePeriod%3E%5BTimePeriod%5D" title="Policy with Applicable Period" class="aligncenter" /></p>
<p>It&#8217;s sort of like a .NET <a href="http://msdn.microsoft.com/en-us/library/system.timespan.aspx">TimeSpan</a> but represents a <em>specific</em> period of time, e.g. seven days starting from yesterday morning &#8212; not seven days in general.</p>
<p>Here&#8217;s the behaviour we&#8217;ve implemented so far, taking care of things like comparisons and overlapping periods:</p>
<pre class="brush: csharp;">/// &lt;summary&gt;
/// A value type to represent a period of time with known end points (as
/// opposed to just a period like a timespan that could happen anytime).
/// The end point of a TimeRange can be infinity.
/// &lt;/summary&gt;
public class TimePeriod : IEquatable&lt;TimePeriod&gt;
{
    public DateTime Start { get; }
    public DateTime? End { get; }
    public bool IsInfinite { get; }
    public TimeSpan Duration { get; }
    public bool Includes(DateTime date);
    public bool StartsBefore(TimePeriod other);
    public bool StartsAfter(TimePeriod other);
    public bool EndsBefore(TimePeriod other);
    public bool EndsAfter(TimePeriod other);
    public bool ImmediatelyPrecedes(TimePeriod other);
    public bool ImmediatelyFollows(TimePeriod other);
    public bool Overlaps(TimePeriod other);
    public TimePeriod GetRemainingSlice();
    public TimePeriod GetRemainingSliceAsAt(DateTime when);
    public bool HasPassed();
    public bool HasPassedAsAt(DateTime when);
    public float GetPercentageElapsed();
    public float GetPercentageElapsedAsAt(DateTime when);
}</pre>
<p>Encapsulating logic all in one place means we can get rid of all that ugly duplication (DRY), and it still maps cleanly to StartDate/EndDate columns in the database as an NHibernate component or IValueType.</p>
<p>You can grab our initial implementation here:</p>
<ul>
<li><a href='http://richarddingwall.name/wp-content/uploads/2009/11/TimePeriod.cs'>TimePeriod.cs</a></li>
<li><a href='http://richarddingwall.name/wp-content/uploads/2009/11/TimePeriodTests.cs'>TimePeriodTests.cs</a></li>
</ul>
<img src="http://feeds.feedburner.com/~r/RichardDingwall/~4/DVzMfKs2v70" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://richarddingwall.name/2009/11/25/ddd-making-the-time-period-concept-explicit/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		<feedburner:origLink>http://richarddingwall.name/2009/11/25/ddd-making-the-time-period-concept-explicit/</feedburner:origLink></item>
		<item>
		<title>The trouble with soft delete</title>
		<link>http://feedproxy.google.com/~r/RichardDingwall/~3/GrtV8Y15vZo/</link>
		<comments>http://richarddingwall.name/2009/11/20/the-trouble-with-soft-delete/#comments</comments>
		<pubDate>Fri, 20 Nov 2009 10:44:44 +0000</pubDate>
		<dc:creator>Richard</dc:creator>
				<category><![CDATA[Refactoring insights]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[featured]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://richarddingwall.name/?p=1909</guid>
		<description><![CDATA[Soft delete is a commonly-used pattern amongst database-driven business applications. In my experience, however, it usually ends up causing more harm than good. Here&#8217;s a few reasons why it can fail in bigger applications, and some less-painful alternatives to consider.
Tomato, Tomato
I&#8217;ve seen a few different implementations of this pattern in action. First is the standard [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Soft delete</strong> is a commonly-used pattern amongst database-driven business applications. In my experience, however, it usually ends up causing more harm than good. Here&#8217;s a few reasons why it can fail in bigger applications, and some less-painful alternatives to consider.</p>
<h4>Tomato, Tomato</h4>
<p>I&#8217;ve seen a few different implementations of this pattern in action. First is the standard deleted flag to indicate an item should be ignored:</p>
<pre class="brush: sql; toolbar: false;">SELECT * FROM Product WHERE IsDeleted = 0</pre>
<p>Another style uses meaningful status codes:</p>
<pre class="brush: sql; toolbar: false;">SELECT * FROM Task WHERE Status = 'Pending'</pre>
<p>You can even give an item a fixed lifetime that starts and ends at a specific time (it might not have started yet):</p>
<pre class="brush: sql; toolbar: false;">SELECT * FROM Policy WHERE GETDATE() BETWEEN StartDate AND EndDate</pre>
<p><img src="http://richarddingwall.name/wp-content/uploads/2009/11/Highway_of_death.jpg" alt="Highway of death" title="Highway of death" width="286" height="215" class="alignright size-full wp-image-2479" /></p>
<p>All of these styles are all flavours of the same concept: instead of pulling dead or infrequently-used items out of active set, you simply mark them and change queries to step over the corpses at runtime.</p>
<p>This is a trade-off: soft delete columns are easy to implement, but incur a cost to query complexity and database performance later down the track.</p>
<h4>Complexity</h4>
<p>To prevent mixing active and inactive data in results, all queries must be made aware of the soft delete columns so they can explicitly exclude them. It&#8217;s like a tax; a mandatory WHERE clause to ensure you don&#8217;t return any deleted rows.</p>
<p>This extra WHERE clause is similar to checking return codes in programming languages that don&#8217;t throw exceptions (like C). It&#8217;s very simple to do, but if you forget to do it in even one place, bugs can creep in very fast. And it is background noise that detracts away from the real intention of the query.</p>
<h4>Performance</h4>
<p>At first glance you might think evaluating soft delete columns in every query would have a noticeable impact on performance.</p>
<p>However, I&#8217;ve found that most RDBMSs are actually pretty good at recognizing soft delete columns (probably because they are so commonly used) and does a good job at optimizing queries that use them. In practice, filtering inactive rows doesn&#8217;t cost too much in itself.</p>
<p>Instead, the performance hit comes simply from the volume of data that builds up when you don&#8217;t bother clearing old rows. For example, we have a table in a system at work that records an organisations day-to-day tasks: pending, planned, and completed. It has around five million rows in total, but of that, only a very small percentage (2%) are still active and interesting to the application. The rest are all historical; rarely used and kept only to maintain foreign key integrity and for reporting purposes.</p>
<p>Interestingly, the biggest problem we have with this table is not slow read performance but writes. Due to its high use, we index the table heavily to improve query performance. But with the number of rows in the table, it takes so long to update these indexes that the application frequently times out waiting for DML commands to finish.</p>
<p>This table is becoming an increasing concern for us &#8212; it represents a major portion of the application, and with around a million new rows being added each year, the performance issues are only going to get worse.</p>
<h4>Back to the original problem</h4>
<p>The trouble with implementing soft delete via a column is that it simply doesn&#8217;t scale well for queries targeting multiple tables &#8212; we need a different strategy for larger data models.</p>
<p>Let&#8217;s take a step back and examine the reasons why you might want to implement soft deletes in a database. If you think about it, there really are only four categories:</p>
<ol>
<li>To provide an &#8216;undelete&#8217; feature.</li>
<li>Auditing.</li>
<li>For soft create.</li>
<li>To keep historical items.</li>
</ol>
<p>Let&#8217;s look at each of these and explore what other options are available.</p>
<h4>Soft delete to enable undo</h4>
<p><img src="http://richarddingwall.name/wp-content/uploads/2009/11/recycle-bin.png" alt="Windows 7 Recycle Bin" title="Windows 7 Recycle Bin" width="96" height="96" class="alignright size-full wp-image-2583" /></p>
<p>Human error is inevitable, so it&#8217;s common practice to give users the ability to bring something back if they delete it by accident. But this functionality can be tricky to implement in a RDBMS, so first you need to ask an important question &#8212; do you really need it?</p>
<p>There are two styles I have encountered that are achieved via soft delete:</p>
<ol>
<li>There is an undelete feature available somewhere in the UI, or</li>
<li>Undelete requires running commands directly against the database.</li>
</ol>
<p>If there is an undo delete button available somewhere for users, then it is an important use case that needs to be factored into your code.</p>
<p>But if you&#8217;re just putting soft delete columns on out of habit, and undelete still requires a developer or DBA to run a command against the database to toggle the flags back, then this is a maintenance scenario, not a use case. Implementing it will take time and add significant complexity to your data model, and add very little benefit for end users, so why bother? It&#8217;s a pretty clear <abbr title="you ain't gonna need it">YAGNI</abbr> violation &#8212; in the rare case you really <em>do</em> need to restore deleted rows, you can just get them from the previous night&#8217;s backup.</p>
<p>Otherwise, if there really is a requirement in your application for users to be able to undo deletes, there is already a well-known pattern specifically designed to take care of all your undo-related scenarios.</p>
<h4>The memento pattern</h4>
<p>Soft delete only supports undoing deletes, but the <a href="http://en.wikipedia.org/wiki/Memento_pattern">memento pattern</a> provides a standard means of handling <em>all</em> undo scenarios your application might require.</p>
<p>It works by taking a snapshot of an item just before a change is made, and putting it aside in a separate store, in case a user wants to restore or rollback later. For example, in a job board application, you might have two tables: one transactional for live jobs, and an undo log that stores snapshots of jobs at previous points in time:</p>
<p><img src="http://yuml.me/diagram/scruffy;dir:lr;scale:90/class/%5BJobs.Listing|ListingId%20GUID%3BTitle%20VARCHAR%28255%29%3BAnnualSalary%20INT%3BDescription%20VARCHAR%28MAX%29%3B%20...%5D%2C%20%5BJobs.Listing%5D-%5Bnote%3A%20Transactional%20table%20only%20contains%20active%20job%20listings%7Bbg%3Acornsilk%7D%5D%2C%20%5BApp.UndoLog|ObjectId%20GUID%3BVersion INT%3BSerializedObject%20XML%5D%2C%20%5BApp.UndoLog%5D-%5Bnote%3A%20Undo%20log%20contains%20snapshots%20of%20jobs%20before%20they%20were%20edited%20or%20deleted%7Bbg%3Acornsilk%7D%5D" title="Separation of mementos from transactional table" class="aligncenter" /></p>
<p>If you want to restore one, you simply deserialize it and insert it back in. This is much cleaner than messing up your transactional tables with ghost items, and lets you handle all undo operations together using the same pattern.</p>
<h4>Soft delete for auditing</h4>
<p>Another common practice I have seen is using soft delete as a means of auditing: to keep a record of when an item was deleted, and who deleted it. Usually additional columns are added to store this information:</p>
<p><img src="http://yuml.me/diagram/scruffy/class/%5BProduct%7CName%20VARCHAR%28255%29%3B...%3BDeletedAt%20DATETIME%3BDeletedByUserID%20INT%3B%5D" class="aligncenter" title="Table with DeletedBy/DeletedAt columns" /></p>
<p>As with undo, you should ask a couple of questions before you implement soft delete for auditing reasons:</p>
<ul>
<li>Is there a requirement to log when an item is deleted?</li>
<li>Is there a requirement to log any <em>other</em> significant application events?</li>
</ul>
<p>In the past I have seen developers (myself included) automatically adding delete auditing columns like this as a convention, without questioning why it&#8217;s needed (aka <a href="http://en.wikipedia.org/wiki/Cargo_cult_programming">cargo cult programming</a>).</p>
<p>Deleting an object is only one event we might be interested in logging. If a rogue user performs some malicious acts in your application, updates could be just as destructive so we should know about those too.</p>
<p>One possible conclusion from this thought is that you simply log all DML operations on the table. You can do this pretty easily with triggers:</p>
<pre class="brush: sql; toolbar: false;">-- Log all DELETE operations on the Product table
CREATE TRIGGER tg_Product_Delete ON Product AFTER DELETE
AS
	INSERT INTO [Log]
	(
		[Timestamp],
		[Table],
		Command,
		ID
	)
	SELECT
		GETDATE(),
		'Product',
		'DELETE',
		ProductID
	FROM
		Deleted

CREATE TRIGGER tg_Product_Update ON Product AFTER UPDATE
AS
-- ...etc
</pre>
<h4>Contextual logging</h4>
<p><img src="http://richarddingwall.name/wp-content/uploads/2009/11/the-hangover.jpg" alt="The Hangover" title="The Hangover" width="93" height="143" class="alignright size-full wp-image-2553" /></p>
<p>If something goes wrong in the application and we want to retrace the series of steps that led to it, CREATES, UPDATES and DELETES by themselves don&#8217;t really explain much of what the user was trying to achieve. Getting useful audit logs from DML statements alone is like trying to figure out what you did last night from just your credit card bill.</p>
<p>It would be more useful if the logs were expressed in the context of the use case, not just the database commands that resulted from it. For example, if you were tracking down a bug, would you rather read this:</p>
<pre class="brush: plain; toolbar: false;">[09:30:24] DELETE ProductCategory 142 13 dingwallr</pre>
<p>&#8230; or this?<?p></p>
<pre class="brush: plain; toolbar: false;">[09:30:24] Product 'iPhone 3GS' (#142) was removed from the catalog by user dingwallr. Categories: 'Smart Phones' (#13), 'Apple' (#15).</pre>
<p>Logging at the row level simply cannot provide enough context to give a true picture of what the user is doing. Instead it should be done at a higher level where you know the full use-case (e.g. application services), and the logs should be kept out of the transactional database so they can be managed separately (e.g. rolling files for each month).</p>
<h4>Soft create</h4>
<p>The soft delete pattern can also be extended for item activation &#8212; instead of simply creating an item as part of the active set, you create it in an inactive state and flick a switch or set a date for when it should become active.</p>
<p>For example:</p>
<pre class="brush: sql; toolbar: false;">-- Get employees who haven't started work yet
SELECT * FROM Employee WHERE GETDATE() &amp;lt; StartDate</pre>
<p>This pattern is most commonly seen in publishing systems like blogs and CMSs, but I&#8217;ve also seen it used as an important part of an ERP system for scheduling changes to policy before it comes into effect.</p>
<h4>Soft delete to retain historical items</h4>
<p><img src="http://richarddingwall.name/wp-content/uploads/2009/11/arkwarehouse.jpg" alt="Raiders of the Lost Database" title="Raiders of the Lost Database" width="489" height="323" class="aligncenter size-full wp-image-2597" /></p>
<p>Many database-backed business applications are required to keep track of old items for historical purposes &#8212; so users can go back and see what the state of the business was six months ago, for example.</p>
<p>(Alternatively, historical data is kept because the developer can&#8217;t figure out how to delete something without breaking foreign key constraints, but this really amounts to the same thing.)</p>
<p>We need to keep this data <em>somewhere</em>, but it&#8217;s no longer immediately interesting to the application because either:</p>
<ul>
<li>The item explicitly entered a dormant state &#8211; e.g. an expired eBay listing or deactivated Windows account, or</li>
<li>The item was implicitly dropped from the active set &#8211; e.g. my Google Calendar appointments from last week that I will probably never look at again</li>
</ul>
<p>I haven&#8217;t included deleted items here because there are very few cases I can think of in business applications where data is simply deleted (unless it was entered in error) &#8212; usually it is just transformed from one state to another. Udi Dahan explains this well in his article <a href="http://www.udidahan.com/2009/09/01/dont-delete-just-dont/">Don&#8217;t Delete &#8212; Just&#8217; Don&#8217;t</a>:<br />
<blockquote>Orders aren’t deleted – they’re cancelled. There may also be fees incurred if the order is canceled too late.</p>
<p>Employees aren’t deleted – they’re fired (or possibly retired). A compensation package often needs to be handled.</p>
<p>Jobs aren’t deleted – they’re filled (or their requisition is revoked).</p></blockquote>
<p>Unless your application is pure CRUD (e.g. data grids), these states most likely represent totally different use cases. For example, in a timesheet application, complete tasks may be used for invoicing purposes, while incomplete tasks comprise your todo list.</p>
<h4>Different use cases, different query needs</h4>
<p>Each use case has different query requirements, as the information the application is interested in depends on the context. To achieve optimal performance, the database should reflect this &#8212; instead of lumping differently-used sets of items together in one huge table with a flag or status code as a discriminator, consider splitting them up into separate tables.</p>
<p>For example, in our job board application, we might store open, expired and filled listings using a table-per-class strategy:</p>
<p><img src="http://yuml.me/diagram/scruffy;dir:lr/class/%5BJobs.Listing|ListingID%20GUID%5D%2C%20%5BJobs.Listing%5D--%5BJobs.ExpiredListing|ListingID%20GUID%3BExpiredDate%20DATETIME%3B...%5D%2C%20%5BJobs.Listing%5D--%5BJobs.FilledListing|ListingID%20GUID%3BFilledDate%20DATETIME%3B%20FilledByApplicantID%20GUID%3B...%5D%2C%20%5BJobs.Listing%5D--%5BJobs.OpenListing|ListingID%20GUID%3BExpiryDate%20DATETIME%3B...%5D" class="aligncenter" title="Split up tables by state" /></p>
<p>Physically separating job listings by state allows us to optimize them for different use cases &#8212; focusing on write performance for active items, and read performance for past ones, with different columns, indexes and levels of (de)normalization for each.</p>
<h4>Isn&#8217;t this all overkill?</h4>
<p>Probably. If you&#8217;re already using soft delete and haven&#8217;t had any problems then you don&#8217;t need to worry &#8212; soft delete was a sensible trade-off for your application that hasn&#8217;t caused any serious issues so far.</p>
<p>But if you&#8217;re anticipating growth, or already encountering scalability problems as dead bodies pile up in your database, you might like to look at alternatives that better satisfy your application&#8217;s requirements.</p>
<p>The truth is soft delete is a poor solution for most of the problems it promises to solve. Instead, focus on what you&#8217;re <em>actually</em> trying to achieve. Keep everything simple and follow these guidelines:</p>
<ul>
<li>Primary transactional tables should only contain data that is valid and active right now.</li>
<li>Do you really need to be able to undo deletes? If so, there are dedicated patterns to handle this.</li>
<li>Audit logging at the row level sucks. Do it higher up where you know the full story.</li>
<li>If a row doesn&#8217;t apply yet, put it in a queue until it does.</li>
<li>Physically separate items in different states based on their query usage.</li>
</ul>
<p>Above all, make sure you&#8217;re not gold plating tables with soft delete simply out of habit!</p>
<img src="http://feeds.feedburner.com/~r/RichardDingwall/~4/GrtV8Y15vZo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://richarddingwall.name/2009/11/20/the-trouble-with-soft-delete/feed/</wfw:commentRss>
		<slash:comments>22</slash:comments>
		<feedburner:origLink>http://richarddingwall.name/2009/11/20/the-trouble-with-soft-delete/</feedburner:origLink></item>
	</channel>
</rss><!-- Dynamic Page Served (once) in 0.385 seconds -->
