<?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:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><title>Jimmy Bogard</title><link>http://www.lostechies.com/blogs/jimmy_bogard/default.aspx</link><description>Professional driver on closed road.  Do not attempt.</description><language>en</language><generator>CommunityServer 2008.5 (Build: 30929.2835)</generator><creativeCommons:license>http://creativecommons.org/licenses/by/3.0/</creativeCommons:license><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/GrabBagOfT" type="application/rss+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item><title>MVC Best Practices</title><link>http://feedproxy.google.com/~r/GrabBagOfT/~3/2TW4o4UVPoM/mvc-best-practices.aspx</link><category>ASP.NET MVC</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">bogardj</dc:creator><pubDate>Wed, 28 Oct 2009 05:45:26 PDT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:28845</guid><description>&lt;p&gt;Simone has a great post (as usual) on &lt;a href="http://codeclimber.net.nz/archive/2009/10/27/12-asp.net-mvc-best-practices.aspx"&gt;12 ASP.NET MVC Best Practices&lt;/a&gt;:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;strong&gt;Controller:&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;1 - Delete the AccountController&lt;/p&gt;    &lt;p&gt;2 - Isolate controllers from the outside world&lt;/p&gt;    &lt;p&gt;3 - Use an IoC Container&lt;/p&gt;    &lt;p&gt;4 - So NO to “magic strings”&lt;/p&gt;    &lt;p&gt;5 - Build your own personal conventions&lt;/p&gt;    &lt;p&gt;6 - Pay attention to the verbs&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;Model:&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;7 – Domain Model != ViewModel&lt;/p&gt;    &lt;p&gt;8 – Use ActionFilters for “shared” data&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;View:&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;9 – NEVER use code-behind&lt;/p&gt;    &lt;p&gt;10 – Write HTML each time you can&lt;/p&gt;    &lt;p&gt;11 – If there is an if, write an HtmlHelper extension&lt;/p&gt;    &lt;p&gt;12 – Choose your ViewEngine carefully&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;This is a fantastic list, and of course I have my own additions/suggestions :)&amp;#160; First, I’m not a fan of action filters for shared data.&amp;#160; If we’re doing strongly-typed views, using action filters for shared data puts us back into the magic string land, where we have to either use inheritance in our ViewModels, or the dictionary part of ViewData.&amp;#160; I don’t like either approach, I’d &lt;a href="http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/06/18/the-filter-viewdata-anti-pattern.aspx"&gt;rather go with something like RenderAction&lt;/a&gt; to truly enforce SRP in my ViewModels.&amp;#160; Not everyone appreciates the elegance of this approach, but I’m sure they’ll agree eventually.&lt;/p&gt;  &lt;p&gt;I also don’t like writing an HtmlHelper extension just because I have logic in the view.&amp;#160; For a half-decent view engine, it shouldn’t be that problematic to have view logic in the view.&amp;#160; HtmlHelper extensions enforce the Helper object anti-pattern – a bunch of procedural logic hanging off one static class.&amp;#160; Instead, we went the route of building intelligent input builders for input elements, and only really using HtmlHelper when we want to eliminate duplication between multiple views.&amp;#160; I see these constructs:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;HtmlHelper&lt;/li&gt;    &lt;li&gt;Partials&lt;/li&gt;    &lt;li&gt;Master Pages&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;All as means of eliminating duplication in our views, but not much more.&amp;#160; If there’s logic in a view, that’s fine by me as long as it’s not duplicated.&amp;#160; It’s not my fault that C# looks downright bizarre mixed in with HTML markup, but that’s what &lt;a href="http://sparkviewengine.com/"&gt;other view engines are for&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Finally, if there was an award for How Not to Design a Controller, the AccountController would be the runaway champ.&amp;#160; I still can’t imagine why it’s necessary, and the idea of &lt;a href="http://jeffreypalermo.com/blog/mvccontrib-working-on-portable-areas/"&gt;portable areas&lt;/a&gt; would be a better fit for its functionality than the Thing We Always Delete with Extreme Prejudice.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;a href="http://www.dotnetkicks.com/kick/?title=MVC+Best+Practices&amp;url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f10%2f28%2fmvc-best-practices.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f10%2f28%2fmvc-best-practices.aspx" border="0" alt="Kick It on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=28845" width="1" height="1"&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=2TW4o4UVPoM:G1F0GlxOeFw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=2TW4o4UVPoM:G1F0GlxOeFw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=2TW4o4UVPoM:G1F0GlxOeFw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=2TW4o4UVPoM:G1F0GlxOeFw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=2TW4o4UVPoM:G1F0GlxOeFw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GrabBagOfT/~4/2TW4o4UVPoM" height="1" width="1"/&gt;</description><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">13</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/rsscomments.aspx?PostID=28845</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/commentapi.aspx?PostID=28845</wfw:comment><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/10/28/mvc-best-practices.aspx</feedburner:origLink></item><item><title>MVC Web Testing Strategies – verifying content</title><link>http://feedproxy.google.com/~r/GrabBagOfT/~3/5zjJp2b46W8/mvc-web-testing-strategies-verifying-content.aspx</link><category>ASP.NET MVC</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">bogardj</dc:creator><pubDate>Tue, 27 Oct 2009 18:51:46 PDT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:28642</guid><description>&lt;p&gt;Some of the questions during the C4MVC presentation concerned how I liked to locate data displayed in the rendered HTML for validation purposes.&amp;#160; You have quite a few options for doing so, such as:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Traverse HTML directly through the DOM &lt;/li&gt;    &lt;li&gt;Using existing semantic HTML information &lt;/li&gt;    &lt;li&gt;Adding semantic HTML information &lt;/li&gt;    &lt;li&gt;Wrapping data with specific HTML &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;I’ll dismiss the first option immediately, it’s quite brittle to traverse only the DOM to locate data on a screen.&amp;#160; If I have to have intimate knowledge of the entire HTML document rendered, the test will become far too dependent on the layout on the screen.&amp;#160; If I decide to move information out of a table and into a definition list, my test will likely break.&lt;/p&gt;  &lt;p&gt;From there, I’m left with basically two options – semantic HTML, whether it’s existing or added, or wrapping each data piece with custom HTML.&amp;#160; In the presentation, two questions came up:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;When locating a piece of information in a row in a table, why not use something more meaningful, such as the underlying entity’s ID to tag the data? &lt;/li&gt;    &lt;li&gt;Again in the table, why not use semantic information on the row, instead of adding meaningless HTML? &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Before we look at the different ways to verify content, let’s first look at what we want to verify.&lt;/p&gt;  &lt;h3&gt;The original content&lt;/h3&gt;  &lt;p&gt;In the scenario I highlighted in the screencast, I walk though editing some information, then verifying that data was changed correctly.&amp;#160; I still have tests for controllers, repositories and so on, but I want a high level scenario-based test to make sure the entire pipeline is working as expected.&amp;#160; We try and pull the information out of the HTML content rendered, using some sort of UI testing tool.&amp;#160; Without modifying the content, here’s what we have to work with: &lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;div &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;main&amp;quot;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;h2&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Products&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;h2&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;table&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;thead&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Details&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Name&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Manufacturer&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Price&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;thead&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;tbody&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;a &lt;/span&gt;&lt;span style="color: red"&gt;href&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;/Product/Edit/1&amp;quot;&amp;gt;&lt;/span&gt;Edit&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;a&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Insignia® - 26&amp;quot; Class / 720p / 60Hz / LCD HDTV DVD Combo&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Insignia&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;359.99&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;a &lt;/span&gt;&lt;span style="color: red"&gt;href&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;/Product/Edit/2&amp;quot;&amp;gt;&lt;/span&gt;Edit&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;a&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Insignia® - 19&amp;quot; Class / 720p / 60Hz / LCD HDTV&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Insignia&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;189.99&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;a &lt;/span&gt;&lt;span style="color: red"&gt;href&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;/Product/Edit/3&amp;quot;&amp;gt;&lt;/span&gt;Edit&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;a&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Dynex® - 15&amp;quot; Class / 720p / 60Hz / LCD HDTV&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Dynex&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;159.99&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;tbody&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;table&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;There’s more rendered than just this HTML, but this is the piece that really matters.&amp;#160; We have some semantic CSS information, the DIV with an ID of “main”, but that’s about it.&amp;#160; In our CSS, we style our tables based on an ID-Element selector, but we could have just have easily used a class name on the table.&amp;#160; I’d like to verify that the price on the first product was changed correctly, but how do I verify this?&amp;#160; How do I make sure that the value in that one cell is the new price?&lt;/p&gt;

&lt;h3&gt;Choosing a strategy&lt;/h3&gt;

&lt;p&gt;I don’t want false positives or false negatives.&amp;#160; I don’t want to look for just any table or any table cell in the markup, I want really the piece just around “359.99”.&amp;#160; A few options to do so include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Locating the outer DIV, finding the table, the first row, last cell, etc. &lt;/li&gt;

  &lt;li&gt;Apply a special class to the TD just where that price is shown &lt;/li&gt;

  &lt;li&gt;Add markup only around data-bound elements &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When I first started doing UI testing, I assumed that I wanted to be as semantic and pure as possible, and not try to change my markup just for tests.&amp;#160; That idea lasted about an hour, and reality set in that in general, things not designed with testing in mind will be hard to test.&amp;#160; Hard to write tests, hard to maintain tests.&lt;/p&gt;

&lt;p&gt;My next idea was to add information as needed, perhaps a class name to an existing surrounding element that might double for styling.&amp;#160; But I’ve moved completely away from that strategy as well, as &lt;strong&gt;styling and UI testing are two different concerns that should not mix&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Why keep these concerns separate?&amp;#160; Frankly, because both concerns have two completely different reasons to change.&amp;#160; Styling and behavior (such as IDs added for jQuery) are about design and interaction.&amp;#160; UI testing is about verifying site behavior.&amp;#160; Mixing the two concerns means my tests are more likely to break because I’ve changed the design.&amp;#160; But design can change without behavior changing, so I don’t want to couple my tests to the visual design.&amp;#160; Coupling UI tests to the site design is like unit testing using only the reflection API.&lt;/p&gt;

&lt;p&gt;Instead, I’d rather couple my tests to something that better represents the view – and that would be the ViewModel.&lt;/p&gt;

&lt;h3&gt;Strongly-typed views, strongly-typed tests&lt;/h3&gt;

&lt;p&gt;We use strongly-typed views because using a dictionary just leads to brittleness and fear of change.&amp;#160; Strongly-typed views, along with the concept of the &lt;a href="http://codebetter.com/blogs/jeremy.miller/archive/2008/10/23/our-opinions-on-the-asp-net-mvc-introducing-the-thunderdome-principle.aspx"&gt;Thunderdome Principle&lt;/a&gt;, let us move past the issues of broken views and broken model binding.&amp;#160; Instead of writing black-box tests against our UI, we can take advantage of the strongly-typed views, and modify our HTML rendered to get access to the rendered ViewModel.&amp;#160; If you look at views from the point of view of “how to render a ViewModel”, then your UI tests can now talk in the language of the ViewModel.&lt;/p&gt;

&lt;p&gt;But to help our UI tests out, we need to be able to locate information rendered from a ViewModel.&amp;#160; Looking at our original HTML, the most fool-proof, straightforward way to do this would be to add HTML as close to the rendered ViewModel as possible.&amp;#160; Let’s look at our view to see where this might be:&lt;/p&gt;

&lt;pre class="code"&gt;    &lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;h2&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Products&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;h2&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &lt;/span&gt;&lt;span style="background: #ffee62"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color: blue"&gt;var &lt;/span&gt;products = Model; &lt;span style="background: #ffee62"&gt;%&amp;gt;
&lt;/span&gt;    
    &lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;table&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;thead&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Details&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Name&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Manufacturer&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Price&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;thead&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;tbody&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &lt;/span&gt;&lt;span style="background: #ffee62"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: blue"&gt;var &lt;/span&gt;product &lt;span style="color: blue"&gt;in &lt;/span&gt;products) { &lt;span style="background: #ffee62"&gt;%&amp;gt;
