CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Jeremy D. Miller -- The Shade Tree Developer

Under the hood and working with .Net, TDD, Software Design, and Agile Stuff

March 2006 - Posts

  • TDD Misconceptions

    Jeffrey's post on Rocky Lhotka's off the cuff remarks about TDD is spawning a good discussion and several rebuttals.  Several people have gone off on agile zealots as well.  I'm pretty sure I'm included in the zealot bag there.  We all like to think we're one of the reasonable people and everyone else is the crazy zealot, but...

    [EDIT 4/5/2006] Of course I also think the words "jihad" and "zealot" got tossed around far too casually and unfairly.  If you go read Jeffrey's post, he didn't say anybody was a bad developer for not doing TDD, just that Rocky made some erroneous or mistaken statements about TDD.

    Rocky's response here:

    I've seen several common misconceptions, or just plain concerns and doubts, about TDD repeated that I'd like to respond to.  I'll especially pick on Sahil's comment on Rocky's post just because he's Sahil.

    TDD can, and probably should, coexist with other design tools and methodologies.  Rocky and several other people mention they prefer using Responsibility Driven Design with or without CRC cards.  I wholeheartedly agree (but I've never managed to get into CRC cards).  I had an article last year on using RDD to make TDD easier.  Use anything that works for you (I still like to sketch out UML just before coding), as long as testability is always in the forefront of your design thinking.  It will make TDD easier.  Nothing is more difficult to me than just sitting in front of a blank screen trying to figure out how to write that first test. 

    The great thing about TDD as a design tool is that it really enforces loose coupling and high cohesion.  Forcing yourself to write a unit test first, or at least immediately afterwards, makes loose coupling a necessity to retain the hair on your head.  One way to think about it is that testability is frequently an accurate "test" of your design.  External dependencies are always difficult to test, but code that is hard to test usually points to an issue with coupling or cohesion.

    This is close to a cliche and it's already been said several times, but TDD is primarily a design tool.  The fact that the "design specification" is a large body of executable unit tests is an undeniably huge benefit as well.

    Occasionally you'll see a claim that TDD == 0 debugging.  That's obviously false, but effective usage of TDD drives debugging time down and that's still good.  From my experience, when the unit tests are granular the need for the debugger goes way down.  When I do have to fire up the debugger I debug through the unit tests themselves.  Cutting down the scope of any particular debugging session helps remarkably.  The caveat is that you really must be doing granular unit tests.  A lot of debugging usage is often a cue to rethink how you're unit testing. 

    TDD isn't enough testing by itself.  Duh.  I don't think many people are trying to claim TDD does away with the need for testers.  The fact that TDD isn't a comprehensive set of tests doesn't mean that the TDD unit tests don't add a lot of value.  We use a full Taxonomy of Tests, not just our TDD tests.  I've seen a very correlation between the thoroughness of our unit tests and the bug counts in different areas of the code.  Sahil mentions that TDD doesn't directly address concerns like load testing, transactional rules, and concurrency.  Ok, then do some load testing and exploratory testing too.  You can test performance and transactions with TDD, it's just harder.  What TDD excels at is getting the business functionality and mainline logic correct.  Get that out of the way and you should, at least in theory, be able to spend more time on other types of testing for non-functional qualities.

    And the constant stereotype about developers being bad testers, that's just unfair.  It's like saying developers don't have good social skills, wait, nevermind.

    You must write a test first!  I probably write test first about 80-90% of the time.  There's always exceptions.  I certainly don't spend any time writing unit tests for simple getter/setters, especially when they're codegen'ed by ReSharper.  Just use your best judgement.  One rule of thumb I've read from Kent Beck is that you just need to TDD any code that might change.

    We'll have to maintain all of those unit tests.  True, but in general the unit tests should make your code easier to maintain, and not just because of the automated regression safety net.  Unit tests can be a great living document about the system.  The ability to refactor a system safely is priceless.  Now, there is a need to write unit tests well in order to keep them from being a burden.  I've bumped into places where the unit tests were written in such a way that I was afraid to change the code for fear of breaking the unit tests.  It's awfully important to treat your unit test code as something important and keep loose coupling between your tests and the implementation.  That's often a very real complaint about excessive usage of mock objects.  There's more than a little bit of art to writing non-brittle unit tests.

    Just to head the comment off, there might come a day when our programming languages reach a high enough level of abstraction that the usefulness of TDD goes away because the code will perfectly express its intention.  That would be nice, but we'll just have to wait and see.

    I do feel a bit for Rocky on this one and I know that I jumped the gun a little bit.  I think if he'd just gotten to say something like "I haven't done much TDD yet, but here are the things I don't buy about TDD" this wouldn't have been any big deal. 

    As far as being a zealot, yeah I'm definitely going to tone down my blog.  I've never enjoyed working with runaway XP zealots, so I do get the irritation.

  • SomethingManager Classes

    [EDIT] - The key point I was trying to make is to watch out for class names that do not communicate their intention.  If SomethingManager has a specific meaning in your system and your team is happy with it, that's all good.  A code smell means something to be concerned about, not automatically something that is wrong and has to be changed.

     

    Jeff Atwood on Coding Horror has a good post up called "I shall call it.. SomethingManager" that's collecting some good comments as well. 

    C. Keith Ray also had a related post late last year about "SomethingUtility" classes.

    For my part I'd label classes named "SomethingManager" and "SomethingUtility" as a full fledged code smell.  I.e., an indication that something *might* be wrong with your code that requires some of your attention. 

    Ideally all classes have a distinct role and responsibility within the greater system.  That role and responsibility should be reflected by the class name.  Like Keith says, a "utility" or "manager" class might be indicative of a procedural system where class responsibilities aren't being adequately understood or modeled.  If you can't think of a better name for a class than "SomethingManager" it's a sign that you don't fully understand the scope of its responsibility.

    I work with some legacy code that has a lot of catch all utility classes that just lump a lot of broadly related methods together.  The result is a handful of very large classes that have too many unrelated responsibilities and a considerable amount of difficulty in locating code. 

    The analogy I would try to draw is which situation would you rather have, "the gardening shears are on the tool shelf" or "they're in the garage somewhere?"  Figuring out where to put a responsibility in the system in such a way that others could readily find it later is a key exercise in creating maintainable systems.

     

  • When time crawls

    I had one of those days today where you spend a hurtful amount of time just waiting for something to happen.  I'm not terribly patient to begin with, and this stuff is aggravating:

    • Waiting on the CC.Net build and the "Check In Dance."  Keeping the build optimized for speed is important for productivity.
    • The "Tyranny of the Little Green (hard drive) Light" - I haven't gotten my RAM upgrade at work yet and the hard drive thrashing is just awful
    • Having a ReSharper moment.  I shudder to think about coding sans ReSharper, but I can't wait for the background loading in the 2.0 version
    • Switching solutions in VS.Net when all you need to do is make a one line code fix
    • I'm home alone all week and I'm playing my way through DOOM 3 on the XBox.  Just like the original games, the slowest time in the world is waiting on the shotgun to reload while some sort of baddie uses you for a scratching post.

    There you go, my bad coding analogy for the week is that a slow or insufficiently automated build is like being cornered by a room full of Imps without enough firepower.

     

  • Roy Osherove on Testability Design

    Roy Osherove has started a great series called Achieving And Recognizing Testable Software Designs that covers a lot of the main design issues and strategies for Test Driven Development.

    In particular, he describes marking a method as virtual so you can create a subclass specific for unit testing that overrides the virtual method to remove a dependency on configuration within a unit test.  This is a great strategy in certain situations (legacy code and code that is executed within a loop come to mind) that I don't think to use often enough. 

    I'm going to cover some of the same ground soon in "Jeremy's Laws of TDD", but I'd put money on Roy to finish first;)

  • Issues viewing my blog

    I've had a few comments lately that my blog format is cutting off material or hard to read in some cases.  Bear with me a little while and I'll try to address the issues next week.  Please send any suggestions.   
  • One Year Blogging Anniversary, and going dark for awhile

    Today marks the one year anniversary for blogging.  About 125 posts, more that a few rants, and a handful of foot in mouth episodes.  I'll be on vacation in Sydney, Austrailia for the next two weeks so I probably won't be blogging or checking comments (if you were a ten minute walk from a great beach, would you be blogging?). 

    When I do get back, I'm more or less on the hook for:

    • Model View Presenter with WinForms, using RhinoMocks for testing
    • Design Patterns post for a coworker
    • Mock object constraints
    • Mocks and Stubs with StructureMap
    • Some NFit/Fitnesse samples.  Our Austin Agile group has turned into an NHibernate and FitNesse support group.
  • Jeremy's Second Law of TDD: Push, Don't Pull

    Laws of TDD is probably something that should be written by someone with more authority in the community, but I've got a blog and I thought of it first, so here goes.  I'll expound on each of these at some point in the misty future, but just for fun here is Jeremy's Laws of Test Driven Development (I'm certainly not claiming any kind of originality here.  Some of these rules predate TDD anyway).

    1. Isolate the Ugly Stuff
    2. Push, Don't Pull (this post)
    3. Test small before testing big
    4. Avoid a long tail
    5. Favor composition over inheritance
    6. Go declarative whenever possible
    7. Don't treat testing code like a second class citizen
    8. Isolate your unit tests, or suffer the consequences!
    9. The unit tests will break someday
    10. Unit tests shall be easy to setup

    And the overriding "Zeroeth Law" is "If code is hard to test, change it."

    We're told that the key to safe lifting is to "Push, Don't Pull."  Pushing gives you more control over a load, greater leverage, and it is safer and easier for your back.  We can apply the same principle to software development to create code more efficiently.  The goal of "Push, Don't Pull" is threefold:

    1. Making unit tests easier to setup.  
    2. Greater chance of reusing code because of the shorter "tail."
    3. Looser coupling because functionality is isolated from its configuration and/or data store

    One of my favorite quotes about code quality is from Michael Feathers:

    "I don't care how good you think your design is. If I can't walk in and write a test for an arbitrary method of yours in five minutes its not as good as you think it is, and whether you know it or not, you're paying a price for it."

    In many ways I think testability is the ultimate test of code and design quality in the small.  If a class is easy to test it's often because its dependencies are minimized or at least loosely coupled.  A class or method that is hard to unit test is often indicative of a coupling problem.  So back to the Michael Feathers quote, let's talk about how to make unit tests easy to setup and execute.  The easiest test to write is a state-based test where you can easily create the test inputs inside the unit test, execute the code, and verify the results without any external environment setup.  Interaction tests are good too, as long as you can keep the mock object setup to a reasonable level.  In both cases you're pushing the data and any dependencies into the class or method being tested inside the test. Much more difficult is a class that "pulls" data, configuration, or dependencies for itself. To test this code you often have to do much more setup work to get the class to function in a test harness.  Even worse is the possibility that the test probably depends on data that is external to the test.  Understanding a test can be much more difficult if you have to "ALT-TAB" between a sql script, a web.config file, and the test fixture class to relate the inputs of the test to the expected outcome.

    Here's an example of changing "pull" to "push."  We have some code in our system we inherited that is responsible for translating an older flat file format to a new industry standard hierarchical xml format.  It's obviously a vital piece of code in the system that has to be rock solid with tests.  There's a large number of permutations of data that require test scenarios.  I've also wanted to reuse the code in a couple other situations but I couldn't easily do it because the translator code "pulls" too much stuff from the database and it's coupled to a singleton deep in the bowels.  The code is difficult to test because there is all of the extra environment setup necessary to run the translation, both in terms of the database state and configuration around the data access code.  My answer, when we get around to it, is to refactor the translation code so that its data needs are pushed into the constructor function.  The dependency on the singleton can probably be eliminated and moved to an Observer pattern class that will also be injected into the translator class.  Once we get to the point where the translation code is given everything it needs to function, that code will be much easier to test and reuse in different situations because it no longer depends on so many other application services.  We will be able to completely unit test the translation code without ever involving a database.

    When is Now?

    Scott Bellware and I had a conversation at the Austin Code Camp about testing date sensitive business rules.  It's something we take for granted, but the call to DateTime.Now is a tight coupling to the system clock.  Say you want to create a static set of test data that should exercise a set of business validations against the Invoice object below.  The test data might be stored in a flat file (we're talking testers here), an xml file, or database tables.  The point being that the dates in the test data are static.  In order for the tests to function the same way going forward we need a way to fake the system clock to make the test behave like the current date is the day the test was created.  You could fiddle with the system clock, but that'll make the tests harder to run.  An easy solution is to push in the "Now" time into the OverdueInvoiceProcessor.ProcessOverdueInvoices(DateTime) method like the code below.  I've used this technique before to great effect, but there's another approach at the very bottom of the post that I like better now.*

        public class Invoice
        {
            private DateTime _invoiceDate;
            private string _invoiceNumber;
     
     
            public Invoice(DateTime invoiceDate, string invoiceNumber)
            {
                _invoiceDate = invoiceDate;
                _invoiceNumber = invoiceNumber;
            }
     
            public DateTime InvoiceDate
            {
                get { return _invoiceDate; }
                set { _invoiceDate = value; }
            }
     
            public string InvoiceNumber
            {
                get { return _invoiceNumber; }
                set { _invoiceNumber = value; }
            }
        }
     
     
        public class OverdueInvoiceProcessor
        {
            public void ProcessOverdueInvoices(DateTime nowTime)
            {
                // do stuff
            }
        }
     
        public class OverdueInvoiceProcessorTester
        {
            [Test]
            public void ProcessOverdueInvoices()
            {
                setupTestData();
                setupExpectations();
     
                OverdueInvoiceProcessor processor = new OverdueInvoiceProcessor();
                processor.ProcessOverdueInvoices(new DateTime(2006,3,1));
     
                verifyTestResults();
            }
        }

    Dependency Injection

    Dependency Injection is a common stratagem for creating testable code.  Most classes will depend on other classes to perform other actions or gather information.  Typically a class has created its own dependencies when it has needed them.  The call to the "new Dependency()" constructor function of a concrete class is a hidden form of tight coupling.  If the dependency is something that is hard to test against, or you need looser coupling between the server and client, you'll want to push in the dependency object with some sort of Dependency Injection. 

    Here's a class called Client that uses ServiceProvider within its DoSomething() method.  In this incarnation, Client cannot function at all unless the ServiceProvider class is completely configured with all of its dependencies.

        public class ServiceProvider
        {
            public void ProvideService()
            {
                // Provide the Service
            }
        }
     
        public class Client
        {
            public void DoSomething()
            {
                // Needs a ServerProvider, so it just creates one as its needed
                ServiceProvider provider = new ServiceProvider();
                provider.ProvideService();
            }
        }

    Here's the same class, but this time use Dependency Injection to "push" in an IServiceProvider argument to its constructor function.  Client simply executes with the IServiceProvider member that it is handed.  The IServerProvider could be a mock object, a stub, the original ServiceProvider, or some totally new implementation of IServiceProvider.  Simply by inverting the control over dependency location we've greatly increased the testability and potential reuse for the Client class.

        public interface IServiceProvider
        {
            void ProvideService();
        }
     
        public class Client
        {
            private readonly IServiceProvider _provider;
     
            // Client is not responsible for instantiating an instance of IServerProvider
            public Client(IServiceProvider provider)
            {
                _provider = provider;
            }
     
            public void DoSomething()
            {
                _provider.ProvideService();
            }
        }
     
        [TestFixture]
        public class ClientTester
        {
            [Test]
            public void DoSomethingHappyPath()
            {
                // Mock IServiceProvider with RhinoMocks
                MockRepository mocks = new MockRepository();
                IServiceProvider provider = (IServiceProvider) mocks.CreateMock(typeof(IServiceProvider));
     
                // Setup expectations on the mock object
                mocks.ReplayAll();
     
                Client client = new Client(provider);
                client.DoSomething();
     
                // Verify the expected interactions between Client and IServiceProvider
                mocks.VerifyAll();
            }
        }

    Use the Lowly Builder Pattern

    Builder Pattern - "Separate the construction of a complex object from its representation so that the same construction process can create different representations." 

    I'm not entirely sure what the original GoF definition means, but the Builder design pattern is a simple and effective way to isolate logic from the mucky details of configuration and persistence.  Think of it this way, when a rock band like Aerosmith is playing a concert they don't set up the sound stage, unload the instruments, and plug everything together.  The roadies and the concert crews put all of the stage and equipment together.  Aerosmith just has to swoop in, pick up the instruments that are waiting**, and play the show.  A Builder class is like the concert crew.  The Builder's only job is to put together everything that another class needs in order to do its work.  The great advantage of using a Builder pattern is to isolate business logic away from logistical code.  We can concentrate on making the Aerosmith classes work first and get the desired functionality working, then create some roadie classes to handle the logistics later.

    Here's an example that's taken from work my team did last year to rewrite a custom rules engine component.  We had to work a couple months with the legacy component a little while and ran into some significant trouble:

    1. The input data had to be put into the database.  The rules engine absolutely could not run except by pulling information from the database.  The database tables in question had a lot of referential integrity.  The overhead cost of setting up test data was substantial.
    2. The rules had to be placed in a SOAP serialized xml file that the rules engine expected to be at a certain absolute path.
    3. There was no way to programmatically configure rules and test data inside the test harness.

    There was a large number of permutations of rule configuration and test data that needed to be executed.  By forcing us to load up test data in a database and create and move around separate rules configuration files (that weren't human readable) around made for a tremendous amount of friction in development.  When we built the replacement we were able to dramatically improve this situation by separating configuration away from the basic processing engine.  The processing engine is given the correct rule objects and data.  All it has to do is execute the rules and coordinate the resulting actions.  All services are attached through either Dependency Injection or a Service Locator, so it's relatively easy to substitute mock or stub objects in testing.

    Let's say your building a system to automate the fulfillment of drug prescriptions.  When a prescription order is made a series of Event-Condition-Action rules need to be executed to determine actions to take based on the patient's medical history, prescription, and insurance coverage.  Here's a "before" skeleton of the implementation that could be difficult test.  The prescriptions to examine have to be pulled from the database.  The rule objects are assembled from configuration of some sort.

        public class Patient
        {
            public string PatientId;
            public DataSet MedicalHistory;
        }
     
        public class Prescription
        {
            public string Id;
            public string PatientId;
            public string PrescriptionType;
        }
     
        // Interface for the prescription rules
        public interface IPrescriptionHandler
        {
            void ProcessPrescription(Prescription prescription, Patient patient);
        }
     
        /// <summary>
        /// The initial version that "Pulls" rules and data as it needs it inside the processing
        /// This version is much more difficult to test because of the tight coupling with
        /// the database and the rules configuration
        /// </summary>
        public class PrescriptionRulesEngine1
        {
            public void ProcessPrescriptions(string prescriptionId)
            {
                // Fetch the Prescription object from the persisted database data
                Prescription prescription = fetchPrescription(prescriptionId);
     
                // Fetch the Patient object from the persisted database data
                Patient patient = fetchPatient(prescription.PatientId);
     
                // Query the database for a list of all the IPrescriptionHandler objects that handle
                // this type of Prescription
                IPrescriptionHandler[] handlers = fetchRelatedHandlers(prescription.PrescriptionType);
     
                foreach (IPrescriptionHandler handler in handlers)
                {
                    handler.ProcessPrescription(prescription, patient);
                }
            }
     
            private Prescription fetchPrescription(string prescriptionId){} 
            private Patient fetchPatient(string patientid){} 
            private IPrescriptionHandler[] fetchRelatedHandlers(string prescriptionType){}
        }

    Now, here's a second implementation that follows the "Push, Don't Pull" law.  In this version the rules engine accepts an array of IPrescriptionHandler objects in the constructor and works on the Prescription and Patient objects passed into the ProcessPrescription() method.  This version makes new rules far simpler to test because you can create an instance of an IPrescriptionHandler rule object and the input data completely inside of an NUnit test fixture class and validate the results.

        public class PrescriptionRulesEngine2
        {
            private readonly IPrescriptionHandler[] _handlers;
     
            // The IPrescriptionHandler[] array is pushed in through the constructor
            public PrescriptionRulesEngine2(IPrescriptionHandler[] handlers)
            {
                _handlers = handlers;
            }
     
            // All the Prescription and Patient data is pushed in through the method
            public void ProcessPrescription(Prescription prescription, Patient patient)
            {
                foreach (IPrescriptionHandler handler in _handlers)
                {
                    handler.ProcessPrescription(prescription,  patient);
                }
            }
        }
     
     
        public class PrescriptionRulesEngineBuilder
        {
            // Assemble the proper array of IPrescriptionHandler objects for the requested PrescriptionType
            public PrescriptionRulesEngine2 CreateRulesForPrescriptionType(string prescriptionType)
            {
                throw new NotImplementedException();
            }
        }

     

    Configuration & Persistence Last

    One of the pieces of advice I try to give to people that are new to software design is to concentrate on creating functionality first, and worry about configuration second.  Let the business functionality drive the need for configuration.  Trying to create the configuration, or persistence for that matter, at the same time as the business logic can just cloud the issue.  Focus on one responsibility at a time.

     

    * There's an easier alternative for date sensitive testing that might be more intention revealing anyway.  We have a lot of business rules that are date sensitive like "Invoice shall be rejected if older than # days."  Inside of unit tests you just set up test data by saying "DateTime invoiceDate = DateTime.Now.AddDays(-30)."  In our FitNesse acceptance tests we've coded the fixtures to translate "(today+-#)" into the date relative to the current time as the test is executed.

    InvoiceFixture
    Invoice Date Invoice Start Date
    (today-5) (today)
    (today-30) (today+1)

    **Here's a story for you Austinites out there, when my wife and I first moved to Austin I begged her to go see Billie Joe Shaver play at the Saxon Pub.  Malford Milligan (Storyville lead singer) was tagging along just to help the band carry in their sound equipment.  I'm betting Aerosmith doesn't have to do that anymore.  It was a hell of a show by the way.  RIP, Eddy.

     

     

  • Things we talked about at the Austin Code Camp

    This past Saturday was the Austin Code Camp.  I had a great time and the general consensus was that it was a success.  Kudos to Jeffrey for organizing the event.  I just wanted to follow up with some links to resources that were mentioned in talks and try to tackle a few questions.  Other than one Ron Burgundy moment in my code smells talk, I thought things went pretty smoothly.  I'll definitely submit only one talk next time though.  The content for all the presentations and the sample code will be posted at http://adnug.org.

    Depressing, but Common Comments

    • How can I convince my management to let us do [insert process or practice here]? 
    • Schedule trumps everything

    We heard from several people who are working in less than ideal circumstances in shops that don't really do things well.  I don't mean "they stink because they aren't doing pure XP exactly like Kent Beck says," or "they're CMM level 1!" if you prefer.  I'm talking about shops that aren't even using source control or aren't doing any kind of unit testing or most importantly, developers are getting crushed with too many hours.  Yes, schedule trumps everything, but I loved the line my colleague, Steve Donie, used in his talk - "I don't have time to sharped my saw, I'm too busy cutting wood!"  If you're in a position like that at a company with poor software development approaches, you've got two choices:

    1. Be a self-starter, learn about better ways to build software that would help your shop, and try to be an agent for positive change.  If you can do this, my hat's off to you.
    2. Vote with your feet and jump ship to a better shop.  You might get to learn a lot more at a shop with good practices and strong developers.  I learned a heck of a lot more when I jumped out of a dysfunctional development organization into a very strong software consulting company.  Both about coding and about software craftsmanship in general.  I wasn't the dominant technical talent anymore, but it was a lot more fulfilling.

    As far as selling management on new practices, I don't have a clue.  What we've learned in the last year is to just do it.  Don't wait for permission, start doing more build automation, crank up the test automation, and control your own work practices whenever you can.  All most management cares about is productivity anyway. 

    Code Smells

    I wrote a longish blog post last year about removing little code smells from your code as you go:  Use a refactoring checklist to pay down Technical Debt as you work

    More Stuff on Dependency Injection

    Model View Presenter, A.K.A. "The Humble Dialog Box"

    This pattern for organizing user interface logic came up several times, and for good reason.  It's the best way that I know of for creating a user interface code base that's easy to test and maintain.  At some point in the nearish future I've promised another post on using MVP for WinForms development.  In the meantime, try these links for more:

    Books I Mentioned

    There's never time to read everything, but here's a rundown of the books I mentioned or recommeded during the talks.

    1. Refactoring by Martin Fowler - The canonical work on refactoring, but a great book on coding in the small as well
    2. Refactoring to Patterns by Joshua Keriesvky
    3. Applying UML and Patterns by Craig Larman - Still my pick for a great introduction to Object Oriented Programming.  I think the latest version scales back the RUP stuff.
    4. Working Effectively with Legacy Code by Michael Feathers - Best book I read last year
    5. The Pragmatic Programmer

     

More Posts

Our Sponsors

Free Tech Publications

This Blog

Syndication

News

All opinions expressed here constitute my (Jeremy D. Miller's) personal opinion, and do not necessarily represent the opinion of any other organization or person, including (but not limited to) my fellow employees, my employer, its clients or their agents.

About Me

"Best Of" Compendium

StructureMap (Dependency Injection for .Net)

StoryTeller (Supercharged Fit)

Build your own Cab

TestDriven

MVP