<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	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/"
	>

<channel>
	<title>Philosophical Geek &#187; Software Development</title>
	<atom:link href="http://www.philosophicalgeek.com/category/software-development/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.philosophicalgeek.com</link>
	<description>Code and musings by Ben Watson</description>
	<lastBuildDate>Mon, 26 Jul 2010 18:29:36 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Measure Amount of Data to Serialize with a Null Stream</title>
		<link>http://www.philosophicalgeek.com/2010/07/26/measure-amount-of-data-to-serialize-with-a-null-stream/</link>
		<comments>http://www.philosophicalgeek.com/2010/07/26/measure-amount-of-data-to-serialize-with-a-null-stream/#comments</comments>
		<pubDate>Mon, 26 Jul 2010 17:00:00 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[serialization]]></category>

		<guid isPermaLink="false">http://www.philosophicalgeek.com/2010/07/26/measure-amount-of-data-to-serialize-with-a-null-stream-3/</guid>
		<description><![CDATA[If you’ve got to serialize some data, especially in a binary format, it’s common to output the length of the data. This is useful for versioning, random access, knowing when you’re done reading the records, among other reasons. Therefore, you need to know the size of the data you’re going to serialize. There are a [...]]]></description>
			<content:encoded><![CDATA[<p>If you’ve got to serialize some data, especially in a binary format, it’s common to output the length of the data. This is useful for versioning, random access, knowing when you’re done reading the records, among other reasons.</p>
<p>Therefore, you need to know the size of the data you’re going to serialize. There are a few ways to do this:</p>
<ol>
<li>Measure the position you’re at, write the data, measure the new position, subtract, and that’s your length. </li>
<li>If you want to write the length first (which is usually better), you can write a dummy value, such as 0, then writing the data, then backing up in the stream, and writing the real value. </li>
<li>If you can’t back up the stream (very possible in some situations, or undesirable in others), you can measure the amount of data before you write. However, now you have to maintain that code in addition to the actual serialization. </li>
<li>My solution presented here, avoids having to maintain separate code by writing the data to a null stream which does not write any data, but keeps track of how much data was “written.” </li>
</ol>
<pre class="csharpcode"><span class="kwrd">class</span> NullStream : System.IO.Stream
{
    <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">bool</span> CanRead { get { <span class="kwrd">return</span> <span class="kwrd">false</span>; } }

    <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">bool</span> CanSeek { get { <span class="kwrd">return</span> <span class="kwrd">false</span>; } }

    <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">bool</span> CanWrite {get { <span class="kwrd">return</span> <span class="kwrd">true</span>; } }

    <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">void</span> Flush() { <span class="rem">/*do nothing*/</span> }

    <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">long</span> Length { get { <span class="kwrd">return</span> Position; } }

    <span class="kwrd">private</span> <span class="kwrd">long</span> _position = 0;
    <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">long</span> Position
    {
        get
        {
            <span class="kwrd">return</span> _position;
        }
        set
        {
            _position = <span class="kwrd">value</span>;
        }
    }

    <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">int</span> Read(<span class="kwrd">byte</span>[] buffer, <span class="kwrd">int</span> offset, <span class="kwrd">int</span> count)
    {
        <span class="kwrd">throw</span> <span class="kwrd">new</span> InvalidOperationException();
    }

    <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">void</span> Write(<span class="kwrd">byte</span>[] buffer, <span class="kwrd">int</span> offset, <span class="kwrd">int</span> count)
    {
        Position += count;
    }

    <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">long</span> Seek(<span class="kwrd">long</span> offset, System.IO.SeekOrigin origin)
    {
        <span class="kwrd">throw</span> <span class="kwrd">new</span> InvalidOperationException();
    }

    <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">void</span> SetLength(<span class="kwrd">long</span> <span class="kwrd">value</span>)
    {
        <span class="kwrd">throw</span> <span class="kwrd">new</span> InvalidOperationException();
    }
}</pre>
<style type="text/css">
<p>.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
<p>You can use it like this:</p>
<pre class="csharpcode"><span class="kwrd">long</span> GetDataSize()
{
    <span class="kwrd">using</span> (NullStream stream = <span class="kwrd">new</span> NullStream())
    {
        <span class="kwrd">if</span> (SaveData(stream))
        {
            <span class="kwrd">return</span> stream.Position;
        }
    }
    <span class="kwrd">return</span> 0;
}</pre>
<style type="text/css">
<p>.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
<p>There is a downside to something like this: you’re still essentially doing a lot of the work of serialization. Sure, you’re not writing out the bytes anywhere, but if, say, you need to encode a string as bytes before writing to the stream, that’s still going to happen. </p>
<p>Still, this technique made sense in my case, maybe it will work for you.</p>
<img src="http://www.philosophicalgeek.com/?ak_action=api_record_view&id=599&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.philosophicalgeek.com/2010/07/26/measure-amount-of-data-to-serialize-with-a-null-stream/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Get a Free, Autographed Copy of C# 4.0 How-To!</title>
		<link>http://www.philosophicalgeek.com/2010/05/10/get-a-free-autographed-copy-of-c-4-0-how-to/</link>
		<comments>http://www.philosophicalgeek.com/2010/05/10/get-a-free-autographed-copy-of-c-4-0-how-to/#comments</comments>
		<pubDate>Mon, 10 May 2010 21:04:04 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Books]]></category>
		<category><![CDATA[Software Development]]></category>

		<guid isPermaLink="false">http://www.philosophicalgeek.com/2010/05/10/get-a-free-autographed-copy-of-c-4-0-how-to/</guid>
		<description><![CDATA[To celebrate how well C# 4.0 How-To is doing, I’m going to give away two free copies of the book! Here’s how it’s going to work: 1. Leave a comment on this post describing a project you’d like to build with C# 4. 2. I’ll pick two people from those comments at random. (Make sure [...]]]></description>
			<content:encoded><![CDATA[<p>To celebrate how well <a href="http://www.amazon.com/gp/product/0672330636?ie=UTF8&amp;tag=philosophic0d-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0672330636">C# 4.0 How-To</a> is doing, I’m going to give away two free copies of the book!</p>
<p>Here’s how it’s going to work:</p>
<p>1. Leave a comment on this post describing a project you’d like to build with C# 4.</p>
<p>2. I’ll pick two people from those comments at random.</p>
<p>(Make sure you enter your e-mail address where asked—it won’t be published to the blog, but I need it to contact you.)</p>
<p>I’ll leave the comments open for a while and I’ll update this post with the closing date.</p>
<p>Feel free to share a link to this blog post, tweet it, etc. If I get a lot of responses I may give away more.</p>
<p>Thanks to all those have already bought it!</p>
<p>UPDATE 18 May: I am going to close comments on Saturday morning (22 May) and pick the winners then. Thanks for commenting!</p>
<p>UPDATE 22 May: Comments are closed.</p>
<img src="http://www.philosophicalgeek.com/?ak_action=api_record_view&id=582&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.philosophicalgeek.com/2010/05/10/get-a-free-autographed-copy-of-c-4-0-how-to/feed/</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
		<item>
		<title>Interview with Me</title>
		<link>http://www.philosophicalgeek.com/2010/03/19/interview-with-me/</link>
		<comments>http://www.philosophicalgeek.com/2010/03/19/interview-with-me/#comments</comments>
		<pubDate>Fri, 19 Mar 2010 17:05:16 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Books]]></category>
		<category><![CDATA[Link/News]]></category>
		<category><![CDATA[Personal]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Thoughts On Tech and More]]></category>

		<guid isPermaLink="false">http://www.philosophicalgeek.com/2010/03/19/interview-with-me/</guid>
		<description><![CDATA[InformIT has just published an interview with me where they asked me a bunch of questions related to C# 4.0 How-To. We got into the multicore future, Internet versus books, why C# programmers need to know about UAC, and a lot more. Check it out!]]></description>
			<content:encoded><![CDATA[<p>InformIT has just published <a href="http://www.informit.com/articles/article.aspx?p=1573024">an interview</a> with me where they asked me a bunch of questions related to <a href="http://www.amazon.com/gp/product/0672330636?ie=UTF8&amp;tag=philosophic0d-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0672330636">C# 4.0 How-To</a>. We got into the multicore future, Internet versus books, why C# programmers need to know about UAC, and a lot more. Check it out!</p>
<img src="http://www.philosophicalgeek.com/?ak_action=api_record_view&id=566&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.philosophicalgeek.com/2010/03/19/interview-with-me/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>C# 4.0 How-To Available Now!</title>
		<link>http://www.philosophicalgeek.com/2010/03/08/c-4-0-how-to-available-now/</link>
		<comments>http://www.philosophicalgeek.com/2010/03/08/c-4-0-how-to-available-now/#comments</comments>
		<pubDate>Mon, 08 Mar 2010 21:41:15 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Books]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[Personal]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.philosophicalgeek.com/2010/03/08/c-4-0-how-to-available-now/</guid>
		<description><![CDATA[Well, it’s finally out! Amazon no longer lists the book as available for pre-sale, and it should be shipping to purchasers today or tomorrow. If you’re a B&#38;N shopper, you can also order it there, or grab it in stores within a few days. From the product description: Real Solutions for C# 4.0 Programmers Need [...]]]></description>
			<content:encoded><![CDATA[<p><iframe style="width: 120px; height: 240px" marginheight="0" src="http://rcm.amazon.com/e/cm?lt1=_blank&amp;bc1=FFFFFF&amp;IS2=1&amp;nou=1&amp;bg1=FFFFFF&amp;fc1=000000&amp;lc1=0000FF&amp;t=philosophic0d-20&amp;o=1&amp;p=8&amp;l=as1&amp;m=amazon&amp;f=ifr&amp;md=10FE9736YVPPT7A0FBG2&amp;asins=0672330636" frameborder="0" marginwidth="0" scrolling="no" align="left"></iframe>
<p>Well, it’s finally out! <a href="http://www.amazon.com/gp/product/0672330636?ie=UTF8&amp;tag=philosophic0d-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0672330636">Amazon</a> no longer lists the book as available for pre-sale, and it should be shipping to purchasers today or tomorrow. If you’re a B&amp;N shopper, you can also order it <a href="http://search.barnesandnoble.com/C-40-How-to/Ben-Watson/e/9780672330636/?itm=4&amp;USRI=c%23+4.0">there</a>, or grab it in stores within a few days.</p>
<p>From the product description:</p>
<h3>Real Solutions for C# 4.0 Programmers</h3>
<p>Need fast, robust, efficient code solutions for Microsoft C# 4.0? This book delivers exactly what you’re looking for. You’ll find more than 200 solutions, best-practice techniques, and tested code samples for everything from classes to exceptions, networking to XML, LINQ to Silverlight. Completely up-to-date, this book fully reflects major language enhancements introduced with the new C# 4.0 and .NET 4.0. When time is of the essence, turn here first: Get answers you can trust and code you can use, right now!</p>
<p>Beginning with the language essentials and moving on to solving common problems using the .NET Framework, <i><b><i>C# 4.0 How-To</i> </b></i>addresses a wide range of general programming problems and algorithms. Along the way is clear, concise coverage of a broad spectrum of C# techniques that will help developers of all levels become more proficient with C# and the most popular .NET tools.</p>
<p><b>Fast, Reliable, and Easy to Use!</b></p>
<ul>
<li>Write more elegant, efficient, and reusable code </li>
<li>Take advantage of real-world tips and best-practices advice </li>
<li>Create more effective classes, interfaces, and types </li>
<li>Master powerful data handling techniques using collections, serialization, databases, and XML </li>
<li>Implement more effective user interfaces with both WPF and WinForms </li>
<li>Construct Web-based and media-rich applications with ASP.NET and Silverlight </li>
<li>Make the most of delegates, events, and anonymous methods </li>
<li>Leverage advanced C# features ranging from reflection to asynchronous programming </li>
<li>Harness the power of regular expressions </li>
<li>Interact effectively with Windows and underlying hardware </li>
<li>Master the best reusable patterns for designing complex programs </li>
</ul>
<p>I’ll be doing a book giveaway at some point as well, once I get my own shipment. Stay tuned!</p>
<p>Get it from <a href="http://www.amazon.com/gp/product/0672330636?ie=UTF8&amp;tag=philosophic0d-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0672330636">Amazon</a></p>
<p>Get it from <a href="http://search.barnesandnoble.com/C-40-How-to/Ben-Watson/e/9780672330636/?itm=6&amp;USRI=ben+watson">Barnes and Noble</a></p>
<img src="http://www.philosophicalgeek.com/?ak_action=api_record_view&id=523&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.philosophicalgeek.com/2010/03/08/c-4-0-how-to-available-now/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>How to learn WPF (or anything else)</title>
		<link>http://www.philosophicalgeek.com/2009/01/29/how-to-learn-wpf-or-anything-else/</link>
		<comments>http://www.philosophicalgeek.com/2009/01/29/how-to-learn-wpf-or-anything-else/#comments</comments>
		<pubDate>Thu, 29 Jan 2009 05:51:20 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Tips]]></category>

		<guid isPermaLink="false">http://www.philosophicalgeek.com/2009/01/29/how-to-learn-wpf-or-anything-else/</guid>
		<description><![CDATA[I’ve recently been learning WPF. This is a huge topic that is uncontainable by any single book, tutorial, or web-site. The complexity and breadth of this framework is nearly oppressive, but the results are incredible. Or rather, I should say, potentially incredible. My first book, C# 4.0 How-To is now shipping! If you like tips [...]]]></description>
			<content:encoded><![CDATA[<p>I’ve recently been learning WPF. This is a huge topic that is uncontainable by any single book, tutorial, or web-site. The complexity and breadth of this framework is nearly oppressive, but the results are incredible. Or rather, I should say, <em>potentially</em> incredible.</p>
<p><strong>My first book, <a href="http://www.amazon.com/gp/product/0672330636?ie=UTF8&amp;tag=philosophic0d-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0672330636">C# 4.0 How-To</a> is now shipping! If you like tips you can use, check it out!</strong></p>
<p>From everything I’ve read, people who have suffered through the WPF learning curve have this to say, more or less:</p>
<blockquote><p><span style="background-color: #ffffff; color: #333333;">yeah, it was really tough going for a few months. But now I can create awesome apps in a fraction of the time it would take with older technologies.</span></p></blockquote>
<p>So with that in mind, I really do want to learn WPF. I have a number of C# references, weighty tomes that bend my shelves, but the main book I use is <a href="http://www.amazon.com/gp/product/0596510373?ie=UTF8&amp;tag=philosophic0d-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0596510373">Programming WPF</a><img style="margin: 0px; border-style: none! important;" src="http://www.assoc-amazon.com/e/ir?t=philosophic0d-20&amp;l=as2&amp;o=1&amp;a=0596510373" border="0" alt="" width="1" height="1" />by Chris Sells and Ian Griffiths. I really like this book—it goes in deep. However, I realized that reading through it cover to cover and doing all the sample apps wasn’t going to work—it gets boring, no matter how good the book is. So here is my recommendation on how to learn WPF (and it probably applies to any programming technology):</p>
<ol>
<li>Start reading the book, do the code, type stuff in, copy it, tweak it. Do this for as long as you can.</li>
<li>Once step 1 becomes boring, <strong>STOP</strong>. It is not productive to force yourself through the whole thing like this.</li>
<li>Find a sample project in your target technology. I used <a href="http://www.vertigo.com/familyshow.aspx">Family.Show</a>. There are plenty out there.</li>
<li>Think of a project YOU find interesting that would be good in [WPF|other]. Start doing this. Even if you don’t know where to start at all.</li>
<li>While getting started, every step will be a challenge. Figure it out step-by-step, going back to the book and online resources.</li>
</ol>
<p>You might be tempted to skip steps 1-2. I think this is a bad idea. You need at least some foundational understanding. Only when you can’t take it any more and you’re in danger of quitting, move on.</p>
<p>This has worked well for me in learning WPF. I decided to implement a game (if it ever gets into a polished state, I’ll share it).</p>
<p>Don’t underestimate the challenges in step 4, though. I had to think about how to even start, going back to the book numerous times, reading large sections. I looked up articles online about patterns and WPF, user controls, and more. Many seemingly-small steps in just displaying windows took hours to figure out. Figuring out data binding (<em>really</em> figuring it out in the context of my app) took hours. The point of doing your own project isn’t because it’s easier than following the book—it’s because it’s fun and you have more motivation to learn.</p>
<p><strong>My first book, <a href="http://www.amazon.com/gp/product/0672330636?ie=UTF8&amp;tag=philosophic0d-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0672330636">C# 4.0 How-To</a> is now shipping! If you like tips you can use, check it out!</strong></p>
<img src="http://www.philosophicalgeek.com/?ak_action=api_record_view&id=435&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.philosophicalgeek.com/2009/01/29/how-to-learn-wpf-or-anything-else/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>NDepend: A short review</title>
		<link>http://www.philosophicalgeek.com/2008/11/29/ndepend-a-short-review/</link>
		<comments>http://www.philosophicalgeek.com/2008/11/29/ndepend-a-short-review/#comments</comments>
		<pubDate>Sun, 30 Nov 2008 00:28:54 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Link/News]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[reviews]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://www.philosophicalgeek.com/2008/11/29/ndepend-a-short-review/</guid>
		<description><![CDATA[NDepend is a tool I’d heard about for years, but had yet to really dive into recently. Thanks to the good folks developing it, I was able to try out a copy and have been analyzing my own projects with it. Here’s a brief run-down of my initial experience with it. Installation There is no [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.ndepend.com/">NDepend</a> is a tool I’d heard about for years, but had yet to really dive into recently. Thanks to the good folks developing it, I was able to try out a copy and have been analyzing my own projects with it.</p>
<p>Here’s a brief run-down of my initial experience with it.</p>
<h2>Installation</h2>
<p>There is no installation file—everything is packaged into a zip. After running, I was greeted by a project selection screen, in which I created a new project and added some assemblies. <a href="http://www.philosophicalgeek.com/wp-content/uploads/2008/11/ndepend-mainscreen.png"><img title="NDepend main screen" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="232" alt="NDepend main screen" src="http://www.philosophicalgeek.com/wp-content/uploads/2008/11/ndepend-mainscreen-thumb.png" width="404" border="0" /></a> </p>
<h2>Analysis</h2>
<p>Once you have all the assemblies you want to analyze selected, you can run the analysis, which generates both an HTML report with graphics, and an interactive report that you can use to drill down into almost any detail of your code. Indeed, it’s almost overwhelming the amount of detail present in this tool.</p>
<p>One graph you see almost immediately is Abstractness Vs. Instability.</p>
<p><a href="http://www.philosophicalgeek.com/wp-content/uploads/2008/11/ndepend-abstractnessvsinstability.png"><img title="Abstractness vs. Instability" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="404" alt="Abstractness vs. Instability" src="http://www.philosophicalgeek.com/wp-content/uploads/2008/11/ndepend-abstractnessvsinstability-thumb.png" width="404" border="0" /></a> </p>
<p>This is a good high-level overview of your entire project at the assembly level. Basically, what this means is that assemblies that are too abstract and unstable are potentially useless and should be culled, while assemblies that are concrete and stable can be hard to maintain. Instability is defined in the help docs in terms of coupling (internal and external), while abstractness is the ratio of abstract types to total types in an assembly.</p>
<p>This is followed by the dependency graph:</p>
<p><a href="http://www.philosophicalgeek.com/wp-content/uploads/2008/11/ndepend-dependencies.png"><img title="Dependency graph" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="124" alt="Dependency graph" src="http://www.philosophicalgeek.com/wp-content/uploads/2008/11/ndepend-dependencies-thumb.png" width="404" border="0" /></a> </p>
<p>After these graphics come lots of reports that dig into your code for all sorts of conditions.</p>
<p>For example, the first one in my report was “Quick summary of methods to refactor&quot;.” That seems pretty vague, until you learn how they determine this. All the reports in NDepend are built off of a SQL-like query language called CQL (Code Query Language). The syntax for this is extremely easy. The query and result for this report are:</p>
<p><a href="http://www.philosophicalgeek.com/wp-content/uploads/2008/11/ndepend-refactormethods.png"><img title="NDepend_RefactorMethods" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="234" alt="NDepend_RefactorMethods" src="http://www.philosophicalgeek.com/wp-content/uploads/2008/11/ndepend-refactormethods-thumb.png" width="404" border="0" /></a> </p>
<p>With very little work on my part, I instantly have a checklist of items I need to look at to improve code quality and maintainability.</p>
<p>There are tons of other reports: methods that are too complex, methods that are poorly commented, have too many parameters, to many local variables, or classes with too many methods, etc. And of course, you can create your own (which I demonstrate below).</p>
<h2>Interactive Visualization</h2>
<p>All of these reports are put into the HTML report. But as I said, you can use the interactive visualizer to drill down further into your code.</p>
<p>The first thing you’re likely to see is a group of boxes looking like this:</p>
<p><a href="http://www.philosophicalgeek.com/wp-content/uploads/2008/11/ndepend-metrics.png"><img title="NDepend_Metrics" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="174" alt="NDepend_Metrics" src="http://www.philosophicalgeek.com/wp-content/uploads/2008/11/ndepend-metrics-thumb.png" width="404" border="0" /></a> </p>
<p>These boxes show the relative sizes of your code from the assembly level down to the methods. Holding the mouse over a box will bring up more information about the method. You can also change the metric you’re measuring by—say to <a href="http://en.wikipedia.org/wiki/Cyclomatic_complexity">cyclomatic complexity</a>.</p>
<p>Another view, perhaps the most useful of all is the CQL Queries view. In this, you can see the results from all of hundreds of code queries, as well as create your own. For instance, I can see all the types with poor cohesion in my codebase:</p>
<p><a href="http://www.philosophicalgeek.com/wp-content/uploads/2008/11/ndepend-cohesion.png"><img title="NDepend_Cohesion" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="327" alt="NDepend_Cohesion" src="http://www.philosophicalgeek.com/wp-content/uploads/2008/11/ndepend-cohesion-thumb.png" width="404" border="0" /></a> </p>
<p>In this view, the CQL queries are selected in the bottom-right, and the results show up on the left. The metrics view highlights the affected methods.</p>
<h2>Creating a query</h2>
<p>Early in the development of my project, I named quite a few classes starting with a LB prefix. I’ve changed some of them, but I think there are still a few lying around and I want to change them as well. So I’ll create CQL query to return all the types that begin with “LB.”</p>
<div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, &#39;Courier New&#39;, courier, monospace; background-color: #f4f4f4">
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060">   1:</span> <span style="color: #008000">// &lt;Name&gt;Types beginning with LB&lt;/Name&gt;</span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060">   2:</span> WARN IF Count &gt; 0 IN SELECT TYPES WHERE </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060">   3:</span>  NameLike <span style="color: #006080">&quot;LB&quot;</span> AND     </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060">   4:</span>  !IsGeneratedByCompiler AND </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060">   5:</span>  !IsInFrameworkAssembly     </pre>
</p></div>
</div>
<p><a href="http://www.philosophicalgeek.com/wp-content/uploads/2008/11/ndepend-lb.png"><img title="NDepend_LB" style="border-right: 0px; border-top: 0px; display: inline; margin-left: 0px; border-left: 0px; margin-right: 0px; border-bottom: 0px" height="244" alt="NDepend_LB" src="http://www.philosophicalgeek.com/wp-content/uploads/2008/11/ndepend-lb-thumb.png" width="128" align="right" border="0" /></a> That’s it! You can see the results to the right. It’s ridiculously easy to create your own queries to examine nearly any aspect of your code. And that’s if the hundreds of included queries don’t do it for you. In many ways, the queries are similar to the analysis <a href="http://msdn.microsoft.com/en-us/library/bb429476(VS.80).aspx">FxCop</a> does, but I think CQL seems generally more powerful (while lacking some of the cool things FxCop has).</p>
<p>&#160;</p>
<h2>VS and Reflector Add-ins</h2>
<p>NDepend has a couple of extras that enable integration of Visual Studio (2005 and 2008) and NDepend and Reflector. When you right-click on an item in VS, you will have some additional options available:</p>
<p><a href="http://www.philosophicalgeek.com/wp-content/uploads/2008/11/ndepend-vsplugin1.png"><img title="NDepend_VSPlugin1" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="484" alt="NDepend_VSPlugin1" src="http://www.philosophicalgeek.com/wp-content/uploads/2008/11/ndepend-vsplugin1-thumb.png" width="415" border="0" /></a> </p>
<p>Clicking on the submenu gives you options to directly run queries in NDepend. Very cool stuff.</p>
<h2>Summary and where to get more info</h2>
<p>If you are at all interested in code metrics, and how good your code is behaving, how maintainable it is, you need this tool. It’s now going to be a standard part of my toolbox for evaluating the quality of my code and what parts need attention.</p>
<p>If you’re using NDepend for personal and non-commercial reasons, you can download it for free. It doesn’t have <a href="http://www.ndepend.com/Editions.aspx">all the features</a>, but it has more than enough. Professional use does require a license.</p>
<p>One of the things I was particularly impressed with was the amount of <a href="http://www.ndepend.com/GettingStarted.aspx">help content</a> available. There are tons of tutorials for every part of the program. </p>
<p>I’m going to keep playing with this and I’m sure I’ll mention some more things as I discover them. For now, NDepend is very cool—it’s actually fun to play with, and it gives you good information for what to work on.</p>
<p>Links:</p>
<ul>
<li><a href="http://www.ndepend.com/">NDepend homepage</a></li>
<li><a href="http://www.hanselman.com/blog/content/binary/NDepend%20metrics%20placemats%201.1.pdf">NDepend metrics explanation</a></li>
</ul>
<img src="http://www.philosophicalgeek.com/?ak_action=api_record_view&id=413&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.philosophicalgeek.com/2008/11/29/ndepend-a-short-review/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>On the importance of ignoring your problems</title>
		<link>http://www.philosophicalgeek.com/2008/11/20/on-the-importance-of-ignoring-your-problems/</link>
		<comments>http://www.philosophicalgeek.com/2008/11/20/on-the-importance-of-ignoring-your-problems/#comments</comments>
		<pubDate>Fri, 21 Nov 2008 01:34:30 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[microsoft]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[Tips]]></category>

		<guid isPermaLink="false">http://www.philosophicalgeek.com/2008/11/20/on-the-importance-of-ignoring-your-problems/</guid>
		<description><![CDATA[I’ve been having a great time at Microsoft over the last couple of months, but the ramp to full productivity is very steep. Recently, I’ve been working on an important improvement to some monitoring software, which requires a fairly good understanding of part of the system. It can be a little overwhelming trying to design [...]]]></description>
			<content:encoded><![CDATA[<p>I’ve been having a great time at Microsoft over the last couple of months, but the ramp to full productivity is very steep. Recently, I’ve been working on an important improvement to some monitoring software, which requires a fairly good understanding of part of the system. It can be a little overwhelming trying to design something to handle all the nuances involved. Add to that the time crunch, and things get a little interesting. Last night, I ran into a little wall where I was uncertain about how to proceed. This kind of situation is always a little precarious. I was worried because today and tomorrow I have full-day training and won’t be able to dedicate a lot of time to solving this problem.</p>
<p>Half way through the training, while discussing something tangentially related to my problems, I realized the technical solution to the specific issue I was facing.</p>
<p>Sometimes you just need to ignore the problem for a while, and come back to it from a different angle.</p>
<img src="http://www.philosophicalgeek.com/?ak_action=api_record_view&id=392&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.philosophicalgeek.com/2008/11/20/on-the-importance-of-ignoring-your-problems/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Software Creativity and Strange Loops</title>
		<link>http://www.philosophicalgeek.com/2008/11/03/software-creativity-and-strange-loops/</link>
		<comments>http://www.philosophicalgeek.com/2008/11/03/software-creativity-and-strange-loops/#comments</comments>
		<pubDate>Tue, 04 Nov 2008 02:11:15 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[A Better Future]]></category>
		<category><![CDATA[Books]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Thoughts On Tech and More]]></category>
		<category><![CDATA[creativity]]></category>
		<category><![CDATA[future]]></category>
		<category><![CDATA[intelligence]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[star trek]]></category>
		<category><![CDATA[strange loop]]></category>

		<guid isPermaLink="false">http://www.philosophicalgeek.com/2008/11/03/software-creativity-and-strange-loops/</guid>
		<description><![CDATA[I’ve been thinking a lot lately about the kind of technology and scientific understanding that would need to go into a computer like the one on the Enterprise in Star Trek, and specifically its interaction with people. It’s a computer that can respond to questions in context—that is, you don’t have to restart in every [...]]]></description>
			<content:encoded><![CDATA[<p>I’ve been thinking a lot lately about the kind of technology and scientific understanding that would need to go into a computer like the one on the Enterprise in Star Trek, and specifically its interaction with people. It’s a computer that can respond to questions in context—that is, you don’t have to restart in every question everything needed to answer. The computer has been monitoring the conversation and has thus built up a context that it can use to understand and intelligently respond.</p>
<p>A computer that records and correlates conversations real-time must have a phenomenal ability (compared to our current technology) to not just syntactically parse the content, but also construct semantic models of it. If a computer is going to respond intelligently to you, it has to understand you. This is far beyond our current technology, but we’re moving there. In 20 years who knows where this will be. In 100, we can’t even imagine it. 400 years is nearly beyond contemplation.</p>
<p>The philosophy of computer understanding, and human-computer interaction specifically is incredibly interesting. I was led to think a lot about this while reading Robert Glass’s <a href="http://www.amazon.com/gp/product/0977213315?ie=UTF8&amp;tag=philosophic0d-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0977213315">Software Creativity 2.0</a><img style="margin: 0px; border-top-style: none! important; border-right-style: none! important; border-left-style: none! important; border-bottom-style: none! important" height="1" alt="" src="http://www.assoc-amazon.com/e/ir?t=philosophic0d-20&amp;l=as2&amp;o=1&amp;a=0977213315" width="1" border="0" />. This book is about the design and construction of software, but it has a deep philosophical undercurrent running throughout that kept me richly engaged. Much of the book is presented as conflicts between opposing forces:</p>
<ul>
<li>Discipline versus Flexibility </li>
<li>Formal Methods versus Heuristics </li>
<li>Optimizing versus <a href="http://en.wikipedia.org/wiki/Satisficing">satisficing</a> </li>
<li>Quantitative versus qualitative reasoning </li>
<li>Process versus product </li>
<li>Intellectual versus clerical </li>
<li>Theory versus practice </li>
<li>Industry versus academe </li>
<li>Fun versus getting serious </li>
</ul>
<p>Too often, neither one of these sides is “right”—they are just part of the problem (or the solution). While the book was written from the perspective of software construction, I think you can twist the intention just a little and consider them as attributes of software itself, not just how to write it, but how software must function. Most of those titles can be broken up into a dichotomy of Thinking versus Doing.</p>
<p><strong>Thinking</strong>: Flexibility, Heuristics, Satisficing, Qualitative, Process, Intellectual, Theory, Academe</p>
<p><strong>Doing</strong>: Discipline, Formal Methods, Optimizing, Quantitative, Product, Clerical, Practice, Industry</p>
<p>Computers are wonderful at the doing, not so much at the thinking. Much of thinking is synthesizing information, recognizing patterns, and highlighting the important points so that we can understand it. As humans, we have to do this or we are overwhelmed and have no comprehension. A computer has no such requirement—all information is available to it, yet it has no capability to synthesize, apply experience and perhaps (seemingly) unrelated principles to the situation. In this respect, the computer’s advantage in quantity is far outweighed by its lack of understanding. It has all the context in the world, but no way to apply it.</p>
<p>A good benchmark for a reasonable AI on the level I’m dreaming about is a program that can synthesize a complex set of documents (be they text, audio, or video) and produce a comprehensible summary that is not just selected excerpts from each. This functionality implies an ability to understand and comprehend on many levels. To do this will mean a much deeper understanding of the problems facing us in computer science, as represented in the list above.</p>
<p>You can start to think of these attributes/actions as mutually beneficial and dependent, influencing one another, recursively, being distinct (at&#160; first), and then morphing into a spiral, both being inputs to the other. Quantitative reasoning leads to qualitative analysis which leads back to qualitative measures, etc. </p>
<p>It made me think of Douglas R. Hofstadter’s opus <a href="http://www.amazon.com/gp/product/0465026567?ie=UTF8&amp;tag=philosophic0d-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0465026567">Godel, Escher, Bach: An Eternal Golden Braid</a><img style="margin: 0px; border-top-style: none! important; border-right-style: none! important; border-left-style: none! important; border-bottom-style: none! important" height="1" alt="" src="http://www.assoc-amazon.com/e/ir?t=philosophic0d-20&amp;l=as2&amp;o=1&amp;a=0465026567" width="1" border="0" />. This is a fascinating book that, if you can get through it (I admit I struggled through parts), wants you to think of consciousness as the attempted resolution of a very high-order <em>strange loop</em>. </p>
<blockquote><p>The Strange Loop phenomenon occurs whenever, by moving upwards (or downwards) through the levels of some hierarchical system, we unexpectedly find ourselves right back where we started. </p>
</blockquote>
<p>In the book, he discusses how this pattern appears in many areas, most notably music, the works of <a href="http://search.live.com/images/results.aspx?q=escher&amp;FORM=BIRE#">Escher</a>, and in philosophy, as well as consciousness.</p>
<blockquote><p>My belief is that the explanations of “emergent” phenomena in our brains—for instance, ideas, hopes, images, analogies, and finally consciousness and free will—are based on a kind of Strange Loop, an interaction between levels in which the top level reaches back down towards the bottom level and influences it, while at the same time being itself determined by the bottom level. In other words, a self-reinforcing “resonance” between different levels… The self comes into being at the moment it has the power to reflect itself.</p>
</blockquote>
<p>I can’t help but think that this idea of a strange loop, combined with Glass’s attributes of software creativity are what will lead to more intelligent computers. </p>
<img src="http://www.philosophicalgeek.com/?ak_action=api_record_view&id=389&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.philosophicalgeek.com/2008/11/03/software-creativity-and-strange-loops/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>No American resumes? &#8211; state of CS education</title>
		<link>http://www.philosophicalgeek.com/2008/08/28/no-american-resumes-state-of-cs-education/</link>
		<comments>http://www.philosophicalgeek.com/2008/08/28/no-american-resumes-state-of-cs-education/#comments</comments>
		<pubDate>Thu, 28 Aug 2008 14:52:34 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[computer science]]></category>
		<category><![CDATA[education]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.philosophicalgeek.com/2008/08/28/no-american-resumes-state-of-cs-education/</guid>
		<description><![CDATA[I had been planning on writing a blog entry on the apparently sad state of our CS industry these days, and the complete lack of qualified American resumes that come across my desk, when we actually got a decent one today. Still, there is much to be said about the poor quality of education. At [...]]]></description>
			<content:encoded><![CDATA[<p><!--adsense--></p>
<p>I had been planning on writing a blog entry on the apparently sad state of our CS industry these days, and the complete lack of qualified American resumes that come across my desk, when we actually got a decent one today.</p>
<p>Still, there is <a href="http://www.joelonsoftware.com/articles/ThePerilsofJavaSchools.html">much</a> to be <a href="http://www.stsc.hill.af.mil/CrossTalk/2008/01/0801DewarSchonberg.html">said</a> about the poor quality of education. At some points, we&#8217;ve gone through dozens of candidates that had such weak skills that I&#8217;m surprised they graduated from a reputable institution.</p>
<p>Then I noticed on the Google blog today a <a href="http://googleblog.blogspot.com/2008/08/strengthening-study-of-computer-science.html">new initiative</a> to partner with CS programs around the country. I applaud this effort and all like it. Serious companies like Google, Microsoft, Yahoo, Amazon, Adobe, Apple, and everybody else who builds amazing software need to get involved and lay down the expectations.</p>
<p>Does anyone know if Microsoft has a similar comprehensive program? I know that they have <a href="http://msdn.microsoft.com/en-us/academic/default.aspx">MSDNAA</a>, but that seems more like giving software in a marketing campaign than setting the agenda. I do see smaller efforts with <a href="http://www.microsoft.com/presspass/features/2006/jul06/07-12robotics.mspx">robotics</a> that are great, but a more general push is needed.</p>
<p>I consider myself lucky for having gone through a fantastic <a href="http://cs.byu.edu/">computer science education at BYU</a>. I found it even much better than my graduate program.</p>
<p>The thought leaders need to start insisting on higher standards, and we need to shame schools that churn out useless bodies whose jobs will soon be outsourced.</p>
<p>I can see some pushback from academic circles because they won&#8217;t want big business telling them how to teach, but the reality is that when schools are doing such a poor job of preparing people, they need to change and listen to those who are going to be hiring.</p>
<p>We need to stop complaining and start changing the situation.</p>
<img src="http://www.philosophicalgeek.com/?ak_action=api_record_view&id=370&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.philosophicalgeek.com/2008/08/28/no-american-resumes-state-of-cs-education/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Top 10 Reasons Why I&#8217;m Excited to Work at Microsoft</title>
		<link>http://www.philosophicalgeek.com/2008/08/20/top-10-reasons-why-im-excited-to-work-at-microsoft/</link>
		<comments>http://www.philosophicalgeek.com/2008/08/20/top-10-reasons-why-im-excited-to-work-at-microsoft/#comments</comments>
		<pubDate>Wed, 20 Aug 2008 15:16:55 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[microsoft]]></category>
		<category><![CDATA[jobs]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.philosophicalgeek.com/2008/08/20/top-10-reasons-why-im-excited-to-work-at-microsoft/</guid>
		<description><![CDATA[My last post was well and good (definitely read the comments), but I think I should be serious about my new employer because I really am excited to work there. Here are some reasons why: The opportunity to work with people smarter than me. The chance to meet some of the people I admire in [...]]]></description>
			<content:encoded><![CDATA[<p>My <a href="http://www.philosophicalgeek.com/2008/08/19/top-10-things-to-do-my-first-week-at-microsoft/">last</a> post was well and good (definitely read the comments), but I think I should be serious about my new employer because I really am excited to work there. Here are some reasons why:</p>
<ol>
<li>The opportunity to work with people smarter than me. The chance to meet some of the people I admire in the software community.</li>
<li>The projects and technology under development always inspire me. Almost every event I&#8217;ve gone to has had me come away wanting to look into some other cool technology and thinking of the ways it can change the world.</li>
<li>A real career path as a software engineer. </li>
<li>Chance to change projects whenever I want. During my interviews, many people were quite open with me: they get bored with a project eventually and want to switch after two years or so. Microsoft&#8217;s culture easily allows this.</li>
<li>Compete with Google. Google needs some real competition. Just as Firefox lit a fire under the IE team, MS needs to light a fire under Google.</li>
<li>The <a href="http://members.microsoft.com/careers/mslife/benefits/plan.mspx">benefits</a> are awesome. They truly treat you well.</li>
<li>They are extremely open on telecommuting. </li>
<li>How many companies can you work at where your stuff affects so many people? There aren&#8217;t that many&#8230;</li>
<li>The challenge. I love challenges. I love learning new things, and working hard to solve problems. Challenges are how you grow.</li>
<li>The area. Beautiful country. Cheaper than DC. The rain.</li>
</ol>
<p>What will be more interesting is to compare this list with what I come up with in a year.</p>
<img src="http://www.philosophicalgeek.com/?ak_action=api_record_view&id=365&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.philosophicalgeek.com/2008/08/20/top-10-reasons-why-im-excited-to-work-at-microsoft/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>log4cxx + VS2005 + Windows SDK v6.0 = compile error</title>
		<link>http://www.philosophicalgeek.com/2008/07/09/log4cxx-vs2005-windows-sdk-v60-compile-error/</link>
		<comments>http://www.philosophicalgeek.com/2008/07/09/log4cxx-vs2005-windows-sdk-v60-compile-error/#comments</comments>
		<pubDate>Wed, 09 Jul 2008 15:55:16 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[visual studio]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://www.philosophicalgeek.com/2008/07/09/log4cxx-vs2005-windows-sdk-v60-compile-error/</guid>
		<description><![CDATA[If you are following the instructions to build log4cxx 0.10 in Visual Studio 2005, and you have the Windows Platform SDK v6.0 installed, you may get errors compiling multicast.c in the apr project. I found the solution, and it&#8217;s pretty easy. Open up multicast.c and edit the lines: 136: #if MCAST_JOIN_SOURCE_GROUP 148: #if MCAST_JOIN_SOURCE_GROUP to [...]]]></description>
			<content:encoded><![CDATA[<p><!--adsense--></p>
<p>If you are following the <a href="http://logging.apache.org/log4cxx/building/vstudio.html">instructions</a> to build log4cxx 0.10 in Visual Studio 2005, and you have the Windows Platform SDK v6.0 installed, you may get errors compiling multicast.c in the apr project.</p>
<p>I <a href="http://markmail.org/message/czvxefjjw3nighwe#query:apr%20multicast.c%20compile+page:1+mid:zgapgvhwygbujibm+state:results">found the solution</a>, and it&#8217;s pretty easy. Open up multicast.c and edit the lines:</p>
<p>136: #if MCAST_JOIN_SOURCE_GROUP  </p>
<p>148: #if MCAST_JOIN_SOURCE_GROUP  </p>
<p>to be, instead:</p>
<p>136: #if defined(group_source_req) </p>
<p>148: #if defined(group_source_req)</p>
<p>&nbsp;</p>
<p>e voilà! now it compiles.</p>
<img src="http://www.philosophicalgeek.com/?ak_action=api_record_view&id=348&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.philosophicalgeek.com/2008/07/09/log4cxx-vs2005-windows-sdk-v60-compile-error/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Adapting to Changes</title>
		<link>http://www.philosophicalgeek.com/2008/06/12/adapting-to-changes/</link>
		<comments>http://www.philosophicalgeek.com/2008/06/12/adapting-to-changes/#comments</comments>
		<pubDate>Thu, 12 Jun 2008 19:56:45 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[adaptability]]></category>
		<category><![CDATA[census]]></category>
		<category><![CDATA[government]]></category>
		<category><![CDATA[management]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[unit testing]]></category>

		<guid isPermaLink="false">http://www.philosophicalgeek.com/?p=345</guid>
		<description><![CDATA[Change is a fact of life. Nowhere is this more obvious in a medium where the very thing we make is completely intangible and malleable: software development. There is almost nothing that is impossible in software&#8211;there are only limited resources. This malleability has been one of the reasons for the enormous pace of change we&#8217;ve [...]]]></description>
			<content:encoded><![CDATA[<p><!--adsense--></p>
<p>Change is a fact of life. Nowhere is this more obvious in a medium where the very thing we make is completely intangible and malleable: software development. There is almost nothing that is impossible in software&#8211;there are only limited resources.</p>
<p>This malleability has been one of the reasons for the enormous pace of change we&#8217;ve seen in computers in the last half century, but at the same time it&#8217;s been a stumbling block to true engineering practices.</p>
<p>Regardless of philosophy, change will happen in all software projects to some degree. There are two extremes of development that most organizations fall between:</p>
<ul>
<li>A single coder hacks together whatever the boss needs changed today. (Also fixes bugs from yesterday&#8217;s fixes.)  </li>
<li>NASA&#8217;s awesomely rigid development practices for the Space Shuttle software (see the Manager&#8217;s Handbook for Software Development <a href="http://www.philosophicalgeek.com/2007/11/21/books/">on the Book list</a>) resulting in extremely high-quality, virtually bug-free software (at a very high price).</li>
</ul>
<p>For most of us, neither extreme is appropriate. Deciding the right balance of change control is a hard problem, but it&#8217;s not impossible. Still, some organizations manage to do so badly at it that it deserves to be studied and dissected.</p>
<h3>The Census</h3>
<p>As an example, consider the <a href="http://www.census.gov/2010census/">2010 Census</a>, a project that has been covered in the press and on tech blogs over the last few months. The following is from the second paragraph of the <a href="http://www.gao.gov/new.items/d08550t.pdf" target="_blank">report on the GAO&#8217;s study</a> of this massive program:</p>
<blockquote><p>In October 2007, GAO reported that changes to requirements had been a contributing factor to both cost increases and schedule delays experienced by the FDCA [Field Data Collection Automation] program. Increases in the number of requirements led to the need for additional work and staffing. In addition, an initial underestimate of the contract costs caused both cost and schedule revisions. In response to the cost and schedule changes, the Bureau decided to delay certain system functionality, which increased the likelihood that the systems testing&#8230;would not be as comprehensive as planned.[...] Without effective management of these and other key risks, the FDCA program faced an increased probability that the system would not be delivered on schedule and within budget or perform as expected. Accordingly, GAO recommended that the FDCA project team strengthen its risk management activities, including risk identification and oversight.</p>
<p>The Bureau has recently made efforts to further define the requirements for the FDCA program, and it has estimated that the revised requirements will result in significant cost increases.</p>
</blockquote>
<p>As with many government projects, there is enough failure to go around. The key idea I want to focus on is a failure on the part of the government agency and on the part of the contractor implementing the technology to adequately plan for change.</p>
<p>Before that, though, I want to say that I have no knowledge of their specific management or technical practices, other than what is publicly reported. For all I know, all parties performed extremely well and still failed. (However, from friends and acquaintances in government and contractor positions around D.C., I think it&#8217;s fair to say that most organizations here are behind the curve in software best practices, to put it politely.)</p>
<p>With that (admittedly harsh) assumption, it&#8217;s apparent that the agency failed to adequately plan, think through requirements, and communicate effectively to the contracted company. On the developer&#8217;s side, it&#8217;s apparent they didn&#8217;t have effective mechanisms for handling changes.</p>
<p>Before a project is undertaken, a set of fundamental principles must be agreed upon:</p>
<ol>
<li>The client will change their minds. There is no such thing as &#8220;written in stone.&#8221;  </li>
<li>Making changes is hard or impossible. </li>
</ol>
<p>These two principles are fundamentally in conflict. On the one hand, the developer must know that changes are going to occur: sometimes <em>large </em>changes. They can plan for that from the code level up to their organization and processes.</p>
<p>On the other hand, the client, must realize that they can&#8217;t just suggest a change at the end of the project and expect it to be thrown in and work correctly.</p>
<p>The tension between these two principles implies certain practices and expectations on all parties, which in an ideal world would lead to a successful outcome more often. </p>
<h3>Developer Responsibilities</h3>
<p>The developer, knowing that the client does not understand the full set of requirements up front, designs their system in a way that can easily handle change. This means modularity, this means testability. From details as small as designing methods to operate on Streams instead of filenames, to as large as easily reusable components.</p>
<p><!--adsense#LinkUnit--></p>
<p>The first step is a change in mind set: an acceptance that change will occur, and that it&#8217;s ok. When I first started development, frequent changes really frustrated me. Sometimes they still do, but I&#8217;m getting better (I hope). Once the mind is malleable, practices can be implemented to handle it effectively.</p>
<p>A few coding practices that encourage changes:</p>
<ul>
<li><strong>Test-driven development </strong>(or at least full <strong>unit testing</strong>). In this day and age, with how easy it is to accomplish this, is there a good reason not to do it? I&#8217;m not convinced by many arguments against unit testing. A full suite of unit tests gives you confidence in your code, and the ability to safely refactor even large portions of your program. Full TDD I could go either way.  </li>
<li><strong>Constant refactoring</strong> to fit the best design possible (within reason. Obviously, there is no &#8220;best&#8221; design). Software, like everything else in the universe, obeys the law of entropy. Without constant maintenance, it will degrade. Designs degrade as you add on to them. Classes degrade as you stuff them full of things. Don&#8217;t stand for it&#8211;take the time to make things neat. Get some <a href="http://www.philosophicalgeek.com/2007/11/21/books/">good books</a> on refactoring if you don&#8217;t know how to start.  </li>
<li><strong>Highly Modular</strong>. Apply all your OO-design skills here. It matters. Cohesion and coupling really do matter.  </li>
<li><strong>Small, frequent iterations. </strong>Most software systems these days are too big and too complex to understand at once. Iterative development is the key to success.  </li>
<li><strong>Strong source-control practices</strong>. Does this even need to be discussed? If your organization doesn&#8217;t have good source control, you&#8217;re doing software wrong.</li>
</ul>
<p>Other practices on the developer&#8217;s part read like a list of <a href="http://en.wikipedia.org/wiki/Extreme_programming#XP_values" target="_blank">Extreme programming</a> <a href="http://www.extremeprogramming.org/rules.html" target="_blank">fundamentals</a>:</p>
<ul>
<li><strong>Communication</strong> &#8211; The key to any relationship, whether personal or corporate, is communication. The right amount should be discovered and adhered to. It should probably be slightly more than you&#8217;re comfortable with (since many developers would rather not talk to anyone <img src='http://www.philosophicalgeek.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .  </li>
<li><strong>Simplicity</strong> &#8211; I believe that the single hardest thing to do in developing software is to manage complexity. It&#8217;s requires more brainpower and creativity than all other activities. Coding is easy. Coding so that it is easy to understand a year from now is difficult. If the design is needlessly complex up front, then change is that much harder to implement.&nbsp; Always remember that software complexity increases exponentially.  </li>
<li><strong>Courage</strong> &#8211; Stand up for correct principles. Don&#8217;t allow politics to interfere with what needs to be done. Don&#8217;t be afraid to change the design if it needs to happen. Change coding practices as needed. Never be afraid of the truth&#8211;just deal with it.  </li>
<li><strong>Respect</strong> &#8211; Both sides need to remember that the other is expert in their domain. <a href="http://www.philosophicalgeek.com/2008/01/20/5-attributes-of-highly-effective-programmers/" target="_blank">Humility</a> is key.  </li>
<li><strong>Responsibility</strong> &#8211; this is something I fear is lacking much in government. Everybody needs to take responsibility for their part. This implies accountability. This can be shared responsibility at some levels, or the-buck-stops-here responsibility at higher levels. If no one is responsible, nobody cares if it fails. Courage is a prerequisite to this. </li>
</ul>
<p>This mind set needs to encompass not just pure software development, but also processes at the organizational level. This can take many forms, but a few ideas:</p>
<ul>
<li>Personal relationships between clients and developers  </li>
<li>Flexible team structure and members  </li>
<li>An easy way to submit and discuss change requests  </li>
<li>A culture that accepts changes  </li>
<li>A good understanding of the problem domain</li>
</ul>
<p><a href="http://codebetter.com/blogs/jeremy.miller/default.aspx">Jeremy Miller (The Shade Tree Developer)</a> talks a lot about <a href="http://codebetter.com/blogs/jeremy.miller/archive/2007/04/08/On-Process-and-Practices.aspx">processes and practices</a> and it is a very good read.</p>
<p>Unfortunately, there exists an attitude at many companies that it&#8217;s better to milk the clients for as much money as possible rather than do the hard work of getting a good process.</p>
<h3>Client Responsibilities</h3>
<p>I think my introduction and the discussion about developer responsibilities may imply that because software is so ephemeral, it is therefore easy to change it. After all, it&#8217;s not a physical object that has to be broken down and rebuilt&#8211;what&#8217;s so hard? To anyone who has worked on non-trivial projects, this is laughable. Let&#8217;s clarify:</p>
<p><em>It is easy to program. It&#8217;s painfully, mind-bendingly, insanely difficult to design software</em>. So difficult, in fact, that no one can do it well. The sooner everybody understand that, the sooner we can get started with real work. Good design is thought-work, iterated over and over, added to experience and analysis.</p>
<p>Some details are easy to change. Others are fundamental to the structure of the building. By way of metaphor, changing your mind about a house you&#8217;re building to suggest a stone facade instead of brick is relatively easy. Deciding you would like to have ten stories added onto your house changes the game significantly. Now you have to build a completely new foundation.</p>
<p>I believe the customer&#8217;s responsibility is to gain knowledge and insight into the development practice so they understand why things are difficult. <strong>Computers are so fundamental to our culture, we can no longer afford to have companies and agencies run by people who don&#8217;t understand them</strong> to some degree. The exact degree is debatable, but it&#8217;s certainly higher than where we&#8217;re at now. In my own situation, I think that when I started my boss did not realize how seemingly-trivial changes could be phenomenally difficult to implement, and therefore bug-prone&#8211;all because of design decisions made earlier. I now have him understanding that there is no such thing as a simple change.&nbsp; (Of course, I still occasionally <a href="http://en.wikipedia.org/wiki/Montgomery_Scott#Birthplace_controversy">underpromise and overdeliver</a>&#8211;I have to maintain my miracle-worker image after all. <img src='http://www.philosophicalgeek.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>A client who wants software done and doesn&#8217;t want to end up paying an <a href="http://www.census.gov/Press-Release/www/releases/archives/2010_census/011773.html">extra $3,000,000,000 for software</a> should understand that critical requirements can&#8217;t be left until the product is being delivered. &#8220;We didn&#8217;t think of it before&#8221; is not a good excuse.</p>
<p>A client who understands this will realize how critical initial requirements are and ensure they&#8217;re communicated clearly. Most of all, they don&#8217;t wait around twirling their thumbs, only to reject the system when it&#8217;s done because it doesn&#8217;t meet their requirements. They will insist on periodic feedback and demos to make sure things are going the right way.</p>
<p>The responsibility for huge failures is on everybody&#8217;s shoulders. I believe that it can often be traced back to an unwillingness to face up to the truth, lack of responsibility, and misunderstanding the nature of the project.</p>
<h3>Large projects aren&#8217;t doomed to fail</h3>
<p>There is a fundamental truth, however, of all projects: there exists at least one change that is too large to do. Maybe the Census required that change&#8211;I don&#8217;t know. I do know that if both sides follow the best practices they can, the number of must-fail changes can be minimized.</p>
<p>That said, here&#8217;s why I refuse to believe the census project wasn&#8217;t sorely mismanaged from the outset by all sides: FedEx, UPS, Amazon, Wal-Mart, Microsoft, and dozens (hundreds?) of other companies have built enormous and complex systems for managing large databases and mobile platforms involving thousands of partners. It is ridiculous to me that they could not have built a system for our government quicker, cheaper, and less <a href="http://www.urbandictionary.com/define.php?term=epic+failure">epic failure</a> than the one they got. If the Census is fundamentally more complex than the problems they deal with, someone please let me know.</p>
<h3>Change is part of everything now</h3>
<p>The ability to adapt to change is critical, not just for software developers, but for everyone in our society. Technology, events, trends, and money all flow so quickly now that those who can adapt quickly will succeed. </p>
<p>It&#8217;s not just software companies that need to adopt sound development practices. There will always be companies that build out our infrastructure (Microsoft, Google, Cisco, etc.), but in the end every company will be a software development company. Disregarding good practices because &#8220;we&#8217;re not a software&#8221; does not work anymore. It&#8217;s not true. You are a software company. We all will be.</p>
<h3>Idealism or&#8230;</h3>
<p>If a lot of this seems idealistic, that&#8217;s ok. I wish the world were like Star Trek as much as the next geek, but I realize that there are a lot of motivation$ out there. The world is what it is, but if we aren&#8217;t trying to improve it by working towards a standard, then what&#8217;s the point? We can improve it. There is no excuse for such catastrophic wastes of time, money, and effort.</p>
<p><!--adsense#Referral--></p>
<img src="http://www.philosophicalgeek.com/?ak_action=api_record_view&id=345&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.philosophicalgeek.com/2008/06/12/adapting-to-changes/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Review: Pragmatic Unit Testing in C# with NUnit, 2nd Ed.</title>
		<link>http://www.philosophicalgeek.com/2008/06/04/review-pragmatic-unit-testing-in-c-with-nunit-2nd-ed/</link>
		<comments>http://www.philosophicalgeek.com/2008/06/04/review-pragmatic-unit-testing-in-c-with-nunit-2nd-ed/#comments</comments>
		<pubDate>Wed, 04 Jun 2008 16:38:01 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Books]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[unit testing]]></category>

		<guid isPermaLink="false">http://www.philosophicalgeek.com/2008/06/04/review-pragmatic-unit-testing-in-c-with-nunit-2nd-ed/</guid>
		<description><![CDATA[I saw this book when I bought Programming WPF a few weeks ago and it looked promising enough to buy. I&#8217;ve been doing unit testing in C# for a few years now, but I thought there were always things to learn and maybe I&#8217;d pick up a few new ideas. It is easy to contrast [...]]]></description>
			<content:encoded><![CDATA[<p><iframe style="width: 120px; height: 240px" align="left" marginwidth="3" hspace="5" marginheight="0" src="http://rcm.amazon.com/e/cm?t=philosophic0d-20&amp;o=1&amp;p=8&amp;l=as1&amp;asins=0977616673&amp;nou=1&amp;fc1=000000&amp;IS2=1&amp;lt1=_blank&amp;lc1=0000FF&amp;bc1=000000&amp;bg1=FFFFFF&amp;f=ifr" frameborder="0" scrolling="no"></iframe>I saw this book when I bought <a href="http://www.amazon.com/gp/product/0596510373?ie=UTF8&amp;tag=philosophic0d-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0596510373">Programming WPF</a> a few weeks ago and it looked promising enough to buy. I&#8217;ve been doing unit testing in C# for a few years now, but I thought there were always things to learn and maybe I&#8217;d pick up a few new ideas.</p>
<p>It is easy to contrast this book with Beck&#8217;s <a href="http://www.amazon.com/gp/product/0321146530?ie=UTF8&amp;tag=philosophic0d-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0321146530">Test Driven Development: By Example</a><img style="margin: 0px; border-top-style: none! important; border-right-style: none! important; border-left-style: none! important; border-bottom-style: none! important" height="1" alt="" src="http://www.assoc-amazon.com/e/ir?t=philosophic0d-20&amp;l=as2&amp;o=1&amp;a=0321146530" width="1" border="0"/>, and the two books definitely have a very different feel.</p>
<p>Beck&#8217;s book has a very evangelical feel to it, and it&#8217;s main purpose is to teach a mind set more than technical details. I believe this is important&#8211;maybe of first importance&#8211;but once you understand that, the rest of the book is a little simplistic for more experienced developers.</p>
<p>Pragmatic Unit Testing, on the other hand, focuses much more on the practical aspects (hmmm&#8230;.I highly suspect that&#8217;s where the title comes from&#8230;.) of unit testing. I liked the ideas on how to use categories and attributes to segregate tests that take too long to run on a regular basis. I also liked the section on singletons and getting around time-dependencies. The DateTime.Now problem is something I&#8217;ve had to deal with quite a bit in our server-side software that has a lot of time-dependant behavior. (In most cases, the problems were solved with refactoring the time into a function parameter.)</p>
<p>There are also good discussions of more mundane issues like how to deploy NUnit, where to put tests in a project, team practices, GUIs, threading, and C#-specific issues.</p>
<p>The discussion about mock objects (a very basic introduction) is also quite clear and understandable&#8211;more so than many resources I&#8217;ve seen on the web, which often assume you already know all about them.</p>
<p>Something I don&#8217;t like: the acronyms (BICEP, CORRECT, A TRIP). They kind of bug me. I like the <strong>ideas</strong> behind the acronyms and I think it&#8217;s more important and effective (for me, anyway) to internalize the principles of testing rather than remembering specific acronyms and the words they go with. YMMV.</p>
<h3>Last Word&#8230;</h3>
<p>I will probably only read Test Drive Development: By Example once,&nbsp; but I will definitely come back to <strong>Pragmatic Unit Testing</strong> occasionally to refresh my ideas.</p>
<p><!--adsense--></p>
<img src="http://www.philosophicalgeek.com/?ak_action=api_record_view&id=342&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.philosophicalgeek.com/2008/06/04/review-pragmatic-unit-testing-in-c-with-nunit-2nd-ed/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Custom data source for Google Earth</title>
		<link>http://www.philosophicalgeek.com/2008/05/20/custom-data-source-for-google-earth/</link>
		<comments>http://www.philosophicalgeek.com/2008/05/20/custom-data-source-for-google-earth/#comments</comments>
		<pubDate>Tue, 20 May 2008 13:21:03 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[GIS]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.philosophicalgeek.com/2008/05/20/custom-data-source-for-google-earth/</guid>
		<description><![CDATA[Using just these links as a guide, we quickly (less than a day) put up a data source over https for our customers to download GIS data to Google Earth. KML reference and tutorial &#8211; KML is the XML language used to describe features that can be displayed in Google Earth and Google Maps. Sample [...]]]></description>
			<content:encoded><![CDATA[<p><!--adsense--></p>
<p>Using just these links as a guide, we quickly (less than a day) put up a data source over https for our customers to download GIS data to Google Earth. </p>
<p><a href="http://code.google.com/apis/kml/documentation/kml_tut.html">KML reference and tutorial</a> &#8211; KML is the XML language used to describe features that can be displayed in Google Earth and Google Maps.</p>
<p><a href="http://geekswithblogs.net/thibbard/articles/92625.aspx">Sample code</a> to generate KML from a web service or web page (it&#8217;s VB.Net).</p>
<p><a href="http://www.rassoc.com/gregr/weblog/2002/06/26/web-services-security-http-basic-authentication-without-active-directory/">How to implement a custom authentication provider</a> for IIS in .Net. Very useful if you need to authenticate your KML-generating web page and you don&#8217;t want to use Active Directory.</p>
<img src="http://www.philosophicalgeek.com/?ak_action=api_record_view&id=339&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.philosophicalgeek.com/2008/05/20/custom-data-source-for-google-earth/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Formational Experiences</title>
		<link>http://www.philosophicalgeek.com/2008/05/15/formational-experiences/</link>
		<comments>http://www.philosophicalgeek.com/2008/05/15/formational-experiences/#comments</comments>
		<pubDate>Thu, 15 May 2008 16:25:14 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Personal]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[BASIC]]></category>
		<category><![CDATA[Code]]></category>

		<guid isPermaLink="false">http://www.philosophicalgeek.com/2008/05/15/formational-experiences/</guid>
		<description><![CDATA[When I was 9, I started playing with GW-BASIC by typing in programs found in the old kid&#8217;s 3-2-1 Contact magazine. This soon progressed to QBASIC, where I mostly made cool graphics with lines and circles. (click for larger image) QBASIC is not included in Windows anymore, but you can still get it. &#160; (click [...]]]></description>
			<content:encoded><![CDATA[<p>When I was 9, I started playing with <a href="http://en.wikipedia.org/wiki/GW-BASIC">GW-BASIC</a> by typing in programs found in the old kid&#8217;s <a href="http://en.wikipedia.org/wiki/3-2-1_Contact#The_magazine">3-2-1 Contact magazine</a>. This soon progressed to <a href="http://en.wikipedia.org/wiki/QBASIC">QBASIC</a>, where I mostly made cool graphics with lines and circles.<a href="http://www.philosophicalgeek.com/wp-content/uploads/2008/05/windowslivewriterformationalexperiences-71a7qbasic-output-2.jpg"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="304" alt="qbasic_output" src="http://www.philosophicalgeek.com/wp-content/uploads/2008/05/windowslivewriterformationalexperiences-71a7qbasic-output-thumb.jpg" width="404" border="0"/></a></p>
<p>(click for larger image)</p>
<p>QBASIC is not included in Windows anymore, but <a href="http://www.petesqbsite.com/sections/introduction/intro.shtml">you can still get it</a>.</p>
<p>&nbsp;<a href="http://www.philosophicalgeek.com/wp-content/uploads/2008/05/windowslivewriterformationalexperiences-71a7qbasic-lines-2.jpg"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="231" alt="qbasic_lines" src="http://www.philosophicalgeek.com/wp-content/uploads/2008/05/windowslivewriterformationalexperiences-71a7qbasic-lines-thumb.jpg" width="444" border="0"/></a></p>
<p>(click for larger image)</p>
<p>I had also tried modifying the including GORILLAS.BAS and NIBBLES.BAS, but I was still a little too new at this.</p>
<p>When I was 14 I was getting into C/C++ via Borland C++ 3.1 in a big way and spent hours coding prank programs. I had two that I remember:</p>
<p>First was a program called Camels that displayed &#8220;I Love Camels!!!&#8221; in a vertical, colorful scrolling sine wave down the screen. It trapped Ctrl-Break/Ctrl-C so you couldn&#8217;t break out of it. If you hit Ctrl-K, it brought up a password screen that allowed you to exit if you knew the password. Then I put it on a lab at school, set AUTOEXEC.BAT to run it, and <a href="http://labmice.techtarget.com/articles/dos6cmd.htm">modified CONFIG.SYS with &#8220;switches /n&#8221;</a> to disallow the user hitting F5 to skip processing of AUTOEXEC.BAT. This stunt kind of got me in trouble&#8211;the day after school ended, I got a call from my computer science teacher that he couldn&#8217;t access the computer and if I wanted a grade I had better get over there and remove that program because he couldn&#8217;t get onto the computer. So I had to bike a few miles to school (my parents were out of town) and remove it. Why didn&#8217;t the instructor just use a boot disk? No idea&#8230; By the way, I got an A.</p>
<p>One of my first Windows programs was something called &#8220;Chucky&#8221; (why? I don&#8217;t know&#8230;). Chucky liked to eat&#8230;.hard disk space. He would startup with no Window, run in the background, and every few minutes it would add a few thousand lines of text to&nbsp; the file C:\Windows\Chucky.txt. It was probably something like &#8220;I am Chucky, I am hungry.&#8221;</p>
<p>I even eventually convinced my parents to get me Turbo C++ so I could build Windows programs (suing <a href="http://en.wikipedia.org/wiki/Object_Windows_Library">OWL</a>).</p>
<p><a href="http://www.philosophicalgeek.com/wp-content/uploads/2008/05/windowslivewriterformationalexperiences-71a7v6up-2.jpg"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="244" alt="v6up" src="http://www.philosophicalgeek.com/wp-content/uploads/2008/05/windowslivewriterformationalexperiences-71a7v6up-thumb.jpg" width="201" align="left" border="0"/></a>When I was in college, I got Visual C++ 6 and thought a fun program would be a desktop utility that occasionally changed your Outlook signature to include a random quotation. You could build up a little database of quotes you liked, and the program would change it on a regular schedule. A friend of mine and I stayed up for nearly 3 days straight working on it. I did most of the programming&#8211;he was thinking of new ideas, ways to do things. It was great fun.</p>
<p>These important formational periods are what got me excited about programing. The learning that goes on during a 72-hour hacking session is something that can&#8217;t be duplicated in a classroom. The glee at creating pranks is not matched (often) by homework assignments. Sometimes when I&#8217;m feeling the drudgery of the current code I work on, I need to remember the excitement I felt back then. </p>
<p>I also need to find something equivalently exciting to work on. One of the things I&#8217;m going to do to &#8220;get the magic back&#8221; (so to speak) is to make sure I&#8217;m always experimenting with the latest and great .Net stuff coming out. I need to finally get into WPF, and I&#8217;ve even got a fun project to apply it to.</p>
<img src="http://www.philosophicalgeek.com/?ak_action=api_record_view&id=338&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.philosophicalgeek.com/2008/05/15/formational-experiences/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Tracking database changes using triggers</title>
		<link>http://www.philosophicalgeek.com/2008/05/13/tracking-database-changes-using-triggers/</link>
		<comments>http://www.philosophicalgeek.com/2008/05/13/tracking-database-changes-using-triggers/#comments</comments>
		<pubDate>Tue, 13 May 2008 12:00:53 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.philosophicalgeek.com/2008/05/13/tracking-database-changes-using-triggers/</guid>
		<description><![CDATA[Tracking changes in database tables is an incredibly useful feature&#8211;especially for operational data that can change often. Having recently had to implement this feature, I thought I&#8217;d share some of the techniques I learned. Sample Database First, let&#8217;s conceptualize a very simple database consisting of user information (name, date of birth), and e-mails. A user [...]]]></description>
			<content:encoded><![CDATA[<p>Tracking changes in database tables is an incredibly useful feature&#8211;especially for operational data that can change often. Having recently had to implement this feature, I thought I&#8217;d share some of the techniques I learned.</p>
</p>
<p><!--adsense--></p>
</p>
<h3>Sample Database</h3>
<p>First, let&#8217;s conceptualize a very simple database consisting of user information (name, date of birth), and e-mails. A user can have more than one e-mail.</p>
<p>&nbsp;</p>
<table cellspacing="0" cellpadding="2" width="400" border="0">
<tbody>
<tr>
<td valign="top" width="200">
<p align="center">Table: <strong>UserData</strong></p>
<div align="center">
<table cellspacing="0" cellpadding="2" width="174" align="center" border="1">
<tbody>
<tr>
<td valign="top" width="69"><strong>Field</strong></td>
<td valign="top" width="103"><strong>Type</strong></td>
</tr>
<tr>
<td valign="top" width="72">ID</td>
<td valign="top" width="103">int (PK, identitiy)</td>
</tr>
<tr>
<td valign="top" width="73">FirstName</td>
<td valign="top" width="103">varchar</td>
</tr>
<tr>
<td valign="top" width="74">LastName</td>
<td valign="top" width="103">varchar</td>
</tr>
<tr>
<td valign="top" width="74">birthdate</td>
<td valign="top" width="103">date</td>
</tr>
</tbody>
</table>
</div>
</td>
<td valign="top" width="200">
<p align="center">Table: <strong>UserEmails</strong></p>
<div align="center">
<table cellspacing="0" cellpadding="2" width="100" align="center" border="1">
<tbody>
<tr>
<td valign="top" width="50"><strong>Field</strong></td>
<td valign="top" width="50"><strong>Type</strong></td>
</tr>
<tr>
<td valign="top" width="50">UserID</td>
<td valign="top" width="50">int (FK)</td>
</tr>
<tr>
<td valign="top" width="50">email</td>
<td valign="top" width="50">varchar</td>
</tr>
</tbody>
</table>
</div>
<p align="center">
<p>&nbsp;</p>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p>We want to track all changes to the FirstName, LastName, and birthdate fields. In addition we want to track when e-mails are added or removed from a user. As we&#8217;ll see, these aims are accomplished using two different methods.</p>
<p>My implementation is done in SQL Server 2000 and C#, but any database that supports triggers can be used.</p>
<h3>Changes in a Single Table</h3>
<p>With this method we want to track the changes to all fields of a table. In our example, we want to know when FirstName, LastName, and birthdate change values in the UserData table.</p>
<p>To accomplish this we need another table to track the history. This table is going to have the exact same fields as UserData, plus a few extra for the change tracking. </p>
<p>Table: <strong>UserDataChanges</strong></p>
<table cellspacing="0" cellpadding="2" width="211" border="1">
<tbody>
<tr>
<td valign="top" width="85"><strong>Field</strong></td>
<td valign="top" width="124"><strong>Type</strong></td>
</tr>
<tr>
<td valign="top" width="89">ChangeID</td>
<td valign="top" width="121">int (PK, identity)</td>
</tr>
<tr>
<td valign="top" width="92">ChangeTime</td>
<td valign="top" width="119">datetime</td>
</tr>
<tr>
<td valign="top" width="94">ChangeUser</td>
<td valign="top" width="118">varchar</td>
</tr>
<tr>
<td valign="top" width="94">ID</td>
<td valign="top" width="118">int (FK)</td>
</tr>
<tr>
<td valign="top" width="94">FirstName</td>
<td valign="top" width="118">varchar</td>
</tr>
<tr>
<td valign="top" width="95">LastName</td>
<td valign="top" width="118">varchar</td>
</tr>
<tr>
<td valign="top" width="95">birthdate</td>
<td valign="top" width="118">date</td>
</tr>
</tbody>
</table>
<p>Now the automated part&#8211;adding a <a href="http://technet.microsoft.com/en-us/library/ms189799.aspx">trigger</a> to populate this automatically:</p>
<div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4">
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #0000ff">CREATE</span> <span style="color: #0000ff">TRIGGER</span> UserDataChangeTrigger <span style="color: #0000ff">ON</span> UserData <span style="color: #0000ff">FOR</span> <span style="color: #0000ff">UPDATE</span>, INSERT</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #0000ff">AS</span>    </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    <span style="color: #0000ff">IF</span> (<span style="color: #0000ff">UPDATE</span> (FirstName) <span style="color: #0000ff">OR</span> <span style="color: #0000ff">UPDATE</span>(LastName) <span style="color: #0000ff">OR</span> <span style="color: #0000ff">UPDATE</span>(birthdate))    </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    <span style="color: #0000ff">BEGIN</span>     </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        INSERT UserDataChanges </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">            (ChangeTime, ChangeUser, ID, FirstName, LastName, birthdate)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">            (<span style="color: #0000ff">SELECT</span> GetUtcDate(), <span style="color: #0000ff">user</span>, ID, FirstName,LastName,birthdate </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">                <span style="color: #0000ff">FROM</span> inserted)     </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    <span style="color: #0000ff">END</span>     </pre>
</div>
</div>
<p>This trigger will insert a new row into the UserDataChanges table whenever a row in the UserData table is updated or inserted. The IF (UPDATE(FirstName)&#8230;. ) is not strictly required in this scenario, but in other cases I did not want a change recorded when certain fields were updated (i.e., you have a field that tracks the last change time of that row, or the number of orders, or any other field that can change frequently and isn&#8217;t important to track&#8211;you don&#8217;t want to create too much noise in this or it will not be useful). The <a href="http://technet.microsoft.com/en-us/library/aa258904(SQL.80).aspx">GetUtcDate()</a> and <a href="http://technet.microsoft.com/en-us/library/aa260664(SQL.80).aspx">user</a> are SQL Server functions that retrieve the current UTC time and the username of the process that caused the change&#8211;very useful for tracking responsibility. The <a href="http://technet.microsoft.com/en-us/library/ms189799.aspx">inserted</a> table is created by the server for use by the trigger and contains all the new values.</p>
<h3>Changes in a Foreign Key Table</h3>
<p>The UserEmails has to be handled differently because there can be multiple e-mails for each user and we can assume they can be added, or removed at will (Remove + Add = Update, so I won&#8217;t consider direct updates here).</p>
<p>The solution I landed on was to have a generic event log table that stores manual log entries as well as &#8220;special&#8221; entries denoting adding or removing e-mails.</p>
<p>Table: <strong>UserEventLog</strong></p>
<table cellspacing="0" cellpadding="2" width="199" border="1">
<tbody>
<tr>
<td valign="top" width="101"><strong>Field</strong></td>
<td valign="top" width="96"><strong>Type</strong></td>
</tr>
<tr>
<td valign="top" width="102">EventID</td>
<td valign="top" width="96">int (PK, identity)</td>
</tr>
<tr>
<td valign="top" width="102">ID</td>
<td valign="top" width="96">int (FK)</td>
</tr>
<tr>
<td valign="top" width="102">EventTime</td>
<td valign="top" width="96">datetime</td>
</tr>
<tr>
<td valign="top" width="102">EventType</td>
<td valign="top" width="96">int</td>
</tr>
<tr>
<td valign="top" width="102">ChangeUser</td>
<td valign="top" width="96">varchar</td>
</tr>
<tr>
<td valign="top" width="102">Notes</td>
<td valign="top" width="96">varchar</td>
</tr>
</tbody>
</table>
<p>This table can be used for both adding text notes to a user and, by using the EventType field, special events. In our example, we have two events we need to track: </p>
<p>&nbsp;</p>
<table cellspacing="0" cellpadding="2" width="100" border="1">
<tbody>
<tr>
<td valign="top" width="50"><strong>Event</strong></td>
<td valign="top" width="50"><strong>Value</strong></td>
</tr>
<tr>
<td valign="top" width="50">EmailAdded</td>
<td valign="top" width="50">1</td>
</tr>
<tr>
<td valign="top" width="50">EmailRemoved</td>
<td valign="top" width="50">2</td>
</tr>
</tbody>
</table>
<p>(In code, I&#8217;ve made these enumerations)</p>
<p>Next we add a trigger on the UserEmails table:</p>
<div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 400px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4">
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #0000ff">CREATE</span> <span style="color: #0000ff">TRIGGER</span> UserEmails_EmailAddedTrigger</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #0000ff">ON</span> UserEmails</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #0000ff">FOR</span> INSERT</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #0000ff">AS</span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"> <span style="color: #0000ff">BEGIN</span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">     INSERT UserEventLog(ID, EventTime, EventType, ChangeUser, Notes)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        (<span style="color: #0000ff">SELECT</span> ID, GetUtcDate(), 1, <span style="color: #0000ff">user</span>, <span style="color: #006080">'{'</span>+email+<span style="color: #006080">'}'</span> <span style="color: #0000ff">FROM</span> inserted)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"> END</pre>
</div>
</div>
<p>The value 1 stands for EmailAdded. I&#8217;ve added braces around the actual e-mail address to set it apart from regular notes (we&#8217;ll see how to integrate everything later).</p>
<p>To handle the deletion of e-mails add another trigger:</p>
<div style="border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; max-height: 200px; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, 'Courier New', courier, monospace; background-color: #f4f4f4">
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #0000ff">CREATE</span> <span style="color: #0000ff">TRIGGER</span> UserEmails_EmailRemovedTrigger</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #0000ff">ON</span> UserEmails</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #0000ff">FOR</span> <span style="color: #0000ff">DELETE</span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #0000ff">AS</span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"> <span style="color: #0000ff">BEGIN</span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">     INSERT UserEventLog(ID, EventTime, EventType, ChangeUser, Notes )</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        (<span style="color: #0000ff">SELECT</span> ID, GetUtcDate(), 2, <span style="color: #0000ff">user</span>, <span style="color: #006080">'{'</span>+email+<span style="color: #006080">'}'</span> <span style="color: #0000ff">FROM</span> deleted)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"> END</pre>
</div>
</div>
<p>The only things different: FOR DELETE (instead of INSERT), changed the EventType to 2 (EmailRemoved), and the values are taken from the SQL Server-supplied deleted table.</p>
<p>That&#8217;s enough to get a pretty good change-tracking system in place, but you&#8217;ll still have to build a UI to display it effectively.</p>
<h3>Displaying the Changes in the UI</h3>
<p>With the above work done, you end up with two types of entities: changes and events. While it would be possible to integrate all functionality into a single event/change table using a lot more logic in the SQL Trigger code, I&#8217;m personally more comfortable with the change logic being in my application code. I think this way the database is kept more &#8220;pure&#8221; and open to changes down the line.</p>
<p>That means we will need to integrate these two types of entities into a single list, ordered by date/time. I&#8217;m going to assume the existence of two classes or structs that represent each of these entities. They&#8217;ll be called UserChange and UserEvent. I&#8217;ll also assume that the lists of each of these are already sorted by time, since that&#8217;s trivial to do in a SQL query.</p>
<p>Given that, we need a function that takes both of these lists and produces a sorted, combined list with an easy-to-understand list.</p>
<p>How the function works:</p>
<ol>
<li>Go through both lists, and pick whichever one is next, time-wise.
</li>
<li>Translate the object into a string/list-view representation of that object.
</li>
<li>If it&#8217;s a UserChange object, compare it to the previous one to figure out what changed.
</li>
<li>Sort the list in reverse order to put newer items at the top.</li>
</ol>
<p>Here&#8217;s the C# code which I&#8217;ve adapted from our production system. Don&#8217;t get hung up on the details:</p>
<p>&nbsp;</p>
<div>
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> FillLog(IList&lt;UserEvent&gt; events, IList&lt;UserChange&gt; changes)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">{</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    List&lt;ListViewItem&gt; tempItems = <span style="color: #0000ff">new</span> List&lt;ListViewItem&gt;();</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">&nbsp;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    <span style="color: #0000ff">int</span> currentEventIdx = 0;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    <span style="color: #0000ff">int</span> currentChangeIdx = 0;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    eventLogListView1.Items.Clear();</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">&nbsp;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    <span style="color: #0000ff">while</span> (currentEventIdx &lt; events.Count</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    || currentChangeIdx &lt; changes.Count)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    UserChange currentChange = <span style="color: #0000ff">null</span>;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    UserChange prevChange = <span style="color: #0000ff">null</span>;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    UserEvent currentEvent = <span style="color: #0000ff">null</span>;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">&nbsp;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    DateTime changeTime = DateTime.MaxValue;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    DateTime eventTime = DateTime.MaxValue;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">&nbsp;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    <span style="color: #0000ff">if</span> (currentChangeIdx &lt; changes.Count)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        currentChange = changes[currentChangeIdx];</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        changeTime = currentChange.ChangeDate;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        <span style="color: #0000ff">if</span> (currentChangeIdx &gt; 0)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        prevChange = changes[currentChangeIdx - 1];</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">&nbsp;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">&nbsp;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    <span style="color: #0000ff">if</span> (currentEventIdx &lt; events.Count)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        currentEvent = events[currentEventIdx];</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        eventTime = currentEvent.EventDate;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    <span style="color: #0000ff">string</span> dateStr;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    <span style="color: #0000ff">string</span> userStr;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    <span style="color: #0000ff">string</span> eventTypeStr=<span style="color: #006080">""</span>;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    <span style="color: #0000ff">string</span> notesStr;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">&nbsp;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    <span style="color: #0000ff">if</span> (changeTime &lt; eventTime)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        dateStr = Utils.FormatDateTime(changeTime);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        userStr = currentChange.UserName;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        notesStr = GetChangeString(currentChange, prevChange);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        currentChangeIdx++;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    <span style="color: #0000ff">else</span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        dateStr = Utils.FormatDate(eventTime);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        userStr = currentEvent.UserName;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        notesStr = currentEvent.Notes;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        eventTypeStr = currentEvent.EventType.ToString();</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        currentEventIdx++;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">&nbsp;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    <span style="color: #0000ff">if</span> (notesStr.Length &gt; 0)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        ListViewItem item = <span style="color: #0000ff">new</span> ListViewItem(dateStr);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        item.SubItems.Add(userStr);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        item.SubItems.Add(eventTypeStr);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        item.SubItems.Add(notesStr);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        item.ToolTipText = notesStr;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        item.BackColor = (tempItems.Count % 2 == 0) ? </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">            Color.Wheat : Color.White;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        tempItems.Add(item);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">&nbsp;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">&nbsp;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    }<span style="color: #008000">//end while</span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    eventLogListView1.BeginUpdate();</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    <span style="color: #0000ff">for</span> (<span style="color: #0000ff">int</span> i = tempItems.Count - 1; i &gt;= 0; i--)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    eventLogListView1.Items.Add(tempItems[i]);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">&nbsp;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    eventLogListView1.AutoResizeColumn(0, </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        ColumnHeaderAutoResizeStyle.ColumnContent);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    eventLogListView1.AutoResizeColumn(1, </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        ColumnHeaderAutoResizeStyle.ColumnContent);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    eventLogListView1.AutoResizeColumn(2, </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        ColumnHeaderAutoResizeStyle.ColumnContent);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    eventLogListView1.Columns[3].Width = eventLogListView1.Width - </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    (eventLogListView1.Columns[0].Width +</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    eventLogListView1.Columns[1].Width +</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    eventLogListView1.Columns[2].Width +10);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">&nbsp;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    eventLogListView1.EndUpdate();</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">}</pre>
</div>
</div>
<p>Now we need to define GetChangeString, which figures out the differences in successive UserChange objects and displays only pertinent information.</p>
<p>&nbsp;</p>
<div>
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #0000ff">private</span> <span style="color: #0000ff">string</span> GetChangeString(</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    BuoyDataChange currentChange, </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    BuoyDataChange prevChange)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">{</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    StringBuilder sb = <span style="color: #0000ff">new</span> StringBuilder();</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">&nbsp;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    <span style="color: #0000ff">if</span> (prevChange == <span style="color: #0000ff">null</span>)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        CompareAndAdd(sb, <span style="color: #006080">"First Name"</span>, </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">            <span style="color: #0000ff">null</span>, currentChange.FirstName);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        CompareAndAdd(sb, <span style="color: #006080">"Last Name"</span>, </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">            <span style="color: #0000ff">null</span>, currentChange.LastName);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">        CompareAndAdd(sb, <span style="color: #006080">"Birth Date"</span>, </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">            <span style="color: #0000ff">null</span>, currentChange.BirthDate);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    <span style="color: #0000ff">else</span></pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        CompareAndAdd(sb, <span style="color: #006080">"First Name"</span>, </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">            prevChange.FirstName, currentChange.FirstName);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        CompareAndAdd(sb, <span style="color: #006080">"Last Name"</span>, </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">            prevChange.LastName, currentChange.LastName);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">        CompareAndAdd(sb, <span style="color: #006080">"Birth Date"</span>, </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">            prevChange.BirthDate, currentChange.BirthDate);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">    <span style="color: #0000ff">return</span> sb.ToString();</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">}</pre>
</div>
</div>
<p>And one last helper function which compares two objects and if different appends the change to a StringBuilder object.</p>
<p>&nbsp;</p>
<div>
<div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> CompareAndAdd(StringBuilder sb, <span style="color: #0000ff">string</span> field, </pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">    <span style="color: #0000ff">object</span> oldVal, <span style="color: #0000ff">object</span> newVal)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">   {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">       <span style="color: #0000ff">if</span> (oldVal == <span style="color: #0000ff">null</span> &amp;&amp; newVal == <span style="color: #0000ff">null</span>)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">           <span style="color: #0000ff">return</span>;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">&nbsp;</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">       <span style="color: #0000ff">if</span> (oldVal == <span style="color: #0000ff">null</span> || !oldVal.Equals(newVal))</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">       {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">           <span style="color: #0000ff">if</span> (sb.Length &gt; 0)</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">           {</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">               sb.Append(<span style="color: #006080">", "</span>);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">           }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">           sb.AppendFormat(<span style="color: #006080">"{0}:{1} -&gt; {2}"</span>, field, oldVal, newVal);</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none">       }</pre>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none">   }</pre>
</div>
</div>
<p>In this way you can end up with an automated system that displays all changes in an easy-to-understand format.</p>
<p>Here&#8217;s a sample of what our system looks like (click to enlarge):</p>
<p><a href="http://www.philosophicalgeek.com/wp-content/uploads/2008/05/windowslivewriter651daced397f-b08bchangelog-screenshot-2.jpg"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="108" alt="Change log screenshot" src="http://www.philosophicalgeek.com/wp-content/uploads/2008/05/windowslivewriter651daced397f-b08bchangelog-screenshot-thumb.jpg" width="444" border="0"/></a> </p>
<p>Other ways to accomplish this? Better ways? Please leave a comment!</p>
</p>
<p><a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fwww.philosophicalgeek.com%2f2008%2f05%2f13%2ftracking-database-changes-using-triggers%2f"><img alt="kick it on DotNetKicks.com" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.philosophicalgeek.com%2f2008%2f05%2f13%2ftracking-database-changes-using-triggers%2f" border="0"/></a></p>
<img src="http://www.philosophicalgeek.com/?ak_action=api_record_view&id=331&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.philosophicalgeek.com/2008/05/13/tracking-database-changes-using-triggers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Opening Visual Studio solutions from Explorer in Vista</title>
		<link>http://www.philosophicalgeek.com/2008/05/12/opening-visual-studio-solutions-from-explorer-in-vista/</link>
		<comments>http://www.philosophicalgeek.com/2008/05/12/opening-visual-studio-solutions-from-explorer-in-vista/#comments</comments>
		<pubDate>Mon, 12 May 2008 13:53:07 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[vista]]></category>
		<category><![CDATA[visual studio]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://www.philosophicalgeek.com/2008/05/12/opening-visual-studio-solutions-from-explorer-in-vista/</guid>
		<description><![CDATA[You&#8217;ve installed Visual Studio 2005 on Vista and dutifully changed it to run as administrator, like you&#8217;re supposed to. And then&#8230; Problem: Visual Studio 2005 solutions no longer open when you double-click them in Windows Vista. In fact, when you double-click nothing happens. Solution: Change them to open with Visual Studio 2005 directly instead of [...]]]></description>
			<content:encoded><![CDATA[<p>You&#8217;ve installed Visual Studio 2005 on Vista and dutifully <a href="http://msdn.microsoft.com/en-us/vs2005/aa972193.aspx">changed it to run as administrator</a>, like you&#8217;re supposed to. And then&#8230;</p>
<p><strong>Problem</strong>: Visual Studio 2005 solutions no longer open when you double-click them in Windows Vista. In fact, when you double-click <em>nothing </em>happens.</p>
<p><strong>Solution</strong>: Change them to open with Visual Studio 2005 directly instead of the vslauncher.exe (which opens up the solution with the correct version of Visual Studio if you have more than one). </p>
<p><strong>Caveat</strong>: Only makes sense if&nbsp; you use <em>only</em> Visual Studio 2005.</p>
<p><strong>How-to</strong>:</p>
<ol>
<li>Right-click on a solution file.</li>
<li>Choose &#8220;Open With&#8230;&#8221;</li>
<li>Choose &#8220;Browse&#8230;&#8221;</li>
<li>Browse to file &#8220;C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\devenv.exe&#8221; (or wherever you installed Visual Studio)</li>
<li>Click &#8220;Open&#8221; button</li>
<li>Check &#8220;Always use the selected program to open this kind of file&#8221;</li>
</ol>
<p><a href="http://www.philosophicalgeek.com/wp-content/uploads/2008/05/openwith.jpg"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="374" alt="openwith" src="http://www.philosophicalgeek.com/wp-content/uploads/2008/05/openwith-thumb.jpg" width="454" border="0"/></a> </p>
<p>Now your solutions will load Visual Studio, bring up the UAC prompt, and it all works great.</p>
<p>Found via <a href="http://bphillips76.spaces.live.com/blog/cns!F9B548E4C21D6166!362.entry">here</a> and <a href="http://www.pluralsight.com/blogs/matt/archive/2007/05/21/47446.aspx">here</a>.</p>
<img src="http://www.philosophicalgeek.com/?ak_action=api_record_view&id=327&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.philosophicalgeek.com/2008/05/12/opening-visual-studio-solutions-from-explorer-in-vista/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>4 Principles of Not Wasting Time</title>
		<link>http://www.philosophicalgeek.com/2008/05/06/4-principles-of-not-wasting-time/</link>
		<comments>http://www.philosophicalgeek.com/2008/05/06/4-principles-of-not-wasting-time/#comments</comments>
		<pubDate>Tue, 06 May 2008 15:35:11 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[goals]]></category>
		<category><![CDATA[productivity]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[self-improvement]]></category>

		<guid isPermaLink="false">http://www.philosophicalgeek.com/2008/05/06/4-principles-of-not-wasting-time/</guid>
		<description><![CDATA[There are so many postings out there on all sorts of blogs about how not to waste time that I&#8217;m not sure I can contribute something very meaningful (certainly not new), but since it&#8217;s something I&#8217;ve been thinking about, I might as well spill some ideas about it. My first book, C# 4.0 How-To is [...]]]></description>
			<content:encoded><![CDATA[<p>There are so many postings out there on all sorts of blogs about how not to waste time that I&#8217;m not sure I can contribute something very meaningful (certainly not new), but since it&#8217;s something I&#8217;ve been thinking about, I might as well spill some ideas about it.</p>
<p><strong>My first book, <a href="http://www.amazon.com/gp/product/0672330636?ie=UTF8&amp;tag=philosophic0d-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0672330636">C# 4.0 How-To</a> is now shipping! If you like tips you can use, check it out!</strong></p>
<p><!--adsense--></p>
<h3>Definition</h3>
<p>Any discussion of time-wasting is profitless unless you define what wasting time is. My definition is:</p>
<blockquote><p>Wasting time is doing anything that does not contribute to my goals.</p></blockquote>
<p>That is a very broad definition, but it is very useful. It presupposes a goal-oriented mind set and I don&#8217;t want to get too far down that path here. If you&#8217;re really interested in a goal-focused system, I highly encourage you to read <a href="http://www.amazon.com/gp/product/0743269519?ie=UTF8&amp;tag=philosophic0d-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0743269519">The 7 Habits of Highly Effective People</a><img style="margin: 0px; border-style: none! important;" src="http://www.assoc-amazon.com/e/ir?t=philosophic0d-20&amp;l=as2&amp;o=1&amp;a=0743269519" border="0" alt="" width="1" height="1" />, which is a principles-based approach to effectiveness and goal-setting is a huge part of it.</p>
<p>Whatever your personal system, much of the corporate world and building software specifically revolves around goals (aka &#8220;milestones&#8221;, &#8220;targets&#8221;).</p>
<p>This definition includes taking breaks and eating lunch, but let&#8217;s not be silly&#8211;we&#8217;re not talking about that and I&#8217;m not going to water down the definition nor am I going to spend pages talking pointlessly about exceptions to it. We&#8217;re all intelligent people here and can understand the important principles.</p>
<h3>Many Small Goals Are Better Than One Large One</h3>
<p>Software development processes have been undergoing evolution since the beginning and lately the whole <a href="http://en.wikipedia.org/wiki/Agile_software_development">agile process</a> seems to be taking over. Whatever the process, many companies are finding more success in breaking down large projects into tiny goal-driven chunks, sometimes lasting as little as a week.</p>
<p>This same principles can be applied to ourselves at both large and fine-grained levels. It is definitely good and desirable to have the overall vision of our project in mind, but  this doesn&#8217;t often help us get the work done. Some of my most productive days are when I break down a huge task into tiny subtasks and set a goal for each one (&#8220;I will have this done by 11am today, then I will wrap up this other small one by 4pm.&#8221;)</p>
<p>An example: I&#8217;m currently writing some code to move a huge amount of data around in our production database. We&#8217;re going to be rolling out a major update that requires some fundamental changes to how things operate. This task is so large and daunting that I get a headache just thinking about it and so I <em>could </em>put it off, just spinning my wheels until I decide to face the inevitable. Instead, I&#8217;ve broken it into several smaller tasks that are each easily managed and understood.</p>
<table border="1" cellspacing="0" cellpadding="2" width="400">
<tbody>
<tr>
<td width="200" valign="top"><strong>Before</strong></td>
<td width="200" valign="top"><strong>After</strong></td>
</tr>
<tr>
<td width="200" valign="top">
<ul>
<li>Convert database to new format</li>
</ul>
</td>
<td width="200" valign="top">
<ul>
<li>Export SQL script of new tables, triggers, indexes, etc. directly from SQL Server</li>
<li>Aggregate data from Table1 into NewTableX</li>
<li>Move data from Table2 to NewTableY</li>
<li>Move data from Table3 to NewTableZ</li>
<li>Verify moved data</li>
<li>drop old tables</li>
<li>drop old columns</li>
<li>etc.</li>
</ul>
</td>
</tr>
</tbody>
</table>
<p>(In my example, the After column actually contains about 30 items, depending on how far I want to break it down&#8230;it could be more.)</p>
<p>Now, instead of being overwhelmed by the complexity of a large task (and thus doing nothing), I can easily handle each of the sub-steps efficiently. I&#8217;ve changed a two-week task into many hour-long tasks.</p>
<p>The psychological effect of  too-hard/too-complex/too-much is devastating. You can&#8217;t handle something like that&#8211;no one can, and so you won&#8217;t&#8211;you&#8217;ll just end up wasting time fretting about it. Break it up for your sanity and happiness, as well as productivity.</p>
<h3>Motivation is Crucial</h3>
<p>Often, a key to not wasting time is having sufficient motivation. Motivation can come in all sorts of ways&#8211;the key is to figure out what motivates you and then set yourself up to succeed by using that motivation as a carrot to pull you forward. It can be a good idea to share your motivations with managers so they understand what drives you.</p>
<p>Motivation can often begin with picking good goals. If your goals are unrealistic, you are almost guaranteed to fail in some way. Despair feeds on itself and will sink your productivity and cause you to engage in anything but work. Not only will you avoid the drudgery of work, but you won&#8217;t take steps to improve yourself or change the situation. This cycle must be broken immediately.</p>
<p>If your projects are just not that interesting this can be a challenge. Everybody has tasks they don&#8217;t particularly like, but if the majority of your time is spent doing stuff you get no pleasure out of, you are doing a huge disservice to yourself and your future. Eventually, you&#8217;ll become wasted and useless to both yourself and your employer. Fix the situation&#8211;get a new project, get a new job, find side projects to do that you do enjoy as rewards for getting through the drudgery&#8211;anything to avoid becoming the shell of a person you once were.</p>
<p>Maybe you don&#8217;t necessarily need a new job right now&#8211;maybe you just need to fix the situation at your current job, get some enjoyable hobbies at home, spend more time with the family. The needed changes aren&#8217;t always drastic&#8211;but figure them out so you don&#8217;t spend every day wallowing in a mire not doing anything useful.</p>
<h3>Eliminate Distractions Now</h3>
<p>I don&#8217;t think I&#8217;ve answered my office phone in about a year. Not that many people call it in the first place, e-mail being highly-preferred around here, but I like to say I stand on principle. You can read a lot about creating the right environment for highly-skilled software developers in the fabulous book <a href="http://www.amazon.com/gp/product/0932633439?ie=UTF8&amp;tag=philosophic0d-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0932633439">Peopleware: Productive Projects and Teams</a><img style="margin: 0px; border-style: none! important;" src="http://www.assoc-amazon.com/e/ir?t=philosophic0d-20&amp;l=as2&amp;o=1&amp;a=0932633439" border="0" alt="" width="1" height="1" />.</p>
<p>I&#8217;ve also stuck to the practice of <a href="http://www.philosophicalgeek.com/2007/10/08/getting-the-most-out-of-outlook-2007/">keeping my e-mail inbox cleared</a>. I delete almost everything I receive unless I need to store it for later or act on it.</p>
<p>In my entry about <a href="http://www.philosophicalgeek.com/2008/04/14/how-i-work-8-hour-days/">working an 8-hour day</a>, I talked about various time-wasting activities that I&#8217;ve observed, such as  wandering the halls, micro-managing, too many words, poor inbox management skills, and more.</p>
<p>The goal of eliminating distractions is not to completely choke off any aspect of fun, diversion, and other social aspects of working in an office&#8211;those are good things. The goal is eliminate the things that don&#8217;t help us in our jobs and that aren&#8217;t really all that enjoyable to us anyway, all things considered.</p>
<p>One way of eliminating your distractions is to go out of your way ahead of time to manage them so they don&#8217;t come up later. Some ideas:</p>
<ul>
<li>If you need somebody to do a task, anticipate questions, concerns, or problems they may have. Try to address these in an e-mail or in person (or both) quickly so that the person can expect it and won&#8217;t come to you later with problems.</li>
<li>Shut  the office door, turn off the phone, close e-mail. Don&#8217;t let people find a way to distract you.</li>
<li>Shut down your feed-reader, disable pop-up notifications from it. Set aside time during the day to review feeds and news.</li>
<li>Have a clean desk. Keep only things you&#8217;re actively working on visible.</li>
<li>Set a schedule or a signal to your peers and supervisors of times when you are busy and should not be bothered. Be assertive and enforce it.</li>
<li>Focus on one project at a time. Everybody has a million things to do.</li>
</ul>
<h3>Plan Weekly, Daily, Hourly</h3>
<p>Finally, bringing it around full circle back to goals: plan as much as you can to the extent it makes sense. That&#8217;s a weasel sentence, I know, but there&#8217;s no way around it. In general, though, I think we could all do with more planning.</p>
<p>Effective planning combines all the above principles into a coherent framework for your work week.</p>
<p>Every week, you have certain meetings, tasks to be completed, issues to be researched, people to be spoken to.</p>
<p>Every day, a certain subset of those must be done.</p>
<p>Every hour, you must pick a task to work on.</p>
<p>My plan is to take 10-20 minutes every day to plan the day&#8217;s activities, set min-goals, while at the same time strategizing to eliminate distractions. Every Monday morning I take an additional 10-20 minutes to review and set the major goals for the week, ensure meetings are scheduled, projects are given the correct priority, I know my tasks and responsibilities, and that I have enough dead-time left unscheduled because things always come up (we operate quickly-growing 24/7/365 services&#8211;there&#8217;s no avoiding issues).</p>
<p>Every time you finish a task, there should be another one waiting, whether you decide to tackle it right away or take a break and do something else. As long as you have a plan, it&#8217;s ok.</p>
<p>There are tons of other resources out there&#8211;I&#8217;ll just link to some in <a href="http://www.stevepavlina.com/forums/personal-effectiveness/8208-wasted-too-much-time.html">the forums of Steve Pavlina</a>.</p>
<p>Now I should stop wasting time and get back to work&#8230; <img src='http://www.philosophicalgeek.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><strong>My first book, <a href="http://www.amazon.com/gp/product/0672330636?ie=UTF8&amp;tag=philosophic0d-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0672330636">C# 4.0 How-To</a> is now shipping! If you like tips you can use, check it out!</strong></p>
<img src="http://www.philosophicalgeek.com/?ak_action=api_record_view&id=322&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.philosophicalgeek.com/2008/05/06/4-principles-of-not-wasting-time/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Announcing: GeekSoftworks.com</title>
		<link>http://www.philosophicalgeek.com/2008/05/05/announcing-geeksoftworkscom/</link>
		<comments>http://www.philosophicalgeek.com/2008/05/05/announcing-geeksoftworkscom/#comments</comments>
		<pubDate>Mon, 05 May 2008 22:24:40 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Link/News]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[Personal]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://www.philosophicalgeek.com/2008/05/05/announcing-geeksoftworkscom/</guid>
		<description><![CDATA[I&#8217;ve setup a new domain for a front page for my software hobbies and what will eventually be my &#8220;store front&#8221;: Geek Softworks It uses WordPress, but it&#8217;s not a blog&#8211;it&#8217;s for the software I write. So far, only a few products are up, including DiskSlicer (a new version!), Windows Media Top 10 Plugin, and [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve setup a new domain for a front page for my software hobbies and what will eventually be my &#8220;store front&#8221;:</p>
<p><a href="http://www.geeksoftworks.com/">Geek Softworks</a></p>
<p>It uses WordPress, but it&#8217;s not a blog&#8211;it&#8217;s for the software I write. So far, only a few products are up, including <a href="http://www.geeksoftworks.com/products/diskslicer/">DiskSlicer</a> (a new version!), <a href="http://www.geeksoftworks.com/products/wmtop10/">Windows Media Top 10 Plugin</a>, and <a href="http://www.geeksoftworks.com/products/word-count-for-windows-live-writer/">Word Count for Windows Live Writer</a>.</p>
<p>I also setup forums for those projects. The site is still pretty small, but it&#8217;s functional and it will grow.</p>
<p>Thanks for looking!</p>
<img src="http://www.philosophicalgeek.com/?ak_action=api_record_view&id=321&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.philosophicalgeek.com/2008/05/05/announcing-geeksoftworkscom/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Please help with Word Count Plugin</title>
		<link>http://www.philosophicalgeek.com/2008/04/29/please-help-with-word-count-plugin/</link>
		<comments>http://www.philosophicalgeek.com/2008/04/29/please-help-with-word-count-plugin/#comments</comments>
		<pubDate>Tue, 29 Apr 2008 19:46:43 +0000</pubDate>
		<dc:creator>Ben</dc:creator>
				<category><![CDATA[Personal]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://www.philosophicalgeek.com/2008/04/29/please-help-with-word-count-plugin/</guid>
		<description><![CDATA[I was taking a look at the download page for my Word Count Plugin for Windows Live Writer. It&#8217;s gotten a few hundred downloads (thanks!), but the single review is actually spam. Unfortunately, I can&#8217;t remove it or even report the review from my account since it&#8217;s my own software. Plea for help: Can a [...]]]></description>
			<content:encoded><![CDATA[<p>I was taking a look at the download page for my <a href="http://gallery.live.com/liveitemdetail.aspx?li=154bc65c-ed38-4295-851c-fff9d7d0a929&amp;pl=8&amp;bt=9">Word Count Plugin for Windows Live Writer.</a></p>
<p>It&#8217;s gotten a few hundred downloads (thanks!), but the single review is actually spam. Unfortunately, I can&#8217;t remove it or even report the review from my account since it&#8217;s my own software.</p>
<p><strong>Plea for help</strong>: Can a helpful reader out there please report this review as spam and request it to be removed? Also, could someone out there who does use Live Writer write a real review of the plug-in?</p>
<p>If you have further ideas to improve it, please let me know.</p>
<img src="http://www.philosophicalgeek.com/?ak_action=api_record_view&id=317&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.philosophicalgeek.com/2008/04/29/please-help-with-word-count-plugin/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