&lt;/span&gt;            &lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background: #ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue"&gt;= &lt;/span&gt;Html.ActionLink(&lt;span style="color: #a31515"&gt;&amp;quot;Edit&amp;quot;&lt;/span&gt;, &lt;span style="color: #a31515"&gt;&amp;quot;Edit&amp;quot;&lt;/span&gt;, &lt;span style="color: blue"&gt;new &lt;/span&gt;{ id = product.Id }) &lt;span style="background: #ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background: #ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue"&gt;= &lt;/span&gt;product.Name &lt;span style="background: #ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background: #ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue"&gt;= &lt;/span&gt;product.ManufacturerName &lt;span style="background: #ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background: #ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue"&gt;= &lt;/span&gt;product.Price &lt;span style="background: #ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &lt;/span&gt;&lt;span style="background: #ffee62"&gt;&amp;lt;%&lt;/span&gt; } &lt;span style="background: #ffee62"&gt;%&amp;gt;
&lt;/span&gt;        &lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;tbody&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;table&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;So what’s the ideal spot here?&amp;#160; On the table?&amp;#160; The table body?&amp;#160; Row?&amp;#160; Cell?&amp;#160; These are all possible…and all coupled to the design of the UI, rather than the shape of the ViewModel.&amp;#160; Instead of coupling to the design of the HTML, we can instead change every spot where we render the ViewModel directly to have extra HTML used only for UI tests.&amp;#160; In the presentation, I move towards this model:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;tbody&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&lt;/span&gt;&lt;span style="background: #ffee62"&gt;&amp;lt;%&lt;/span&gt; &lt;span style="color: blue"&gt;var &lt;/span&gt;i = 0; &lt;span style="background: #ffee62"&gt;%&amp;gt;
&amp;lt;%&lt;/span&gt; &lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: blue"&gt;var &lt;/span&gt;product &lt;span style="color: blue"&gt;in &lt;/span&gt;products) { &lt;span style="background: #ffee62"&gt;%&amp;gt;
&lt;/span&gt;    &lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background: #ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue"&gt;= &lt;/span&gt;Html.ActionLink(&lt;span style="color: #a31515"&gt;&amp;quot;Edit&amp;quot;&lt;/span&gt;, &lt;span style="color: #a31515"&gt;&amp;quot;Edit&amp;quot;&lt;/span&gt;, &lt;span style="color: blue"&gt;new &lt;/span&gt;{ id = product.Id }) &lt;span style="background: #ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background: #ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue"&gt;= &lt;/span&gt;Html.Span(m =&amp;gt; m.Name) &lt;span style="background: #ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background: #ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue"&gt;= &lt;/span&gt;Html.Span(m =&amp;gt; m.ManufacturerName) &lt;span style="background: #ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;span style="background: #ffee62"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color: blue"&gt;= &lt;/span&gt;Html.Span(m =&amp;gt; m.Price) &lt;span style="background: #ffee62"&gt;%&amp;gt;&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&lt;/span&gt;&lt;span style="background: #ffee62"&gt;&amp;lt;%
&lt;/span&gt;    i++;
} &lt;span style="background: #ffee62"&gt;%&amp;gt;
&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;tbody&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;In practice, I’ll use a similar concept to the &lt;a href="http://www.lostechies.com/blogs/hex/archive/2009/06/09/opinionated-input-builders-for-asp-net-mvc-using-partials-part-i.aspx"&gt;Opinionated Input Builders Eric highlighted a while back&lt;/a&gt;.&amp;#160; Instead of input elements, I’ll solely render at the core, span tags.&amp;#160; Here is the rendered HTML:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;div &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;main&amp;quot;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;h2&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Products&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;h2&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;table&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;thead&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Details&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Name&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Manufacturer&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;Price&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;

            &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;thead&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;tbody&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;a &lt;/span&gt;&lt;span style="color: red"&gt;href&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;/Product/Edit/1&amp;quot;&amp;gt;&lt;/span&gt;Edit&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;a&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;span &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;='_0__Name'&amp;gt;&lt;/span&gt;Insignia® - 26&amp;quot; Class / 720p / 60Hz / LCD HDTV DVD Combo&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;span&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;span &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;='_0__ManufacturerName'&amp;gt;&lt;/span&gt;Insignia&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;span&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;span &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;='_0__Price'&amp;gt;&lt;/span&gt;359.99&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;span&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;a &lt;/span&gt;&lt;span style="color: red"&gt;href&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;/Product/Edit/2&amp;quot;&amp;gt;&lt;/span&gt;Edit&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;a&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;span &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;='_1__Name'&amp;gt;&lt;/span&gt;Insignia® - 19&amp;quot; Class / 720p / 60Hz / LCD HDTV&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;span&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;span &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;='_1__ManufacturerName'&amp;gt;&lt;/span&gt;Insignia&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;span&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;span &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;='_1__Price'&amp;gt;&lt;/span&gt;189.99&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;span&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;a &lt;/span&gt;&lt;span style="color: red"&gt;href&lt;/span&gt;&lt;span style="color: blue"&gt;=&amp;quot;/Product/Edit/3&amp;quot;&amp;gt;&lt;/span&gt;Edit&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;a&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;span &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;='_2__Name'&amp;gt;&lt;/span&gt;Dynex® - 15&amp;quot; Class / 720p / 60Hz / LCD HDTV&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;span&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;span &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;='_2__ManufacturerName'&amp;gt;&lt;/span&gt;Dynex&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;span&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
                &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;span &lt;/span&gt;&lt;span style="color: red"&gt;id&lt;/span&gt;&lt;span style="color: blue"&gt;='_2__Price'&amp;gt;&lt;/span&gt;159.99&lt;span style="color: blue"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;span&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;td&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
            &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;tr&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
        &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;tbody&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
    &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;table&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Notice that each data-bound output is wrapped with a span tag – and a special span tag at that.&amp;#160; The span tag has a unique ID that represents the expression used to render that piece of data.&amp;#160; The first product name shown comes from the expression “m =&amp;gt; m[0].Name”.&amp;#160; Because I know the ViewModel used to render this view, I can use an expression combined with a UI testing tool to locate the rendering of any piece of information on the screen.&lt;/p&gt;

&lt;p&gt;The downside of this strategy is the amount of HTML added to the final document render.&amp;#160; But since we’ve separated HTML used for styling and behavior, and HTML rendered strictly for testing, we can put a switch in our application so that for environments not doing UI testing, the span tag isn’t ever rendered!&amp;#160; We can then get the best of both worlds – non-obtrusive JavaScript on top of semantic HTML, and flip a switch to be able to get to any piece of information on the rendered HTML.&lt;/p&gt;

&lt;p&gt;Because our UI tests also use the ViewModel types and expressions to locate the same rendered ViewModels that the views used to render, we no longer run into the issue where our UI tests become disconnected from the views rendered.&amp;#160; If we delete a property on our ViewModel, guess what, the UI test no longer compiles!&lt;/p&gt;

&lt;h3&gt;Wrapping it up&lt;/h3&gt;

&lt;p&gt;Developing a UI testing strategy isn’t the easiest thing in the world.&amp;#160; In our current project, I think we had three or four evolutions before we finally settled on a UI testing strategy we like.&amp;#160; And it’s still not perfect – we’re still looking at ways to make UI testing easy, expressive, and more valuable.&amp;#160; But gone are the days where a styling change broke our tests.&amp;#160; When our UI tests fail now, it’s more along the lines of a new required field, changing business rules and so on.&lt;/p&gt;

