<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://devlicio.us/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Billy McCafferty : C#, Refactoring</title><link>http://devlicio.us/blogs/billy_mccafferty/archive/tags/C_2300_/Refactoring/default.aspx</link><description>Tags: C#, Refactoring</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP1 (Build: 31106.3070)</generator><item><title>IT Samurai School coming soon...</title><link>http://devlicio.us/blogs/billy_mccafferty/archive/2009/05/03/it-samurai-school-coming-soon.aspx</link><pubDate>Mon, 04 May 2009 02:32:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:46471</guid><dc:creator>Billy McCafferty</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;As if my life wasn&amp;#39;t boring enough trying to get S#arp Architecture 1.0 out the door...&lt;/p&gt;
&lt;p&gt;&lt;a target="_blank" href="http://www.itsamuraischool.com/"&gt;&lt;img style="border:0;" alt="www.itsamuraischool.com" src="http://devlicio.us/resized-image.ashx/__size/600x450/__key/CommunityServer.Components.UserFiles/00.00.00.21.06/itsamuraischool.gif" width="550" height="347" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=46471" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/Architecture/default.aspx">Architecture</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/.NET/default.aspx">.NET</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/Software+Development/default.aspx">Software Development</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/Algorithms/default.aspx">Algorithms</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/Refactoring/default.aspx">Refactoring</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/NHibernate/default.aspx">NHibernate</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/Project+Management/default.aspx">Project Management</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/Test-Driven+Development/default.aspx">Test-Driven Development</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/Agile+Development/default.aspx">Agile Development</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/MVC.NET/default.aspx">MVC.NET</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/S_2300_arp+Architecture/default.aspx">S#arp Architecture</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/DDD/default.aspx">DDD</category></item><item><title>Refactor It! Challenge 3 - The State of Things</title><link>http://devlicio.us/blogs/billy_mccafferty/archive/2006/12/18/refactor-it-challenge-3.aspx</link><pubDate>Tue, 19 Dec 2006 06:23:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:1923</guid><dc:creator>Billy McCafferty</dc:creator><slash:comments>13</slash:comments><description>If you're not familiar with the Refactor It! challenges, please &lt;A href="http://devlicio.us/blogs/billy_mccafferty/archive/2006/11/13/refactor-it-the-weekly-book-giveaway.aspx"&gt;read this post&lt;/A&gt;. (Yes, this one is quite a bit overdue.) Now on to challenge 3...&lt;BR&gt;&lt;BR&gt;Welcome back to another refactoring challenge! This challenge will pit your skills against the very useful &lt;A class="" href="http://www.dofactory.com/Patterns/PatternState.aspx"&gt;State Design Pattern&lt;/A&gt; along with writing your own unit tests. It should take 1-2 hours for senior developers and a couple more for others. While the previous challenge made you focus only on the refactoring without worrying about writing unit tests, this challenge requires you to complete the refactoring &lt;I&gt;along with&lt;/I&gt; writing your own unit tests. Here's the premise...&lt;BR&gt;&lt;BR&gt;&lt;B&gt;Background &amp;amp; Problem&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;This "refactoring to patterns" challenge surfaced during the past couple of weeks on an actual project. The real-world project is a project management tool that interfaces with a schedule management tool. The schedule management tool maintains a listing of project activities which include scheduled start/finish dates, actual start/finish dates (if they're available), and a remaining duration of the activity. (For the purposes of this challenge, many other activity properties have been dropped for simplification.) Since an API was not available to work with the scheduling tool's data, I had to communicate with its database directly. The problem was that quite a lot of business rules were executed when an activity changed from Not Started to Started, for example. ("Not Started" activities have scheduled start/finish dates but no actual dates; "Started" activities have an actual start date, a scheduled finish date but no other dates; and "Finished" activities have actual start/finish dates and no scheduled start/finish dates.) Taking a quick look at the class Challenge3.Domain.ProjectActivity shows how quickly this is getting out of hand. &lt;BR&gt;&lt;BR&gt;&lt;B&gt;Your Incentive&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;Up for grabs this week is the following book along with a &lt;A class="" href="http://submain.com/?nav=products.cio" target=_blank&gt;CodeIt.Once Refactoring&lt;/A&gt; tool 3-User license pack! This seminal writing has become a required part of any serious developer's bookshelf.&lt;BR&gt;
&lt;P&gt;&lt;IMG alt="Design Patterns: Elements of Reusable Object-Oriented Software" src="http://www.awprofessional.com/ShowCover.asp?isbn=0201633612&amp;amp;type=c" width=125&gt;&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.awprofessional.com/bookstore/product.asp?isbn=0201633612&amp;amp;rl=1"&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/A&gt;&lt;BR&gt;By Erich Gamma, Richard Helm, Ralph Johnson, John M. Vlissides.&lt;/P&gt;&lt;B&gt;Instructions to Enter&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;Make sure you read all the instructions as they're different from the previous challenge! 
&lt;OL&gt;
&lt;LI&gt;Make sure you have NUnit installed; available at &lt;A href="http://www.nunit.org/" target=_blank&gt;http://www.nunit.org/&lt;/A&gt;.&lt;/LI&gt;
&lt;LI&gt;Download Challenge3.zip, found below.&lt;/LI&gt;
&lt;LI&gt;Open the solution with VS 2005 and compile it.&lt;/LI&gt;
&lt;LI&gt;Open NUnit, go to File/Open, then open &amp;lt;solution directory&amp;gt;/Challenge3.Tests/bin/Debug/Challenge3.Tests.dll. Click run and make sure all the tests pass. There should be a few unit tests that are ignored; but none should be failing.&lt;/LI&gt;
&lt;LI&gt;Complete the refactorings as described below. Be sure to follow the style of the code that is already in place: classes, methods and public properties in PascalCase, private members in camelCase, etc. Following the style that's already there is always a good rule of thumb when modifying legacy code.&lt;/LI&gt;
&lt;LI&gt;When finished with the refactorings, make sure all the unit tests are still passing and that no test is being ignored, zip up your solution and send to &lt;A href="mailto:challenge3@emccafferty.com"&gt;challenge3@emccafferty.com&lt;/A&gt;. As you may only win once, only submit a solution if you'd like to be eligible for the prize or let me know that you don't want to be entered for the drawing.&lt;BR&gt;Because of the upcoming holiday schedule, the due date for your submission is &lt;SPAN style="FONT-WEIGHT:bold;COLOR:red;"&gt;Thursday night at midnight, January 4, US mountain time&lt;/SPAN&gt;.&lt;/LI&gt;&lt;/OL&gt;&lt;B&gt;Challenge 3 Download Overview&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;The VS 2005 solution contains two projects: 
&lt;UL&gt;
&lt;LI&gt;Challenge3.Core: This class library contains the business logic layer of the application. This class library is further broken down as follows: 
&lt;UL&gt;
&lt;LI&gt;The Domain folder contains all the entities and value objects. It also contains a sub-folder, ActivityState, which will hold the state design-pattern classes.&lt;/LI&gt;
&lt;LI&gt;The Utils folder contains a design-by-contract &lt;A href="http://www.codeproject.com/csharp/designbycontract.asp"&gt;utility class written by Kevin McFarlane&lt;/A&gt;. The utility class is for all the Check.Requires you'll see throughout the code.&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;Challenge3.Tests: This class library contains the unit tests of the application. As there is no defined presentation layer, the unit tests serve as a portal to how the application works.&lt;/LI&gt;&lt;/UL&gt;&lt;B&gt;Now Refactor It!&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;Below is a listing of smells that need to be fixed within the project. Each point indicates the file that contains the smell, a description of the problem and any guidelines for completing the refactoring. There may be other smells in the code, but these are the only ones that should be addressed.&lt;BR&gt;&lt;BR&gt;&lt;I&gt;Smell: Conditional Complexity&lt;/I&gt;&lt;BR&gt;&lt;I&gt;Refactoring: &lt;A href="http://industriallogic.com/xp/refactoring/alteringConditionalsWithState.html"&gt;Replace State-Altering Conditionals with State&lt;/A&gt;&lt;/I&gt;&lt;BR&gt;&lt;BR&gt;Although there's only one smell to be refactoring in this challenge, it's an ugly one!&lt;BR&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;I&gt;Challenge3.Domain.ProjectActivity&lt;/I&gt;: This domain class represents a specific activity within a project's schedule. In the real-world app that this was inspired by, I was communicating with a third party database and had to respect the rules of the data communications being performed by the third party client app. (I was bypassing the client app altogether with my own code but needed to ensure continued data integrity.) For example, if an activity is currently Not Started and becomes Started, then the &lt;I&gt;scheduled&lt;/I&gt; start date needs to be set to a null date and the &lt;I&gt;actual&lt;/I&gt; start date then needs to be set, accordingly. In addition to this, the remaining duration of the activity needs to be calculated and set. A simple implementation of the state pattern could remedy the conditional logic in the UpdateActivityStartAndFinishWith method. &lt;I&gt;But here's the kicker...&lt;/I&gt;you need to take into account not only the object's current state but what state it will be in next. For instance, going from Not Started to Finished is &lt;I&gt;not&lt;/I&gt; the same as going from Started to Finished. In the real-world app that this was inspired by, there were unique actions which needed to take place for each of the nine possible transitions; e.g. Not Started to Started, Not Started to Not Started (this isn't necessarily a state change, but the dates can still be modified), Not Started to Finished, Started to Not Started, etc. Your tasks are as follows:&lt;BR&gt;&lt;BR&gt;
&lt;OL&gt;
&lt;LI&gt;Leverage the state design-pattern to simplify the change in states currently being handled by the method UpdateActivityStartAndFinishWith. Any state-related classes should be placed into the folder Challenge3.Domain.ActivityState. There are a few comments in the mentioned method...be sure to pay attention to them!&lt;/LI&gt;
&lt;LI&gt;While implementing the state design pattern, existing unit tests should be maintained and new unit tests should be written for any new code. You shouldn't have to remove any unit tests from Challenge3.Tests.Core.Domain.ProjectProjectActivityStateChangeTests; but you may want to add a new suite of unit tests for the state classes which will be created. Currently 97% of Challenge3.Core.Domain is being unit tested. Your submitted solution must have at least 95% of Challenge3.Core.Domain still under unit tests. You can use a tool such as &lt;A href="http://ncover.org/site/"&gt;NCover&lt;/A&gt; or &lt;A href="http://cenqua.com/clover.net/"&gt;Clover.NET&lt;/A&gt; to verify unit test coverage. (Don't worry about unit testing the Utils namespace; consider this to be a third party DLL.)&lt;/LI&gt;&lt;/OL&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Good luck and let me know if you have any questions. And remember, the first submitter with a correct entry gets his/her name thrown into the hat twice!&lt;/P&gt;
&lt;P&gt;Happy holidays!&lt;BR&gt;&lt;BR&gt;Billy&lt;/P&gt;
&lt;P&gt;12/19/06 9:32 AM Mtn Time - Updated project to use US culture dates within unit tests.&lt;/P&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=1923" width="1" height="1"&gt;</description><enclosure url="http://devlicio.us" length="129116" type="application/x-zip-compressed" /><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/.NET/default.aspx">.NET</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/Refactoring/default.aspx">Refactoring</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/Contests/default.aspx">Contests</category></item><item><title>Refactor It! Challenge 2 Results</title><link>http://devlicio.us/blogs/billy_mccafferty/archive/2006/11/30/refactor-it-challenge-2-results.aspx</link><pubDate>Fri, 01 Dec 2006 01:07:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:970</guid><dc:creator>Billy McCafferty</dc:creator><slash:comments>4</slash:comments><description>Congratulations to Michaël Willemot who is the winner of &lt;A href="http://devlicio.us/blogs/billy_mccafferty/archive/2006/11/23/refactor-it-challenge-2.aspx"&gt;Challenge 2&lt;/A&gt;! Michaël has won a copy of &lt;A href="http://www.awprofessional.com/bookstore/product.asp?isbn=0321268202&amp;amp;rl=1"&gt;Applying Domain-Driven Design and Patterns: With Examples in C# and .NET&lt;/A&gt; by Jimmy Nilsson along with a 3-user license pack for &lt;A href="http://submain.com/?nav=products.cio"&gt;CodeIt.Once Refactoring&lt;/A&gt;. (The winner was randomly selected from all correct entries received.) Geert Baeyaert had the first correct submission and, incidentally, the first correct bonus entry as well.&lt;BR&gt;&lt;BR&gt;There were 19 entries altogether with 17 correct entries. 11 entries attempted the bonus but only 5 entries correctly completed the bonus with a mock logger. Here's a run down of the correct entrants: Adam Vandenberg (bonus as well), Andrzej Kuczynski, Avi A, Bill Arnette, Brian Sherwin, Franck Tetard, Geert Baeyaert (first entry and bonus as well), Harry Chou (bonus as well), John Penokie, Jonathan Roe, Joshua McKinney (bonus as well), Matt Payne, Michael Willemot, Navneet Gupta, Rasmus Faber-Espensen, Rune Rystad (last week's winner, so not eligible for prize, but got bonus as well), Vitaly Davidovich. Nice work all!&lt;BR&gt;&lt;BR&gt;&lt;B&gt;Interesting Finds&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;Below are a few items of particular interest that were found in the submissions: 
&lt;UL&gt;
&lt;LI&gt;A few entrants included an abstract "join spec" that acted as the parent for the AndSpec, NotSpec and OrSpec. This helped centralize functionality and reduce duplicated code. Furthermore, a couple of entrants also made the spec pattern completely generic so its structure could be easily reused with different domain objects. Great call on both approaches.&lt;/LI&gt;
&lt;LI&gt;I forgot to mention, and I'm glad I did, to remove the two unit tests that were affected when you removed the methods FindByNotTypeAndAtLeastTotalCost and FindAtLeastQuantityOrAtLeastTotalCost. Quite a few people wondered whether they should be left alone, modified, or deleted. I'm glad it brought up this unintended conversation. Unit tests should be seen as a dynamic, living part of the code and are subject to the same level of refactoring as the "real" code. If a unit test is no longer pulling its weight or is no longer applicable, get rid of it. As Brian Sherwin noted, a great book to take a look at is &lt;A href="http://www.awprofessional.com/bookstore/product.asp?isbn=0321146530&amp;amp;rl=1"&gt;Test-Driven Development&lt;/A&gt; by Kent Beck. This book demonstrates just how dynamic unit test development really is. With full-throttle TDD, the unit tests morph as much, if not more, as the production code itself.&lt;/LI&gt;
&lt;LI&gt;The log4net bonus tripped up entrants mainly due to two reasons: 1) two separate logs needed to be generated, as was working in the original code, not just one, and 2) the singleton methods were tricky to mock. One solution to the first trip-point was to pass two loggers, one for the owner's log and one for the auditor's log to the nightly log process. The drawback to this approach is the maintenance headache with having to later on pass a third, forth, or nth logger to the class or to another class altogether. Alternatively, another approach is to supply a simplified &lt;A href="http://java.sun.com/blueprints/corej2eepatterns/Patterns/ServiceLocator.html"&gt;Service Locator&lt;/A&gt;. This "logger locator" could be easily passed to anything and extended easily. I've attached a zip file, ExampleSolutions.zip, which contains four entries which used this type of approach (and contain a few variants of the spec pattern as well). The second trip-point was dealing with mocking the call to a method on a singleton. You can make a wrapper for the object, or, if you're in a real pickle, you can use a tool such as &lt;A href="http://www.typemock.com/"&gt;TypeMock&lt;/A&gt; which can mock just about anything, even sealed classes. The drawback to using a tool such as this is that it makes it easier to write more tightly coupled code. As mentioned in a previous post, Michael Feather's &lt;A href="http://www.phptr.com/bookstore/product.asp?isbn=0131177052&amp;amp;rl=1"&gt;Working Effectively with Legacy Code&lt;/A&gt; has a number of great ideas for dealing with these types of situations without resorting to such a powerful tool. (You saw what the ring of power did to Frodo, didn't you?)&lt;/LI&gt;
&lt;LI&gt;Someone brought up the question of what to do if you find yourself writing duplicated spec-creation code in different areas of the code. One solution is to create concrete "combination spec" classes for each of these variants. The problem with this is that it leads to the same type of combinatorial class explosion that we were running into before. Alternatively, for the duplicated spec combinations, you could create a CombinationSpecFactory class. This would have one or more creation methods that would return a Spec class; one method for each unique combination which is duplicated in more than one place. You might ask, what's better about having a factory with combination-spec-creation methods vs. having a number of concrete-combination spec classes? My preference of a factory over individual classes would be to keep the Spec class package clean; I want to keep my Spec class names to be as atomic as possible. I'd love to hear other thoughts on this issue!&lt;/LI&gt;&lt;/UL&gt;Instead of describing the smell refactorings in detail, I'll let the code speak for itself. I've attached ExampleSolutions.zip below which contains four projects that have the bonus challenge included along with well-written log4net wrappers.&amp;nbsp; Your comments are most welcome as to pros and cons of each approach.&lt;BR&gt;&lt;BR&gt;I hope these refactoring challenges continue to be useful, offering plenty of food for thought. Stay tuned to the next challenge which will be rearing its ugly head sometime next week!&lt;BR&gt;&lt;BR&gt;Billy&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=970" width="1" height="1"&gt;</description><enclosure url="http://devlicio.us" length="587238" type="application/x-zip-compressed" /><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/Refactoring/default.aspx">Refactoring</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/Contests/default.aspx">Contests</category></item><item><title>Refactor It! Challenge 2</title><link>http://devlicio.us/blogs/billy_mccafferty/archive/2006/11/23/refactor-it-challenge-2.aspx</link><pubDate>Thu, 23 Nov 2006 08:46:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:746</guid><dc:creator>Billy McCafferty</dc:creator><slash:comments>4</slash:comments><description>If you're not familiar with&amp;nbsp;the Refactor It! challenges, please &lt;A href="http://devlicio.us/blogs/billy_mccafferty/archive/2006/11/13/refactor-it-the-weekly-book-giveaway.aspx"&gt;read this post&lt;/A&gt;. (Yes, this one is a little late in being published...but it's worth it!) Now on to challenge 2...&lt;BR&gt;&lt;BR&gt;Welcome back to another refactoring challenge! I'm excited about this week's challenge and am sure it'll be interesting and challenging for all skill levels. It should take about 2 hours for senior developers and a couple more for intermediate developers. While last week's challenge served as a good introduction to refactoring in general, this week's challenge focuses on design pattern refactorings. Here's the premise...&lt;BR&gt;&lt;BR&gt;&lt;B&gt;Background &amp;amp; Problem&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;This application continues from the theme started in last week's challenge and includes a logging system for the local tiki bar. Each day, very early in the morning, a logging process kicks off which creates two logs summarizing orders placed on the previous day. An order has a customer, a date, a specific tiki drink, and a quantity of that drink. If the customer wants different types of tiki drinks, they need to place an order for each type. It's not your tiki bar, so that's just the way it is! The first log created each night is for the bar owner and includes all orders which had a total cost of at least $20 &lt;I&gt;or&lt;/I&gt; had a quantity of at least 5. The second log is for the auditor and includes all tiki drink orders which had a total cost of at least $10 &lt;I&gt;and&lt;/I&gt; were not for the drink called the "London Fog Cutter." (Don't ask me why the auditor doesn't want to know about these drinks...I just work here!)&lt;BR&gt;&lt;BR&gt;The problem, in a nutshell, is two-fold. The first problem is that the filtering mechanism for figuring out which orders should be logged is getting quite complicated. The &lt;A href="http://www.martinfowler.com/apsupp/spec.pdf"&gt;specification design pattern&lt;/A&gt;, a specialized version of the &lt;A href="http://www.dofactory.com/Patterns/PatternInterpreter.aspx"&gt;interpreter design pattern&lt;/A&gt;, needs to be employed to make the filtering easier to maintain. The second problem is that a bi-directional dependency exists between the data layer and the business logic layer. Consequently, it's very difficult to unit test the business logic layer without actually hitting the database. We'll need to introduce a &lt;A href="http://www.martinfowler.com/eaaCatalog/separatedInterface.html"&gt;separated interface&lt;/A&gt;, also known as the &lt;A href="http://www.objectmentor.com/resources/articles/dip.pdf"&gt;dependency inversion principle&lt;/A&gt;, to decouple the business logic layer from the data access layer. We'll then need to use a &lt;A href="http://www-128.ibm.com/developerworks/library/j-mocktest.html"&gt;mock object&lt;/A&gt; so that we can predictably test the business logic layer without needing to worry about having a database around. (Tools exist to automate mock object creation, but let's we'll use one developed by hand.)&lt;BR&gt;&lt;BR&gt;&lt;B&gt;Your Incentive&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;Up for grabs this week is the following book along with a &lt;A class="" href="http://submain.com/?nav=products.cio" target=_blank&gt;CodeIt.Once Refactoring&lt;/A&gt; tool 3-User license pack! This is a great book and will be a well-earned prize.&lt;BR&gt;
&lt;P&gt;&lt;IMG alt="Applying Domain-Driven Design and Patterns: With Examples in C# and .NET" src="http://www.awprofessional.com/ShowCover.asp?isbn=0321268202&amp;amp;type=c" width=125&gt; &lt;/P&gt;
&lt;DIV id=cover&gt;
&lt;P&gt;&lt;A href="http://www.awprofessional.com/bookstore/product.asp?isbn=0321268202&amp;amp;rl=1"&gt;Applying Domain-Driven Design and Patterns: With Examples in C# and .NET&lt;/A&gt;&lt;BR&gt;By Jimmy Nilsson.&lt;/P&gt;&lt;B&gt;Instructions to Enter&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;Make sure you read all the instructions as they're different from last week's challenge! 
&lt;OL&gt;
&lt;LI&gt;Make sure you have NUnit installed; available at &lt;A href="http://www.nunit.org/" target=_blank&gt;http://www.nunit.org/&lt;/A&gt;.&lt;/LI&gt;
&lt;LI&gt;Download Challenge2.zip found below.&lt;/LI&gt;
&lt;LI&gt;Open the solution with VS 2005 and compile it.&lt;/LI&gt;
&lt;LI&gt;Open NUnit, go to File/Open, then open &amp;lt;solution directory&amp;gt;/Challenge2.Tests/bin/Debug/Challenge2.Tests.dll. Click run and make sure all the tests pass. There should be a few unit tests that are ignored; but none should be failing.&lt;/LI&gt;
&lt;LI&gt;After running the tests, confirm that two log were generated in &amp;lt;solution directory&amp;gt;/Challenge2.Tests/bin/Debug/. The log files are named Auditor.log and Owner.log and contain a number of order summaries pulled from the "database."&lt;/LI&gt;
&lt;LI&gt;Complete the refactorings as described below. Be sure to follow the style of the code that is already in place: classes, methods and public properties in PascalCase, private members in camelCase, etc. Following the style that's already there is always a good rule of thumb when modifying legacy code.&lt;/LI&gt;
&lt;LI&gt;When finished with the refactorings, make sure all the unit tests are still passing and that no test is being ignored, zip up your solution and send to &lt;A href="mailto:challenge2@emccafferty.com"&gt;challenge2@emccafferty.com&lt;/A&gt;. As you may only win once, only submit a solution if you'd like to be eligible for the prize or let me know that you don't want to be entered for the drawing.&lt;BR&gt;Because of the lateness of this post and this week's holiday, the due date for your submission is &lt;SPAN style="FONT-WEIGHT:bold;COLOR:red;"&gt;Wednesday night at midnight, Nov. 29, US mountain time&lt;/SPAN&gt;. It's not an easy one, so I wouldn't wait until Wednesday to get started!&lt;/LI&gt;&lt;/OL&gt;&lt;B&gt;Challenge 2 Download Overview&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;The VS 2005 solution contains two projects (at the moment): 
&lt;UL&gt;
&lt;LI&gt;Challenge2.Core: This class library contains the data access and business logic layers of the application. This class library is further broken down as follows: 
&lt;UL&gt;
&lt;LI&gt;The Data folder contains all the data-access code. The only class within this folder, OrderDao, simulates talking to a real database by generating zero or more sample orders. The unpredictability of the results serves to simulate a real-life database.&lt;/LI&gt;
&lt;LI&gt;The Domain folder contains all the entities and value objects. It also contains a sub-folder, OrderFinder, albeit still in the same namespace, which holds the order-filtering logic.&lt;/LI&gt;
&lt;LI&gt;The Services folder contains the nightly logger process.&lt;/LI&gt;
&lt;LI&gt;The Utils folder contains a design-by-contract &lt;A href="http://www.codeproject.com/csharp/designbycontract.asp"&gt;utility class written by Kevin McFarlane&lt;/A&gt;. The utility class is for all the Check.Requires you'll see throughout the code.&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;Challenge2.Core: This class library contains the unit tests of the application. As there is no defined presentation layer, the unit tests serve as a portal to how the application works.&lt;/LI&gt;
&lt;LI&gt;Challenge2.Data: This isn't in the download, but you'll be adding this class library soon enough.&lt;/LI&gt;&lt;/UL&gt;&lt;B&gt;Now Refactor It!&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;Below is a listing of smells that need to be fixed within the project. Each point indicates the file that contains the smell, a description of the problem and any guidelines for completing the refactoring. There may be other smells in the code, but these are the only ones that should be addressed.&lt;BR&gt;&lt;BR&gt;&lt;I&gt;Smell: Combinatorial Explosion&lt;/I&gt;&lt;BR&gt;&lt;I&gt;Refactoring: &lt;A href="http://industriallogic.com/xp/refactoring/implicitLanguageWithInterpreter.html"&gt;Replace Implicit Language with Interpreter&lt;/A&gt;&lt;/I&gt;&lt;BR&gt;&lt;BR&gt;I have yet to write an application that doesn't include a bit of filtering capabilities. Furthermore, it's often the case that the filtering capabilities need to be extended throughout the life of the application. If only a couple of filters are required, then hard-coding the filter logic isn't that big of a deal. But if the number of filters grow or the logic becomes more complicated than just "AND"s, then using the &lt;A href="http://www.dofactory.com/Patterns/PatternInterpreter.aspx"&gt;interpreter design pattern&lt;/A&gt; may be an appropriate fit. But there's also the question as to whether filtering should be done by the database or by the code. As I prefer to keep database logic to the simplest CRUD (create/read/update/delete) functionality, I avoid putting complicated filtering logic into the database unless performance warrants otherwise. A good rule of thumb is that if you have a couple hundred items or less to filter, and you have more than a few filters that change regularly, then putting the filtering into the business logic layer is a good way to go; otherwise, the database should be doing the basic filtering. Alternatively, ORMs such as NHibernate provide their own implementation of the &lt;A href="http://www.dofactory.com/Patterns/PatternInterpreter.aspx"&gt;interpreter design pattern&lt;/A&gt;. So onto the smell... 
&lt;UL&gt;
&lt;LI&gt;&lt;I&gt;Challenge2.Core.OrderFinder&lt;/I&gt;: This order-filtering class exposes the verbosely named methods FindByNotTypeAndAtLeastTotalCost and FindAtLeastQuantityOrAtLeastTotalCost. Besides taking a while to read, these methods are difficult to extend, likely to change and are far from flexible. Without removing these methods (yet), refactor to the &lt;A href="http://www.martinfowler.com/apsupp/spec.pdf"&gt;specification design pattern&lt;/A&gt; to make the filtering capabilities much more flexible. To assist, uncomment the unit tests within Challenge2.Tests.Core.Domain.OrderFinderTests one at a time, following the order suggested. Get each unit test working by implementing the implied code. Put all your "Spec" classes into the folder Challenge2.Core.Domain.OrderFinder but keep the namespace of those classes to be Challenge2.Core.Domain.&lt;/LI&gt;
&lt;LI&gt;&lt;I&gt;Challenge2.Core.Services.NightlyOrderLogger&lt;/I&gt;: This class creates writes two logs, one for the tiki bar owner and one for the auditor. To get the appropriate orders to log, it makes a call to the database to get all of yesterday's orders, and then leverages the OrderFinder class to filter, accordingly. Refactor this class to use the specification classes that you just created and delete the methods FindByNotTypeAndAtLeastTotalCost and FindAtLeastQuantityOrAtLeastTotalCost from Challenge2.Core.OrderFinder.&lt;/LI&gt;&lt;/UL&gt;&lt;I&gt;Smell: Dependency on Concrete Service&lt;/I&gt;&lt;BR&gt;&lt;I&gt;Refactorings: &lt;A href="http://www.refactoring.com/catalog/extractInterface.html"&gt;Extract Interface&lt;/A&gt; and Introduce &lt;A href="http://www.martinfowler.com/eaaCatalog/separatedInterface.html"&gt;Separated Interface&lt;/A&gt;&lt;/I&gt;&lt;BR&gt;&lt;BR&gt;If you're wondering why you've never heard of the smell listed above, you probably won't be alone. (And if I ever write a book, I'll be sure to change that!) One of the most frequent issues I find with legacy code is direct dependencies on concrete classes that provide a service. A service, in this case, may be a data-access object which communicates with a database, an emailing utility class, an external web service, etc. A service is usually resource intensive, time consuming, or something that shouldn't be executed outside of a production environment. Having dependencies on concrete service classes does not present a problem if the code won't ever be unit tested, but neither will standing in the middle of a highway as long as there's no traffic...but I digress.&lt;BR&gt;&lt;BR&gt;A solution for removing a dependency on a concrete service is to introduce, instead, a dependency on an interface. (I'll discuss more of the benefits of this in a moment.) But if the service class is still within the same physical assembly as the business logic layer, then there's nothing to stop a developer from bypassing the interface and going back to the concrete service class directly. To enforce a policy of services via interfaces, a &lt;A href="http://www.martinfowler.com/eaaCatalog/separatedInterface.html"&gt;separated interface&lt;/A&gt; may be introduced. 
&lt;UL&gt;
&lt;LI&gt;&lt;I&gt;Challenge2.Core.Services.NightlyOrderLogger&lt;/I&gt;: Notice that this class creates a new instance of OrderDao to retrieve relevant orders from the database. This presents two problems. The first is that the process is time consuming from a unit test point of view. If you have a couple hundred unit tests and many of them require communications with a database, the unit testing process can begin to take 10 minutes or more. Once this happens, developers stop running unit tests altogether. (I experienced this on a previous project.) Furthermore, unit tests expect predictable results to verify code is working properly. Unless a database is reinitialized at the beginning of each test run, the results may vary and the tests will begin to break. This is another motivating factor for developers to stop running unit tests. (This was another unpleasant experience from a previous project.) One action you can take to mitigate this is to label any test that depends on a database with a "Database Test" categorization. With this in place, it's easy to "ignore" these tests within NUnit. But how can we test the business logic if we're ignoring much of it?&lt;BR&gt;&lt;BR&gt;You can alleviate these problems by leveraging a mock object that &lt;I&gt;simulates&lt;/I&gt; the service in an efficient and predictable manner. Take a look at Challenge2.Tests.MockObjects.Data.MockOrderDao. This class simulates the behavior of the real OrderDao class but returns the exact same results each time. Consequently, it's possible to use this mock object in place of OrderDao to verify that the business logic is working properly. Using mock objects in place of production data-access objects, you won't need to reinitialize the database on each test run. Carry out the following steps to introduce a &lt;A href="http://www.martinfowler.com/eaaCatalog/separatedInterface.html"&gt;Separated Interface&lt;/A&gt; and inject mock objects into your business logic layer for testing purposes.&lt;BR&gt;&lt;BR&gt;
&lt;OL&gt;
&lt;LI&gt;Use the refactoring technique &lt;A href="http://www.refactoring.com/catalog/extractInterface.html"&gt;Extract Interface&lt;/A&gt; on the class OrderDao to create an interface called IOrderDao. Put the extracted interface into Challenges2.Core.DataInterfaces and have OrderDao implement it. (The interface should have just one method called GetOrderPlacedOn.)&lt;/LI&gt;
&lt;LI&gt;Compile and run the unit tests to make sure everything is still working.&lt;/LI&gt;
&lt;LI&gt;A mock object already exists, to simulate this data-access object, found at Challenge2.Tests.MockObjects.Data.MockOrderDao. Have this class also implement the IOrderDao interface.&lt;/LI&gt;
&lt;LI&gt;Within Challenge2.Tests.Core.Services.NightlyOrderLoggerTests, there's a method called CanExecuteNightlyOrderLogger. Within this method, create an instance of MockOrderDao and pass it as a parameter to the method ExecuteNightlyLogging. You'll get a compilation error at this point. This is OK as we want the unit test to drive our code changes.&lt;/LI&gt;
&lt;LI&gt;Add the following two unit test assertion to the same CanExecuteNightlyOrderLogger method: (You'll still be getting compilation errors from the previous step.)&lt;BR&gt;&lt;PRE&gt;Assert.AreEqual(3, summary.AuditorsLogEntryCount);
Assert.AreEqual(4, summary.OwnersLogEntryCount);&lt;/PRE&gt;&lt;/LI&gt;
&lt;LI&gt;Modify the ExecuteNightlyLogging method of Challenge2.Core.Services.NightlyOrderLogger to accept an IOrderDao object. Be sure to use Check.Require to make sure it's not null. The name of the parameter should simply be orderDao. This will conflict with the new instantiation of OrderDao a few lines down. That's expected. Delete the line &lt;CODE&gt;OrderDao orderDao = new OrderDao();&lt;/CODE&gt;. The NightlyOrderLogger is no longer dependent on a concrete service class; e.g. OrderDao. Instead, it only depends on the IOrderDao interface. But developers are still free to use OrderDao directly if they so wish. Now we'll introduce the &lt;A href="http://www.martinfowler.com/eaaCatalog/separatedInterface.html"&gt;separated interface&lt;/A&gt;.&lt;/LI&gt;
&lt;LI&gt;Before proceeding, make sure everything compiles and the unit tests are passing.&lt;/LI&gt;
&lt;LI&gt;Add a new project to the solution called Challenge2.Data. This project will contain classes which communicate with the database.&lt;/LI&gt;
&lt;LI&gt;Move Challenge2.Core.Data.OrderDao to this new project and delete the Data folder from Chanllenge2.Core. (You'll need to add a reference to Challenge2.core from the Challenge2.Data project. While you're add it, also add a reference to Challenge2.Data from the Challenge2.Tests project.)&lt;/LI&gt;
&lt;LI&gt;Finally, repair the namespace reference problems found within Challenge2.Core and Challenge2.Data, compile and confirm that all the unit tests are still passing.&lt;/LI&gt;&lt;/OL&gt;&lt;BR&gt;As an optional, bonus step (and to get your name thrown into the hat twice), pass a mock log4net logger to NightlyOorderLogger in addition to the mocked OrderDao so that log files aren't necessarily generated during unit testing. &lt;/LI&gt;&lt;/UL&gt;So what did we just accomplish? There are a few benefits to what we just did: 1) the unit tests are blazing fast as they don't depend on database communications, 2) the data-access and business logic layers are now loosely coupled, 3) the data-access layer can be easily mocked or even, albeit not likely, replaced with a completely different database communications layer, and 4) developers can no longer introduce new, bi-directional dependencies between the data-access and business logic layers. The last point goes a long way to keeping an application clean, testable and maintainable.&lt;BR&gt;&lt;BR&gt;This refactoring challenge is &lt;I&gt;quite&lt;/I&gt; a few steps beyond the simple, introductory refactorings we saw last week. But I hope I've illustrated that refactoring techniques can not only make a method cleaner, they can also provide direction for refactoring application architecture as a whole.&lt;BR&gt;&lt;BR&gt;Good luck on the challenge and let me know if you have any questions!&lt;BR&gt;&lt;BR&gt;Billy&lt;/DIV&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=746" width="1" height="1"&gt;</description><enclosure url="http://devlicio.us" length="142027" type="application/x-zip-compressed" /><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/Architecture/default.aspx">Architecture</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/.NET/default.aspx">.NET</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/Refactoring/default.aspx">Refactoring</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/Contests/default.aspx">Contests</category></item><item><title>Refactor It! Challenge 1 Results</title><link>http://devlicio.us/blogs/billy_mccafferty/archive/2006/11/20/refactor-it-challenge-1-results.aspx</link><pubDate>Mon, 20 Nov 2006 23:13:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:703</guid><dc:creator>Billy McCafferty</dc:creator><slash:comments>5</slash:comments><description>Congratulations to Rune Rystad who is the winner of &lt;A href="http://devlicio.us/blogs/billy_mccafferty/archive/2006/11/14/refactor-it-challenge-1.aspx"&gt;Challenge 1&lt;/A&gt;! Rune has won a copy of &lt;A href="http://www.awprofessional.com/bookstore/product.asp?isbn=0321246756&amp;amp;rl=1"&gt;Framework Design Guidelines&lt;/A&gt; by Krzysztof Cwalina and Brad Abrams along with a 3-user license pack for &lt;A href="http://submain.com/?nav=products.cio"&gt;CodeIt.Once Refactoring&lt;/A&gt;. (The winner was randomly selected from all correct entries received.) For the record, Jeff Perrin had the first correct submission...so he got his name thrown into the hat twice and gets a nice pat on the back. ;)&lt;BR&gt;&lt;BR&gt;Wow, what a response! There were 21 correct entries out of a total of 25 submissions received before the Sunday night deadline. Due to the number of entrants, if I haven't responded with feedback, you can assume your submission was correct. I was glad to see that people enjoyed working through the challenge and hope you all got something out of it.&lt;BR&gt;&lt;BR&gt;Before digging into the results and the solution itself, I wanted to bring up a couple of notes about refactoring and the challenge itself. There's an important aspect of refactoring that the challenge doesn't illustrate very well: a tenant of refactoring is keeping the code in a working state as much as possible and to only have one unit test failing at a time. Consequently, refactoring should be seen as a process, and not just a before and after state. I'll give an example of this when discussing the example solution. On another note, a couple of entrants brought up the point that there were other smells in the code not mentioned in the challenge description...heck yeah there were! If you've worked with legacy code, and we all have, you'll see smells all over the place. At times, the smells are so bad that it's difficult to make any forward progress with refactoring without feeling that you have to gut the whole thing. In times like these, Michael Feather's &lt;A href="http://www.phptr.com/bookstore/product.asp?isbn=0131177052&amp;amp;rl=1"&gt;Working Effectively with Legacy Code&lt;/A&gt; can be a great resource. These comments have inspired me to include one such example in the the next challenge.&lt;BR&gt;&lt;BR&gt;&lt;B&gt;Interesting Finds&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;Below are a few items of particular interest that were found in the submissions: 
&lt;UL&gt;
&lt;LI&gt;Some created a new class called &lt;CODE&gt;EmailAddress&lt;/CODE&gt; to handle checking the validity of an email address. Although not required for this particular challenge, doing so consolidates the business logic, makes it more reusable and treats an email address as a first class citizen; and it&amp;nbsp;usually should be.&lt;/LI&gt;
&lt;LI&gt;To fix the "magic number" smell in the Customers class, Adam Vandenberg included a clever usage of iterators to get the list of all customers of drinking age:&lt;BR&gt;&lt;TEXTAREA class=c#:nogutter name=code rows=15 cols=50&gt;		/// &amp;lt;summary&amp;gt;
		/// Enumerate only &amp;lt;see cref="Customer"/&amp;gt;s who are of legal drinking age in the USA.
		/// &amp;lt;/summary&amp;gt;
		private IEnumerable&amp;lt;Customer&amp;gt; USADrinkingAgeCustomers {
			get {
				foreach (Customer customer in this)
					if (customer.CanDrinkInUSA)
						yield return customer;
			}
		}
