<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Jon Kruger's Blog</title>
	
	<link>http://jonkruger.com/blog</link>
	<description />
	<pubDate>Thu, 11 Mar 2010 15:40:04 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/JonKrugersBlog" /><feedburner:info uri="jonkrugersblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Improving your validation code — a refactoring exercise</title>
		<link>http://feedproxy.google.com/~r/JonKrugersBlog/~3/1toUc_Fs7hk/</link>
		<comments>http://jonkruger.com/blog/2010/03/11/improving-your-validation-code-a-refactoring-exercise/#comments</comments>
		<pubDate>Thu, 11 Mar 2010 15:40:04 +0000</pubDate>
		<dc:creator>Jon Kruger</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://jonkruger.com/blog/?p=504</guid>
		<description><![CDATA[Today we&#8217;re going to talk about validation.  Most people have some concept where they validate an entity object before it is saved to the database.  There are many ways to implement this, and I&#8217;ve finally found my favorite way of writing validation code.  But what I think is really interesting is the [...]]]></description>
			<content:encoded><![CDATA[<p>Today we&#8217;re going to talk about validation.  Most people have some concept where they validate an entity object before it is saved to the database.  There are many ways to implement this, and I&#8217;ve finally found my favorite way of writing validation code.  But what I think is really interesting is the thought process of the many years of validation refactoring that have got me how I do validation today.  A lot of this has to do with good coding practices that I&#8217;ve picked up over time and little tricks that allow me to write better code.  This is a really good example of how I&#8217;ve learned to write better code, so I thought I&#8217;d walk you through it (and maybe you&#8217;ll like how I do validation too).</p>
<p>In the past, I would&#8217;ve created one method called something like Validate() and put all of the validation rules for that entity inside that method.  It ended up looking something like this.</p>
<p><code><br />
public class Order<br />
{<br />
&nbsp;&nbsp;public Customer Customer { get; set; }<br />
&nbsp;&nbsp;public IList&lt;Product&gt; Products { get; set; }<br />
&nbsp;&nbsp;public string State { get; set; }<br />
&nbsp;&nbsp;public decimal Tax { get; set; }<br />
&nbsp;&nbsp;public decimal ShippingCharges { get; set; }<br />
&nbsp;&nbsp;public decimal Total { get; set; }<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;public ValidationErrorsCollection Validate()<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;var errors = new ValidationErrorsCollection();<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (Customer == null)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;errors.Add(&quot;Customer is required.&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (Products.Count == 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;errors.Add(&quot;You must have at least one product.&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (State == &quot;OH&quot;)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (Tax == 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;errors.Add(&quot;You must charge tax in Ohio.&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;else<br />
&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (ShippingCharges &gt; 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;errors.Add(&quot;You cannot have free shipping outside of Ohio.&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;return errors;<br />
&nbsp;&nbsp;}<br />
}<br />
</code></p>
<p>The problem with this approach is that it&#8217;s a pain to read the Validate() method.  If you have a large object, this method starts getting really cluttered really fast and you have all kinds of crazy <i>if</i> statements floating around that make things hard to figure out.  This method may be called Validate(), but it&#8217;s not telling much about <i>how</i> the object is going to be validated.</p>
<p>So how can we make our validation classes more readable and descriptive?  First, I like to do simple validation using attributes.  I&#8217;m talking about whether a field is required, checking for null, checking for min/max values, etc.  I know that there is a certain percentage of the population that despises attributes on entity objects.  They feel like it clutters up their class.  In my opinion, I like using attributes because it&#8217;s really easy, it reduces duplication, it&#8217;s less work, and I like having attributes that describe a property and give me more information about it than just its type.  On my project, I&#8217;m using <a href="http://nhforge.org/wikis/validator/nhibernate-validator-1-0-0-documentation.aspx" target="_blank">NHibernate.Validator</a> to give me these attributes, and I&#8217;ve also defined several new validation attributes of my own (just open NHibernate.Validator.dll in Reflector and see how the out-of-the-box ones are written and you&#8217;ll be able to create your own attributes with no problems).  Now my class looks more like this:</p>
<p><code><br />
public class Order<br />
{<br />
&nbsp;&nbsp;[Required(&quot;Customer&quot;)]<br />
&nbsp;&nbsp;public Customer Customer { get; set; }<br />
&nbsp;&nbsp;[AtLeastOneItemInList(&quot;You must have at least one product.&quot;)]<br />
&nbsp;&nbsp;public IList&lt;Product&gt; Products { get; set; }<br />
&nbsp;&nbsp;public string State { get; set; }<br />
&nbsp;&nbsp;public decimal Tax { get; set; }<br />
&nbsp;&nbsp;public decimal ShippingCharges { get; set; }<br />
&nbsp;&nbsp;public decimal Total { get; set; }<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;public ValidationErrorsCollection Validate()<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;var errors = new ValidationErrorsCollection();<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (State == &quot;OH&quot;)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (Tax == 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;errors.Add(&quot;You must charge tax in Ohio.&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;else<br />
&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (ShippingCharges &gt; 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;errors.Add(&quot;You cannot have free shipping outside of Ohio.&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;return errors;<br />
&nbsp;&nbsp;}<br />
}<br />
</code></p>
<p>When I put these attributes on properties, I don&#8217;t write unit tests for that validation.  If I was really concerned about whether or not I put an attribute on a property, I could spend 2 seconds going and actually checking to see if that attribute was on the property instead of spending 2 minutes writing a test.  It&#8217;s just so easy to use an attribute that it&#8217;s hard to screw it up.  I haven&#8217;t been burned by this yet.  So already I&#8217;ve eliminated some validation code that was cluttering up my validation methods and I eliminated some tests that I would&#8217;ve otherwise written.</p>
<p>But my Validate() method still looks messy, and it&#8217;s doing a bunch of different validations.  The method name sure isn&#8217;t telling me anything about the type of custom validation that is being done.</p>
<p>Let&#8217;s write some tests and see where our tests might lead us.  </p>
<p><code><br />
[TestFixture]<br />
public class When_validating_whether_tax_is_charged<br />
{<br />
&nbsp;&nbsp;[Test]<br />
&nbsp;&nbsp;public void Should_return_error_if_tax_is_0_and_state_is_Ohio()<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;var order = new Order {Tax = 0, State = &quot;OH&quot;};<br />
&nbsp;&nbsp;&nbsp;&nbsp;order.Validate().ShouldContain(Order.TaxValidationMessage);<br />
&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;[Test]<br />
&nbsp;&nbsp;public void Should_not_return_error_if_tax_is_greater_than_0_and_state_is_Ohio()<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;var order = new Order { Tax = 3, State = &quot;OH&quot; };<br />
&nbsp;&nbsp;&nbsp;&nbsp;order.Validate().ShouldNotContain(Order.TaxValidationMessage);<br />
&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;[Test]<br />
&nbsp;&nbsp;public void Should_not_return_error_if_tax_is_0_and_state_is_not_Ohio()<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;var order = new Order { Tax = 0, State = &quot;MI&quot; };<br />
&nbsp;&nbsp;&nbsp;&nbsp;order.Validate().ShouldNotContain(Order.TaxValidationMessage);<br />
&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;[Test]<br />
&nbsp;&nbsp;public void Should_not_return_error_if_tax_is_greater_than_0_and_state_is_not_Ohio()<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;var order = new Order { Tax = 3, State = &quot;MI&quot; };<br />
&nbsp;&nbsp;&nbsp;&nbsp;order.Validate().ShouldNotContain(Order.TaxValidationMessage);<br />
&nbsp;&nbsp;}<br />
}<br />
&nbsp;<br />
[TestFixture]<br />
public class When_validating_whether_shipping_is_charged<br />
{<br />
&nbsp;&nbsp;[Test]<br />
&nbsp;&nbsp;public void Should_return_error_if_shipping_is_0_and_state_is_not_Ohio()<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;var order = new Order {ShippingCharges = 0, State = &quot;MI&quot;};<br />
&nbsp;&nbsp;&nbsp;&nbsp;order.Validate().ShouldContain(Order.ShippingValidationMessage);<br />
&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;[Test]<br />
&nbsp;&nbsp;public void Should_not_return_error_if_shipping_is_0_and_state_is_Ohio()<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;var order = new Order { ShippingCharges = 0, State = &quot;OH&quot; };<br />
&nbsp;&nbsp;&nbsp;&nbsp;order.Validate().ShouldNotContain(Order.ShippingValidationMessage);<br />
&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;[Test]<br />
&nbsp;&nbsp;public void Should_not_return_error_if_shipping_is_greater_than_0_and_state_is_Ohio()<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;var order = new Order { ShippingCharges = 5, State = &quot;OH&quot; };<br />
&nbsp;&nbsp;&nbsp;&nbsp;order.Validate().ShouldNotContain(Order.ShippingValidationMessage);<br />
&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;[Test]<br />
&nbsp;&nbsp;public void Should_not_return_error_if_shipping_is_greater_than_0_and_state_is_not_Ohio()<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;var order = new Order { ShippingCharges = 5, State = &quot;MI&quot; };<br />
&nbsp;&nbsp;&nbsp;&nbsp;order.Validate().ShouldNotContain(Order.ShippingValidationMessage);<br />
&nbsp;&nbsp;}<br />
}<br />
</code></p>
<p>These tests are testing all of the positive and negative possibilities of each validation rule.  Notice that I&#8217;m not checking just that the object was valid, I&#8217;m testing for the presence of a specific error message.  If you just try to test whether the object is valid or not, how do you really know if your code is working?  If you test that the object should not be valid in a certain scenario and it comes back with some validation error, how would you know that it returned an error for the specific rule that you were testing unless you check for that validation message?</p>
<p>I could just leave the validation code in my implementation class as is.  But I&#8217;m still not happy with the Validate() method because it has a bunch of different rules all thrown in one place, with the potential for even more to get added.  If I just refactor the code in the method into smaller methods, it&#8217;ll read better.  So now I have this:</p>
<p><code><br />
public class Order<br />
{<br />
&nbsp;&nbsp;public const string ShippingValidationMessage = &quot;You cannot have free shipping outside of Ohio.&quot;;<br />
&nbsp;&nbsp;public const string TaxValidationMessage = &quot;You must charge tax in Ohio.&quot;;<br />
&nbsp;<br />
&nbsp;&nbsp;public Customer Customer { get; set; }<br />
&nbsp;&nbsp;public IList&lt;Product&gt; Products { get; set; }<br />
&nbsp;&nbsp;public string State { get; set; }<br />
&nbsp;&nbsp;public decimal Tax { get; set; }<br />
&nbsp;&nbsp;public decimal ShippingCharges { get; set; }<br />
&nbsp;&nbsp;public decimal Total { get; set; }<br />
&nbsp;<br />
&nbsp;&nbsp;public ValidationErrorsCollection Validate()<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;var errors = new ValidationErrorsCollection();<br />
&nbsp;&nbsp;&nbsp;&nbsp;ValidateThatTaxIsChargedInOhio(errors);<br />
&nbsp;&nbsp;&nbsp;&nbsp;ValidateThatShippingIsChargedOnOrdersSentOutsideOfOhio(errors);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return errors;<br />
&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;private void ValidateThatShippingIsChargedOnOrdersSentOutsideOfOhio(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ValidationErrorsCollection errors)<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (State != &quot;OH&quot; &amp;&amp; ShippingCharges == 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;errors.Add(ShippingValidationMessage);<br />
&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;private void ValidateThatTaxIsChargedInOhio(ValidationErrorsCollection errors)<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (State == &quot;OH&quot; &amp;&amp; Tax == 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;errors.Add(TaxValidationMessage);<br />
&nbsp;&nbsp;}<br />
}<br />
</code></p>
<p>That&#8217;s better.  Now when you read my Validate() method, you have more details about what validation rules we are testing for.  This is a more natural way of writing the code when you write your tests first because it just makes sense to create one method for each test class.</p>
<p>Then your boss comes to you with a new rule &#8212; an Ohio customer only gets free shipping on their first order.  This is a little bit trickier to test because now I&#8217;m dealing with data outside of the object that is being validated.  In order to test this, I am going to have to call out to the database in order to see if this customer has an order with free shipping.  How this is done I don&#8217;t really care about in this example, I just know that I&#8217;m going to have some class that determines whether a customer has an existing order with free shipping.</p>
<p>One of the cardinal rules of writing unit tests is that I need to stub out external dependencies (like a database), and in order to do that, I need to use <a href="http://codebetter.com/blogs/jeremy.miller/archive/2005/10/06/132825.aspx" target="_blank">dependency injection</a> and take in those dependencies as interface parameters in my constructor.  But another rule of DI is that I can&#8217;t take dependencies into entity objects.  This means that I&#8217;m going to have to split the validation code out from my entity object.  I&#8217;ll move them out into a class called OrderValidator, and it&#8217;ll look like this:</p>
<p><code><br />
public class OrderValidator : IValidator&lt;Order&gt;<br />
{<br />
&nbsp;&nbsp;private readonly IGetOrdersForCustomerService _getOrdersForCustomerService;<br />
&nbsp;&nbsp;public const string ShippingValidationMessage = &quot;You cannot have free shipping outside of Ohio.&quot;;<br />
&nbsp;&nbsp;public const string TaxValidationMessage = &quot;You must charge tax in Ohio.&quot;;<br />
&nbsp;&nbsp;public const string CustomersDoNotHaveMoreThanOneOrderWithFreeShippingValidationMessage =<br />
&nbsp;&nbsp;&nbsp;&nbsp;&quot;A customer cannot have more than one order with free shipping.&quot;;<br />
&nbsp;<br />
&nbsp;&nbsp;public OrderValidator(IGetOrdersForCustomerService getOrdersForCustomerService)<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;_getOrdersForCustomerService = getOrdersForCustomerService;<br />
&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;public ValidationErrorsCollection Validate(Order order)<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;var errors = new ValidationErrorsCollection();<br />
&nbsp;&nbsp;&nbsp;&nbsp;ValidateThatTaxIsChargedInOhio(order, errors);<br />
&nbsp;&nbsp;&nbsp;&nbsp;ValidateThatShippingIsChargedOnOrdersSentOutsideOfOhio(order, errors);<br />
&nbsp;&nbsp;&nbsp;&nbsp;ValidateThatCustomersDoNotHaveMoreThanOneOrderWithFreeShipping(order, errors);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return errors;<br />
&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;private void ValidateThatCustomersDoNotHaveMoreThanOneOrderWithFreeShipping(Order order, ValidationErrorsCollection errors)<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;var ordersForCustomer = _getOrdersForCustomerService.GetOrdersForCustomer(order.Customer);<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (order.IsNew)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ordersForCustomer.Add(order);<br />
&nbsp;&nbsp;&nbsp;&nbsp;else<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ordersForCustomer = ordersForCustomer.Where(o =&gt; o.Id != order.Id).ToList();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ordersForCustomer.Add(order);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (ordersForCustomer.Count(o =&gt; o.ShippingCharges == 0) &gt; 1)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;errors.Add(CustomersDoNotHaveMoreThanOneOrderWithFreeShippingValidationMessage);<br />
&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;private void ValidateThatShippingIsChargedOnOrdersSentOutsideOfOhio(Order order, ValidationErrorsCollection errors)<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (order.State != &quot;OH&quot; &amp;&amp; order.ShippingCharges == 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;errors.Add(ShippingValidationMessage);<br />
&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;private void ValidateThatTaxIsChargedInOhio(Order order, ValidationErrorsCollection errors)<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (order.State == &quot;OH&quot; &amp;&amp; order.Tax == 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;errors.Add(TaxValidationMessage);<br />
&nbsp;&nbsp;}<br />
}<br />
</code></p>
<p>Notice that the OrderValidator class implements IValidator<Order>.  This interface is pretty simple and looks like this:</p>
<p><code><br />
public interface IValidator&lt;T&gt;<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;ValidationErrorsCollection Validate(T obj);<br />
}<br />
</code></p>
<p>Now that the validation class has been moved outside of the entity object, I need to know which IValidator&lt;T&gt; classes I need to run when I want to validate an object of a certain type.  No worries, I can just create a class that will register validator objects by type.  When the application starts up, I&#8217;ll tell my registration class to go search the assemblies for classes that implement IValidator&lt;T&gt;.  Then when it&#8217;s time to validate, I can ask this registration class for all IValidator&lt;T&gt; types that it found for the type of entity that I need to validate and have it do the validation.</p>
<p>I think we could take this one step further.  Currently our OrderValidator class is doing three different validations.  You could argue that this violates the <a href="http://en.wikipedia.org/wiki/Single_responsibility_principle" target="_blank">Single Responsibility Principle</a> because this class is doing three things.  But you might also be able to argue that it doesn&#8217;t violate the Single Reposibility Principle because OrderValidator is only doing one <i>type</i> of thing.  Does it really matter?</p>
<p>What if you got a new validation rule that says that the State property on the Order can only contain one of the lower 48 U.S. states (any state other than Alaska or Hawaii).  We also want to add this rule to a bunch of other entity objects that only should use the lower 48 states for their State property.  Ideally, I would like to write this validation rule once and use it for all of those objects.</p>
<p>In order to do this, I&#8217;m going to create an interface first:</p>
<p><code><br />
public interface IHasLower48State<br />
{<br />
&nbsp;&nbsp;public string State { get; }<br />
}<br />
</code></p>
<p>I&#8217;ll put this interface on the Order class and all of the other classes that have this rule.  Now I&#8217;ll write my validation code (after I write my tests, of course!).  The only problem is that it doesn&#8217;t really fit inside OrderValidator anymore because I&#8217;m not necessarily validating an Order, I&#8217;m validating a IHasLower48State, which could be an Order, but it also could be something else.</p>
<p>What I really need now is a class for this one validation rule.  I&#8217;m going to give it an uber-descriptive name.</p>
<p><code><br />
public class Validate_that_state_is_one_of_the_lower_48_states : IValidator&lt;IHasLower48State&gt;<br />
{<br />
&nbsp;&nbsp;public const string Message = &quot;State must be one of the lower 48 states.&quot;;<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;public ValidationErrorsCollection Validate(IHasLower48State obj)<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (obj.State == &quot;AK&quot; || obj.State == &quot;HI&quot;)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;errors.Add(Message);<br />
&nbsp;&nbsp;}<br />
}<br />
</code></p>
<p>Some of you are freaking out because I put underscores in the class name.  I put underscores in test class names, and it just seemed natural to use a very descriptive English class name that describes exactly what validation is being performed here.  If you don&#8217;t like the underscores, then call it something descriptive without using underscores.  </p>
<p>Now I change my registration class so that when you ask for all of the validation classes for an entity, it also checks for validation classes for interfaces that the entity implements.</p>
<p>What&#8217;s great about is that if an entity object implements IHasLower48State, it will now pick up this validation rule for free.  My registration class has auto-wired it for me, so I don&#8217;t have to configure anything.  I get functionality for free with no extra work!  I&#8217;m creating cross-cutting validation rules where I&#8217;m validating <i>types</i> of entities.</p>
<h3>Conclusion</h3>
<p>If you made it to this point, you&#8217;re a dedicated reader after making it through all of that (or you just skipped to the end).  I wrote all of this not only to show how I do validation, but also to show you the thought process I go through and the hows and whys behind how I refactor things and find better ways to write code.</p>
		<br />
		<a href="http://www.dotnetkicks.com/kick/?title=Improving your validation code &#8212; a refactoring exercise&url=http%3A%2F%2Fjonkruger.com%2Fblog%2F2010%2F03%2F11%2Fimproving-your-validation-code-a-refactoring-exercise%2F"> 
		<img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3A%2F%2Fjonkruger.com%2Fblog%2F2010%2F03%2F11%2Fimproving-your-validation-code-a-refactoring-exercise%2F" border="0" alt="Kick It on DotNetKicks.com" /> </a>
		<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=1toUc_Fs7hk:BX4m60H4n2o:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=1toUc_Fs7hk:BX4m60H4n2o:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?i=1toUc_Fs7hk:BX4m60H4n2o:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=1toUc_Fs7hk:BX4m60H4n2o:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?i=1toUc_Fs7hk:BX4m60H4n2o:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=1toUc_Fs7hk:BX4m60H4n2o:G79ilh31hkQ"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?d=G79ilh31hkQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/JonKrugersBlog/~4/1toUc_Fs7hk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jonkruger.com/blog/2010/03/11/improving-your-validation-code-a-refactoring-exercise/feed/</wfw:commentRss>
		<feedburner:origLink>http://jonkruger.com/blog/2010/03/11/improving-your-validation-code-a-refactoring-exercise/</feedburner:origLink></item>
		<item>
		<title>A response to the SWE101 attendees who tried to solve the TDD problem without TDD</title>
		<link>http://feedproxy.google.com/~r/JonKrugersBlog/~3/2LE7Zn96VtU/</link>
		<comments>http://jonkruger.com/blog/2010/03/02/a-response-to-the-swe101-attendees-who-tried-to-solve-the-tdd-problem-without-tdd/#comments</comments>
		<pubDate>Tue, 02 Mar 2010 15:10:36 +0000</pubDate>
		<dc:creator>Jon Kruger</dc:creator>
		
		<category><![CDATA[TDD]]></category>

		<guid isPermaLink="false">http://jonkruger.com/blog/?p=488</guid>
		<description><![CDATA[This weekend we did some live TDD at the Software Engineering 101 event and broadcast it over LiveMeeting, which was a lot of fun.  However, some people have posted solutions (here and here - see first comment) on how they solved the Greed scoring problem without using TDD.
I think you missed the point.  [...]]]></description>
			<content:encoded><![CDATA[<p>This weekend we did some live TDD at the Software Engineering 101 event and broadcast it over LiveMeeting, which was a lot of fun.  However, some people have posted solutions (<a href="http://twitter.com/guercheLE/statuses/9747164536" target="_blank">here</a> and <a href="http://jonkruger.com/blog/2010/02/27/code-from-software-engineering-101-tdd-session-more-practice/#comments" target="_blank">here - see first comment</a>) on how they solved the Greed scoring problem without using TDD.</p>
<p>I think you missed the point.  The point was to help you learn the TDD thought process and how to put TDD into practice.  There are lots of benefits to TDD, and I&#8217;ll use these non-TDD examples to illustrate.</p>
<h3>How do you know your code works?</h3>
<p>Those of you who solved the problem without TDD probably did some sort of manual testing in order to prove that your code is working.  You could probably do that with a simple example like the one we had (there were only a few scoring rules).  But what happens as we add rules (and in real life we&#8217;re always adding rules) and you have to manually test 16 rules?  For the record, I took the solution posted <a href="http://twitter.com/guercheLE/statuses/9747164536" target="_blank">here</a> and ran my tests against it.</p>
<p><img src="http://jonkruger.com/blog/wp-content/uploads/2010/03/fail.jpg" alt="failing test" title="failing test" width="600" height="428"  /></p>
<h3>Tests are documentation</h3>
<p>Tests document what the code is supposed to do.  Since we wrote our test methods as sentences that read like English, you can figure out the rules just from reading our tests (as you can see in the image above).  This is not documentation in Word format which becomes stale, this is living, breathing executable documentation of what the code is supposed to do.</p>
<h3>Readability is important</h3>
<p>I feel that the solution that we ended up with was very readable.  Here is our implementation code:</p>
<p><code><br />
public class GreedScorer<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;public double Score(params Die[] dice)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var score = 0;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;score += ScoreASetOfThreeOnes(dice);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;score += ScoreASetOfThreeTwos(dice);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;score += ScoreASetOfThreeThrees(dice);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;score += ScoreASetOfThreeFours(dice);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;score += ScoreASetOfThreeFives(dice);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;score += ScoreASetOfThreeSixes(dice);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;score += ScoreEachOneThatIsNotAPartOfASetOfThree(dice);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;score += ScoreEachFiveThatIsNotAPartOfASetOfThree(dice);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return score;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private int ScoreASetOfThreeOnes(Die[] dice)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (dice.Count(die =&gt; die.Value == 1) &gt;= 3)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 1000;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private int ScoreASetOfThreeTwos(Die[] dice)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (dice.Count(die =&gt; die.Value == 2) &gt;= 3)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 200;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private int ScoreASetOfThreeThrees(Die[] dice)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (dice.Count(die =&gt; die.Value == 3) &gt;= 3)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 300;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private int ScoreASetOfThreeFours(Die[] dice)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (dice.Count(die =&gt; die.Value == 4) &gt;= 3)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 400;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private int ScoreASetOfThreeFives(Die[] dice)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (dice.Count(die =&gt; die.Value == 5) &gt;= 3)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 500;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private int ScoreASetOfThreeSixes(Die[] dice)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (dice.Count(die =&gt; die.Value == 6) &gt;= 3)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 600;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private int ScoreEachOneThatIsNotAPartOfASetOfThree(Die[] dice)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (dice.Count(die =&gt; die.Value == 1) &lt; 3)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return (dice.Count(die =&gt; die.Value == 1) * 100);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (dice.Count(die =&gt; die.Value == 1) &gt; 3)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return ((dice.Count(die =&gt; die.Value == 1) - 3) * 100);<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private int ScoreEachFiveThatIsNotAPartOfASetOfThree(Die[] dice)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (dice.Count(die =&gt; die.Value == 5) &lt; 3)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return (dice.Count(die =&gt; die.Value == 5) * 50);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (dice.Count(die =&gt; die.Value == 5) &gt; 3)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return ((dice.Count(die =&gt; die.Value == 5) - 3) * 50);<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
</code></p>
<p>Look how readable our code is.  Read the score method.  Notice how it tells you exactly what it&#8217;s doing.  Contrast that with <a href="http://twitter.com/guercheLE/statuses/9747164536" target="_blank">one of the other solutions</a>:</p>
<p><code><br />
static int Score(int[] numbers)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;int valueToReturn = 0;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;for (int numberIndex = 0; numberIndex &lt; numbers.Length; numberIndex++)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch (numbers[numberIndex])<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case 1:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(numberIndex + 1 &lt; numbers.Length &amp;&amp; numbers[numberIndex + 1] == 1) &amp;&amp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(numberIndex + 2 &lt; numbers.Length &amp;&amp; numbers[numberIndex + 2] == 1)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;valueToReturn += 1000;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;numberIndex += 2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;valueToReturn += 100;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case 5:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(numberIndex + 1 &lt; numbers.Length &amp;&amp; numbers[numberIndex + 1] == 5) &amp;&amp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(numberIndex + 2 &lt; numbers.Length &amp;&amp; numbers[numberIndex + 2] == 5)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;valueToReturn += 500;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;numberIndex += 2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;valueToReturn += 50;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(numberIndex + 1 &lt; numbers.Length &amp;&amp; numbers[numberIndex + 1] == numbers[numberIndex]) &amp;&amp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(numberIndex + 2 &lt; numbers.Length &amp;&amp; numbers[numberIndex + 2] == numbers[numberIndex])<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;valueToReturn += 100 * numbers[numberIndex];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;numberIndex += 2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;return valueToReturn;<br />
}<br />
</code></p>
<p>To me, this code is not very readable.  If you had to implement a new rule in this method, it would be hard to  do (plus you have no tests to tell you that you broke an existing rule).</p>
<p>The point of this exercise was not to find a clever way to solve a brain teaser.  If you want to do a brain teaser, try and write code that will output a Fibonacci sequence using one LINQ expression.  That&#8217;s the kind of geek stuff that you might do at night for fun.  But when you&#8217;re writing real code, we care about things like readability and maintainability.  When you&#8217;re writing implementation code, use common language and write methods whose names tell you what they do.</p>
<h3>TDD leads to well-designed code</h3>
<p>As we were writing our first test, our test told us that we needed some class that would score the Greed game.  So we named it GreedScorer, which does exactly what the name intends.  This class will most likely end up following the <a href="http://www.objectmentor.com/resources/articles/srp.pdf" target="_blank">single responsibility principle</a> because we gave it a very specific name.</p>
<h3>But you guys took so long!</h3>
<p>We weren&#8217;t trying to finish as fast as possible.  We were not doing a coding competition.  We were <b>practicing</b> and <b>learning</b> the TDD mindset and trying to explain things as we went.  As you get better at TDD, it becomes more natural and you learn tricks that help you go faster (for example, sometimes writing a whole bunch of tests, watching them all fail, then making them all go pass is faster than  just writing one test at a time and making them pass one at a time).</p>
<p>The bottom line is that we came out with <a href="http://jonkruger.com/blog/2010/02/27/code-from-software-engineering-101-tdd-session-more-practice/">some good, readable, maintainable code</a> (with props to <a href="http://twitter.com/SweetSirena" target="_blank">Sirena</a> who helped write it).  We were able to prove that our code is working.  We don&#8217;t have any code that we don&#8217;t need.  We could easily respond to <b>change</b> and implementing new scoring rules would be pretty easy.  Implementing the Score method was fairly easy because we were building it incrementally (solving lots of little problems is easier than trying to solve a big problem all at once).  This is why we do TDD!</p>
		<br />
		<a href="http://www.dotnetkicks.com/kick/?title=A response to the SWE101 attendees who tried to solve the TDD problem without TDD&url=http%3A%2F%2Fjonkruger.com%2Fblog%2F2010%2F03%2F02%2Fa-response-to-the-swe101-attendees-who-tried-to-solve-the-tdd-problem-without-tdd%2F"> 
		<img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3A%2F%2Fjonkruger.com%2Fblog%2F2010%2F03%2F02%2Fa-response-to-the-swe101-attendees-who-tried-to-solve-the-tdd-problem-without-tdd%2F" border="0" alt="Kick It on DotNetKicks.com" /> </a>
		<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=2LE7Zn96VtU:1zTMDdvTdpo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=2LE7Zn96VtU:1zTMDdvTdpo:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?i=2LE7Zn96VtU:1zTMDdvTdpo:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=2LE7Zn96VtU:1zTMDdvTdpo:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?i=2LE7Zn96VtU:1zTMDdvTdpo:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=2LE7Zn96VtU:1zTMDdvTdpo:G79ilh31hkQ"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?d=G79ilh31hkQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/JonKrugersBlog/~4/2LE7Zn96VtU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jonkruger.com/blog/2010/03/02/a-response-to-the-swe101-attendees-who-tried-to-solve-the-tdd-problem-without-tdd/feed/</wfw:commentRss>
		<feedburner:origLink>http://jonkruger.com/blog/2010/03/02/a-response-to-the-swe101-attendees-who-tried-to-solve-the-tdd-problem-without-tdd/</feedburner:origLink></item>
		<item>
		<title>Code from Software Engineering 101 TDD session + more practice</title>
		<link>http://feedproxy.google.com/~r/JonKrugersBlog/~3/-CBJIzu1APc/</link>
		<comments>http://jonkruger.com/blog/2010/02/27/code-from-software-engineering-101-tdd-session-more-practice/#comments</comments>
		<pubDate>Sat, 27 Feb 2010 22:36:26 +0000</pubDate>
		<dc:creator>Jon Kruger</dc:creator>
		
		<category><![CDATA[TDD]]></category>

		<guid isPermaLink="false">http://jonkruger.com/blog/?p=484</guid>
		<description><![CDATA[Thanks to everyone who tuned in to watch our live TDD session.  Here is the completed code that we ended up with.  If you want to try it for yourself, you can get the rules for the Greed game here.
Here are some other &#8220;kata&#8221; exercises that you can use to help with your [...]]]></description>
			<content:encoded><![CDATA[<p>Thanks to everyone who tuned in to watch our live TDD session.  Here is the <a href="http://github.com/downloads/JonKruger/solid-principles/SWE101%20Greed%20-%20Completed.zip">completed code</a> that we ended up with.  If you want to try it for yourself, you can get the rules for the Greed game <a href="http://github.com/downloads/JonKruger/solid-principles/greed%20rules.txt">here</a>.</p>
<p>Here are some other &#8220;kata&#8221; exercises that you can use to help with your TDD practice.  These are other simple examples similar to the Greed game.</p>
<p><a href="http://katas.softwarecraftsmanship.org/?p=80" target="_blank">String Calculator</a><br />
<a href="http://en.wikipedia.org/wiki/Ten-pin_bowling" target="_blank">Bowling scoring</a><br />
<a href="http://en.wikipedia.org/wiki/Tennis#Scoring" target="_blank">Tennis scoring</a></p>
<p>Happy testing!</p>
		<br />
		<a href="http://www.dotnetkicks.com/kick/?title=Code from Software Engineering 101 TDD session + more practice&url=http%3A%2F%2Fjonkruger.com%2Fblog%2F2010%2F02%2F27%2Fcode-from-software-engineering-101-tdd-session-more-practice%2F"> 
		<img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3A%2F%2Fjonkruger.com%2Fblog%2F2010%2F02%2F27%2Fcode-from-software-engineering-101-tdd-session-more-practice%2F" border="0" alt="Kick It on DotNetKicks.com" /> </a>
		<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=-CBJIzu1APc:q6nSKDoPWB0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=-CBJIzu1APc:q6nSKDoPWB0:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?i=-CBJIzu1APc:q6nSKDoPWB0:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=-CBJIzu1APc:q6nSKDoPWB0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?i=-CBJIzu1APc:q6nSKDoPWB0:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=-CBJIzu1APc:q6nSKDoPWB0:G79ilh31hkQ"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?d=G79ilh31hkQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/JonKrugersBlog/~4/-CBJIzu1APc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jonkruger.com/blog/2010/02/27/code-from-software-engineering-101-tdd-session-more-practice/feed/</wfw:commentRss>
		<feedburner:origLink>http://jonkruger.com/blog/2010/02/27/code-from-software-engineering-101-tdd-session-more-practice/</feedburner:origLink></item>
		<item>
		<title>Software Engineering 101 - Sat., Feb. 27 - Nashville and online!</title>
		<link>http://feedproxy.google.com/~r/JonKrugersBlog/~3/mVhjbvtC9wo/</link>
		<comments>http://jonkruger.com/blog/2010/02/24/software-engineering-101-sat-feb-27-nashville-and-online/#comments</comments>
		<pubDate>Thu, 25 Feb 2010 01:46:51 +0000</pubDate>
		<dc:creator>Jon Kruger</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://jonkruger.com/blog/?p=479</guid>
		<description><![CDATA[Leon Gersing, Jim Holmes, and I are putting on our Software Engineering 101 event this Saturday, Februrary 27 in Nashville.  If you&#8217;re not in Nashville (and you probably aren&#8217;t), you can watch the entire event online on LiveMeeting!  
We&#8217;ll cover topics like object-oriented programming, the SOLID principles, and code metrics and we&#8217;ll spend [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://fallenrogue.com" target="_blank">Leon Gersing</a>, <a href="http://http://frazzleddad.blogspot.com/" target="_blank">Jim Holmes</a>, and I are putting on our Software Engineering 101 event this Saturday, Februrary 27 in Nashville.  If you&#8217;re not in Nashville (and you probably aren&#8217;t), you can watch the entire event online on LiveMeeting!  </p>
<p>We&#8217;ll cover topics like object-oriented programming, the <a href="http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod" target="_blank">SOLID principles</a>, and code metrics and we&#8217;ll spend the afternoon doing some hands-on test-driven development.  This event was a lot of fun the first time we did it and I&#8217;m really looking forward to it.</p>
<p>You can register for this FREE event <a href="http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032441780&#038;EventCategory=2&#038;culture=en-US&#038;CountryCode=US" target="_blank">here</a> (you need to register if you want to watch online to get the LiveMeeting info).</p>
		<br />
		<a href="http://www.dotnetkicks.com/kick/?title=Software Engineering 101 - Sat., Feb. 27 - Nashville and online!&url=http%3A%2F%2Fjonkruger.com%2Fblog%2F2010%2F02%2F24%2Fsoftware-engineering-101-sat-feb-27-nashville-and-online%2F"> 
		<img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3A%2F%2Fjonkruger.com%2Fblog%2F2010%2F02%2F24%2Fsoftware-engineering-101-sat-feb-27-nashville-and-online%2F" border="0" alt="Kick It on DotNetKicks.com" /> </a>
		<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=mVhjbvtC9wo:uOCV3C_2ObM:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=mVhjbvtC9wo:uOCV3C_2ObM:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?i=mVhjbvtC9wo:uOCV3C_2ObM:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=mVhjbvtC9wo:uOCV3C_2ObM:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?i=mVhjbvtC9wo:uOCV3C_2ObM:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=mVhjbvtC9wo:uOCV3C_2ObM:G79ilh31hkQ"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?d=G79ilh31hkQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/JonKrugersBlog/~4/mVhjbvtC9wo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jonkruger.com/blog/2010/02/24/software-engineering-101-sat-feb-27-nashville-and-online/feed/</wfw:commentRss>
		<feedburner:origLink>http://jonkruger.com/blog/2010/02/24/software-engineering-101-sat-feb-27-nashville-and-online/</feedburner:origLink></item>
		<item>
		<title>The automated testing triangle</title>
		<link>http://feedproxy.google.com/~r/JonKrugersBlog/~3/tKflft-5vfo/</link>
		<comments>http://jonkruger.com/blog/2010/02/08/the-automated-testing-triangle/#comments</comments>
		<pubDate>Mon, 08 Feb 2010 15:08:14 +0000</pubDate>
		<dc:creator>Jon Kruger</dc:creator>
		
		<category><![CDATA[Quality]]></category>

		<category><![CDATA[TDD]]></category>

		<category><![CDATA[unit testing]]></category>

		<guid isPermaLink="false">http://jonkruger.com/blog/?p=453</guid>
		<description><![CDATA[Recently I had the privilege of hearing Uncle Bob Martin talk at the Columbus Ruby Brigade.  Among the many nuggets of wisdom that I learned that night, my favorite part was the Automated Testing Triangle.  I don&#8217;t know if Uncle Bob made this up or if he got it from somewhere else, but [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I had the privilege of hearing <a href="http://www.objectmentor.com/omTeam/martin_r.html" target="_blank">Uncle Bob Martin</a> talk at the <a href="http://columbusrb.com" target="_blank">Columbus Ruby Brigade</a>.  Among the many nuggets of wisdom that I learned that night, my favorite part was the Automated Testing Triangle.  I don&#8217;t know if Uncle Bob made this up or if he got it from somewhere else, but it goes something like this.</p>
<p><img src="http://jonkruger.com/blog/wp-content/uploads/2010/02/testing_triangle-300x233.jpg" alt="The Automated Testing Triangle" title="The Automated Testing Triangle" width="300" height="233" style="float: right;" />At the bottom of the triangle we have <b>unit tests</b>.  These tests are testing <i>code</i>, individual methods in classes, really small pieces of functionality.  We mock out dependencies in these tests so that we can test individual methods in isolation.  These tests are written using testing frameworks like NUnit and use mocking frameworks like Rhino Mocks.  Writing these kinds of tests will help us prove that our code is working and it will help us design our code.  They will ensure that we only write enough code to make our tests pass.  Unit tests are the foundation of a maintainable codebase.</p>
<p>But there will be situations where unit tests don&#8217;t do enough for us because we will need to test multiple parts of the system working together.  This means that we need to write <b>integration tests</b> &#8212; tests that test the <i>integration</i> between different parts of the system.  The most common type of integration test is a test that interacts with the database.  These tests tend to be slower and are more brittle, but they serve a purpose by testing things that we can test with unit tests.</p>
<p>Everything we&#8217;ve discussed so far will test technical behavior, but doesn&#8217;t necessarily test <i>functional business specifications</i>.  At some point we might want to write tests that read like our technical specs so that we can show that our code is doing what the business wants it to do.  This is when we write <b>acceptance tests</b>.  These tests are written using tools like Cucumber, Fitnesse, StoryTeller, and NBehave.  These tests are usually written in plain text sentences that a business analyst could write, like this:<br />
<code>As a user<br />
When I enter a valid username and password and click Submit<br />
Then I should be logged in<br />
</code></p>
<p>At this point, we&#8217;re are no longer just testing technical aspects of our system, we are testing that our system meets the functional specifications provided by the business.</p>
<p>By now we should be able to prove that our individual pieces of code are working, that everything works together, and that it does what the business wants it to do &#8212; <i>and all of it is automated</i>.  Now comes the manual testing.  This is for all of the random stuff &#8212; checking to make sure that the page looks right, that fancy AJAX stuff works, that the app is fast enough.  This is where you try to break the app, hack it, put weird values in, etc.  </p>
<p><img src="http://jonkruger.com/blog/wp-content/uploads/2010/02/bad_testing_triangle-300x234.jpg" alt="The un-automated testing triangle" title="The un-automated testing triangle" width="300" height="234" style="float: right;" />I find that the testing triangle on most projects tends to look more like this triangle.  There are some automated integration tests, but these tests don&#8217;t use mocking frameworks to isolate dependencies, so they are slow and brittle, which makes them less valuable.  An enormous amount of manpower is spent on manual testing.  </p>
<p>Lots of projects are run this way, and many of them are successful.  So what&#8217;s the big deal?  Becuase what really matters is the <b>total cost of ownership</b> of an application over the entire lifetime of the application.  Most applications need to be changed quite often, so there is much value in doing things that will allow the application be changed easily and quickly.</p>
<p>Many people get hung up on things like, &#8220;I don&#8217;t have time to write tests!&#8221;  This is a short term view of things.  Sometimes we have deadlines that cannot be moved, so I&#8217;m not denying this reality.  But realize that you are making a short term decision that will have long term effects.</p>
<p>If you&#8217;ve ever worked on a project that had loads of manual testing, then you can at least imagine how nice it would be to have automated tests that would test a majority of your application by clicking a button.  You could deploy to production quite often because regression testing would take drastically less time.</p>
<p>I&#8217;m still trying to figure out how to achieve this goal.  I totally buy into Uncle Bob&#8217;s testing triangle, but it requires a big shift in the way we staff teams.  For example, it would really help if QA people knew how to use automated testing tools (which may require basic coding skills).  Or maybe we have developers writing more automated tests (beyond the unit tests that they usually write).  Either way, the benefits of automated testing are tremendous and will save loads of time and money over the life of an application.</p>
		<br />
		<a href="http://www.dotnetkicks.com/kick/?title=The automated testing triangle&url=http%3A%2F%2Fjonkruger.com%2Fblog%2F2010%2F02%2F08%2Fthe-automated-testing-triangle%2F"> 
		<img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3A%2F%2Fjonkruger.com%2Fblog%2F2010%2F02%2F08%2Fthe-automated-testing-triangle%2F" border="0" alt="Kick It on DotNetKicks.com" /> </a>
		<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=tKflft-5vfo:myf7ib3e00U:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=tKflft-5vfo:myf7ib3e00U:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?i=tKflft-5vfo:myf7ib3e00U:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=tKflft-5vfo:myf7ib3e00U:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?i=tKflft-5vfo:myf7ib3e00U:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=tKflft-5vfo:myf7ib3e00U:G79ilh31hkQ"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?d=G79ilh31hkQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/JonKrugersBlog/~4/tKflft-5vfo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jonkruger.com/blog/2010/02/08/the-automated-testing-triangle/feed/</wfw:commentRss>
		<feedburner:origLink>http://jonkruger.com/blog/2010/02/08/the-automated-testing-triangle/</feedburner:origLink></item>
		<item>
		<title>Announcing TDD Boot Camp - comprehensive test-driven development training in .NET</title>
		<link>http://feedproxy.google.com/~r/JonKrugersBlog/~3/ZLeppy2N8QA/</link>
		<comments>http://jonkruger.com/blog/2010/02/02/announcing-tdd-boot-camp-comprehensive-test-driven-development-training-in-net/#comments</comments>
		<pubDate>Tue, 02 Feb 2010 14:55:25 +0000</pubDate>
		<dc:creator>Jon Kruger</dc:creator>
		
		<category><![CDATA[TDD]]></category>

		<guid isPermaLink="false">http://jonkruger.com/blog/?p=450</guid>
		<description><![CDATA[If any of you have tried to learn test-driven development, you&#8217;ve probably discovered that it is not easy to learn.  It&#8217;s not something where you can just go read a book or find a few good blog posts and start doing it tomorrow.  You have to learn to how to write tests first, [...]]]></description>
			<content:encoded><![CDATA[<p>If any of you have tried to learn test-driven development, you&#8217;ve probably discovered that it is not easy to learn.  It&#8217;s not something where you can just go read a book or find a few good blog posts and start doing it tomorrow.  You have to learn to how to write tests first, how to use testing frameworks, how to write testable code, how to do dependency injection, how to use mocking frameworks, and on and on.</p>
<p>People have asked me for advice on how to learn TDD and I really haven&#8217;t had a good answer for them.  I&#8217;ve tried doing lunch and learn sessions on TDD and other people have done half-day sessions on TDD.  All of these are good, but there&#8217;s no way that you can cover all of the subjects that you would need to understand in order to do TDD on real world projects in such a short amount of time.  Sure, there&#8217;s definitely value in these sessions, but when I did my lunch and learn session on TDD, I felt like people went away feeling more confused about all of the stuff that they just realized that they didn&#8217;t understand.</p>
<p>Which is why I&#8217;m developing the <a href="http://tddbootcamp.com">TDD Boot Camp</a>, a comprehensive, three day training course that will cover everything that you need to know in order to do TDD on <b>real world .NET projects</b>.  It will be very hands-on with a lot of coding exercises that will help you understand all of the hows and whys of test driven development in .NET.  My goal is to teach all of the concepts, tools, and techniques that you need to know to do TDD so that, with some practice, you will effectively be able to do TDD (and hopefully teach others how to do it too!).</p>
<p>I&#8217;m working on scheduling some events, so keep an eye on the <a href="http://tddbootcamp.com" target="_blank">website</a> as I get things set up.  I can also come out to your site if that would work better.  Hopefully this will fill in the TDD learning gap so that more people can start realizing the benefits of test driven development.</p>
		<br />
		<a href="http://www.dotnetkicks.com/kick/?title=Announcing TDD Boot Camp - comprehensive test-driven development training in .NET&url=http%3A%2F%2Fjonkruger.com%2Fblog%2F2010%2F02%2F02%2Fannouncing-tdd-boot-camp-comprehensive-test-driven-development-training-in-net%2F"> 
		<img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3A%2F%2Fjonkruger.com%2Fblog%2F2010%2F02%2F02%2Fannouncing-tdd-boot-camp-comprehensive-test-driven-development-training-in-net%2F" border="0" alt="Kick It on DotNetKicks.com" /> </a>
		<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=ZLeppy2N8QA:x6goNNssAoA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=ZLeppy2N8QA:x6goNNssAoA:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?i=ZLeppy2N8QA:x6goNNssAoA:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=ZLeppy2N8QA:x6goNNssAoA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?i=ZLeppy2N8QA:x6goNNssAoA:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=ZLeppy2N8QA:x6goNNssAoA:G79ilh31hkQ"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?d=G79ilh31hkQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/JonKrugersBlog/~4/ZLeppy2N8QA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jonkruger.com/blog/2010/02/02/announcing-tdd-boot-camp-comprehensive-test-driven-development-training-in-net/feed/</wfw:commentRss>
		<feedburner:origLink>http://jonkruger.com/blog/2010/02/02/announcing-tdd-boot-camp-comprehensive-test-driven-development-training-in-net/</feedburner:origLink></item>
		<item>
		<title>The business value of test-driven development</title>
		<link>http://feedproxy.google.com/~r/JonKrugersBlog/~3/ceXxpnrCrBo/</link>
		<comments>http://jonkruger.com/blog/2010/01/25/the-business-value-of-test-driven-development/#comments</comments>
		<pubDate>Mon, 25 Jan 2010 15:37:00 +0000</pubDate>
		<dc:creator>Jon Kruger</dc:creator>
		
		<category><![CDATA[TDD]]></category>

		<guid isPermaLink="false">http://jonkruger.com/blog/?p=438</guid>
		<description><![CDATA[Most businesses are creating software for one primary reason &#8212; to make money.  In order to make money, we need software that meets the needs of the business and can be developed and maintained in a reasonable amount of time with a high level of quality.  Test-driven development is a discipline that will [...]]]></description>
			<content:encoded><![CDATA[<p>Most businesses are creating software for one primary reason &#8212; to make money.  In order to make money, we need software that meets the needs of the business and can be developed and maintained in a reasonable amount of time with a high level of quality.  Test-driven development is a discipline that will help you achieve these goals.</p>
<p><a href="http://en.wikipedia.org/wiki/Test-driven_development" target="_blank">Test-driven development</a> involves writing automated unit tests to prove that code is working.  The test code is written <i>before</i> the implementation code is written.  By writing the tests first, you will know when the code is working once the tests pass.  Test names are <a href="http://dannorth.net/introducing-bdd" target="_blank">written as sentences in plain English</a> so that the tests describe what the code is supposed to do.  Over time, you will end up with a large suite of automated tests which you can run in a short amount of time.  These tests will prove to you that your code is working and will continue to work as you modify or refactor the code base.</p>
<p>Most software applications are intended to be used for many years, and throughout most of their existence, someone will be changing them.  The total cost of ownership of an application goes far beyond the cost of the initial effort to create the initial version of the software.  The first release is the easy part &#8212; you can build the application from the ground up, you don&#8217;t have many hindrances, and developers feel very productive.  But as time goes on, productivity tends to decrease due to complexity, developer turnover, poor software design, and any number of other reasons.  This is where software development really becomes expensive.  So much focus is placed on the original cost of building an application without considering how the original development effort will affect the cost of maintaining that application over several years.</p>
<p>Test-driven development can <a href="http://haacked.com/archive/2005/12/06/unit-tests-cost-more-to-write.aspx" target="_blank">reduce the total cost of ownership</a> of an application.  New developers on the team will be able to change the code without fear of breaking something important.  The application will have fewer defects (and far fewer major defects), reducing the need for manual QA testing.  Your code will be self-documenting because the tests will describe the intended behavior of the code.  All of this leads to flexible, maintainable software that can be changed in less time with higher quality.</p>
<p>Software is intended to deliver business value, and test-driven development will help you write higher quality, more maintainable software that can be changed at the fast pace of the business.  Test-driven development will lead to successful software projects and enable you to write software that will withstand the test of time.</p>
		<br />
		<a href="http://www.dotnetkicks.com/kick/?title=The business value of test-driven development&url=http%3A%2F%2Fjonkruger.com%2Fblog%2F2010%2F01%2F25%2Fthe-business-value-of-test-driven-development%2F"> 
		<img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3A%2F%2Fjonkruger.com%2Fblog%2F2010%2F01%2F25%2Fthe-business-value-of-test-driven-development%2F" border="0" alt="Kick It on DotNetKicks.com" /> </a>
		<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=ceXxpnrCrBo:mUgl-C5wKzc:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=ceXxpnrCrBo:mUgl-C5wKzc:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?i=ceXxpnrCrBo:mUgl-C5wKzc:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=ceXxpnrCrBo:mUgl-C5wKzc:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?i=ceXxpnrCrBo:mUgl-C5wKzc:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=ceXxpnrCrBo:mUgl-C5wKzc:G79ilh31hkQ"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?d=G79ilh31hkQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/JonKrugersBlog/~4/ceXxpnrCrBo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jonkruger.com/blog/2010/01/25/the-business-value-of-test-driven-development/feed/</wfw:commentRss>
		<feedburner:origLink>http://jonkruger.com/blog/2010/01/25/the-business-value-of-test-driven-development/</feedburner:origLink></item>
		<item>
		<title>Going independent</title>
		<link>http://feedproxy.google.com/~r/JonKrugersBlog/~3/V9u6S5mTj0w/</link>
		<comments>http://jonkruger.com/blog/2010/01/22/going-independent/#comments</comments>
		<pubDate>Sat, 23 Jan 2010 03:37:38 +0000</pubDate>
		<dc:creator>Jon Kruger</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://jonkruger.com/blog/?p=434</guid>
		<description><![CDATA[Three years ago, my three year plan was to go off on my own as an independent consultant.  Well, it&#8217;s year 3 and the time has come to make it happen.
For the past four years, I have worked at Quick Solutions and I have loved it.  I came into Quick Solutions never having [...]]]></description>
			<content:encoded><![CDATA[<p>Three years ago, my three year plan was to go off on my own as an independent consultant.  Well, it&#8217;s year 3 and the time has come to make it happen.</p>
<p>For the past four years, I have worked at <a href="http://quicksolutions.com" target="_blank">Quick Solutions</a> and I have loved it.  I came into Quick Solutions never having done ASP.NET and ended up getting all kinds of experience in all kinds of different technologies.  I never could&#8217;ve learned as much as I did and I certainly would not be in this spot today if it weren&#8217;t for all of the really smart people that I got to work with.</p>
<p>So what am I going to be doing now?  I&#8217;m still going to be leading a .NET project for Quick Solutions.  There will be plenty of blogging and I have some side business ideas to work on.  You will most likely see plenty of me at various community events, lunches, <a href="http://codeandcoffee.info" target="_blank">code and coffee</a>, and whatever else is going on.  </p>
<p>I don&#8217;t know what the future will hold, but I always remember the line in <i>Good Will Hunting</i> where Robin Williams says that he&#8217;s going to put his money on the table and see what cards he&#8217;ll get.  I&#8217;m really looking forward to it.</p>
		<br />
		<a href="http://www.dotnetkicks.com/kick/?title=Going independent&url=http%3A%2F%2Fjonkruger.com%2Fblog%2F2010%2F01%2F22%2Fgoing-independent%2F"> 
		<img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3A%2F%2Fjonkruger.com%2Fblog%2F2010%2F01%2F22%2Fgoing-independent%2F" border="0" alt="Kick It on DotNetKicks.com" /> </a>
		<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=V9u6S5mTj0w:I0pIWFpTJp8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=V9u6S5mTj0w:I0pIWFpTJp8:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?i=V9u6S5mTj0w:I0pIWFpTJp8:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=V9u6S5mTj0w:I0pIWFpTJp8:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?i=V9u6S5mTj0w:I0pIWFpTJp8:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=V9u6S5mTj0w:I0pIWFpTJp8:G79ilh31hkQ"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?d=G79ilh31hkQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/JonKrugersBlog/~4/V9u6S5mTj0w" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jonkruger.com/blog/2010/01/22/going-independent/feed/</wfw:commentRss>
		<feedburner:origLink>http://jonkruger.com/blog/2010/01/22/going-independent/</feedburner:origLink></item>
		<item>
		<title>Speakers appreciate your feedback</title>
		<link>http://feedproxy.google.com/~r/JonKrugersBlog/~3/nw0e-hY0Wxo/</link>
		<comments>http://jonkruger.com/blog/2010/01/17/speakers-appreciate-your-feedback/#comments</comments>
		<pubDate>Mon, 18 Jan 2010 00:42:26 +0000</pubDate>
		<dc:creator>Jon Kruger</dc:creator>
		
		<category><![CDATA[Speaking]]></category>

		<guid isPermaLink="false">http://jonkruger.com/blog/?p=429</guid>
		<description><![CDATA[I was fortunate enough to have been given the opportunity to speak at CodeMash this past week.  One thing I&#8217;ve noticed is that pretty much every time I speak (regardless of where it is), people will come up to me and offer feedback, advice, etc.
Personally, I really appreciate this.  I&#8217;ve done my share [...]]]></description>
			<content:encoded><![CDATA[<p>I was fortunate enough to have been given the opportunity to speak at <a href="http://codemash.org" target="_blank">CodeMash</a> this past week.  One thing I&#8217;ve noticed is that pretty much every time I speak (regardless of where it is), people will come up to me and offer feedback, advice, etc.</p>
<p>Personally, I really appreciate this.  I&#8217;ve done my share of speaking over the years (both technical and non-technical), so I don&#8217;t think that I&#8217;m a bumbling idiot, but I certainly am aware that I have a lot of room for improvement.  My biggest fear when giving a talk is that people won&#8217;t understand or I&#8217;ll say something wrong and no one will ever let me know what I&#8217;m doing wrong.  </p>
<p>So I don&#8217;t care if you have been speaking for 20 years or if you have never given a talk in your life, I appreciate your feedback and especially your suggestions.  If you come up to me and say, &#8220;That talk was terrible,&#8221; I might not be so happy!  But if you come to me and tell me what I can do to improve, I&#8217;ll all ears.</p>
		<br />
		<a href="http://www.dotnetkicks.com/kick/?title=Speakers appreciate your feedback&url=http%3A%2F%2Fjonkruger.com%2Fblog%2F2010%2F01%2F17%2Fspeakers-appreciate-your-feedback%2F"> 
		<img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3A%2F%2Fjonkruger.com%2Fblog%2F2010%2F01%2F17%2Fspeakers-appreciate-your-feedback%2F" border="0" alt="Kick It on DotNetKicks.com" /> </a>
		<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=nw0e-hY0Wxo:R491BK_BLMM:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=nw0e-hY0Wxo:R491BK_BLMM:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?i=nw0e-hY0Wxo:R491BK_BLMM:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=nw0e-hY0Wxo:R491BK_BLMM:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?i=nw0e-hY0Wxo:R491BK_BLMM:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=nw0e-hY0Wxo:R491BK_BLMM:G79ilh31hkQ"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?d=G79ilh31hkQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/JonKrugersBlog/~4/nw0e-hY0Wxo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jonkruger.com/blog/2010/01/17/speakers-appreciate-your-feedback/feed/</wfw:commentRss>
		<feedburner:origLink>http://jonkruger.com/blog/2010/01/17/speakers-appreciate-your-feedback/</feedburner:origLink></item>
		<item>
		<title>Convincing others how to do TDD, OOP/SOLID talks @ CodeMash</title>
		<link>http://feedproxy.google.com/~r/JonKrugersBlog/~3/MU8ertc73bw/</link>
		<comments>http://jonkruger.com/blog/2010/01/09/convincing-others-how-to-do-tdd-oopsolid-talks-codemash/#comments</comments>
		<pubDate>Sat, 09 Jan 2010 20:51:44 +0000</pubDate>
		<dc:creator>Jon Kruger</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://jonkruger.com/blog/?p=427</guid>
		<description><![CDATA[If you&#8217;re going to CodeMash next week, I&#8217;ll be speaking at a couple of sessions.  On Wednesday morning, I&#8217;ll be doing a PreCompiler session on object-oriented programming and the SOLID principles.  I&#8217;m not big on 101 level talks, so this will be very little beginner material and mostly advanced OOP ninja stuff.  [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;re going to <a href="http://codemash.org" target="_blank">CodeMash</a> next week, I&#8217;ll be speaking at a couple of sessions.  On Wednesday morning, I&#8217;ll be doing a PreCompiler session on <a href="http://codemash.org/Precompiler#OOP" target="_blank">object-oriented programming and the SOLID principles</a>.  I&#8217;m not big on 101 level talks, so this will be very little beginner material and mostly advanced OOP ninja stuff.  I know this doesn&#8217;t sound very sexy, but learning advanced OOP and SOLID has drastically improved the code that I write, which is why I&#8217;m talking about it.  We&#8217;ll do some hands-on coding too, so bring your laptop and get ready to learn from each other.</p>
<p>I&#8217;ll also be doing a short 30-minute session on how to convince others to do test-driven development.  This is a touchy, difficult task that requires lots of tact, patience, and passion for TDD, but it can be done!  I&#8217;m not sure what time I&#8217;ll be doing this, but check the schedule when you get there and you should find it (it will be in the vendor session timeslot).</p>
		<br />
		<a href="http://www.dotnetkicks.com/kick/?title=Convincing others how to do TDD, OOP/SOLID talks @ CodeMash&url=http%3A%2F%2Fjonkruger.com%2Fblog%2F2010%2F01%2F09%2Fconvincing-others-how-to-do-tdd-oopsolid-talks-codemash%2F"> 
		<img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3A%2F%2Fjonkruger.com%2Fblog%2F2010%2F01%2F09%2Fconvincing-others-how-to-do-tdd-oopsolid-talks-codemash%2F" border="0" alt="Kick It on DotNetKicks.com" /> </a>
		<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=MU8ertc73bw:nkI-oW1CPGs:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=MU8ertc73bw:nkI-oW1CPGs:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?i=MU8ertc73bw:nkI-oW1CPGs:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=MU8ertc73bw:nkI-oW1CPGs:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?i=MU8ertc73bw:nkI-oW1CPGs:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/JonKrugersBlog?a=MU8ertc73bw:nkI-oW1CPGs:G79ilh31hkQ"><img src="http://feeds.feedburner.com/~ff/JonKrugersBlog?d=G79ilh31hkQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/JonKrugersBlog/~4/MU8ertc73bw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://jonkruger.com/blog/2010/01/09/convincing-others-how-to-do-tdd-oopsolid-talks-codemash/feed/</wfw:commentRss>
		<feedburner:origLink>http://jonkruger.com/blog/2010/01/09/convincing-others-how-to-do-tdd-oopsolid-talks-codemash/</feedburner:origLink></item>
	</channel>
</rss>