&lt;p&gt;I don’t like mixing styling and behavior with locating data-bound UI elements, simply because both have very different reasons for change.&amp;#160; But by taking advantage of our strongly-typed views in our UI tests, we can render the ViewModel in such a way that makes it dirt-simple to locate individual pieces of our ViewModel on the final rendered page.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;a href="http://www.dotnetkicks.com/kick/?title=MVC+Web+Testing+Strategies+%e2%80%93+verifying+content&amp;url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f10%2f27%2fmvc-web-testing-strategies-verifying-content.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f10%2f27%2fmvc-web-testing-strategies-verifying-content.aspx" border="0" alt="Kick It on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=28642" width="1" height="1"&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=5zjJp2b46W8:q1pOP63aXS8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=5zjJp2b46W8:q1pOP63aXS8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=5zjJp2b46W8:q1pOP63aXS8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=5zjJp2b46W8:q1pOP63aXS8:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=5zjJp2b46W8:q1pOP63aXS8:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GrabBagOfT/~4/5zjJp2b46W8" height="1" width="1"/&gt;</description><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">10</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/rsscomments.aspx?PostID=28642</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/commentapi.aspx?PostID=28642</wfw:comment><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/10/27/mvc-web-testing-strategies-verifying-content.aspx</feedburner:origLink></item><item><title>C4MVC UI Testing screencast posted</title><link>http://feedproxy.google.com/~r/GrabBagOfT/~3/h89Ok1SXwPc/c4mvc-ui-testing-screencast-posted.aspx</link><category>ASP.NET MVC</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">bogardj</dc:creator><pubDate>Thu, 22 Oct 2009 18:37:41 PDT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:27601</guid><description>&lt;p&gt;Yesterday the &lt;a href="http://www.c4mvc.net/"&gt;C4MVC&lt;/a&gt; guys hosted a screencast with me on UI testing ASP.NET MVC.&amp;#160; It was a lot of fun, but I actually forgot I was being videotaped (webcam’d?), so all those times I turned off my mic to catch a drink of water or cough uncontrollably are caught in glorious 370i.&amp;#160; Anyway, check out the video here:&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:974b11f8-c28d-438c-a18e-4b5d362d0af7" class="wlWriterEditableSmartContent"&gt;&lt;div&gt;&lt;embed src="http://www.viddler.com/player/a4c23795//" width="437" height="370" wmode="transparent" type="application/x-shockwave-flash" allowScriptAccess="always" allowFullScreen="true" name="viddler_a4c23795/"&gt;&lt;/embed&gt;&lt;/div&gt;&lt;/div&gt;  &lt;p&gt;Unfortunately, I didn’t leave enough time for questions at the end, and I had some good ones from the audience.&amp;#160; You can also find the &lt;a href="http://grabbagoftimg.s3.amazonaws.com/uitesting-trunk.zip"&gt;complete code and slides here&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Thanks again to the C4MVC guys for hosting me!&amp;#160; Since I didn’t have time to answer too many questions, feel free to ask them in the comments, or you can always use the Contact Me link.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;a href="http://www.dotnetkicks.com/kick/?title=C4MVC+UI+Testing+screencast+posted&amp;url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f10%2f22%2fc4mvc-ui-testing-screencast-posted.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f10%2f22%2fc4mvc-ui-testing-screencast-posted.aspx" border="0" alt="Kick It on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=27601" width="1" height="1"&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=h89Ok1SXwPc:BEv0cv5CO_I:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=h89Ok1SXwPc:BEv0cv5CO_I:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=h89Ok1SXwPc:BEv0cv5CO_I:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=h89Ok1SXwPc:BEv0cv5CO_I:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=h89Ok1SXwPc:BEv0cv5CO_I:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GrabBagOfT/~4/h89Ok1SXwPc" height="1" width="1"/&gt;</description><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">7</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/rsscomments.aspx?PostID=27601</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/commentapi.aspx?PostID=27601</wfw:comment><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/10/22/c4mvc-ui-testing-screencast-posted.aspx</feedburner:origLink></item><item><title>C4MVC meeting on UI testing</title><link>http://feedproxy.google.com/~r/GrabBagOfT/~3/f_o-pmIlQnU/c4mvc-meeting-on-ui-testing.aspx</link><category>ASP.NET MVC</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">bogardj</dc:creator><pubDate>Wed, 21 Oct 2009 06:38:41 PDT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:27314</guid><description>&lt;p&gt;Today I’m showing giving a talk on UI testing MVC applications for the &lt;a href="http://www.c4mvc.net/"&gt;Community for MVC.Net folks&lt;/a&gt;.&amp;#160; Those that went to my presentations in Arkansas and Houston have seen this talk already, so they’re off the hook on this one.&amp;#160; I’ll be covering ways to create UI tests that don’t break when a butterfly flaps its wings in Japan, and how we can design our MVC applications for UI testability.&lt;/p&gt;  &lt;p&gt;The presentation is done via LiveMeeting, (&lt;a href="http://Meeting.c4mvc.net"&gt;http://Meeting.c4mvc.net&lt;/a&gt;), so make sure you’ve hit that link before the start time, which is 12:00 PM CST today.&amp;#160; For more details, check out the C4MVC site:&lt;/p&gt;  &lt;p&gt;&lt;a title="http://www.c4mvc.net/" href="http://www.c4mvc.net/"&gt;http://www.c4mvc.net/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;In the WebForms world, it was quite difficult to create maintainable UI tests.&amp;#160; But in ASP.NET MVC, we have far more control over the HTML generated, allowing us to design our UI for testability.&amp;#160; It should be a good discussion, I’m looking forward to seeing everyone there!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;a href="http://www.dotnetkicks.com/kick/?title=C4MVC+meeting+on+UI+testing&amp;url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f10%2f21%2fc4mvc-meeting-on-ui-testing.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f10%2f21%2fc4mvc-meeting-on-ui-testing.aspx" border="0" alt="Kick It on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=27314" width="1" height="1"&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=f_o-pmIlQnU:YKjZob_mMl4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=f_o-pmIlQnU:YKjZob_mMl4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=f_o-pmIlQnU:YKjZob_mMl4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=f_o-pmIlQnU:YKjZob_mMl4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=f_o-pmIlQnU:YKjZob_mMl4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GrabBagOfT/~4/f_o-pmIlQnU" height="1" width="1"/&gt;</description><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">4</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/rsscomments.aspx?PostID=27314</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/commentapi.aspx?PostID=27314</wfw:comment><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/10/21/c4mvc-meeting-on-ui-testing.aspx</feedburner:origLink></item><item><title>How not to implement a failing test</title><link>http://feedproxy.google.com/~r/GrabBagOfT/~3/Vq_MxSbNoJc/how-not-to-implement-a-failing-test.aspx</link><category>TDD</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">bogardj</dc:creator><pubDate>Mon, 19 Oct 2009 06:45:30 PDT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:26956</guid><description>&lt;p&gt;One of the first things I change in ReSharper, along with one of my biggest pet peeves is a failing test that fails because of something like this:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;CombinedStreetAddressResolver 
    &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;NullSafeValueResolver&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Address&lt;/span&gt;, &lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;
{
    &lt;span style="color: blue"&gt;protected override string &lt;/span&gt;ResolveCore(&lt;span style="color: #2b91af"&gt;Address &lt;/span&gt;model)
    {
        &lt;span style="color: blue"&gt;throw new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;NotImplementedException&lt;/span&gt;();
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;In the Red-Green-Refactor progression, the Red of a failing test should come from an &lt;em&gt;assertion failure&lt;/em&gt; not a “my code is stupid” failure.&amp;#160; The Red part is intended to triangulate and calibrate your test, to make sure that your test can fail correctly.&amp;#160; A NotImplementedException won’t cause a meaningful failure, and only serves the purpose of getting your code to compile.&lt;/p&gt;

&lt;p&gt;Throwing exceptions means your assertions never get executed in RGR until you attempt to make a passing test, in which case you still haven’t proven your test to be correct.&amp;#160; If you don’t know that your test is correct, you have two points of failure: your test, and code under test.&lt;/p&gt;

&lt;p&gt;That’s why I’ve set ReSharper to return default values instead of throw exceptions.&amp;#160; I want meaningful failures from a valid test, otherwise I’m better off skipping the Red step altogether.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;a href="http://www.dotnetkicks.com/kick/?title=How+not+to+implement+a+failing+test&amp;url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f10%2f19%2fhow-not-to-implement-a-failing-test.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f10%2f19%2fhow-not-to-implement-a-failing-test.aspx" border="0" alt="Kick It on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=26956" width="1" height="1"&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=Vq_MxSbNoJc:zhA98OqIv7I:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=Vq_MxSbNoJc:zhA98OqIv7I:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=Vq_MxSbNoJc:zhA98OqIv7I:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=Vq_MxSbNoJc:zhA98OqIv7I:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=Vq_MxSbNoJc:zhA98OqIv7I:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GrabBagOfT/~4/Vq_MxSbNoJc" height="1" width="1"/&gt;</description><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">17</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/rsscomments.aspx?PostID=26956</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/commentapi.aspx?PostID=26956</wfw:comment><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/10/19/how-not-to-implement-a-failing-test.aspx</feedburner:origLink></item><item><title>More missing LINQ operators</title><link>http://feedproxy.google.com/~r/GrabBagOfT/~3/RQGPoK31Bus/more-missing-linq-operators.aspx</link><category>LINQ</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">bogardj</dc:creator><pubDate>Thu, 15 Oct 2009 20:19:55 PDT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:26581</guid><description>&lt;p&gt;Continuing an &lt;a href="http://www.lostechies.com/blogs/jimmy_bogard/archive/2008/06/07/some-improved-linq-operators.aspx"&gt;old post on missing LINQ operators&lt;/a&gt;, the wonders of extension methods allow us as developers to fill potential holes in LINQ operators.&amp;#160; Whether it’s a Zip method (now included in .NET 4.0), or better methods for IComparer-based operators, I find myself adding more and more helpful LINQ operators, I wish were already in the framework.&lt;/p&gt;  &lt;h3&gt;Alternate&lt;/h3&gt;  &lt;p&gt;Do you ever want to weave two collections together, like shuffling a deck of cards?&amp;#160; Well I know I do!&amp;#160; Suppose we have this collection:&lt;/p&gt;  &lt;p&gt;[1, 3, 5]&lt;/p&gt;  &lt;p&gt;And this collection:&lt;/p&gt;  &lt;p&gt;[2, 4, 6]&lt;/p&gt;  &lt;p&gt;I’d like to create new collection that is the alternating items from the first and second list:&lt;/p&gt;  &lt;p&gt;[1, 2, 3, 4, 5, 6]&lt;/p&gt;  &lt;p&gt;Here’s the code to do it:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IEnumerable&lt;/span&gt;&amp;lt;TSource&amp;gt; Alternate&amp;lt;TSource&amp;gt;(&lt;span style="color: blue"&gt;this &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IEnumerable&lt;/span&gt;&amp;lt;TSource&amp;gt; first, &lt;span style="color: #2b91af"&gt;IEnumerable&lt;/span&gt;&amp;lt;TSource&amp;gt; second)
{
    &lt;span style="color: blue"&gt;using &lt;/span&gt;(&lt;span style="color: #2b91af"&gt;IEnumerator&lt;/span&gt;&amp;lt;TSource&amp;gt; e1 = first.GetEnumerator())
    &lt;span style="color: blue"&gt;using &lt;/span&gt;(&lt;span style="color: #2b91af"&gt;IEnumerator&lt;/span&gt;&amp;lt;TSource&amp;gt; e2 = second.GetEnumerator())
        &lt;span style="color: blue"&gt;while &lt;/span&gt;(e1.MoveNext() &amp;amp;&amp;amp; e2.MoveNext())
        {
            &lt;span style="color: blue"&gt;yield return &lt;/span&gt;e1.Current;
            &lt;span style="color: blue"&gt;yield return &lt;/span&gt;e2.Current;
        }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Very simple, I iterate both enumerables at the same time, yielding the first, then second collection’s current item.&amp;#160; So how is this useful?&amp;#160; How about this action:&lt;/p&gt;

&lt;pre class="code"&gt;[&lt;span style="color: #2b91af"&gt;Test&lt;/span&gt;]
&lt;span style="color: blue"&gt;public void &lt;/span&gt;Word_play()
{
    &lt;span style="color: blue"&gt;var &lt;/span&gt;source = &lt;span style="color: blue"&gt;new&lt;/span&gt;[] {&lt;span style="color: #a31515"&gt;&amp;quot;The&amp;quot;&lt;/span&gt;, &lt;span style="color: #a31515"&gt;&amp;quot;quick&amp;quot;&lt;/span&gt;, &lt;span style="color: #a31515"&gt;&amp;quot;brown&amp;quot;&lt;/span&gt;, &lt;span style="color: #a31515"&gt;&amp;quot;fox&amp;quot;&lt;/span&gt;};

    &lt;span style="color: blue"&gt;var &lt;/span&gt;result = source.Alternate(Spaces()).Aggregate(&lt;span style="color: blue"&gt;string&lt;/span&gt;.Empty, (a, b) =&amp;gt; a + b);

    result.ShouldEqual(&lt;span style="color: #a31515"&gt;&amp;quot;The quick brown fox &amp;quot;&lt;/span&gt;);
}

&lt;span style="color: blue"&gt;private &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IEnumerable&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt; Spaces()
{
    &lt;span style="color: blue"&gt;while &lt;/span&gt;(&lt;span style="color: blue"&gt;true&lt;/span&gt;)
        &lt;span style="color: blue"&gt;yield return &lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;quot; &amp;quot;&lt;/span&gt;;
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;I cheated a little bit with an infinite sequence (the Spaces() method), but I found this method useful when I had to split, then reconstruct new sequences of strings.&lt;/p&gt;

&lt;h3&gt;Append&lt;/h3&gt;

&lt;p&gt;I really hate this syntax:&lt;/p&gt;

&lt;pre class="code"&gt;[&lt;span style="color: #2b91af"&gt;Test&lt;/span&gt;]
&lt;span style="color: blue"&gt;public void &lt;/span&gt;Bad_concat_method()
{
    &lt;span style="color: blue"&gt;var &lt;/span&gt;ints = &lt;span style="color: blue"&gt;new&lt;/span&gt;[] {1, 2, 3};

    &lt;span style="color: blue"&gt;var &lt;/span&gt;oneToFour = ints.Concat(&lt;span style="color: #2b91af"&gt;Enumerable&lt;/span&gt;.Repeat(4, 1));

    &lt;span style="color: #2b91af"&gt;CollectionAssert&lt;/span&gt;.AreEqual(&lt;span style="color: blue"&gt;new&lt;/span&gt;[] { 1, 2, 3, 4 }, oneToFour.ToArray());
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;I want to just stick an item on the end of an existing collection, but I have to use this arcane Enumerable.Repeat method to do so.&amp;#160; Instead, let’s create an operator that lets us tack an item on to the end of a collection:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IEnumerable&lt;/span&gt;&amp;lt;TSource&amp;gt; Append&amp;lt;TSource&amp;gt;(&lt;span style="color: blue"&gt;this &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IEnumerable&lt;/span&gt;&amp;lt;TSource&amp;gt; source, TSource element)
{
    &lt;span style="color: blue"&gt;using &lt;/span&gt;(&lt;span style="color: #2b91af"&gt;IEnumerator&lt;/span&gt;&amp;lt;TSource&amp;gt; e1 = source.GetEnumerator())
        &lt;span style="color: blue"&gt;while &lt;/span&gt;(e1.MoveNext())
            &lt;span style="color: blue"&gt;yield return &lt;/span&gt;e1.Current;

    &lt;span style="color: blue"&gt;yield return &lt;/span&gt;element;
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Now our code becomes much easier to understand:&lt;/p&gt;

&lt;pre class="code"&gt;[&lt;span style="color: #2b91af"&gt;Test&lt;/span&gt;]
&lt;span style="color: blue"&gt;public void &lt;/span&gt;Easier_concat_with_append()
{
    &lt;span style="color: blue"&gt;var &lt;/span&gt;ints = &lt;span style="color: blue"&gt;new&lt;/span&gt;[] {1, 2, 3};

    &lt;span style="color: blue"&gt;var &lt;/span&gt;oneToFour = ints.Append(4);

    &lt;span style="color: #2b91af"&gt;CollectionAssert&lt;/span&gt;.AreEqual(&lt;span style="color: blue"&gt;new&lt;/span&gt;[] { 1, 2, 3, 4 }, oneToFour.ToArray());
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;h3&gt;Prepend&lt;/h3&gt;

&lt;p&gt;Append wouldn’t be complete without the converse, Prepend, now would it?&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IEnumerable&lt;/span&gt;&amp;lt;TSource&amp;gt; Prepend&amp;lt;TSource&amp;gt;(&lt;span style="color: blue"&gt;this &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IEnumerable&lt;/span&gt;&amp;lt;TSource&amp;gt; source, TSource element)
{
    &lt;span style="color: blue"&gt;yield return &lt;/span&gt;element;

    &lt;span style="color: blue"&gt;using &lt;/span&gt;(&lt;span style="color: #2b91af"&gt;IEnumerator&lt;/span&gt;&amp;lt;TSource&amp;gt; e1 = source.GetEnumerator())
        &lt;span style="color: blue"&gt;while &lt;/span&gt;(e1.MoveNext())
            &lt;span style="color: blue"&gt;yield return &lt;/span&gt;e1.Current;
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Now putting something on the beginning of a list is easier as well:&lt;/p&gt;

&lt;pre class="code"&gt;[&lt;span style="color: #2b91af"&gt;Test&lt;/span&gt;]
&lt;span style="color: blue"&gt;public void &lt;/span&gt;Easier_concat_with_prepend()
{
    &lt;span style="color: blue"&gt;var &lt;/span&gt;ints = &lt;span style="color: blue"&gt;new&lt;/span&gt;[] {1, 2, 3};

    &lt;span style="color: blue"&gt;var &lt;/span&gt;zeroToThree = ints.Prepend(0);

    &lt;span style="color: #2b91af"&gt;CollectionAssert&lt;/span&gt;.AreEqual(&lt;span style="color: blue"&gt;new&lt;/span&gt;[] { 0, 1, 2, 3 }, zeroToThree.ToArray());
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Much more readable.&amp;#160; I have a few more around replacing the IEqualityComparer&amp;lt;T&amp;gt; overloads, but those are a little bit more esoteric in their examples of crazy set-based logic.&amp;#160; What’s really cool about all these methods is they still allow all sorts of fun chaining, allowing me to create very terse chains of operations on lists, with what would have taken a bazillion cryptic for..each loops.&amp;#160; Cool stuff!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;a href="http://www.dotnetkicks.com/kick/?title=More+missing+LINQ+operators&amp;url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f10%2f15%2fmore-missing-linq-operators.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f10%2f15%2fmore-missing-linq-operators.aspx" border="0" alt="Kick It on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=26581" width="1" height="1"&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=RQGPoK31Bus:3SJDeaTCgoQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=RQGPoK31Bus:3SJDeaTCgoQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=RQGPoK31Bus:3SJDeaTCgoQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=RQGPoK31Bus:3SJDeaTCgoQ:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=RQGPoK31Bus:3SJDeaTCgoQ:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GrabBagOfT/~4/RQGPoK31Bus" height="1" width="1"/&gt;</description><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">17</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/rsscomments.aspx?PostID=26581</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/commentapi.aspx?PostID=26581</wfw:comment><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/10/15/more-missing-linq-operators.aspx</feedburner:origLink></item><item><title>Thanks Arkansas!</title><link>http://feedproxy.google.com/~r/GrabBagOfT/~3/SDBzOyNeSuc/thanks-arkansas.aspx</link><category>Misc</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">bogardj</dc:creator><pubDate>Thu, 15 Oct 2009 19:01:17 PDT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:26576</guid><description>&lt;p&gt;This week I made the drive from Austin to Fort Smith and Springdale, Arkansas to speak at the &lt;a href="http://www.fsdnug.org/"&gt;Fort Smith DNUG&lt;/a&gt; and the &lt;a href="http://www.nwadnug.org/"&gt;Northwest Arkansas DNUG&lt;/a&gt; on UI testing ASP.NET MVC.&amp;#160; Although I showed tools such as WatiN and Gallio, I focused more on design for UI testability, and covered items such as:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Site navigation&lt;/li&gt;    &lt;li&gt;Filling out forms&lt;/li&gt;    &lt;li&gt;Verifying results&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;We stepped through a working, but horribly fragile UI test, and walked through how we can put in a few design techniques to share knowledge between view design and the UI test.&amp;#160; Hopefully, my message of “ban test recorders” gets through to someone, as the UI test recorder is something that threw me off for years on creating maintainable UI tests.&lt;/p&gt;  &lt;p&gt;You can find the slides and code here:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://grabbagoftimg.s3.amazonaws.com/uitesting-trunk.zip"&gt;Testing the last mile in ASP.NET MVC&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Thanks to all the guys in Arkansas for the great conversations, and I hope to see everyone soon!&amp;#160; One parting shot from a trip to &lt;a href="http://www.arkansasstateparks.com/devilsden/"&gt;Devil’s Den&lt;/a&gt;:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/jimmy_5F00_bogard/DSC00219_5F00_0B8F93E7.jpg"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="DSC00219" border="0" alt="DSC00219" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/jimmy_5F00_bogard/DSC00219_5F00_thumb_5F00_259379D6.jpg" width="644" height="484" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;My jeans were soaked up to my knees from that hike…&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;a href="http://www.dotnetkicks.com/kick/?title=Thanks+Arkansas!&amp;url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f10%2f15%2fthanks-arkansas.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f10%2f15%2fthanks-arkansas.aspx" border="0" alt="Kick It on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=26576" width="1" height="1"&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=SDBzOyNeSuc:rIllGfk1tLU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=SDBzOyNeSuc:rIllGfk1tLU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=SDBzOyNeSuc:rIllGfk1tLU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=SDBzOyNeSuc:rIllGfk1tLU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=SDBzOyNeSuc:rIllGfk1tLU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GrabBagOfT/~4/SDBzOyNeSuc" height="1" width="1"/&gt;</description><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">4</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/rsscomments.aspx?PostID=26576</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/commentapi.aspx?PostID=26576</wfw:comment><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/10/15/thanks-arkansas.aspx</feedburner:origLink></item><item><title>An AutoMapper success story</title><link>http://feedproxy.google.com/~r/GrabBagOfT/~3/ezrb2SlOQsY/an-automapper-success-story.aspx</link><category>AutoMapper</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">bogardj</dc:creator><pubDate>Thu, 08 Oct 2009 09:38:32 PDT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:26027</guid><description>&lt;p&gt;I got a cool message on the &lt;a href="http://groups.google.com/group/automapper-users"&gt;AutoMapper mailing list&lt;/a&gt; from &lt;a href="http://consultingblogs.emc.com/howardvanrooijen/"&gt;Howard Van Rooijen&lt;/a&gt; on how they used &lt;a href="http://automapper.codeplex.com/"&gt;AutoMapper&lt;/a&gt; in a site they recently launched to production:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Hello AutoMapper Community,&lt;/p&gt;    &lt;p&gt;I just wanted to let you know that an e-commerce site which uses AutoMapper as part of it's core architecture has just been released into the wild: &lt;/p&gt;    &lt;p&gt;&lt;a href="http://www.fancydressoutfitters.co.uk/"&gt;http://www.&lt;/a&gt;&lt;a href="http://www.fancydressoutfitters.co.uk/"&gt;fancydressout&lt;/a&gt;&lt;a href="http://www.fancydressoutfitters.co.uk/"&gt;fitters.co.uk&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;And I wanted to say a HUGE thank-you to Jimmy &amp;amp; the Community for this wonderful tool - that helps remove so much commodity plumbing code from the solution. &lt;/p&gt;    &lt;p&gt;We were a little sceptical at the start of the project that AutoMapper would &amp;quot;cut the mustard&amp;quot; when it came to the performance requirements of a public facing, high load, e-commerce site because of the amount of reflection AutoMapper uses at its core, but we have been incredibly impressed with the performance of the solution under load.&lt;/p&gt;    &lt;p&gt;The site is based on the S#arp Architecture Framework and its become very apparent how well AutoMapper fits into MVC style architecture as it enables easy separation of concerns with regards to object conversion (entities &amp;amp; ViewModels). Once we moved from hand-cranked converters to AutoMapper it was amazing how much cleaner our code became - so much so that we modified the overall solution architecture to incorporate explicit mapping layers (see attached image). Our general pattern of usage within MVC is as follows:&lt;/p&gt;    &lt;p&gt;1. Map input into Domain Entities in the Controller&lt;/p&gt;    &lt;p&gt;2. Pass Domain Entities into Task Layer to &amp;quot;do stuff&amp;quot;&lt;/p&gt;    &lt;p&gt;3. Map output of Task Layer (Domain Entities) into ViewModel&lt;/p&gt;    &lt;p&gt;4. Pass ViewModel to ViewEngine&lt;/p&gt;    &lt;p&gt;Simple, slick and clean.&lt;/p&gt;    &lt;p&gt;To formalise the Mapping Layer and make it testable we implemented a simple interface:&lt;/p&gt;    &lt;p&gt;public interface IMapper&amp;lt;TInput, TOutput&amp;gt;&lt;/p&gt;    &lt;p&gt;{&lt;/p&gt;    &lt;p&gt;TOutput MapFrom(TInput input);&lt;/p&gt;    &lt;p&gt;}&lt;/p&gt;    &lt;p&gt;Next we'd implement a custom marker interface so that we could resolve the mapper from the DI container and we adopted the naming convention &amp;lt;Input Type&amp;gt;&amp;lt;Output Type&amp;gt;Mapper:&lt;/p&gt;    &lt;p&gt;public interface IEditModelEntityMapper : IMapper&amp;lt;EditModel, Entity&amp;gt;&lt;/p&gt;    &lt;p&gt;{&lt;/p&gt;    &lt;p&gt;}&lt;/p&gt;    &lt;p&gt;Then finally implement the interface:&lt;/p&gt;    &lt;p&gt;public class EditModelEntityMapper : IEditModelEntityMapper &lt;/p&gt;    &lt;p&gt;{&lt;/p&gt;    &lt;p&gt;public EditModelEntityMapper()&lt;/p&gt;    &lt;p&gt;{&lt;/p&gt;    &lt;p&gt;Mapper.CreateMap&amp;lt;EditModel, Entity&amp;gt;()&lt;/p&gt;    &lt;p&gt;.ForMember(x =&amp;gt; x.Property, y =&amp;gt; y.MapFrom(z =&amp;gt; z.Property));&lt;/p&gt;    &lt;p&gt;}&lt;/p&gt;    &lt;p&gt;public Entity MapFrom(EditModel input)&lt;/p&gt;    &lt;p&gt;{&lt;/p&gt;    &lt;p&gt;return Mapper.Map&amp;lt;EditModel, Entity&amp;gt;(input);&lt;/p&gt;    &lt;p&gt;}&lt;/p&gt;    &lt;p&gt;}&lt;/p&gt;    &lt;p&gt;Then to actually use it in the MVC app:&lt;/p&gt;    &lt;p&gt;public class CustomController : Controller&lt;/p&gt;    &lt;p&gt;{&lt;/p&gt;    &lt;p&gt;private readonly ITasks tasks;&lt;/p&gt;    &lt;p&gt;private readonly IEditModelEntityMapper editModelEntityMapper;&lt;/p&gt;    &lt;p&gt;private readonly IOutputViewModelMapper outputViewModelMapper;&lt;/p&gt;    &lt;p&gt;public CustomController(ITasks tasks, &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IEditModelEntityMapper editModelEntityMapper,&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; IOutputViewModelMapper outputViewModelMapper)&lt;/p&gt;    &lt;p&gt;{&lt;/p&gt;    &lt;p&gt;this.tasks = tasks;&lt;/p&gt;    &lt;p&gt;this.editModelEntityMapper = editModelEntityMapper;&lt;/p&gt;    &lt;p&gt;this.outputViewModelMapper = outputViewModelMapper;&lt;/p&gt;    &lt;p&gt;}&lt;/p&gt;    &lt;p&gt;public ActionResult Index(EditEntity input)&lt;/p&gt;    &lt;p&gt;{&lt;/p&gt;    &lt;p&gt;var entity = this.editModelEntityMapper.MapFrom(input);&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; var output = this.tasks.DoSomething(entity)&lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; var viewModel = this.outputViewModelMapper.MapFrom(output);&lt;/p&gt;    &lt;p&gt;return View(viewModel);&lt;/p&gt;    &lt;p&gt;}&lt;/p&gt;    &lt;p&gt;}&lt;/p&gt;    &lt;p&gt;For those who are interested - here's a little more info:&lt;/p&gt;    &lt;p&gt;- We ran the project using Scrum and delivered in 20 weeks: 10 x 2 week iterations&lt;/p&gt;    &lt;p&gt;- It's based on the &lt;a href="http://www.sharparchitecture.net/"&gt;S#arp Architecture&lt;/a&gt; framework, which we extended to support, AutoMapper, Spark and ViewModels      &lt;br /&gt;- Solution performs very well: 1000 concurrent users per web server, generating around 180 pages per second across 2x single quad core 64bit servers.&lt;/p&gt;    &lt;p&gt;Again, many thanks,&lt;/p&gt;    &lt;p&gt;Howard&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Howard also shared a neat little diagram of his architecture:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/jimmy_5F00_bogard/image_5F00_18A008AF.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/jimmy_5F00_bogard/image_5F00_thumb_5F00_312FA5FF.png" width="478" height="484" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;This is one of the greatest feelings from doing OSS – that something you created basically just for yourself can also help out other folks out there trying to deliver value for their customers.&amp;#160; Thanks for all the feedback everyone, as well as kudos to the S#arp Architecture team for building such a great framework for MVC.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;a href="http://www.dotnetkicks.com/kick/?title=An+AutoMapper+success+story&amp;url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f10%2f08%2fan-automapper-success-story.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f10%2f08%2fan-automapper-success-story.aspx" border="0" alt="Kick It on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=26027" width="1" height="1"&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=ezrb2SlOQsY:AL1d2cmq9ls:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=ezrb2SlOQsY:AL1d2cmq9ls:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=ezrb2SlOQsY:AL1d2cmq9ls:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=ezrb2SlOQsY:AL1d2cmq9ls:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=ezrb2SlOQsY:AL1d2cmq9ls:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GrabBagOfT/~4/ezrb2SlOQsY" height="1" width="1"/&gt;</description><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">9</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/rsscomments.aspx?PostID=26027</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/commentapi.aspx?PostID=26027</wfw:comment><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/10/08/an-automapper-success-story.aspx</feedburner:origLink></item><item><title>Bugs, defects and feedback</title><link>http://feedproxy.google.com/~r/GrabBagOfT/~3/LHOD1n0a_ao/bugs-defects-and-feedback.aspx</link><category>Agile</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">bogardj</dc:creator><pubDate>Wed, 30 Sep 2009 10:58:35 PDT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:25679</guid><description>&lt;p&gt;In &lt;a href="http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/09/29/my-favorite-bug-tracking-system.aspx"&gt;my last post&lt;/a&gt;, I talked about how we like to track bugs, with just pieces of paper.&amp;#160; At lot of the responses were interesting, but I think some came back to the issue of “what is a bug?”&amp;#160; Some felt that bugs needed to live in a more durable system (as if paper isn’t durable, and previous to around 1985 no one knew how to manage information).&amp;#160; But for us, bugs don’t live more than 1 business day, so there’s no need to keep them around, unless we want to do trend analysis.&lt;/p&gt;  &lt;p&gt;But one important issue is how we deal with feedback.&amp;#160; A user can come up to us and say, “the site is broken”.&amp;#160; That could mean a lot of things.&amp;#160; It could mean the site is blowing up, or it could mean that they couldn’t find the “Submit Order” button.&amp;#160; To the user, the site is broken.&lt;/p&gt;  &lt;p&gt;Instead of referring to negative user feedback as “bugs”, we treat them as “issues”.&amp;#160; So what is an “issue”?&amp;#160; &lt;strong&gt;An issue is negative user feedback with potentially actionable fix.&lt;/strong&gt;&amp;#160;&amp;#160; Note “potentially”.&lt;/p&gt;  &lt;h3&gt;The feedback process&lt;/h3&gt;  &lt;p&gt;When we get an issue from a user, the issue goes into triage with the Product Owner.&amp;#160; The Product Owner is the person/team deciding what gets developed, so it’s logical that they decide what action to take with an issue.&amp;#160; An issue falls into two broad categories:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Bug&lt;/li&gt;    &lt;li&gt;Defect&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;strong&gt;A bug is an issue where the site is unusable or acceptance criteria has not been met&lt;/strong&gt;.&amp;#160; This includes things from “the site is down” to “you misspelled a word”.&amp;#160; All of our stories have tangible and intangible acceptance criteria, functional and non-functional requirements.&amp;#160; The expectations of these have been laid forth a long time ago, so we don’t really negotiate too much on what is or is not a bug.&amp;#160; The user may have a different idea of the classification of bug, but they don’t get to decide.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;A defect is an issue where the site is usable and acceptance criteria have been met, but the application does not work as expected&lt;/strong&gt;.&amp;#160; Things in this category are “data field should be over here”, “add this label”, “this business rule isn’t quite right” and so on.&amp;#160; We don’t expect the users to know all of the stories we’ve developed, but there are still situations where the site isn’t working like it should, but works as agreed.&amp;#160; We work hard to do good JIT analysis, but we still miss things.&lt;/p&gt;  &lt;h3&gt;Actions on bugs&lt;/h3&gt;  &lt;p&gt;Bugs are fixed immediately, with an SLA of one business day.&amp;#160; We do things like branch and release-per-feature, automated builds and deployments, so we’re never more than about 15 minutes away from a commit to production fix.&amp;#160; We refuse to keep an inventory of open bugs, so bugs are fixed as they arrive, and the team will stop their work to fix a bug.&amp;#160; Because we stop-the-line, we strive to eliminate as many bugs as we can.&amp;#160; This includes good design, a strong testing culture, and post-mortems on bugs to see how we can improve the next time around and eliminate the possibility of a bug like that to arise again.&lt;/p&gt;  &lt;h3&gt;Actions on defects&lt;/h3&gt;  &lt;p&gt;Defects need to be analyzed just as much as regular stories need to, so defects enter a second queue where they either turn into stories, or something we call “tweak stories”.&amp;#160; Stories take 1-5 business days to deliver, while a “tweak story” gets turned around as quickly as a bug.&amp;#160; It all comes down to the complexity of the defect.&amp;#160; In any case, the Product Owner prioritizes these defects along with stories, and ultimately it’s the PO that decides when (or if) the team takes action on a defect.&lt;/p&gt;  &lt;h3&gt;The feedback cycle&lt;/h3&gt;  &lt;p&gt;For critical bugs, like “the site blows up”, there is no need to triage.&amp;#160; It’s unacceptable that the site blows up, so we’ll fix those immediately.&amp;#160; But for more subtle feedback, the developer team is ill-equipped to make a determination on the nature of an issue.&amp;#160; Often, the development team attempts to fix every issue that comes their way, whether it’s a bug or not, in an effort to make the user happy.&amp;#160; But the guy that says “the customer is always right”?&amp;#160; He goes broke.&amp;#160; The customer &lt;em&gt;isn’t&lt;/em&gt; always right, so it’s the PO’s responsibility for determining the classification of the issue.&lt;/p&gt;  &lt;p&gt;Ultimately, it’s about roles and responsibilities.&amp;#160; Developer teams are usually quite poor at determining the priority of work, as they don’t always have the deep business/project understanding of scope, deadlines, priorities and so on.&amp;#160; Instead, we place the responsibility of triage and prioritization where it belongs, with the Product Owner.&lt;/p&gt;  &lt;p&gt;With this system in place, we have no need to keep what we call “bugs” around in a durable format.&amp;#160; Once artifacts become durable, people hesitate to delete them, and now they need to become managed.&amp;#160; At one point, I kept bugs.&amp;#160; But I found I never looked at them, as our practice of post-mortems on bugs as they are fixed was perfectly adequate.&amp;#160; Instead, I (or nowadays, the originator) just toss them when they’re done, and it feels quite liberating.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;a href="http://www.dotnetkicks.com/kick/?title=Bugs%2c+defects+and+feedback&amp;url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f09%2f30%2fbugs-defects-and-feedback.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f09%2f30%2fbugs-defects-and-feedback.aspx" border="0" alt="Kick It on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=25679" width="1" height="1"&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=LHOD1n0a_ao:nLBVo2UMis0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=LHOD1n0a_ao:nLBVo2UMis0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=LHOD1n0a_ao:nLBVo2UMis0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=LHOD1n0a_ao:nLBVo2UMis0:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=LHOD1n0a_ao:nLBVo2UMis0:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GrabBagOfT/~4/LHOD1n0a_ao" height="1" width="1"/&gt;</description><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/rsscomments.aspx?PostID=25679</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/commentapi.aspx?PostID=25679</wfw:comment><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/09/30/bugs-defects-and-feedback.aspx</feedburner:origLink></item><item><title>My favorite bug-tracking system</title><link>http://feedproxy.google.com/~r/GrabBagOfT/~3/ir5_vTM7VIM/my-favorite-bug-tracking-system.aspx</link><category>Agile</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">bogardj</dc:creator><pubDate>Tue, 29 Sep 2009 10:57:03 PDT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:25628</guid><description>&lt;p&gt;I’m of the opinion that a process must demonstrate the need for software, before software is put in place to manage that process.&amp;#160; Bug tracking is a process, but often we jump straight to a software solution for managing/tracking bugs before considering lower-tech, lower-risk and lower-overhead approaches.&amp;#160; In our bug-tracking process, we employ a few main principles:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Bugs are a normal part of the development process&lt;/li&gt;    &lt;li&gt;Most bugs are rework, therefore waste, and we should strive to eliminate this waste&lt;/li&gt;    &lt;li&gt;Bugs are fixed as they are found (&lt;a href="http://www.informit.com/articles/article.aspx?p=664147&amp;amp;seqNum=5"&gt;stop-the-line&lt;/a&gt;), and do not live for more than 1 business day&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Given that bugs do not live for more than one business day, it is not necessary for us to maintain an inventory of bugs.&amp;#160; Instead, we want a system than can accurately report a bug, and make it easy for it to be verified.&lt;/p&gt;  &lt;p&gt;With these constraints in mind, my favorite bug tracking system is a &lt;a href="http://www.officemax.com/office-supplies/post-it-notes-flags/post-it-super-sticky-notes/product-ARS23443"&gt;5x8” orange sticky note&lt;/a&gt;:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/jimmy_5F00_bogard/23443p_5F00_011_5F00_1C3BC831.jpg"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="23443p_01[1]" border="0" alt="23443p_01[1]" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/jimmy_5F00_bogard/23443p_5F00_011_5F00_thumb_5F00_1FD9E30E.jpg" width="401" height="357" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;On this giant sticky note, the person that finds the bug writes:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Their initials&lt;/li&gt;    &lt;li&gt;The name of the story&lt;/li&gt;    &lt;li&gt;A short description&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;If there is a screenshot, this will be stapled to the back.&amp;#160; When the developer is done with the bug, they write:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Their initials&lt;/li&gt;    &lt;li&gt;The revision # of the commit that fixed the bug&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The revision number is used to make sure that the currently deployed version is up-to-date enough to check the fix.&amp;#160; So how does this bug tracking system work?&amp;#160; Here is our process:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Person finds bug.&amp;#160; Person could be anyone, developer, BA, product owner.&lt;/li&gt;    &lt;li&gt;Finder creates orange card for bug, following the specified template (every piece of information goes in a certain spot on the giant post-it)&lt;/li&gt;    &lt;li&gt;If the bug is a blow-up, or blocks the delivery of a story, it is placed on the desk of the tech lead (me)&lt;/li&gt;    &lt;li&gt;If the bug is not specifically called out in acceptance criteria, it is placed on the desk of the BA lead.&lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;These bugs go through triage, because sometimes things “work as designed” but not “work as expected”.&amp;#160; Those in the latter category need to go through the normal story process.&lt;/li&gt;   &lt;/ul&gt;    &lt;li&gt;The tech lead assigns the bug to a developer (or themselves), by placing the bug on the assigned developer’s desk&lt;/li&gt;    &lt;li&gt;When the fix is done, the developer writes their initials and the revision number, and gives the orange card back to the originator, with a smile&lt;/li&gt;    &lt;li&gt;The originator of the bug verifies the fix, and places the orange card in the trash with a “thumbs up” to let the developer know the bug is verified fixed.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;This is about as lightweight as we can get it, without chaos.&amp;#160; This process has evolved over time, but we’ve always fit our tools (post-its) to our process, instead of fitting our process to a tool.&amp;#160; We’re all in the same room, so there is absolutely zero need to track bugs electronically.&amp;#160; Tracking them electronically would create waste, as we would now have inventory to manage in some other system.&amp;#160; It really can’t get much easier than a bright piece of paper on my desk.&lt;/p&gt;  &lt;h3&gt;Fit the tool to the process&lt;/h3&gt;  &lt;p&gt;This process evolved given the attributes of the constraints of our system.&amp;#160; We all sit in the same room.&amp;#160; We strive for face-to-face, verbal communication over all other forms.&amp;#160; We don’t want to add overhead by tracking information that no one cares about.&amp;#160; When someone suggests to use a software bug tracker, it needs to come from a need to have that information in that format, not because geeks like software.&lt;/p&gt;  &lt;p&gt;But what if we had different constraints?&amp;#160; What if we weren’t all in the same room?&amp;#160; Fine, software it is!&amp;#160; Until then, I’ll choose the absolute lowest overhead solution.&lt;/p&gt;  &lt;p&gt;But how does it scale?&amp;#160; Well, if you keep an inventory of bugs for more than a day, not too well.&amp;#160; If bugs are fixed when they happen, it’s just not possible to have more than a dozen bugs out at a time.&amp;#160; Scaling needs a vector, you have to understand in which direction it can scale.&amp;#160; It scales with the size of the team, but not with geography or volume.&amp;#160; That’s fine, we keep those two small and constant.&amp;#160; Those choices were intentional, as separated teams and higher volume through poor quality or turnaround decreases delivery throughput.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;a href="http://www.dotnetkicks.com/kick/?title=My+favorite+bug-tracking+system&amp;url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f09%2f29%2fmy-favorite-bug-tracking-system.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f09%2f29%2fmy-favorite-bug-tracking-system.aspx" border="0" alt="Kick It on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=25628" width="1" height="1"&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=ir5_vTM7VIM:LacGxu2uDhk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=ir5_vTM7VIM:LacGxu2uDhk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=ir5_vTM7VIM:LacGxu2uDhk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=ir5_vTM7VIM:LacGxu2uDhk:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=ir5_vTM7VIM:LacGxu2uDhk:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GrabBagOfT/~4/ir5_vTM7VIM" height="1" width="1"/&gt;</description><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">19</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/rsscomments.aspx?PostID=25628</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/commentapi.aspx?PostID=25628</wfw:comment><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/09/29/my-favorite-bug-tracking-system.aspx</feedburner:origLink></item><item><title>Thanks Houston TechFest!</title><link>http://feedproxy.google.com/~r/GrabBagOfT/~3/UrhJgM5djrQ/thanks-houston-techfest.aspx</link><category>ASP.NET MVC</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">bogardj</dc:creator><pubDate>Mon, 28 Sep 2009 05:41:01 PDT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:25606</guid><description>&lt;p&gt;This past weekend I gave a talk on one of my favorite topics – UI testing.&amp;#160; In it, I focused almost exclusively on techniques for authoring maintainable UI tests, and how design for testability extends to views, models and controllers in MVC land.&amp;#160; It’s trivial to write UI tests that break easily, but not much more difficult to write maintainable tests, given that you’ve intentionally designed your UI layer for UI testability.&lt;/p&gt;  &lt;p&gt;Big thanks to the Houston TechFest organizers, who put on a fantastic conference, and to all the attendees, who had to put up with me for an hour.&amp;#160; For those that are interested, you can find the code and slides here:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://grabbagoftimg.s3.amazonaws.com/uitesting-trunk.zip"&gt;Testing the Last Mile in ASP.NET MVC code and slides&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;I had a lot of people asking about the wrappers on top of our browser automation tool, WatiN, and if they were open source.&amp;#160; The answer is no, not yet, but we’re working on it.&amp;#160; A quick road to fragile UI tests is browser automation code directly in your UI tests, so the sample code provided should at least provide some ideas and guidance to craft your own wrappers.&amp;#160; And as always, my door is always open for questions.&amp;#160; My email door, at least.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;a href="http://www.dotnetkicks.com/kick/?title=Thanks+Houston+TechFest!&amp;url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f09%2f28%2fthanks-houston-techfest.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f09%2f28%2fthanks-houston-techfest.aspx" border="0" alt="Kick It on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=25606" width="1" height="1"&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=UrhJgM5djrQ:DTHJv-TTGZA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=UrhJgM5djrQ:DTHJv-TTGZA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=UrhJgM5djrQ:DTHJv-TTGZA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=UrhJgM5djrQ:DTHJv-TTGZA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=UrhJgM5djrQ:DTHJv-TTGZA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GrabBagOfT/~4/UrhJgM5djrQ" height="1" width="1"/&gt;</description><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">6</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/rsscomments.aspx?PostID=25606</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/commentapi.aspx?PostID=25606</wfw:comment><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/09/28/thanks-houston-techfest.aspx</feedburner:origLink></item><item><title>The case for two-way mapping in AutoMapper</title><link>http://feedproxy.google.com/~r/GrabBagOfT/~3/WMsv7ANqLrg/the-case-for-two-way-mapping-in-automapper.aspx</link><category>AutoMapper</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">bogardj</dc:creator><pubDate>Thu, 17 Sep 2009 18:33:17 PDT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:24932</guid><description>&lt;p&gt;I’m getting more and more requests around the area of two-way mapping, meaning you’d do something like:&lt;/p&gt;  &lt;p&gt;Product –&amp;gt; ProductDTO&lt;/p&gt;  &lt;p&gt;ProductDTO –&amp;gt; Product&lt;/p&gt;  &lt;p&gt;Product being an entity, I can’t for the life of me understand why I’d want to dump a DTO straight back in to a model object.&amp;#160; To get some understanding of how we use AutoMapper, we have:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;1500 individual mapping definitions&lt;/li&gt;    &lt;li&gt;75 custom value resolvers&lt;/li&gt;    &lt;li&gt;38 custom value formatters&lt;/li&gt;    &lt;li&gt;5 individual profiles&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;So what are we using AutoMapper for?&amp;#160; Our five profiles include:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;From Domain to ViewModel (strongly-typed view models for MVC)&lt;/li&gt;    &lt;li&gt;From Domain to EditModel (strongly-typed view models for forms in MVC)&lt;/li&gt;    &lt;li&gt;From EditModel to CommandMessages – going from the loosely-typed EditModel to strongly-typed, broken out messages.&amp;#160; A single EditModel might generate a half-dozen messages.&lt;/li&gt;    &lt;li&gt;From Domain to ReportModel – strongly-typed Telerik reports&lt;/li&gt;    &lt;li&gt;From Domain to EDI Model – flattened models used to generate EDI reports&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;There is no two-way mapping because we never need two-way mapping.&amp;#160; There was a point very early on where we were at a critical junction, and could decide to do two-way mapping.&amp;#160; &lt;strong&gt;But we didn’t&lt;/strong&gt;.&amp;#160; Why?&amp;#160; Because then our mapping layer would influence our domain model.&amp;#160; I strongly believe in POCOs, and a very writeable domain model meant that POCOs were out.&amp;#160; What exactly would two-way mapping do to our domain layer?&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Force mutable, public collection , like “public EntitySet&amp;lt;Category&amp;gt; Categories { get; }” &amp;lt;- NO.&lt;/li&gt;    &lt;li&gt;Make testing much, much harder, as we only ever wanted to update a portion of a domain model&lt;/li&gt;    &lt;li&gt;Force our domain model to be mutable everywhere&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;So my question to those wanting two-way mapping:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;What scenarios are you looking at doing two-way mapping?&lt;/li&gt;    &lt;li&gt;What impact would two-way mapping have on the originating source type?&lt;/li&gt;    &lt;li&gt;How would you test two-way mappings?&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;I think using AutoMapper because you don’t want to use the “=” operator is a bit lazy.&amp;#160; Instead, we use it to flatten and reshape, optimizing for the destination type’s environment.&amp;#160; Remember, my original motivation for AutoMapper was:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Enable protecting the domain layer from other layers by mapping to DTOs&lt;/li&gt;    &lt;li&gt;Enable easy testing of the mappings, which would otherwise prevent us from creating the mapping in the first place&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;So…why two-way mapping?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;a href="http://www.dotnetkicks.com/kick/?title=The+case+for+two-way+mapping+in+AutoMapper&amp;url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f09%2f17%2fthe-case-for-two-way-mapping-in-automapper.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f09%2f17%2fthe-case-for-two-way-mapping-in-automapper.aspx" border="0" alt="Kick It on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=24932" width="1" height="1"&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=WMsv7ANqLrg:XyVF2ctg_PU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=WMsv7ANqLrg:XyVF2ctg_PU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=WMsv7ANqLrg:XyVF2ctg_PU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=WMsv7ANqLrg:XyVF2ctg_PU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=WMsv7ANqLrg:XyVF2ctg_PU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GrabBagOfT/~4/WMsv7ANqLrg" height="1" width="1"/&gt;</description><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">14</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/rsscomments.aspx?PostID=24932</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/commentapi.aspx?PostID=24932</wfw:comment><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/09/17/the-case-for-two-way-mapping-in-automapper.aspx</feedburner:origLink></item><item><title>AutoMapper 1.0 RC1 released</title><link>http://feedproxy.google.com/~r/GrabBagOfT/~3/AFyvZ_lm0OM/automapper-1-0-rc1-released.aspx</link><category>AutoMapper</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">bogardj</dc:creator><pubDate>Mon, 14 Sep 2009 17:34:23 PDT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:24839</guid><description>&lt;p&gt;It’s been quite a long journey with &lt;a href="http://automapper.codeplex.com/"&gt;AutoMapper&lt;/a&gt;, with the origins written just over a year ago now.&amp;#160; I’ve focused on stability and performance since the 0.3.1 release back in May, and from here to the 1.0 release, I’ll just be doing bug fixes.&amp;#160; I did work in quite a few new enhancements, but I’m waiting on bigger changes until after the 1.0 release.&amp;#160; From the &lt;a href="http://automapper.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=32994"&gt;CodePlex download site&lt;/a&gt;:&lt;/p&gt;  &lt;h3&gt;New Features&lt;/h3&gt;  &lt;ul&gt;   &lt;li&gt;Added non-generic CreateMap overload &lt;/li&gt;    &lt;li&gt;Can specify custom mapping ordering for individual destination members &lt;/li&gt;    &lt;li&gt;Before/After map callbacks for custom pre/post processing &lt;/li&gt;    &lt;li&gt;Registration of custom pre- and postfixes on member type names (i.e. CustomerKey can map to Customer) &lt;/li&gt;    &lt;li&gt;Mapping from dictionaries to split out key-value pairs &lt;/li&gt;    &lt;li&gt;Basic support for IDataReader/IDataRecord &lt;/li&gt;    &lt;li&gt;Support for custom naming conventions &lt;/li&gt;    &lt;li&gt;Support for IListSource (for Entity Framework)&lt;/li&gt; &lt;/ul&gt;  &lt;h3&gt;Enhancements&lt;/h3&gt;  &lt;ul&gt;   &lt;li&gt;AllowNullDestinationValues now defaults to &amp;quot;true&amp;quot; &lt;/li&gt;    &lt;li&gt;Mapping operations thread-safe &lt;/li&gt;    &lt;li&gt;Performance improvements for mapping pipeline, including late-bound expression trees and Lightweight Code Generation &lt;/li&gt;    &lt;li&gt;Allowing using the destination value for individual members &lt;/li&gt;    &lt;li&gt;Lots of internal refactoring around the mapping engine to support various IoC scenarios &lt;/li&gt;    &lt;li&gt;Assembly marked as CLS compliant &lt;/li&gt;    &lt;li&gt;Registering global and profile-specific aliases for names &lt;/li&gt;    &lt;li&gt;Support for custom destination type constructors &lt;/li&gt;    &lt;li&gt;Upgraded to latest LinFu release&lt;/li&gt; &lt;/ul&gt;  &lt;h3&gt;Bug Fixes&lt;/h3&gt;  &lt;ul&gt;   &lt;li&gt;Validation errors on explicitly implemented interfaces &lt;/li&gt;    &lt;li&gt;Collections with null elements caused exceptions &lt;/li&gt;    &lt;li&gt;Readonly destination members were causing validation errors &lt;/li&gt;    &lt;li&gt;Removed null checking in custom value resolvers&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Enjoy!!!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;a href="http://www.dotnetkicks.com/kick/?title=AutoMapper+1.0+RC1+released&amp;url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f09%2f14%2fautomapper-1-0-rc1-released.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f09%2f14%2fautomapper-1-0-rc1-released.aspx" border="0" alt="Kick It on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=24839" width="1" height="1"&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=AFyvZ_lm0OM:_HvEcGXZN-A:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=AFyvZ_lm0OM:_HvEcGXZN-A:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=AFyvZ_lm0OM:_HvEcGXZN-A:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=AFyvZ_lm0OM:_HvEcGXZN-A:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=AFyvZ_lm0OM:_HvEcGXZN-A:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GrabBagOfT/~4/AFyvZ_lm0OM" height="1" width="1"/&gt;</description><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">11</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/rsscomments.aspx?PostID=24839</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/commentapi.aspx?PostID=24839</wfw:comment><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/09/14/automapper-1-0-rc1-released.aspx</feedburner:origLink></item><item><title>Wither the Repository</title><link>http://feedproxy.google.com/~r/GrabBagOfT/~3/_hpdAdA0jlM/wither-the-repository.aspx</link><category>Domain-Driven Design</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">bogardj</dc:creator><pubDate>Thu, 10 Sep 2009 19:05:00 PDT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:24711</guid><description>&lt;p&gt;Looking at the different Repository pattern implementations, one thing really surprised me – how far off these implementations are from the original Fowler definition of the Repository.&amp;#160; Instead, we see a transformation to the examples in the Evans description of Repository.&amp;#160; Fowler’s definition for a Repository is:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;i&gt;Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.&lt;/i&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;But in our original Repository pattern implementations, we see far more than Querying, but persistence as well (Create, Update and Delete).&amp;#160; This is consistent with some of the descriptions in Evans book, where the collection-like interface also allows for modifications – adding and removing – thus completing the lifecycle of a domain object.&lt;/p&gt;  &lt;p&gt;But is this Repository pattern needed?&amp;#160; What exactly is the Repository buying us?&amp;#160; In normal usage, I see the Repository pattern doing two main tasks:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Encapsulate the data mapping layer &lt;/li&gt;    &lt;li&gt;Encapsulating difficult queries (in the Named Query Method approach) &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;In some systems, including the one I’m working on right now, each entity corresponds 1 to 1 with a repository implementation – whether or not the repository implementation is doing anything.&amp;#160; Looking back at the Fowler PoEAA book, there is another interesting pattern at play – the &lt;a href="http://martinfowler.com/eaaCatalog/unitOfWork.html"&gt;Unit of Work pattern&lt;/a&gt;.&amp;#160; The Unit of Work:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;i&gt;Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems.&lt;/i&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;A common Unit of Work implementation wraps the underlying data access layer, and provides means of creating transactional boundaries:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public interface &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IUnitOfWork &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;IDisposable
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;void &lt;/span&gt;Initialize();
    &lt;span style="color: blue"&gt;void &lt;/span&gt;Commit();
    &lt;span style="color: blue"&gt;void &lt;/span&gt;Rollback();
}

&lt;span style="color: blue"&gt;public interface &lt;/span&gt;&lt;span style="color: #2b91af"&gt;INHibernateUnitOfWork &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;IUnitOfWork
&lt;/span&gt;{
    &lt;span style="color: #2b91af"&gt;ISession &lt;/span&gt;CurrentSession { &lt;span style="color: blue"&gt;get&lt;/span&gt;; }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;The interesting piece here is the ISession interface from NHibernate.&amp;#160; It puts several key patterns together – Unit of Work, Identity Map, as well as the Data Mapper pattern.&amp;#160; Now, I’ve never been on a project that has wanted or needed to swap out ORM solutions (provided they chose an active, mature solution), so what is this encapsulation of the Repository buying us exactly?&lt;/p&gt;

&lt;p&gt;A bigger issue comes into play when trying to implement Command-Query Separation throughout your application – the Repository pattern just does not support it well enough.&amp;#160; Eventually, you’ll likely be left with a class that is Repository in name only, but not the original intent.&amp;#160; Let’s look at some of the problems of Repository to get an idea how CQS doesn’t gel well.&lt;/p&gt;

&lt;h3&gt;Loose aggregate boundaries&lt;/h3&gt;

&lt;p&gt;The problems Aggregate Roots solve is one of spaghetti-coded associations between entities, where I could never figure out the right place to draw the boundary.&amp;#160; I originally assumed that a save operation meant that you would save a single aggregate root, and cascading would take care of the rest.&amp;#160; Unfortunately, that simplicity and rigidity tends to fall flat in larger models.&amp;#160; In an aggregate root, child entities only have identity &lt;em&gt;within the boundaries of the root&lt;/em&gt;, and no outside identity.&lt;/p&gt;

&lt;p&gt;In the web world, that would mean that anything with an Edit link is inherently an aggregate root, as it needs its own global identity to save properly.&amp;#160; We toyed around with local identity, and always passing around the parent object to work on the child.&amp;#160; But all that extra work didn’t buy us anything.&amp;#160; Local identity only bought us anything when you edited an entire entity on one page, including children.&lt;/p&gt;

&lt;p&gt;Cascading poses other issues.&amp;#160; What we found is that cascading depends not on the entity I’m working with, but the specific operation/command I’m trying to perform.&amp;#160; Instead, we’ve seen aggregate boundaries depend completely on the command we perform.&amp;#160; Sometimes the root is object A, sometimes it’s B.&amp;#160; Instead of worrying too much about aggregate boundaries, we greatly reduced the relative boundaries of roots, until it was a use-case per use-case basis that determined where we drew our boundaries.&lt;/p&gt;

&lt;p&gt;Because roots can hold references to other roots, the concept of a boundary and local identity eventually restricted itself to basically screens where you saved the parent and children in one operation.&amp;#160; Again, it was the C in CQS that drove boundaries.&lt;/p&gt;

&lt;p&gt;Thus it started to become confusing how we should handle cascades and save logic.&amp;#160; Since boundaries varied screen-to-screen, it became obvious that any custom save logic in a Repository could be handled perfectly well in the ORM layer, with cascades.&amp;#160; Eventually, our model became extremely connected, with appropriate cascading and modification operations available only when specifically needed.&lt;/p&gt;

&lt;h3&gt;&lt;/h3&gt;

&lt;h3&gt;First-class queries&lt;/h3&gt;

&lt;p&gt;On virtually every screen our application, we show the exact same entity.&amp;#160; That’s around 150 screens or so, where what you see begins with one Person, and filters down from there.&amp;#160; This made things quite interesting from the query optimization standpoint.&amp;#160; We had two choices – go through the root Person entity to all of its children, in one slice.&amp;#160; Or, go from the children, and get back to the parent.&amp;#160; But sometimes we show bits and pieces of various slices of our Person object, things that did not fit well with just one Repository call.&amp;#160; We enabled lazy loading – but only because we wanted a well-connected object model, with the knowledge that we would optimize the access later.&lt;/p&gt;

&lt;p&gt;When we actually got to the optimizations, we could either create a bunch of GetByIdForAbcScreen on our PersonRepository, or, encapsulate all of the fetching in a single Query object.&amp;#160; Guess which route we went…&lt;/p&gt;

&lt;p&gt;With first-class query objects in our system, the need for a true PersonRepository becomes much less.&amp;#160; It doesn’t do any custom queries, those are now in distinct query objects, designed for each situation.&lt;/p&gt;

&lt;h3&gt;Wither the Repository?&lt;/h3&gt;

&lt;p&gt;No, not yet.&amp;#160; Complexity in a system is never uniform, and a single solution rarely fits every circumstance.&amp;#160; The tough part is figuring where to put custom persistence or fetching logic.&amp;#160; New query method on a Repository?&amp;#160; Override the Save method?&amp;#160; Is that custom save logic on &lt;em&gt;every&lt;/em&gt; save for this entity, or just for certain commands?&amp;#160; Complexity resembles more the &lt;a href="http://en.wikipedia.org/wiki/File:WMAP_2008.png"&gt;picture of cosmic background radiation from the Big Bang&lt;/a&gt;, almost random in nature, but a predictable and expected variation.&amp;#160; Most spots are in the middle of the complexity scale, some spots are so easy that the architecture chosen may seem too much, but other spots that bend our architecture to its limits.&amp;#160; The Repository is one of those spots.&lt;/p&gt;

&lt;p&gt;Personally, I see a few trends in Repositories:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Trend towards a Generic Method Repository, where there is no custom logic for CRUD&lt;/li&gt;

  &lt;li&gt;Queries externalized and encapsulated in Query objects when needed, otherwise exposed through LINQ&lt;/li&gt;

  &lt;li&gt;Custom persistence logic externalized and encapsulated in Commands, that utilize the one Repository implementation as needed&lt;/li&gt;

  &lt;li&gt;Repository becomes relegated, in NHibernate terms, as the ISessionFacade&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’m not fully ready to chuck our custom repositories, as I’m still not quite fully cognizant of what this change might mean.&amp;#160; But the parallel inheritance hierarchies are naive and a little difficult to work with, and don’t really reflect the reality we’re trying to model in our controller level of our application – modeling Queries and Commands as first-class citizens. &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;a href="http://www.dotnetkicks.com/kick/?title=Wither+the+Repository&amp;url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f09%2f10%2fwither-the-repository.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f09%2f10%2fwither-the-repository.aspx" border="0" alt="Kick It on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=24711" width="1" height="1"&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=_hpdAdA0jlM:X70nuLzxWKc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=_hpdAdA0jlM:X70nuLzxWKc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=_hpdAdA0jlM:X70nuLzxWKc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=_hpdAdA0jlM:X70nuLzxWKc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=_hpdAdA0jlM:X70nuLzxWKc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GrabBagOfT/~4/_hpdAdA0jlM" height="1" width="1"/&gt;</description><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">10</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/rsscomments.aspx?PostID=24711</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/commentapi.aspx?PostID=24711</wfw:comment><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/09/10/wither-the-repository.aspx</feedburner:origLink></item><item><title>DDD: Repository Implementation Patterns</title><link>http://feedproxy.google.com/~r/GrabBagOfT/~3/u_n1E5mqXf8/ddd-repository-implementation-patterns.aspx</link><category>Domain-Driven Design</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">bogardj</dc:creator><pubDate>Wed, 02 Sep 2009 18:00:32 PDT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:24515</guid><description>&lt;p&gt;One of the major structural patterns encountered in DDD (and one of the most argued about) is the &lt;a href="http://martinfowler.com/eaaCatalog/repository.html"&gt;Repository pattern&lt;/a&gt;.&amp;#160; You’ve created a persistent domain model, and now you need to be able to retrieve these objects from an encapsulated store.&amp;#160; In Fowler’s PoEAA, the Repository pattern is described as:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;i&gt;Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects&lt;/i&gt;.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;In many DDD implementations, the use of a Repository is widened to go beyond retrieval, but the other pieces in the CRUD acronym.&amp;#160; This is natural, as a Repository provides a centralized facade over some backing store, whether that backing store is a database, XML, SOAP, REST and so on.&amp;#160; But what about the actual interface of the Repository?&amp;#160; What kinds of options do we have for designing the actual Repository itself?&amp;#160; There are quite a few different schools of thought here, each with their own benefits and drawbacks.&lt;/p&gt;  &lt;h3&gt;The Generic Repository Interface&lt;/h3&gt;  &lt;p&gt;In the generic repository interface, the interface definition itself is generic, with implementations for individual entity types.&amp;#160; The generic type parameter denotes the entity type of the repository.&amp;#160; One example is in S#arp Architecture:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public interface &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IRepositoryWithTypedId&lt;/span&gt;&amp;lt;T, IdT&amp;gt;
{
    T Get(IdT id);

    &lt;span style="color: #2b91af"&gt;IList&lt;/span&gt;&amp;lt;T&amp;gt; GetAll();

    &lt;span style="color: #2b91af"&gt;IList&lt;/span&gt;&amp;lt;T&amp;gt; FindAll(&lt;span style="color: #2b91af"&gt;IDictionary&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;, &lt;span style="color: blue"&gt;object&lt;/span&gt;&amp;gt; propertyValuePairs);

    T FindOne(&lt;span style="color: #2b91af"&gt;IDictionary&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;, &lt;span style="color: blue"&gt;object&lt;/span&gt;&amp;gt; propertyValuePairs);

    T SaveOrUpdate(T entity);

    &lt;span style="color: blue"&gt;void &lt;/span&gt;Delete(T entity);

    &lt;span style="color: #2b91af"&gt;IDbContext &lt;/span&gt;DbContext { &lt;span style="color: blue"&gt;get&lt;/span&gt;; }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;If you want a repository for a specific type of entity, you create a derived type, closing the interface type with the entity:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public interface &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ICustomerRepository &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;INHibernateRepositoryWithTypedId&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Customer&lt;/span&gt;, &lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;
{
    &lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Customer&lt;/span&gt;&amp;gt; FindByCountry(&lt;span style="color: blue"&gt;string &lt;/span&gt;countryName);
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Note that this repository supplies an additional, specialized query method for a specific find method.&amp;#160; The nice thing about a generic repository interface is that a corresponding base repository implementation can be designed so that all of the data access code that doesn’t change from repository to repository can have a place to live.&amp;#160; The actual implementation can then rely on a common base implementation for the non-changing behavior:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;CustomerRepository &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;NHibernateRepositoryWithTypedId&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Customer&lt;/span&gt;, &lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;, &lt;span style="color: #2b91af"&gt;ICustomerRepository
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Customer&lt;/span&gt;&amp;gt; FindByCountry(&lt;span style="color: blue"&gt;string &lt;/span&gt;countryName) {
        &lt;span style="color: #2b91af"&gt;ICriteria &lt;/span&gt;criteria = Session.CreateCriteria(&lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;Customer&lt;/span&gt;))
            .Add(&lt;span style="color: #2b91af"&gt;Expression&lt;/span&gt;.Eq(&lt;span style="color: #a31515"&gt;&amp;quot;Country&amp;quot;&lt;/span&gt;, countryName));

        &lt;span style="color: blue"&gt;return &lt;/span&gt;criteria.List&amp;lt;&lt;span style="color: #2b91af"&gt;Customer&lt;/span&gt;&amp;gt;() &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Customer&lt;/span&gt;&amp;gt;;
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;But, we still get the type safety of generics.&amp;#160; However, we tend to muddy the contract of the ICustomerRepository a little if our entity does not support all of the operations of the base repository interface.&amp;#160; It’s basically a sacrifice of a common base implementation that you violate the Interface Segregation Principle for some simplification on the implementation side.&amp;#160; For example, in my current domain, deleting an entity has legal ramifications, so we basically don’t allow it for quite a few entities.&amp;#160; Instead, things are marked as various stages of “soft” deletes.&lt;/p&gt;

&lt;p&gt;One big benefit is that most modern IoC containers allow configuring the container such that the most derived type of IRepository&amp;lt;T&amp;gt; can be resolved.&amp;#160; I can ask the container for IRepository&amp;lt;Customer&amp;gt;, and the CustomerRepository implementation is returned.&amp;#160; This is especially helpful in APIs where we might abstract “saving” to some base layer.&amp;#160; Again, the downside is that our interface has methods to support every operation, whether we actually &lt;em&gt;want&lt;/em&gt; to support them or not.&lt;/p&gt;

&lt;h3&gt;The Generic Method Repository&lt;/h3&gt;

&lt;p&gt;In the generic method repository, our repository implementations do not expose methods for specific queries.&amp;#160; Additionally, no specific repository for an entity is defined.&amp;#160; Instead, only general-purpose methods are exposed for querying, persisting and retrieval.&amp;#160; The methods are generic, providing type safety, but there is only one implementation.&amp;#160; Consider the Alt.Oxite repository implementation from FubuMVC Contrib:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public interface &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IRepository
&lt;/span&gt;{
    &lt;span style="color: blue"&gt;void &lt;/span&gt;Save&amp;lt;ENTITY&amp;gt;(ENTITY entity)
        &lt;span style="color: blue"&gt;where &lt;/span&gt;ENTITY : &lt;span style="color: #2b91af"&gt;DomainEntity&lt;/span&gt;;

    ENTITY Load&amp;lt;ENTITY&amp;gt;(&lt;span style="color: #2b91af"&gt;Guid &lt;/span&gt;id)
        &lt;span style="color: blue"&gt;where &lt;/span&gt;ENTITY : &lt;span style="color: #2b91af"&gt;DomainEntity&lt;/span&gt;;

    &lt;span style="color: #2b91af"&gt;IQueryable&lt;/span&gt;&amp;lt;ENTITY&amp;gt; Query&amp;lt;ENTITY&amp;gt;()
        &lt;span style="color: blue"&gt;where &lt;/span&gt;ENTITY : &lt;span style="color: #2b91af"&gt;DomainEntity&lt;/span&gt;;

    &lt;span style="color: #2b91af"&gt;IQueryable&lt;/span&gt;&amp;lt;ENTITY&amp;gt; Query&amp;lt;ENTITY&amp;gt;(&lt;span style="color: #2b91af"&gt;IDomainQuery&lt;/span&gt;&amp;lt;ENTITY&amp;gt; whereQuery)
        &lt;span style="color: blue"&gt;where &lt;/span&gt;ENTITY : &lt;span style="color: #2b91af"&gt;DomainEntity&lt;/span&gt;;
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;In this implementation, the repository itself is not generic.&amp;#160; A single repository dependency can perform all needed CRU (not D) operations against any well-known entity.&amp;#160; Because most ORMs nowadays are generic, the implementation of a generic repository is very straightforward, it simply wraps the ORM.&amp;#160; The actual definition of queries is left to something else.&amp;#160; In the above case, LINQ queries utilize the Query method to retrieve persistent objects.&lt;/p&gt;

&lt;p&gt;The advantage to this pattern is that we do not need to create an interface for each type of entity we create.&amp;#160; Instead, we remove the responsibility of forming specific queries to the callers, including worrying about fetching, caching, projection and so on.&amp;#160; Since this logic does not change, we don’t have to pull in a repository for every entity we want to retrieve.&amp;#160; Instead, operations flow through one general-purpose interface.&lt;/p&gt;

&lt;p&gt;The disadvantage to this pattern is we lose named query methods on our repository, as &lt;a href="http://codebetter.com/blogs/gregyoung/archive/2009/01/16/ddd-the-generic-repository.aspx"&gt;Greg pointed out a while back&lt;/a&gt;.&amp;#160; The ICustomerRepository from the previous pattern exposed (and encapsulated) a well-known query with a intention-revealing name.&amp;#160; With a generic method repository, there is only one implementation.&amp;#160; Creating a derived ICustomerRepository of a generic method repository would be rather strange, as the base interface allows any entity under the sun.&lt;/p&gt;

&lt;h3&gt;The Encapsulated Role-Specific Repository&lt;/h3&gt;

&lt;p&gt;Classes that use a repository rarely use every method inside of it.&amp;#160; A class that does a query against Customers probably isn’t going to then go delete them.&amp;#160; Instead, we’re likely querying for some other purpose, whether it’s to display information, look up information for business rules, and so on.&amp;#160; Instead of a catch-all repository that exposes every method under the sun, we could alternatively apply the Interface Segregation Principle for role-based interfaces, and define interfaces that expose only what one class needs.&amp;#160; With these repositories, you’ll much more likely find encapsulated query methods, that do not expose the ability to arbitrarily query a backing data store:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public interface &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IProductRepositoryForNewOrder
&lt;/span&gt;{
    &lt;span style="color: #2b91af"&gt;Product&lt;/span&gt;[] FindDiscontinuedProducts();
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;A single repository implementation implements all Product repository interfaces, but only the single method needed is exposed and used by the caller.&amp;#160; This way, you do not see Save, Delete, and other query operations that you do not care about.&amp;#160; The down side is that this implementation tends to be more difficult to combine with IoC containers, as auto-wiring does not work as expected.&amp;#160; At some point, it starts to look like these types of repositories are glorified query objects, a single class that represents a query.&lt;/p&gt;

&lt;h3&gt;&lt;/h3&gt;

&lt;h3&gt;Wrapping it up&lt;/h3&gt;

&lt;p&gt;In our projects, we’ve tended to use the generic repository interface, as it allows us to override implementations for custom behavior.&amp;#160; We still will include a default implementation that gets wired in, a non-abstract RepositoryBase&amp;lt;T&amp;gt;.&amp;#160; The IoC container is configured to pick the most specific implementation, but if one doesn’t exist, we don’t need to create a blank repository.&amp;#160; Sometimes, things like Save or Delete need to do custom things, and I’d rather put this in the repository rather than some other anonymous domain service.&lt;/p&gt;

&lt;p&gt;In the end, it really depends on the situation of each project.&amp;#160; I’ve tended to stick with a generic interface, as it’s the easiest to scale complexity.&amp;#160; However, quite a few smart folks use the generic method repository, and rely on external queries for the hard stuff.&amp;#160; Complexity with saves and deletes is then handled by the cascading behavior of the underlying ORM.&amp;#160; It’s quite intriguing, but I’ve been reticent to give up a tried-and-true pattern.&amp;#160; I’m curious to see what other repository patterns people use out there.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;a href="http://www.dotnetkicks.com/kick/?title=DDD%3a+Repository+Implementation+Patterns&amp;url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f09%2f02%2fddd-repository-implementation-patterns.aspx"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.lostechies.com%2fblogs%2fjimmy_bogard%2farchive%2f2009%2f09%2f02%2fddd-repository-implementation-patterns.aspx" border="0" alt="Kick It on DotNetKicks.com" /&gt;&lt;/a&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=24515" width="1" height="1"&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=u_n1E5mqXf8:1hv_M8itaok:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=u_n1E5mqXf8:1hv_M8itaok:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=u_n1E5mqXf8:1hv_M8itaok:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/GrabBagOfT?a=u_n1E5mqXf8:1hv_M8itaok:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/GrabBagOfT?i=u_n1E5mqXf8:1hv_M8itaok:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GrabBagOfT/~4/u_n1E5mqXf8" height="1" width="1"/&gt;</description><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">18</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/rsscomments.aspx?PostID=24515</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://www.lostechies.com/blogs/jimmy_bogard/commentapi.aspx?PostID=24515</wfw:comment><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/09/02/ddd-repository-implementation-patterns.aspx</feedburner:origLink></item></channel></rss>