&lt;/TEXTAREA&gt; &lt;/LI&gt;
&lt;LI&gt;Some created a configuration-settings, reader class that centralized the mining of the config file into a single class. This is an example of what Martin Fowler calls a &lt;A href="http://www.martinfowler.com/eaaCatalog/gateway.html"&gt;Gateway&lt;/A&gt;. I thought it was a great idea and have included it in the example solution. (Another good time to use a gateway is when working with data stored in Session.) The major benefit of using this approach is that if the config (or session) keys change, then you only need to change them in one spot outside of the config file.&lt;/LI&gt;&lt;/UL&gt;&lt;B&gt;Smell Refactorings&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;Now let's take a look at &lt;I&gt;one&lt;/I&gt; possible solution to the refactorings. There are many different approaches to the challenge, and many of them are equally valid.&lt;BR&gt;&lt;BR&gt;&lt;I&gt;Smell: Comments&lt;/I&gt; 
&lt;UL&gt;
&lt;LI&gt;Challenge1.Core.Domain.Customer: There were two comments at the top of this class dictating business rules for "age" and "emailAddress." As mentioned before, some entries included an &lt;CODE&gt;EmailAddress&lt;/CODE&gt; class to encapsulate the logic for verifying the validity of an email address. This particular refactoring, unsurprisingly enough, is called &lt;A href="http://www.refactoring.com/catalog/moveMethod.html"&gt;Move Method&lt;/A&gt;. Detailing how this is done, without breaking existing code, you would take the following refactoring steps:&lt;BR&gt;&lt;BR&gt;
&lt;OL&gt;
&lt;LI&gt;Introduce a new method in the &lt;CODE&gt;Customer&lt;/CODE&gt; class called &lt;CODE&gt;IsEmailAddressValid&lt;/CODE&gt;. This method would accept an email address and return whether or not it's valid. This refactoring is called &lt;A href="http://www.refactoring.com/catalog/extractMethod.html"&gt;Extract Method&lt;/A&gt;. This method could then be used to enforce a valid email address in the constructor of &lt;CODE&gt;Customer&lt;/CODE&gt;. Now we can get rid of the comment concerning passing a valid email. But should the &lt;CODE&gt;Customer&lt;/CODE&gt; class really know how to check for the validity of an email address? We'll address this concern after we make sure we haven't broken anything.&lt;/LI&gt;
&lt;LI&gt;Run the unit tests to make sure everything still works as expected.&lt;/LI&gt;
&lt;LI&gt;Create a unit test class, called &lt;CODE&gt;EmailAddressTests&lt;/CODE&gt; for a yet, non-existent &lt;CODE&gt;EmailAddress&lt;/CODE&gt; class. (This class is in the solution as Challenge1.Tests.Core.Domain.EmailAddressTests.)&lt;/LI&gt;
&lt;LI&gt;Add a unit test called &lt;CODE&gt;CheckValidEmailAddress&lt;/CODE&gt; which creates an instance of an &lt;CODE&gt;EmailAddress&lt;/CODE&gt;, passing in a valid email address, as a string, to its constructor. In the unit test, assert that the &lt;CODE&gt;IsValid&lt;/CODE&gt; method of the object returns true for a valid email address. (You're correct if you're asking yourself, &lt;I&gt;what IsValid method?&lt;/I&gt; This is called &lt;A href="http://www.agiledata.org/essays/tdd.html"&gt;test driven development&lt;/A&gt;...we'll let the unit test tell us what code to write.&lt;/LI&gt;
&lt;LI&gt;Copy the code in &lt;CODE&gt;Customer.IsEmailAddressValid&lt;/CODE&gt; to a new method within &lt;CODE&gt;EmailAddress&lt;/CODE&gt; called &lt;CODE&gt;IsValid&lt;/CODE&gt;. Don't remove the duplicate code from &lt;CODE&gt;Customer&lt;/CODE&gt; yet...we want to fix the currently breaking unit test before moving on to anything else. (Incidentally, some entries checked for the email address, validity check in the constructor of &lt;CODE&gt;EmailAddress&lt;/CODE&gt; while others left it to other classes to ask &lt;CODE&gt;EmailAddress&lt;/CODE&gt; if it was valid. Either way may be correct depending on the business requirements and both approaches were considered correct for this challenge.)&lt;/LI&gt;
&lt;LI&gt;Compile and verify that the &lt;CODE&gt;CheckValidEmailAddress&lt;/CODE&gt; unit test is passing.&lt;/LI&gt;
&lt;LI&gt;Add another unit test called &lt;CODE&gt;CheckInvalidEmailAddress&lt;/CODE&gt;, passing in an invalid email address this time, and assert that &lt;CODE&gt;IsValid&lt;/CODE&gt; return false.&lt;/LI&gt;
&lt;LI&gt;Compile and verify that the &lt;CODE&gt;CheckInvalidEmailAddress&lt;/CODE&gt; unit test is passing.&lt;/LI&gt;
&lt;LI&gt;&lt;I&gt;Now&lt;/I&gt;, have &lt;CODE&gt;Customer&lt;/CODE&gt; talk to the &lt;CODE&gt;EmailAddress&lt;/CODE&gt; object directly to determine email address validity instead of the private method &lt;CODE&gt;IsEmailAddressValid&lt;/CODE&gt;.&lt;/LI&gt;
&lt;LI&gt;Compile and run the unit tests again to make sure everything still works.&lt;/LI&gt;
&lt;LI&gt;Delete the &lt;CODE&gt;IsEmailAddressValid&lt;/CODE&gt; method from the &lt;CODE&gt;Customer&lt;/CODE&gt; class and run the tests again.&lt;/LI&gt;&lt;/OL&gt;&lt;BR&gt;The preceding steps&amp;nbsp;included the refactorings &lt;A href="http://www.refactoring.com/catalog/introduceAssertion.html"&gt;Introduce Assertion&lt;/A&gt;, &lt;A href="http://www.refactoring.com/catalog/extractMethod.html"&gt;Extract Method&lt;/A&gt;, &lt;A href="http://www.refactoring.com/catalog/moveMethod.html"&gt;Move Method&lt;/A&gt;, and &lt;A href="http://www.refactoring.com/catalog/decomposeConditional.html"&gt;Decompose Conditional&lt;/A&gt;. No wonder it took so many steps! Although the details of additional refactoring will not be broken down to such detail, I wanted to show how a refactoring is carried out at a lower level. (And if I haven't promoted it enough already, I highly recommend reading Martin Fowler's &lt;A href="http://www.martinfowler.com/books.html#refactoring"&gt;Refactoring&lt;/A&gt; to see each of these refactorings examined in more depth.) The above seems quite tedious, but the entire cycle takes just a couple of minutes and gives you confidently, working code (aka - peace of mind).&lt;BR&gt;&lt;BR&gt;If you've looked at the solution code, you may have noticed calls to &lt;CODE&gt;Check.Require&lt;/CODE&gt; to implement the &lt;A href="http://www.refactoring.com/catalog/introduceAssertion.html"&gt;Introduce Assertion&lt;/A&gt; refactoring. This code calls a wonderful &lt;A href="http://www.codeproject.com/csharp/designbycontract.asp"&gt;design-by-contract class originally written by Kevin McFarlane&lt;/A&gt;. You can read more about it, and design-by-contract in general, &lt;A href="http://devlicio.us/blogs/billy_mccafferty/archive/2006/09/22/Design_2D00_by_2D00_Contract_3A00_-A-Practical-Introduction.aspx"&gt;in a previous post&lt;/A&gt;. Although it seems overkill and unnecessary, sprinkling &lt;CODE&gt;Check.Require&lt;/CODE&gt; all over your code will save you hours upon hours in the debugger. (Just give it a whirl for a couple of days and you'll be convinced.)&lt;/LI&gt;
&lt;LI&gt;Challenge1.Core.Services.EmailService: If I write anything about the comment-smell in this class, I'd create a "duplicated blog content" smell. I.e. see the details of the first point for all the nitty-gritty details.&lt;/LI&gt;&lt;/UL&gt;&lt;I&gt;Smell: Magic Numbers&lt;/I&gt; 
&lt;UL&gt;
&lt;LI&gt;Challenge1.Core.Services.EmailService: There was a hard-coded SMTP server name and email address in the code. The correct solution was to put these values in App.config so that they could easily be changed between development and production environments. Taking it a step further, the example solution includes a new class, Challenge1.Core.ConfigSettings, which provides centralized access to the config settings. A couple of entries suggested this approach.&lt;/LI&gt;
&lt;LI&gt;Challenge1.Core.Domain.Customers: This class also had a hard-coded email address; the previous point's fix also applies to this one. Additionally, this class had a hard-coded value of "21" to represent the legal drinking age in the United States. The refactoring &lt;A href="http://www.refactoring.com/catalog/replaceMagicNumberWithSymbolicConstant.html"&gt;Replace Magic Number with Symbolic Constant&lt;/A&gt; has been used in the example solution to give the number more meaning. I chose to put this magic number into a constant instead of the config file because it is highly unlikely, in spite of how much we tried before we were 21, that this age will change. But the constant's name serves to make the code more readable. Finally, this class had a couple of strings, representing the spam's subject and body, which never changed. Although not implicated before, I've also placed these strings into constants as well. In a real-world situation, these probably would be pulled from a database or flat-file...neither of which I want to get into now! If requirements dictated that either of these be changed in the future, that would be the time to refactor the code to a more maintainable solution.&lt;/LI&gt;&lt;/UL&gt;&lt;I&gt;Smell: Long Method and Complicated Conditionals&lt;/I&gt; 
&lt;UL&gt;
&lt;LI&gt;Challenge1.Core.Domain.Customers: The method &lt;CODE&gt;SendBeerSpamToCustomersOfDrinkingAge&lt;/CODE&gt; has been sliced and diced, using the refactorings &lt;A href="http://www.refactoring.com/catalog/extractMethod.html"&gt;Extract Method&lt;/A&gt;, &lt;A href="http://www.refactoring.com/catalog/decomposeConditional.html"&gt;Decompose Conditional&lt;/A&gt;, and &lt;A href="http://www.refactoring.com/catalog/replaceMagicNumberWithSymbolicConstant.html"&gt;Replace Magic Number with Symbolic Constant&lt;/A&gt; to make it, arguably, easier to understand. The method name &lt;CODE&gt;ConditionallyTrackAndSendSpamTo&lt;/CODE&gt; may seem long, but it fully describes that the method sends spam, conditionally, and tracks any emails that are sent. You should never shorten a method name with acronyms or leave out a responsibility from the name. If you follow this rule of thumb, then long method names may be a sign that a method is trying to do too much. Perhaps we should &lt;A href="http://www.refactoring.com/catalog/extractMethod.html"&gt;Extract Method&lt;/A&gt; again to enable us to make the method name shorter and more concise?&lt;BR&gt;&lt;BR&gt;In carrying out the refactoring &lt;A href="http://www.refactoring.com/catalog/decomposeConditional.html"&gt;Decompose Conditional&lt;/A&gt;, for this class, I introduced the method &lt;CODE&gt;IsHomebrewOrderPurchasedInPastSixMonths&lt;/CODE&gt; to the order class. Now &lt;I&gt;there's&lt;/I&gt; a method name! This is an example of a decomposed conditional taken to the extreme. It perfectly summarizes the conditional in a readable fashion; but it's easy to see that this could get out of hand if we need to add other methods such as &lt;CODE&gt;IsMoonshineOrderPurchasedInPastEightMonths&lt;/CODE&gt;. We could parameterize both the type and the timeframe, but what if we add another variable to the mix...er...mess? If that never happens, then this method may be adequate, but if that very probable situation &lt;I&gt;does&lt;/I&gt; occur, it may be time to refactor to the &lt;A href="http://www.dofactory.com/Patterns/PatternInterpreter.aspx"&gt;interpreter design pattern&lt;/A&gt;. But again, if there's never a need to expand the filtering capabilities for orders, then we needn't invest the time, nor added complexity, of introducing this design pattern. (Down pattern-itus, down! Good dog.)&lt;/LI&gt;&lt;/UL&gt;As I've mentioned, there are many, &lt;I&gt;many&lt;/I&gt; ways to refactor this solution and what I've described is just one of them...with that, I open the floodgates to constructive criticism! ;) To make a preemptive strike, there could be a few more unit tests and the &lt;CODE&gt;Customers&lt;/CODE&gt; class is taking on a few too many responsibilities; but since I've spent way too much time on this post already, I'll leave the remaining smells as food for thought!&lt;BR&gt;&lt;BR&gt;Stay tuned for tomorrow's challenge!&lt;BR&gt;&lt;BR&gt;Billy&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=703" width="1" height="1"&gt;</description><enclosure url="http://devlicio.us" length="35996" type="application/x-zip-compressed" /><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/.NET/default.aspx">.NET</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/Refactoring/default.aspx">Refactoring</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/Contests/default.aspx">Contests</category></item><item><title>Refactor It!  Challenge 1</title><link>http://devlicio.us/blogs/billy_mccafferty/archive/2006/11/14/refactor-it-challenge-1.aspx</link><pubDate>Tue, 14 Nov 2006 21:24:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:592</guid><dc:creator>Billy McCafferty</dc:creator><slash:comments>13</slash:comments><description>&lt;P&gt;For an overview of this contest, read this &lt;A href="http://devlicio.us/blogs/billy_mccafferty/archive/2006/11/13/refactor-it-the-weekly-book-giveaway.aspx"&gt;opening introduction&lt;/A&gt;. Now, onto this week's refactoring challenge...&lt;BR&gt;&lt;BR&gt;As Fowler's subtitle describes, refactoring is about "improving the design of existing code"; an introduction to the subject can be found at &lt;A href="http://www.refactoring.com/" target=_blank&gt;refactoring.com&lt;/A&gt;. This first challenge includes a number of very common smells and straight-forward refactorings to remove those smells. For those of you who are new to refactoring, this particular challenge provides the perfect starting place. For those of who are refactoring guru's, I've got your can of worms coming soon!&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Instructions to Enter&lt;/B&gt;&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Make sure you have NUnit installed; available at &lt;A href="http://www.nunit.org/" target=_blank&gt;http://www.nunit.org&lt;/A&gt;.&lt;/LI&gt;
&lt;LI&gt;Download Challenge1.zip found below.&lt;/LI&gt;
&lt;LI&gt;Open the solution with VS 2005 and compile it.&lt;/LI&gt;
&lt;LI&gt;Open NUnit, go to File/Open, then open &amp;lt;solution directory&amp;gt;/Challenge1.Tests/bin/Debug/Challenge1.Tests.dll. Click run and make sure all the tests pass.&lt;/LI&gt;
&lt;LI&gt;Complete the refactorings as described below. Be sure to follow the style of the code that is already in place: classes, methods and public properties in PascalCase, private members in camelCase, etc. Following the style that's already there is always a good rule of thumb when modifying legacy code.&lt;/LI&gt;
&lt;LI&gt;When finished, make sure all the unit tests are still passing after you've completed the refactorings, zip up your solution and send to &lt;A href="mailto:challenge1@emccafferty.com"&gt;challenge1@emccafferty.com&lt;/A&gt;. As you may only win once, only submit a solution if you'd like to be eligible for the prize.&lt;/LI&gt;&lt;/OL&gt;Up for grabs this week is the following book along with a &lt;A class="" href="http://submain.com/?nav=products.cio" target=_blank&gt;CodeIt.Once Refactoring&lt;/A&gt; tool 3-User license pack!&lt;BR&gt;&lt;BR&gt;
&lt;DIV id=cover&gt;&lt;IMG alt="Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries" src="http://www.awprofessional.com/ShowCover.asp?isbn=0321246756&amp;amp;type=c" width=125&gt; 
&lt;P&gt;&lt;A href="http://www.awprofessional.com/bookstore/product.asp?isbn=0321246756&amp;amp;rl=1"&gt;Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries&lt;BR&gt;&lt;/A&gt;By Krzysztof Cwalina, Brad Abrams.&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Now Refactor It!&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;Below is a listing of smells that need to be fixed within the project. Each point indicates the file that contains the smell, a description of the problem and any guidelines for completing the refactoring.&amp;nbsp; You may find quite a few other smells in the code as well, but only focus on the ones listed here.&lt;BR&gt;&lt;BR&gt;&lt;I&gt;Smell: Comments&lt;/I&gt;&lt;BR&gt;&lt;BR&gt;Not all comments are bad. But many comments are an indication that something is too complex, that a business rule isn't being enforced, or that a method or class is doing too much in one place. Comments should describe &lt;I&gt;why&lt;/I&gt; something is done and not necessarily &lt;I&gt;what&lt;/I&gt; something does unless it's complex and there's no simpler way to do it. Another drawback to comments is that they need to be maintained along with the code. Instead, focus should be put toward making the code speak for itself; this gets rid of the comments and makes it more maintainable. The following are some comment smells found within the code that need to be fixed:&lt;/P&gt;&lt;/DIV&gt;
&lt;UL&gt;
&lt;LI&gt;Challenge1.Core.Domain.Customer: There are two comments concerning the allowable parameters. These comments don't seem to be enforcing much. Enforce these comments and get rid of them to make the code speak for itself. Don't worry about checking to see if the email address is valid. For a hint in the right direction, take a look at the constructor of Challenge1.Core.Domain.Order. (Guideline: Include the refactorings "Extract Method" and "Introduce Assertion.")&lt;/LI&gt;
&lt;LI&gt;Challenge1.Core.Services.EmailService: There's a comment on line 10. How can we get rid of this comment and make the "if" statement which follows a little more understandable? (Guideline: Include the refactorings "Extract Method," "Decompose Conditional" and "Introduce Assertion.")&lt;/LI&gt;&lt;/UL&gt;&lt;I&gt;Smell: Magic Numbers&lt;/I&gt;&lt;BR&gt;&lt;BR&gt;A magic number is a constant which appears in the code itself.&amp;nbsp; There are&amp;nbsp;a few&amp;nbsp;examples of magic numbers in the&amp;nbsp;code that need to be fixed:&lt;BR&gt;
&lt;UL&gt;
&lt;LI&gt;Challenge1.Core.Services.EmailService: There's a hard-coded email address and a hard-coded SMTP server within the method SendEmailTo. &amp;nbsp;(Although not a number, this would still be classified as the Magic Number smell.)&amp;nbsp; If the email address changes or the SMTP server changes, you'll have to make a modification and recompile the entire project. How should this be fixed to make it&amp;nbsp;easier to change these items and to deploy it to various servers?&lt;/LI&gt;
&lt;LI&gt;Challenge1.Core.Domain.Customers: The same type of problem is found at the bottom of the method SendBeerSpamToCustomersOfDrinkingAge. Doh...who programmed this piece of ...!&lt;/LI&gt;
&lt;LI&gt;Challenge1.Core.Domain.Customers: This class contains the magic number "21." How should it be fixed? Is it appropriate to fix it in the same way as the EmailService fix, or do we really need to worry about changes to this number very often? Regardless, this is a magic number which isn't very explicit.&lt;/LI&gt;&lt;/UL&gt;&lt;I&gt;Smell: Long Method and Complicated Conditionals&lt;/I&gt;&lt;BR&gt;&lt;BR&gt;A long method is any method that has more than one responsibility or is too long to understand easily. As a rule of thumb, I try to make sure no method has more than about ten functional lines of code. In practice, I usually find that most of my methods are between three and ten lines long. (As a side note... Taking this to the extreme, is it incorrect to have a method with just one line of code? Not if it helps make your code more explicit and understandable.) In addition to improving readability, short methods make it much easier to spot duplicated code. For the challenge at hand, fix the following smell:&lt;BR&gt;
&lt;UL&gt;
&lt;LI&gt;Challenge1.Core.Domain.Customers: The method SendBeerSpamToAppropriateCustomers is an example of a long method. It has two obvious responsibilities, but it also has a couple of other, subtle responsibilities buried into the conditionals. The comment above the conditional could also be dropped if the conditional were made more explicit. Use the refactorings "Extract Method" and "Decompose Conditional" as many times as appropriate to improve readability and consolidate responsibilities. You needn't introduce any new classes to refactor this method.&lt;/LI&gt;&lt;/UL&gt;To find help or explanations for a particular refactoring, "Extract Method" for example, try googling "extract method refactoring." Good luck and let me know if you have any questions!&lt;BR&gt;&lt;BR&gt;Billy&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=592" width="1" height="1"&gt;</description><enclosure url="http://devlicio.us" length="26755" type="application/x-zip-compressed" /><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/.NET/default.aspx">.NET</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/Refactoring/default.aspx">Refactoring</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/Contests/default.aspx">Contests</category></item><item><title>Refactor It!  The Weekly Book Giveaway</title><link>http://devlicio.us/blogs/billy_mccafferty/archive/2006/11/13/refactor-it-the-weekly-book-giveaway.aspx</link><pubDate>Tue, 14 Nov 2006 04:55:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:575</guid><dc:creator>Billy McCafferty</dc:creator><slash:comments>15</slash:comments><description>&lt;DIV align=left&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN style="WIDTH:100%;TEXT-ALIGN:center;"&gt;&lt;STRONG&gt;Each week, refactor&amp;nbsp;my smelly project and win a free book&lt;BR&gt;along with a &lt;A href="http://submain.com/?nav=products.cio" target=_blank&gt;CodeIt.Once Refactoring&lt;/A&gt; tool 3-User license pack!&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/DIV&gt;
&lt;DIV align=left&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV align=left&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN&gt;&lt;EM&gt;Here's how it'll work&lt;/EM&gt;...&lt;/SPAN&gt;&lt;/SPAN&gt; &lt;/FONT&gt;&lt;/DIV&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV align=left&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN&gt;Each week, beginning tomorrow, Nov. 13, a VS 2005 project will be provided which contains one or more specified "smells."&amp;nbsp; The project may be a Windows App, a Console App,&amp;nbsp;an ASP.NET Web App or even a simple Class Library; but it will always be in C# 2.0.&amp;nbsp; Refactorings may range from simply introducing new methods to applying design patterns.&amp;nbsp; The project will have one or more unit tests, verified with NUnit 2.0, to verify that the project is in working order.&lt;/SPAN&gt;&lt;/SPAN&gt; &lt;/FONT&gt;&lt;/DIV&gt;
&lt;LI&gt;
&lt;DIV align=left&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN&gt;You have until the&amp;nbsp;specified time&amp;nbsp;to submit your zipped, refactored solution.&amp;nbsp; Instructions for submitting your solution will be presented when the contest begins.&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN&gt;&lt;EM&gt;To be considered, the solution must be&amp;nbsp;compilable&amp;nbsp;with all unit tests passing.&lt;/EM&gt; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/DIV&gt;
&lt;LI&gt;
&lt;DIV align=left&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN&gt;The winner will be randomly selected from all "correct" submissions received.&amp;nbsp; (I'll use my 2-year old to pick the name instead of Math.Random to make sure it's truly random!)&amp;nbsp;&amp;nbsp;As there are 1,000 ways to skin a cat - no offense to any PETA readers - "correct" entries will be subjectively determined by yours truly, Billy McCafferty.&amp;nbsp; Along with an announcement of the week's winner, a results summary and&amp;nbsp;refactoring analysis will be presented.&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN&gt;"Correct" can generally be defined as the solution which presents simple, concise, and maintainable refactorings for the specified smells.&amp;nbsp; Other "correctness" guidelines may be provided at the beginning of each challenge.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/DIV&gt;
&lt;LI&gt;
&lt;DIV align=left&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN&gt;To help your chances, the first "correct" solution received will have two names thrown into the hat instead of one.&lt;/SPAN&gt;&lt;/SPAN&gt; &lt;/FONT&gt;&lt;/DIV&gt;
&lt;LI&gt;
&lt;DIV align=left&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN&gt;Only one entry may be submitted for each&amp;nbsp;challenge and,&amp;nbsp;unless specified at the opening of a contest,&amp;nbsp;each&amp;nbsp;participant may only win once.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV align=left&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN&gt;The weekly contest will continue until I get refactoring-itus or I run out of books, whichever comes sooner.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;DIV align=left&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN&gt;&lt;EM&gt;Why refactoring&lt;/EM&gt;...&lt;/SPAN&gt;&lt;/SPAN&gt; &lt;/FONT&gt;&lt;/DIV&gt;
&lt;DIV align=left&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV align=left&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN&gt;Refactoring has been widely adopted as a vital technique for producing high quality software.&amp;nbsp; It is important that we each&amp;nbsp;embrace this practice into our development work.&amp;nbsp; This contest will serve to present an overview of common smells found within code and&amp;nbsp;discuss&amp;nbsp;techniques to correct those smells&amp;nbsp;for creating better software.&lt;/SPAN&gt;&lt;/SPAN&gt; &lt;/FONT&gt;&lt;/DIV&gt;
&lt;DIV align=left&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV align=left&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN&gt;&lt;EM&gt;Resources to help&lt;/EM&gt;...&lt;/SPAN&gt;&lt;/SPAN&gt; &lt;/FONT&gt;&lt;/DIV&gt;
&lt;DIV align=left&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV align=left&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN&gt;The essentials are &lt;U&gt;Refactoring&lt;/U&gt; by Martin Fowler and &lt;U&gt;Refactoring to Patterns&lt;/U&gt; by Joshua Kerievsky.&amp;nbsp; Other&amp;nbsp;resources that may be helpful include &lt;U&gt;Working Effectively with Legacy Code&lt;/U&gt; by Michael Feathers and &lt;U&gt;Patterns of Enterprise Application Architecture&lt;/U&gt; by Martin Fowler.&lt;/SPAN&gt;&lt;/SPAN&gt; &lt;/FONT&gt;&lt;/DIV&gt;
&lt;DIV align=left&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV align=left&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN&gt;&lt;EM&gt;Books up for grabs&lt;/EM&gt;...&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/DIV&gt;
&lt;DIV align=left&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;
&lt;P&gt;&lt;IMG alt="Design Patterns: Elements of Reusable Object-Oriented Software" src="http://www.awprofessional.com/ShowCover.asp?isbn=0201633612&amp;amp;type=c" width=125&gt;&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.awprofessional.com/bookstore/product.asp?isbn=0201633612&amp;amp;rl=1"&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/A&gt;&lt;BR&gt;By Erich Gamma, Richard Helm, Ralph Johnson, John M. Vlissides.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;DIV id=cover&gt;&lt;IMG alt="Essential Windows Workflow Foundation" src="http://www.awprofessional.com/ShowCover.asp?isbn=0321399838&amp;amp;type=c" width=125&gt; 
&lt;P&gt;&lt;A href="http://www.awprofessional.com/bookstore/product.asp?isbn=0321399838&amp;amp;rl=1"&gt;Essential Windows Workflow Foundation&lt;/A&gt;&lt;BR&gt;By Dharma Shukla, Bob Schmidt.&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;DIV id=cover&gt;&lt;IMG alt="Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries" src="http://www.awprofessional.com/ShowCover.asp?isbn=0321246756&amp;amp;type=c" width=125&gt; 
&lt;P&gt;&lt;A href="http://www.awprofessional.com/bookstore/product.asp?isbn=0321246756&amp;amp;rl=1"&gt;Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries&lt;BR&gt;&lt;/A&gt;By Krzysztof Cwalina, Brad Abrams.&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;/STRONG&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;IMG alt="Applying Domain-Driven Design and Patterns: With Examples in C# and .NET" src="http://www.awprofessional.com/ShowCover.asp?isbn=0321268202&amp;amp;type=c" width=125&gt; &lt;/P&gt;
&lt;DIV id=cover&gt;
&lt;P&gt;&lt;A href="http://www.awprofessional.com/bookstore/product.asp?isbn=0321268202&amp;amp;rl=1"&gt;Applying Domain-Driven Design and Patterns: With Examples in C# and .NET&lt;/A&gt;&lt;BR&gt;By Jimmy Nilsson.&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;BR&gt;&lt;IMG alt="Essential ASP.NET With Examples in C#" src="http://www.awprofessional.com/ShowCover.asp?isbn=0201760401&amp;amp;type=c" width=125&gt; &lt;/P&gt;
&lt;DIV id=cover&gt;
&lt;P&gt;&lt;A href="http://www.awprofessional.com/bookstore/product.asp?isbn=0201760401&amp;amp;rl=1"&gt;Essential ASP.NET With Examples in C#&lt;/A&gt;&lt;BR&gt;By Fritz Onion.&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;DIV id=cover&gt;&lt;IMG alt="Essential ASP.NET 2.0" src="http://www.awprofessional.com/ShowCover.asp?isbn=0321237706&amp;amp;type=c" width=125&gt; &lt;/DIV&gt;
&lt;DIV id=cover&gt;
&lt;P&gt;&lt;A href="http://www.awprofessional.com/bookstore/product.asp?isbn=0321237706&amp;amp;rl=1"&gt;Essential ASP.NET 2.0&lt;/A&gt;&lt;BR&gt;By Fritz Onion, Keith Brown.&lt;/P&gt;&lt;/DIV&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/DIV&gt;
&lt;DIV align=left&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV align=left&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN&gt;Stay tuned to &lt;A href="http://devlicio.us/" target=_blank&gt;&lt;FONT color=#3333ff&gt;devlicio.us&lt;/FONT&gt;&lt;/A&gt; and good luck!&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/DIV&gt;
&lt;DIV align=left&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;DIV align=left&gt;&lt;FONT face=Tahoma&gt;&lt;SPAN style="FONT-SIZE:10pt;FONT-FAMILY:Tahoma;"&gt;&lt;SPAN&gt;Billy&lt;/SPAN&gt;&lt;/SPAN&gt; &lt;/FONT&gt;&lt;/DIV&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=575" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/.NET/default.aspx">.NET</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/Refactoring/default.aspx">Refactoring</category><category domain="http://devlicio.us/blogs/billy_mccafferty/archive/tags/Contests/default.aspx">Contests</category></item></channel></rss>