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 2007 - Posts

  • I'm "code complete" on StructureMap 2.0! Release to follow.

    The real release will be over the weekend, but I'm calling myself "code complete" for now on StructureMap development for the long delayed 2.0 release.  If you're curious, the bits are in SVN at https://svn.sourceforge.net/svnroot/structuremap/trunk.  I'll make a much longer set of release notes later, but at a high level:

    • Fullblown support for Generics including "auto-wiring"
    • Ease of use
    • Much, much more flexible configuration options
    • Make composite applications and configuration merging easier
    • New Fluent Interface API for programmatic configuration and component wiring (it turned out much differently than the previous blog post though)
    • DRY'ed out and streamlined Xml configuration.  Express the same configuration with much less xml
    • Plugin ASP.net UserControl's (it's in the Trunk Jeffrey, but it's strictly programmatic at the moment)
    • Use the Prototype pattern
    • Bug fixes of course
    • Little bit better runtime diagnostics

    I'll post several tutorials on the blog post for both the new features and some old features that are probably overlooked.  I occasionally get asked the advantage of StructureMap compared to the other tools, so I think I'll finally get around to that one. 

    Before the release, I still have to:

    • Update the Xml comments for public API's
    • Update the schema documentation
    • Fix a build script problem
    • Wrestle with SourceForge.  I'm debating with myself whether or not I want to move StructureMap to somewhere else in the long term.  I think Tigris is a lot easier to use, so that's a possibility.

     

     

     

    I did get a last minute feature request for better Setter injection support that I'll try to pick up very shortly.

     

     

    And thanks to Ayende for a tip on Generics support - just the comment was enough actually.  The basic support wasn't that bad, but it played havoc with the diagnostic code.

  • Dispassionately Disregard Sunk Costs while Making Architectural Decisions

    From Wikipedia,

    In economics and in business decision-making, sunk costs are costs that have already been incurred and which cannot be recovered to any significant degree.

    In regards to software, I think of a sunk cost as a piece of existing infrastructure that's already completed or purchased.  It's effort, time, or money that you can't get back.

    More germane to making architectural decisions, read this section from the Wikipedia article:

    Economists argue that sunk costs are not taken into account when making rational decisions. In the case of the movie ticket, the ticket buyer can choose between the following two end results:

    1. Having paid the price of the ticket and having suffered watching a movie that he does not want to see, or;
    2. Having paid the price of the ticket and having used the time to do something more fun.

    Choice # 1 is using a bad architecture, framework, or component in the next software project because you've already bought it, paid for it, or built it.  Choice #2 is jettisoning that same architecture, framework, or component and using or building something that does work for the next software project.  Obviously this choice is complicated by the third choice of sinking more time/money/resources into improving the existing architecture, framework, or component to make it more feasible to use.  The learning curve to move in a new direction is also a rational consideration.  One way or another, the decision to keep an existing platform or do something else has to boil down to economics, and economics only.

    Throw it Away!

    I'm as bad as anyone in the world about forming emotional attachments to my technical ideas and frameworks.  Some pride in your workmanship is a very good thing, but our past work can often cloud our judgement in new situations.  Some of the worst design choices I've made have resulted from taking a design or library from project A and using it on project B.  Can you walk away from your current framework or architecture when a better idea comes along?  Will you allow yourself to consider other solutions?  Are you going to shoehorn your pet approach into any new situation?  More pertinent, is there a better, newer solution or technology out there that is better for your next project?  Because if there is, you might be better off throwing away your existing technology.  At a minimum, it's harmful for us to get blinders on about our choice of technical direction.  Venkat Subramaniam and Andrew Hunt did a great podcast on .Net Rocks that addressed this very subject.  Paraphrasing Andy Hunt, sometimes the smartest thing you can do is throwing your old code away.

    Some of the problem is political

    Wait, but it makes sense to use what we know!  Yes it does, absolutely.  But you've also got to factor in what the rest of the development world knows.  Niche or proprietary technologies come with some cost in regards to team composition.  Your ability to bring in new people is much better if you use more common technologies and techniques -- especially for commodity

    In another real world scenario, let's say that you discover that your data access strategy simply can't keep up with scalability requirements anymore.  I walked into a political buzzsaw one time in regards to a system that was known to have very sluggish performance and scalability concerns with its database access.  I looked at the system and suggested that we ditch the awful CSLA persistence implementation in favor of something simpler and more efficient (they were doing a *lot* of string concatenation with VB6's "&" operator and Xml manipulation inefficiently with the MSXML 1.0 library).  Even if we had the manpower to do it, the political heat would have been too intense to take on that rework because adopting CSLA in the first place had been the previous answer to performance problems.  How do you get up in front of management and tell them that the thing we need to do most is rip out and replace the very thing that your immediate predecessor had sold as the silver bullet?  At that point the software development team has very poor credibility (you must protect your credibility with the business).  We didn't really have any choice but to keep on going with the code the way that it was.

    From the same employer, here are two more examples of sunk costs.  In first example the sunk cost played too heavily in their decision making.  In the second example the sunk cost was ignored in our decision making. 

    1. A very large inventory management system was purchased, but not implemented for a couple of years.  The cost of purchasing that software was "sunk," there was no way to get that money back out.  Deploying and implementing that system for real involved a huge (200 people at its peak) effort.  People slept in cots in the team room.  The team had to customize the hell out of that application to make it fit the way the business worked.  Two years later we were still struggling with how to integrate other applications to the inventory system because it didn't have any kind of service layer or extensibility model.  The upgrade path was completely shot because of the customization.  Support was a nightmare because of those very same customizations.  I still think that they would have been better off writing off the cost of purchasing the software and looked for a different solution that better fit the business.
    2. A very large and wellknown consultancy (no names, but you *know* who I'm talking about) walked in and implemented a 3rd party supply chain system for fulfilling factory requests for material from logistics partners.  Again, the 3rd party system did not reflect the way the manufacturing company ran their supply chain (we needed to support a "pull to order" model).  The consultants brought in the script kiddies and hacked together some Perl scripts around the 3rd party system to kind of make it work.  Within 6 weeks of going live it was obvious that the system could not support the business transaction volume and lacked functionality that the business wanted.  The business partner and I hashed out a concept for a 100% complete replacement built from scratch.  We felt that the existing system was a complete wash and just needed to be thrown away altogether.  An 8 person team implemented the new system in a little under 6 months.  At one point I had measured the throughput of the new system to be almost 2 orders of magnitude better than the 3rd party system predecessor (simply by not being stupid in the database access).  To this day it's still the most successful project I've ever done (and no, it was not an Agile project.  More of a "going through the motions waterfall" with me working every weekend process).  

    In the previous two cases there were non-technical political hurdles.  In the first example the political costs were too high to change direction and the organization blundered ahead.  Some of the management doing the project had been responsible for choosing the 3rd party software in the first place.  It's near impossible to make rational decisions inside a "blame" culture when political considerations get far too much weight compared to costs and benefits.  You've got to be able to stand in front of management and say "the choice we made was wrong, we need to go another direction" without fear.  I look at it from the standpoint of an "Individual Contributor" and worry about trusting management enough to do that without getting my legs taken out underneath me.  From management's side, they need the transparency to make rational decisions.  Politics are definitely bad for rational decision making.

    Speculative Design is a leading cause of Sunk Costs

    I think a huge source of waste is speculative design and construction of infrastructure.  Building foundational infrastructure too far ahead of business need greatly increases the chance that you're building the wrong things.  The answer is YAGNI at an organizational level.  Don't buy software you don't need right now.  Don't build frameworks you're not going to use right away.  Efficiency of effort, and a reduction in unnecessary or hurtful sunk costs, can be achieved by only creating code or infrastructure in response to an immediate business requirement.  Infrastructure you don't end up using is waste.  Infrastructure code that doesn't end up solving the eventual business problems efficiently is waste. 

    One last example to illustrate this point about speculative design.  A couple years ago I was on a goofy little project to retrofit a very large ASP.Net application with the company's new standard security framework.  The new security framework had been built by a centralized team of architects and senior developers working outside of any business driven project.  You know what's coming next.  The framework didn't really meet our needs out of the box and I suspect that it took much longer to write code around the framework in order to use it than it would have cost to build the security enhancements that the business did want in the existing application.  You can argue that a standardized framework could potentially reduce support costs across the family of applications, but the real reason we used it was because it was the "standard" that had been built.

    My contention is that they would have been much better off building the security framework specifically for that one application in response to its requirements first, then trying to harvest reuse later.  Centralized framework teams can get themselves and the organization as a whole into trouble fast if their work doesn't solve the actual business problems.  The fact that the centralized team often has political might behind it to enforce the usage of their tools can only make the situation worse.

  • The only thing I miss from VB6

    There was some VB6 abuse from me & other commenters yesterday.  I gotta say that I do miss one thing (maybe two):

    1. Intellisense for enumerations was better in VB6 than VS & C#
    2. With/End With - sorta
    I can't think of anything good to say about COM/COM+/DCOM.  They can stay dead to me. 
  • Metaprogramming with JavaScript

    JavaScript, even more so than VB, has to be the Rodney Dangerfield of programming languages.  I'm going to blow whatever credibility I might have by saying "I actually like programming in JavaScript."  I'm actually building a lot of the screens in StoryTeller with JavaScript running in a WebBrowser control because I think I can do dynamic layout much faster with JavaScript than a WinForms screen.  Besides, the point of a "side" project is to do stuff you don't get to do at your day job.

    Check out this link from AdamLogic.  Granted, I don't see a bunch of people running out to write applications in JavaScript alone, but I think Metaprogramming is going to become more common in the near future.  I'm intrigued by all the ways people are creating little lexical languages to make the code get closer to the actual problem domain.  Little ol' JavaScript is actually decent for building little embedded languages and using Metaprogramming.

    As a thought exercise last year, I played around with using RoR style declarative metaprogramming with JavaScript classes to see if I could build DHTML controls and widgets faster.  Take the example of a JavaScript control that has to create and control an internal hierarchy of DOM elements.  Here was my attempt to pull some of the grunt work of DOM manipulation up into a common superclass:

    function act_as_compound(target){

        target.appendNamedChild = function(name, tag, props){

            var child = document.createElement(tag);

            this.appendChild(child);

     

            // EDIT:  removed the eval() call

            this[name] = child;

     

            if (props != null){

                Object.extend(child, props);

            }

     

            return child;

        }

     

        target.appendSpan = function(name, props){

            return this.appendNamedChild(name, 'SPAN', props);

        }

     

        target.appendDiv = function(name, props){

            return this.appendNamedChild(name, 'DIV', props);

        }

     

        target.appendButton = function(name, props){

            var btn = this.appendNamedChild(name, 'button', props);

            return btn;

        }

     

        return target;

    }

    As an example, here's *part* of a Pager class I'm using inside StoryTeller.  The Pager control is a DIV element with 4 child buttons and a SPAN element to show the current page.  The usage of "acts_as_compound" inside Pager looks like this:

    function Pager(pager, controller){

        if (!pager){

            pager = document.createElement('div');

        }

     

        // Metaprogramming constructs -- add in the methods to support the

        // compound element

        act_as_compound(pager);

        controlled_by(pager, controller);

     

        var pageFunction = function(){

            controller.goToPage(this.pageNumber);

        }

     

        // Use the methods on act_as_compound to add child elements to the parent div

        pager.appendButton('firstButton', {innerHTML: '|<', pageNumber: 1});

        pager.appendButton('previousButton', {innerHTML: '<<'});

        pager.appendSpan('pageSpan');

        pager.appendButton('nextButton', {innerHTML: '>>'});

        pager.appendButton('lastButton', {innerHTML: '>|'});

     

        pager.buttons = [pager.firstButton, pager.previousButton, pager.nextButton, pager.lastButton];

        pager.buttons.each( function(button){

            button.controller = controller;

            button.onclick = function(){

                this.controller.goToPage(this.pageNumber);

            }

        });

     


     

     

        return pager;

    }

    In particular, look at a single call to "appendButton."  That method does a couple different things.  It creates a new button element, sets any of the properties ({innerHTML: '|<', pageNumber: 1} is effectively an anonymous object ala C# 3 defined in JSON), then use the eval() method to set a new member on the Pager object to the new button like this:  this.firstButton = btn;  Other methods in the Pager class contain code like "this.firstButton.enabled = true."

    If you're interested, this JavaScript control is in the StoryTeller SVN repository in the folder:  http://storyteller.tigris.org/svn/storyteller/trunk/src/StoryTeller.JavaScript/GreenJello.js.  All of the JavaScript in StoryTeller leverages the Prototype library.

     

    And yes, this is definitely a case of Safety (C# 2) versus Power (JavaScript or any other dynamic typed language + Obj C & C# 3 to some degree).

     

    P.S.  If you puked as soon as you saw the word "JavaScript,"  make sure to clean up;) 

  • New Client, New Project - What do you want to know?

    I'm starting at a new client in a couple weeks.  Last time I did this I created My Gameplan for Starting a New Project.  I think it mostly held up with a few exceptions, mostly around the quality of the upfront analysis leading into the initial story list.  I think next time I'd like to get just a bit more time and much more access to the business experts for building up the initial story list and release estimates.  Last time I was worried about the effects of Analysis Paralysis and gaining momentum early.  I want to revisit that just a little bit and think about the questions I want to ask my new client team right off the bat:

    • What constitutes success for this project?  What's the primary goal?
    • What's the iron triangle constraints?  Time, resources, or scope?
    • Who are the stakeholders?  End users?  Who's paying for this thing?
    • Who are the business and technical experts that we'll need at some point?
    • How much contact and interaction are we going to be able to have with the end users and business experts?  Are we going to have a customer representative or advocate embedded onto the team?
    • What are the legacy systems we'll need to interact with?  I want to know the challenges around the legacy system or existing infrastructure -- and you know there's always something nasty about a system of any age. 
    • What external teams are we going to need to interact with?
    • Is the team self contained (testers, analysts, developers, and a PM all together under a single organizational structure and team), or is the testing team in a completely separate organization?  Obviously, I think the first choice is far superior in terms of results and efficiency, but you gotta play the cards you're dealt.
    • Obviously, I'm going to try to use Agile practices (mostly XP with some Scrum flavoring).  Is that acceptable to you?  Do you have any experience with a disciplined iterative approach (waterfall is still by far and away the most common SDLC)?  What kind of project management practices do you use today?  How about development practices?  I would try to use Continuous Integration and Test Driven Development no matter what, but other practices can be harder to sell or do in non-Agile organizations.  As an immediate example, I want to do Acceptance Test Driven Development anytime the analysts and testers can and will play along (I think we can in my next project, but couldn't on my current project).
    • A very important question:  can the team exert a great deal of control over their practices and process?  Or are they bound by a corporate standard?
    • Assuming that you can control your own process, what are your pain points today in your existing process?  Theoretically as a consultant, you're supposed to do something to add value ;-)
    • Where's the build server, and can I and the team have full control over it?
    • What is your policy towards using Open Source software?  Obviously I'd never advocate any tool under a viral license, but how about less restrictive licenses?  Do I get my head chopped off for suggesting OSS tools when they're superior to the built in or nonexistent Microsoft offerings?
    • What is it that you're not telling me?  It's worth a shot ;-)
    • Can I get my laptop in the network?  More importantly, what am I not supposed to do on your network.  Never hurts to ask.
    • You are using Subversion right?

     

    What'd I miss?

  • More testing code than production code is typical, but don't let that stop you

    Ian Cooper recently wrote about the Ratio of test code to production code.  Ian is saying that he's routinely seeing a 1:1 or even 1.5:1 ratio of test code to production code.  From my experience with TDD, that's about normal.  Some kinds of code will go even higher.  For example, any kind of significant recursive functionality will make the ratio go throught the roof (a Visitor/Composite pattern combo is central to StoryTeller.  That jacks up the test code LOC relative to the real code LOC significantly).

    All I want to add to Ian's post is that that number should not discourage newcomers to TDD.  All those lines of code are not created equal.  Unit test code does not take anywhere near the same amount of concentration or care as production code.  I say that mainly because unit test code is composed almost entirely of stand alone methods.  They don't interrelate or interract with each other.  The responsibility of a unit test is almost always the same:  setup data, do something, check the results.  The hardest thing about coding is deciding what to code, not the mechanical act of typing.  The hard part of writing a unit test is deciding what the real code is supposed to be doing , then codifying that specification in the unit test.  Since you'd be doing that specification work in your own head or a document anyway, all you've added is the mechanical work to type it out in a unit test method.

    TDD is cost effective when and if the effort you put into writing the tests is less than the corresponding effort would have been for the manual unit testing and additional debugging that you dodge by having comprehensive unit test coverage.  Add in the hard to quantify advantage from the qualities of orthogonality that TDD all but requires (testability design is mostly about creating orthogonality between the pieces).  Plus, if you're good, time spent TDD is also time spent doing design in the small and hopefully creating a useful and human readable set of documentation about the fine grained details of the code.
     

    And while I'm thinking about it, the whole "Who tests the tests" issue?

    A.)  Keep your unit tests as simple, concise, and readable as possible to help catch problems by inspection

    B.)  Just pay attention to what you're doing

    C.)  What Phil Haack said in the link above about the code testing the tests and vice versa.  I find most unit test bugs when the test fails and the code seems perfectly right.

  • I wish I'd written this post...

  • The Don't Repeat Yourself Principle and the Wormhole Anti-Pattern

    Getting back on track with the "Maintainability" series of posts.  I'm doing this way too late at night, so the coherence might be lacking.

    Don't Repeat Yourself

    Don't Repeat Yourself (DRY) is a statement exhorting developers to avoid duplication in code.  Duplication isn't always the easiest thing to spot or even prevent.  From the Pragmatic Programmers:

    DRY says that every piece of system knowledge should have one authoritative, unambiguous representation. Every piece of knowledge in the development of something should have a single representation. A system's knowledge is far broader than just its code. It refers to database schemas, test plans, the build system, even documentation.

    Duplication is an obvious problem for maintenance, but there's a secondary meaning to the DRY Principle.  When I'm adding an all new feature to a system with new classes, database mappings and tables, new screens, web services, etc. I want to make the change with the fewest steps possible with a minimum of repetition.  I want to tell the system what I want to happen, and I want to say it only once.  More on that second meaning later.

     

    Duplication Retards Change

    For the upcoming (soon, knock on wood) StructureMap 2.0 release, I got in and added support for generic templated types.  It was nasty.  It wasn't really nasty because of Generics, it was nasty because I blundered with this innocuous looking code:

        return _pluginType.FullName;

    In some spots it was useful or necessary to identify a .Net Type with a string value and early on I fell into using the full class name as a convention.  I then promptly duplicated that simple Type.FullName logic over 70 times in the codebase.  Flash forward 3 1/2 years to the new Generics support, and I needed a way to go from a string to a type.  The obvious answer was to finally change to using assembly qualified names.  It took me about 6-8 hours total to make that one little change because of the stupid amount of duplication I had introduced with the FullName logic.

    Some other cases:

    • Multiple applications, or even subsystems of the same system, reading and writing to a shared database.  You almost inevitably end up with duplicated work to read, write, validate, and interpret the exact same data.  Think about a column in a database that represents the status of some sort of work item.  The logical entity represented by this row has different constraints and business rules depending upon what the value in that status column.  If you have more than a single piece of code that "knows" how to interpret that status value, you have duplication, and a particularly pernicious sort of duplication because it's hard to spot by looking at any one codebase.  Just as a warning, coding in a data-centric manner can open the door to a great deal of harmful duplication.  Ask yourself, if the database structure or status field changes, how many other pieces of code have to be changes? 
    • Reading and writing values from the HttpContext in ASP.Net.  This little bit of code represents a great deal of potential duplication (even if you eliminate the Magic Number Antipattern):  string something = (string) HttpContext.Current.Session["something"];  What if you want to change your state management strategy altogether?  You'll have to change every single piece of code that dipped directly into HttpContext.
    • In .Net applications, you often need to use a subclass of System.Text.Encoding when converting byte arrays to strings or vice versa.  In an application I worked with there were 67 different references to the ASCIIEncoding class.  Why do I distinctly remember this number you might ask?  Because we needed to localize the application to a Unicode encoding and I found out quickly that the change was going to lead to considerable change and effort to hunt down and make all the necessary changes.  If the character conversion code had been more centralized into some sort of helper class, that change could have been easier.

     

    Stop Duplication in its Tracks

    The worst case I've ever observed was a factory automation system.*  The system was originally built to pull upcoming factory build jobs from a MQSeries queue, go through a series of business rules, then determine the proper routing and push the new directions to other MQSeries queues.  Fine and dandy, until the day that the factory needed to start the basic process manually from a client application on the factory floor.  The developers decided to recreate the business rules portion of the existing code, rule by rule, and created a new implementation of the business rules for the new client.  I spent some time learning about both components, and it was very apparent that the new code was better structured, but trouble was right around the corner.  It's easy to guess what happened next.  Those particular business rules were volatile, but only now you had to make functionally equivalent rules changes in two very different components.  The system became harder to maintain and extend.

    The duplication was created purposely because the team felt that the original code was just too hard to reuse because the business rules and the workflow was deeply intertwined with the code that called into MQSeries.  They didn't have any test automation to catch regression bugs, and the system was hard to deploy, so modifying the existing code was quite risky.  If the original code had been much more orthogonal between business rules and the communication infrastructure, they might have been able to simply write some new glue code to interact with the existing code.  If the system had been backed up with a software ecosystem of effective build automation and comprehensive test automation coverage, the team would have been much better positioned to morph the existing code into a structure that would allow for reuse between both the automatic MQSeries mechanism and the newer manual client process.

    Part of the reason duplication creeps into code is the ease of copy/paste/modify operations to create new code.  Runaway "IDE inheritance" (copy/paste/edit coding, I couldn't find a link) can lead to a system that's very difficult to maintain.  Sometimes developers do the copy/paste/modify trick because the original code isn't quite what they need in the second case.  It definitely requires some skill and experience, but in the "not quite what I need" case, I'd much rather a developer take a little time to refactor out the common pieces first before making the second set of changes.  Refactoring is perhaps more work than copy/paste in the short term, but stamping out duplication can only help in the longer run.  Refactoring is an invaluable skill that's well worth your time.

     

    The Wormhole Anti-Pattern

    Bill Caputo wrote a good description of the Wormhole Anti-Pattern that so commonly afflicts enterprise software systems.  Roughly stated, I would define the wormhole as all of the stages a piece of data goes through to get from the database to the screen or service interface and back again.  When the wormhole gets long and involved, your development work is going to be a struggle -- hence the "Anti-Pattern" designation.

    As an almost canonical example, my first official job in software was supporting a data integration between a third party engineering application and a downstream construction application.  Between the two databases, a flat file report, two rule files, and the Tibco definitions, I counted 8 different variable names and mappings for a single piece of data along the data exchange.  The big problem was that I had to change that mapping pretty frequently -- and that meant following the path through all 8 steps.  Needless to say, that code was very difficult to troubleshoot and modify.  Of course I made all of the modifications in production to support ongoing engineering projects because there wasn't any such thing as a development environment;)  If you're a thrill seeker, nothing is more exciting than coding in the production environment while it's live.

    To apply the Wormhole Anti-Pattern to your architecture efforts, think about how many steps you would have to go through to get a new element on a screen persisted in the database.  Or to add a new feature to your application.  If the thought of jumping through a lot of Xml configuration hoops or database metadata setup or the sheer number of changes gives you pause, you may be exhibiting the Wormhole Anti-Pattern.  At that point you need to start working towards eliminating or combining some of the steps to shorten your wormhole.

    Just for comparison, we had to add some fields to a screen after it was built one week.  Here is the wormhole we have to go through on my current project.  I've had worse, but this is more than enough:

    • Element on the screen
    • Property on a Domain class
    • Property on at least one Data Transfer Object (DTO)
    • Mapping from  DTO to Domain class in the client
    • Repeat on the server side, but differently
    • Change unit tests
    • Add new field to FitNesse tests

     

    In line with the Wormhole Anti-Pattern, you might also check out the Shotgun Surgery code smell.  If you constantly make a repetitive set of changes to the same classes anytime one changes, it might be a sign that you should shorten your Wormhole by collapsing the class structure down into fewer pieces to consolidate related code into a more cohesive structure.  Your goal is to enable changes to your application to be made in fewer mechanical steps.

     

    I only want to tell you this once!

    Going back to the previous section on The Wormhole Anti-Pattern, the second, more proactive goal of the DRY Principle is to express changes in as few steps and places as possible.  My thinking in regards to the quality of a  system architecture has changed quite a bit from my brief exposure to Ruby on Rails.

    From Nico Mommaerts,

    One of the selling points of Rails is that it is built with the DRY principle in mind. DRY stands for Don't Repeat Yourself, meaning that every piece of your system is described once and only once, which should make development and maintenance a lot easier since there is no need to keep multiple parts of the code in sync. Hand in hand with DRY goes 'Convention over Configuration', another one of Rails' core philosophies. Rails uses a set of code and naming conventions that when adhered to eliminates the need for configuring every single aspect of your application. Only the extraordinary stuff needs to be configured, like legacy database schemas or other resources you don't control. Using these two philosophies, DRY and 'Convention Over Configuration', Rails lets you write less code AND more features in the same time as with a typical Java or .NET application, with easier maintenance afterwards.

    Even if you're never going to code in Ruby or build web applications, take a look at how Rails puts the various pieces together to eliminate repetition in code and configuration.  A good design allows for minimizing the amount of repetitious information.

    DRY-ing out StructureMap

    After seeing how Ruby on Rails works, it made StructureMap feel just a little shabby in some places.  Here's a specific example, one of the features in StructureMap is the ability to define configuration profiles and easily switch between them.  Typically, I like to use this feature to handle environmental differences between development, testing, and production.  There's a lot more to the functionality, but for now let's just look at the configuration needed for just a single IService today. 

    Look how ugly this is in general (couldn't get CopyAsHtml to format this for some reason), and the duplicated information between the Profile nodes, the PluginFamily nodes, the Plugin nodes, and the Instance nodes.

    <StructureMap MementoStyle='Attribute' DefaultProfile='Development'>
    <Assembly Name="SomeAssembly"/>

    <Profile Name="Production">
    <Override Type="SomeAssembly.IService" DefaultKey="Production"/>
    </Profile>

    <Profile Name="Testing">
    <Override Type="SomeAssembly.IService" DefaultKey="Testing"/>
    </Profile>

    <Profile Name="Development">
    <Override Type="SomeAssembly.IService" DefaultKey="Development"/>
    </Profile>


    <PluginFamily Type="SomeAssembly.IService" Assembly="SomeAssembly">
    <Plugin Type="SomeAssembly.ConcreteService" Assembly="SomeAssembly" ConcreteKey="Concrete"/>

    <Instance Type="Concrete" Key="Production">
    <Property Name="host" Value="PROD-SERVER"/>
    <Property Name="port" Value="5050"/>
    </Instance>

    <Instance Type="Concrete" Key="Testing">
    <Property Name="host" Value="TEST-SERVER"/>
    <Property Name="port" Value="5050"/>
    </Instance>

    <Instance Type="Concrete" Key="Development">
    <Property Name="host" Value="localhost"/>
    <Property Name="port" Value="2000"/>
    </Instance>
    </PluginFamily>

    </StructureMap>

    A major part of my work for StructureMap 2.0 has been ease of use, and that has meant eliminating the duplication and mechanical steps in configuration.  Below is the exact equivalent of the profile in StructureMap 2.0:

     

    <StructureMap MementoStyle="Attribute" DefaultProfile="Development">

     

      <Assembly Name="SomeAssembly"/>

     

      <Profile Name="Production">

        <Override Type="SomeAssembly.IService">

          <Instance PluggedType="SomeAssembly.ConcreteService,SomeAssembly" host="PROD-SERVER" port="5050"/>

        </Override>

      </Profile>

     

      <Profile Name="Testing">

        <Override Type="SomeAssembly.IService">

          <Instance PluggedType="SomeAssembly.ConcreteService,SomeAssembly" host="TEST-SERVER" port="5050"/>

        </Override>

      </Profile>

     

      <Profile Name="Development">

        <Override Type="SomeAssembly.IService">

          <Instance PluggedType="SomeAssembly.ConcreteService,SomeAssembly" host="localhost" port="2000"/>

        </Override>

      </Profile>

     

    </StructureMap>

     

    All I really did was enable a user to make all the configuration inline in the Profile node itself.  Just doing that took down the number of moving parts and centralized the semantic meaning of the profile configuration into one spot instead of being spread out throughout the Xml file.  The underlying model of StructureMap is unchanged, only the configuration code got more sophisticated to streamline the user experience.

     

     

    More than the Code

    Anytime you talk about improving the way you create software it's very hard to treat coding, design, process, and infrastructure as separate topics because they're all tightly intertwined.  You definitely want to apply the DRY Principle to your change management.  Here are a couple examples of what I mean:

    • Long lived code branches.  A temporary branch that's short lived for production support or a risky change is one thing, but a long lived branch essentially represents a whole new system.  I've seen a couple smaller product companies jeopardize their very existence by maintaining and extending customer specific branches of their system.  Hot fixes and newly demanded features often had to be implemented several different times on somewhat divergent versions of the same code.  Long lived branches need to be treated as a last resort.  If there's any possible way to arrange your system to allow for customer specific features and customizations while maintaining one version of the core code, your company will be far better off.  Microkernal designs with IoC engines (like StructureMap) can help.  Orthogonal code will help by creating plenty of seams to allow for customization.  Build and test automation makes changing code much less risky.
    • WSDL or XSD schemas for integration.  We hit this on my current project.  Our new .Net client communicates with the existing Java server platform by sending Xml messages over a stateful socket.  Quite naturally, we devolved into using XSD schema's to describe the contract of the messages.  Great, we use the XSD.exe tool in .Net to codegen DTO classes on one side, and JAXB to do the same on the Java side.  Both codebases need to have a copy of the XSD's, and that's what we did.  A copy in the .Net SVN repository and another in the Java CVS repository.  Needless to say, any change in schema from either side requires the XSD's to be copied back and forth.  This situation has caused us no small amount of pain from mismatches in the Xml definitions.  One way or another, the XSD definitions from .Net to Java need to be locked together automatically to shut down the potential discrepancies.

     

     

    The Highlander Puts it all into Perspective

    Bellware thought this was an awful analogy, so I absolutely have to use it.  If you're a big fan of the cult movie Highlander (and who isn't?), this will put it all into perspective.  The main characters in the movie were all striving to be the last one standing to win the "Prize."  As Christopher Lambert and Sean Connery intone constantly throughout the movie, "there can be only one!"

    The Don't Repeat Yourself Principle is "There can be only one!" (expression of any rule or functionality that could conceivably change)

    Unfortunately I've been on and seen a couple projects where the basic architecture just didn't allow for outwardly small changes to be made efficiently.  A nasty case of a Wormhole, plus clumsy or inefficient build processes, can make the simple addition of an extra piece of information from persistence to user interface turn into a living hell.  In the Highlander, there is a scene where the bad guy, the "Kurgan" played by Canadian character actor extraordinaire Clancy Brown, wins a sword duel and disembowels Sean Connery's character.  As the Kurgan twists the sword to inflict more pain he utters the line "it hurts, doesn't it!"  When a request for a small change comes across your desk and all you can think about is all of the painful and tedious work it will take to get that change done, that's what I call the "Kurgan Moment."

    To wrap up, the Highlander and DRY good, Kurgan and Wormhole bad.

     

     

    Appropos of nothing here, Locke is easily the best character on Lost.

  • Really fast way to get a StackOverflowException

    From some StoryTeller work this morning after using a ReSharper "Lift Superclass" refactoring:

            public Test Test

            {

                get { return Test; }

                set { Test = value; }

            }

    If NUnit ever goes really, really wacky on you and starts to fail, StackOverflowException is a likely candidate. I found this one quick fortunately.

  • MVP Summit Recapped: Linq for Entities, MonoRail, and Shameless Name Dropping

    Just to get this out of the way, here is my recap from the MVP summit.  You will find something to argue about here, and that's okay.

    LINQ for Entities is NOT the O/R Mapper I want today, but might be if and when they...

    As it stands right now, I would still choose NHibernate (or WilsonORMapper) over Linq for Entities as an O/R Mapping solution, especially since it looks very likely that we'll have Linq support for NHibernate as well.  That's a little disappointing because there is a lot of promise to Linq for Entities.

    At the MVP Summit, the Microsoft team building Linq for Entities very graciously spent some time with several of us to talk over some of the details around making LINQ for Entities more suitable for Domain Driven Design and evolutionary design.  Specifically, we were largely concerned with the intrusiveness of Linq for Entities into your Domain Model classes, the general clumsiness of the configuration model as it is right now, and the mechanisms for tracking object state.  There is definitely some very cool things in Linq for Entities, but it's a shame that the usability isn't there yet.

     

    What I don't like:

    • It does not support a Persistence Ignorant approach.  This is fairly significant to me.  I'm in the camp that really doesn't like any infrastructure code in my business logic classes.  It's also a Signal to Noise problem, the only signal I want to care about is the business logic.  Anything else is noise code.
    • The configuration is too complex because it exposes that 3rd conceptual model. 
    • The "changed" state of the persisted objects is tracked in the objects themselves with a marker interface somewhat like the INotifyPropertyChanged interface.  I really, really don't like this.  I don't like the implicit black magic idea of managing the change state inside of the objects themselves.  I think it adds noise code and makes the transaction boundaries less clear.
    • As of now, Linq for Entities is optimized out of the box for a datacentric approach that calls for designing the database model upfront and then codegen'ing the object model from the database.  This isn't the way I want to work because this approach almost forces you into a heavier upfront design.  We've already got a dozen+ workable solutions for datacentric application building.  I wish they'd delivered a solution upfront for Domain Driven Design to differentiate it more from Linq to SQL.
    • Attributes in the domain model classes.  I'm not sure I have a hard opinion on using attributes for the mapping, but the attributes for Linq for Entities are a duplication of the Xml configuration.  It's a violation of the DRY principle of good design.

    What I want:

    All of these "wants" were promised to us in a post-Orcas release.  I'd like to lay these out here to get more visibility for these "wants" to make sure they get a better place on the Linq to Entities roadmap.

    The first thing I want is support for a pure Persistence Ignorant approach.  No marker interfaces, no codegen, no partial classes.  Just plain "POO."

    The next thing is support for the Unit of Work pattern.  Transaction boundaries are important details.  I want the contents of a transaction explicitly defined, and expressed in a way that is easy to test.  Enter the Unit of Work:

        public interface IUnitOfWork

        {

            void Added(object target);

            void Deleted(object target);

            void Updated(object target);

            void SubmitChanges();

        }


    The configuration model is somewhat divorced from the configuration format already (this was a huge lesson I learned with StructureMap), so we should in theory begin to write alternative configuration formats.  The first thing I would do is create a simplified format that completely hides the conceptual model from the user.  Next, maybe think about a "convention over configuration" approach ala ActiveRecord in Ruby.  I think you could also find a way to generate DDL from an object model the way that you can with NHibernate. 

    Evolutionary or Continuous Design

    I'm a practicing XP'er and a believer in the benefits of using Continuous Design, but it doesn't just come for free.  The obvious objection to Continuous Design is the risk of churn and the cost of changing code, and we try to beat this by purposely choosing tooling that enables easy evolution of a software design.  I'll say this and let the arguing start:  it's significantly easier to evolve the design of the object model first, then let the database drop out from the object model (and then optimized!) only when the object model is solidified.  I want to be able to quickly add properties, rename properties, and add methods to evolve little by little.  I can lean very heavily on refactoring tools and fast running unit tests to make small, evolutionary changes in middle tier code.  C# is soft.  Even with the Agile Database Techniques described by Scott Ambler, the database structure is still more work and effort to change in comparison. 

    I don't want to codegen my domain model classes.  Having your classes split into a pair of partial classes or an abstract class with data elements and a subclass with logic is clumsy to me.  I think that code is harder to understand because of the "CTRL-TAB" factor switching back and forth.  I also don't like having to fire up a modeling tool to make a change, then depend on the compiler to find all the other code I've busted by changing the signature of the model.  Again, I want to lean on ReSharper and my unit tests for little changes.

    What's Cool about Linq for Entities?

    As David Laribee pointed out, Linq for Entities is much more than an O/R Mapper.  It potentially provides us with a unified data access strategy over heterogeneous data sources (web services, xml, non relational databases, etc).  That's great if it succeeds, but that strategy, IMO, has added quite a bit of complexity that's fully exposed to the end users in the form of 3 way mapping (object model, conceptual model, and relational model).  The conceptual model only adds value for mapping non-relational data (I'd say it's Gregor's Canonical Data Model pattern).  If it succeeds and they address the ease of use and POO issues, Linq to Entities could be really good.

    Other things:

    • The underlying database mappers are emitted rather than using reflection
    • It supported every reasonable mapping scenario I could think of to ask about
    • I love the Linq query language to express queries in terms of the Domain Model with Intellisense

    If Linq for Entities should fail, it's going to be an object lesson.  Instead of choosing one major use case first (O/R Mapping) or focusing on the user experience, they put a huge chunk of work into the foundational architecture.  Fine, but at this point Linq for Entities is like a giant big block V8 engine mounted to a weak transmission.  The raw power is there, but it's clumsy to use it in my opinion. 

    What about LINQ for SQL/DLINQ? 

    By and large I actually like DLINQ, but it's not really aimed at the same scenarios as a fullblown O/R Mapper.  In my mind, DLINQ looks like an evolutionary improvement over strongly typed datasets, and applies to basically the same scenarios where a DataSet would be acceptable.  DLINQ is specifically targeted for very data centric development, so I don't think you would want to try a rich domain model approach with it.  I would consider using it for reporting applications, simple CRUD applications, data services maybe, and most immediately for writing automated tests against a database with FIT.  In the end, I think I would describe DLINQ as putting Intellisense on top of the database model.

    Mapping to Stored Procedures

    Yes, you will be able to map entities to stored procedures, and I'm seeing people working through how to do this.  I'm going to make a fearless prediction:  mapping to stored procedures will take significantly more mechanical work than mapping entities directly to database tables and columns.  I don't want to rehash the sproc arguments yet again, but keep in mind the mechanical cost of using sproc's in this case balanced against any kind of perceived value. 

     

    MonoRail is a Watershed Moment for the .Net Community

    I think MonoRail is a huge, huge deal for the .Net community.  Finally, we have an application framework that comes from the community that provides a great deal of value and enables a development style that Microsoft does not.  If you're not already familiar with it, MonoRail is an open source Model View Controller framework for web development.  As you can probably tell, it's somewhat influenced by Ruby on Rails.

    First, let's look at the simplified page cycle in MonoRail (and Rails):

    1. A web request is made.  A Front Controller takes the request first, then using the url of the request, chooses the appropriate action method on a  controller class to call.
    2. Call the action method on a controller
    3. The controller makes any necessary updates
    4. The controller builds a model of some sort
    5. The model is passed into a view for rendering

    There are a lot more details, and I've over simplified a lot, but compare and contrast this to the WebForms page cycle of events.  The MVC nature of MonoRail encourages and even enforces a consistent separation of concerns between the controller and view templates.  MonoRail is also much, much easier to unit test than the equivalent pages in a WebForms application - even with a Model View Presenter structure.  You can test a MonoRail application with less friction because it is much more decoupled from the runtime.  The lifecycle of a MonoRail page is much more in tune with the reality of a web page, so there's much less "leak" in its abstractions.  That in turn makes TDD more valuable as a way to model the actual behavior of the code.  You can MVP the life out of a WebForms page, but you still end up twiddling with the page events to get everything just right.

    More, in no particular order:

    • As an architecture, ASP.Net WebForms has some serious weaknesses in regards to testability and maintainability.  The attempt to abstract web development as a stateful forms based model simply does not work very well.  I thought WebForms was a brilliant idea in 2001, but in use I think it adds far too much heft to development tasks that used to be easy in ASP classic.  It's not just me that feels this way either, a number of the people I spoke to at the MVP Summit shared the same general feeling that the WebForms model just isn't the right direction.  Plus, so does:
    • It's community driven.  It's being built by the very .Net developers that use it, without any assistance from Microsoft.  Read that again.  .Net developers, in the field, are building this thing to suit the way they want to work.  We do not have to wait for Microsoft to do everything for us.  I met a lot of smart people at Microsoft, but they're just as human as you and I, and there's not an infinite number of developers at Microsoft to build everything we could possibly want.  MonoRail is not bound to the Orcas release cycle, so it can move at a much faster rate than something bundled up into the official .Net platform.
    • It represents innovation from outside of Redmond, and we could always use more innovation that in the .Net community.
    • My esteemed CodeBetter colleague, David Hayden, recently compared and contrasted MonoRail to the new Web Client Software Factory.  The WCSF might reduce the mechanical cost of generating the initial code with WebForms and add some better practices like MVP and DI, but MonoRail will still have a potentially large advantage in terms of any type of architecture with WebForms:  Testability & Maintainability.  Over any length of time, these two "ilities" lead to lower Total Cost of Ownership and a better Return on Investment.  The software factory codegen features are cool, but ROI and TCO are sexy to management.
    • As you might have read on Jeffrey's blog post, Scott Guthrie is working on a new concept for a true MVC framework for ASP.Net.  I liked what ScottGu demonstrated, but there's absolutely nothing concrete planned at the moment.  No expected dates, no commitment.  What I'm getting at here is that there is no reason to bypass MonoRail in the near future if you want an MVC framework that provides a high degree of testability and productivity.  Besides, would it really hurt to have some serious diversity in the tooling and approaches you can take for building dynamic websites in .Net?
    • In comparing WebForms to MonoRail think on this.  MonoRail might need some things added to it (documentation, extra features, etc.) to catch up in some spots, but WebForms needs complexity ripped out.  Guess which option is easier - adding or removing complexity?

     

    The latest Hanselminutes podcast is an introduction to MonoRail with the Eleutian guys.  I would highly recommend you give it a listen for some background (I was in the room while they recorded it.  You can blame any background noise on me).

    There, are you happy Hamilton?   Anything big I missed?

     

    Other Observations

    • Big UML is Dead!  Long live Little UML! - Nobody was talking about large scale UML designs anymore.  Executable UML didn't even come up in the talks that were skirting on Model Driven Architecture.  I still think UML is useful, but only in a lightweight whiteboard modeling sense or as documentation after the fact.  One thing that Sam said that I heartily agree with is to be somewhat precise about UML notation when you do use it to avoid misunderstandings.  If you want to go fast, you need to be clear.  I still think I can teach another developer everything they really need to know about UML in 15 minutes.
    • Domain Specific Languages - This was a huge topic all week.  I liked the talk we saw from Don Box on this subject.  One thing he made clear was that DSL's represent an attempt to raise the abstraction level for very specific problems.  Another point I wish he'd made louder is that DSL's do not automatically equate to new modeling dialects or custom Xml formats (coding in Xml, been there, done that).  A lexical DSL written in near English is arguably easier to understand, and probably to write.  I didn't get a chance to talk to him much, but Neal Ford was there representing the Ruby angle on DSL's.  Look for a book from him and some other fatbrain Thoughtworkers on embedding your own DSL's in Ruby soon.
    • Queries are a Business Concern - Ayende said it first, and many people I spoke to thought so too.  There are a lot of business rules embedded into "where" clauses.  I really like the idea of moving this business logic to business logic classes.  I think it reduces the intellectual overhead of understanding a system by gathering related logic into a single place.

    Name Dropping

    I wasn't gonna do this, but everyone else is, so why not?  The MVP Summit was a great experience.  The official content was so-so, but the people I got to interact with were tremendous.  In no particular order, and I'm sure I left someone out:

    I finally met more of the CodeBetter gang - Karl Seguin, Darrell Norton, Raymond Lewellan, Jeff Lynch, and Greg Young.  Plus new CodeBetter addition Jean Paul Boodhoo.  My old Austin friends Scott and Jeffrey were there, as was CodeBetter dean Sam Gentile.  I spent a lot of time around the flower of Des Moines, Iowa development Nick Parker, Tim Gifford, and Javier Lozano.  Somebody let a Google guy in.  I finally met Scott Allen of OdeToCode fame.  Ian Cooper came over from the UK.  I had to go all the way to Seattle to finally meet Don Demsak and David Laribee.  I spoke quite a while with TShak, and Mario Cardinal is a life long friend for asking me about StructureMap.

  • Linq for NHibernate

    I am putting a post together on what we saw from Linq to Entities this week, but let's just say that  I thought the only compelling technical advantage it had over NHibernate is Linq queries.  One of the smart aleck comments somebody made was that Ayende would probably add a Linq frontend to NHibernate over a long weekend.

    Apparently I'm prescient, so scratch that query language advantage soon, 'cause Ayende is doing Linq for NHibernate.

     

     

  • More from the MVP Summit: Go forth and see the world!

    There are obviously exceptions, but as a whole, the entire .Net community would be much better off if we would collectively pay more attention to and interact more with other development communities and traditions.  I was somewhat agitated at the obvious feelings of novelty and excitement when features or technologies were demonstrated yesterday at the MVP Summit that have been available in other products and languages for years (IntelliJ, Eclipse, or even ReSharper).  I've paid attention to the Java world for quite awhile and Agile Java is undoubtedly the primary influence on Agile .Net, but the last couple years have really opened up my eyes to the tools and techniques from other communities (Ruby, etc.).  We've got a lot to learn, and steal, from the rest of the world.  Ignorance, Microsoft blinders, and a bit of an echo chamber effect in .Net are hurting our community.

    Software development is still a young profession that's in a state of constant flux and it's just not smart to put your head in the sand.  I'm seeing plenty of clients that make their development projects more difficult than they have to be because they just don't know about existing tools or better techniques.   "Not Invented Here" isn't just caused by cleverness and arrogance run amok, it's mostly attributable to just not knowing what's out there.

    Yeah, I know, we all want work to end at 5 pm.  But development is the profession we chose, and if constant learning doesn't suit you, it's time to move onto something else.  I know the day will come when I don't want to keep up anymore.  If nothing else, go be the kind of project manager that tells his/her developers that they understand their job because they coded in COBOL (VB6/ASP/PL/SQL for me) back in the day. 

  • Software Factories at the MVP Summit

    I've been dubious about software factories for a long time, but I'm coming around a little bit.  I see factories mostly being useful as just a bit more than what people already do today with things like CodeRush.  I think it would be a helpful mechanism for small scale skeletal code generation for things like Model View Controller generation and automatically creating a test class to match any new concrete class (basically, Scaffolding in Ruby on Rails).  The big hangup that I have with software factories is that I think some atrociously bad systems are going to be created by blindly following the "guidance" from the software factory.  Also, *who* is building the guidance in these software factory thingies?  Are they really good enough to do that?  Is my system really suitable for a generic set of patterns? 

    Many of the worst blunders that I've seen have been a result of choosing a complex pattern too early on and motoring ahead without reflection.  Software factories is going to promote this behavior.  I think the inevitable Achilles heel of software factories, and planning for reuse upfront in any sense, is what happens when you get a case that doesn't fit the previous pattern?  In that case following the model leads to bad code.  Plus that little "the model needs to change" thing that happens from feedback and learning.  There are always edge cases that will break the model.  You cannot ever stop thinking, dammit!

    • In so many words, somebody in the Software Factories talk brought up Case Tools.  Jack Greenfield handled it fairly gracefully, but still...
    • Jack Greenfield is really smart and well spoken.  I'm still iffy on factories though.

    Jeremy's prognosis:  The useful parts could probably be done with CodeRush.  Everything else, we'll see.  I'm not jumping up and down in excitement.

  • Jay's TDD QuickStart, and the underlying problems he stumbled into

    Jay Kimble, CodeBetter's resident AJAX guru, issued a little challenge to us TDD bloggers about using Test Driven Development to develop a custom extension to the MS Ajax ScriptManager control.  In the comments, Jeff Perrin (you need to blog more Jeff) proposes a solution that's about what I would have suggested -- remove most of the functionality to a "POO" class that isn't coupled in any way to the ASP.Net runtime.

    I think the most important things to know or think about upfront before transitioning to TDD are:

    • There is a way to write an automated test for almost any piece of code, including the user interface itself (the idea that the GUI can't be tested is somewhat a myth)
    • The biggest part of driving code through the tests is thinking through *how* you're going to split up the responsibilities of the code to be able to easily write unit tests *before* you commit to writing code.  I know a lot of people blanch at the thought of doing things just for testing, but a lot of making code testable is simply a strong focus on separating responsibilities into cohesive and loosely coupled modules.  Basically, traditionally good design in general.
    • Assume that you will have to change the way you code in order to make writing the unit tests easier.  Maybe you won't, but you should still have an open mind and be prepared to challenge the way that you write code.
    • Specific to .Net, the "Visual Studio way" of creating code often detracts from testability.  More on this below.

     

    Laying down the Law

    Back to Jay's issue, let's try to apply some of Jeremy's Laws of TDD.

    1. Isolate the Ugly Stuff.  In Jay's case the ugly stuff is anything related to the ASP.Net runtime.  Following law #1, boil the "meat" of the real functionality away from the "bones" of the ASP.Net runtime.  Now, the functionality can be tested without all the overhead of a web server. 
    2. Push, Not Pull.  In Jay's control, divide the responsibilities into two pieces.  The control itself is only responsible for handling the interaction with the ASP.Net runtime and delegating to the "POO" class that actually implements the functionality.  If the "POO" class is given everything it needs to do the work, it's completely decoupled from its data source, and therefore easy to test.  Known input, expected outcome.  This is what I call the "Roadies and Aerosmith" analogy.  The "POO" class (Aerosmith) is doing all the sexy work, but the web control (the Roadie) is responsible for giving everything to the "POO" class that it needs to do its work.
    3. Test Small Before Testing Big.  Obviously, the whole thing, control and "POO" class, needs to be tested front to back in an integration test.  Before you even attempt the big bang test, build and test the constituent pieces in isolation first.  That strategy both leads to effective evolutionary design, and keeps the debugger turned off. 
    4. Avoid a Long Tail (forthcoming, but soon because I need some content for my DevTeach talks).  Jay's scenario is really too simple for this law to come into play, but think on this:  if you need to pick up any piece of logic or behavior in your system and write a test for it, how much "stuff" has to come with it?  For example, if you can't test some business logic without a database or Active Directory authentication, you're TDD efforts are going to be much more difficult than they could be.

     

    More Classes?  Yes!

    Again referring to Jay's post, one of the commenter's is concerned that the extra classes will create performance/scalability problems and I'm would also guess an unvoiced concern over extra complexity.  Two points:

    1. I vehemently oppose the attitude that more classes automatically equates to complexity.  I think a much, much more pervasive problem in the wild is classes that are bloated in size with unrelated responsibilities.  In a way, I'm personally more concerned with the complexity of any one single piece of code more than the whole.  I'll take a dozen classes with cohesive responsibilities versus a single 1000 line procedure any day of the week.
    2. I will happily stand up and shout this all damn day.  In all but the most extreme cases, the performance overhead of creating well factored code (smaller classes and methods) is trivial in the grand scheme of things.  Maintainability, of which testability is a crucial component, should never be sacrificed at the alter of performance without very good reason.  I cringe every time I read somebody say to avoid creating more objects as a performance optimization.  Sure it is, but compared to a single inefficient database query or chatty communication?

     

    The Underlying Problems of TDD in the .Net World

    Now, the very real problem that Jay's little example exposes to broad daylight:  in .Net development, and especially ASP.Net WebForms development, you often have to go out of your way to create testable code.  To steal a phrase from Jeffrey Palermo, .Net does not help you "fall into success" with good separation of concerns and testability.  In Jay's case, you can't simply write a small unit test for the control as a whole because any UserControl is tightly coupled to the ASP.Net runtime.  You can fake the HttpContext and the page event cycle, but it's nontrivial and doesn't save you much time (and no, don't ask me exactly how.  The examples I've seen relied on lots of Win32 calls and quite a bit of time with Reflector.  My advice is to go to MonoRail or wrestle WebForms into an MVP structure).  You *can* abstract away the HttpContext by surrounding it with abstracted interface wrappers, and I do recommend this, but the better question I should probably be asking, even as a fervent TDD advocate, is "why do I have to do all this extra stuff for testability?"

    One of the most popular posts I've ever written was on using a Model View Presenter architecture with ASP.Net for testability.  Half a year later I completely lost my enthusiasm for MVP with WebForms in a short morning of presentations from Prag Dave Thomas on Ruby on Rails.  What I saw in only a couple hours was a far more elegant solution for testable presentation code than MVP/WebForms can possibly provide.  At one point I even made Dave stop and repeat a sentence on how state and information was moved from controller to view because their technique eliminated most of the mechanical work we were doing to force ASPX pages into something testable. 

    One of the huge advantages of Ruby on Rails over WebForms is the inherent testability that is baked into Rails.  The way you develop pages in Rails out of the box is inherently testable, in WebForms you have to apply an extra layer of stuff that isn't built in.  Rails comes with built in extensions into the Ruby xUnit tool to stub out the equivalent of the HttpContext at will to simulate user requests, plus more extensions for common assertions for Controller to View interaction.  You can even happily test the generated web page itself without starting up a web server, and that's a huge win in terms of the rapid feedback cycles you want with TDD. 

    Rails straightjackets you into an MVC breakdown by default that separates responsibilities for easier testing.  ASP.Net is all too happy to let you throw everything into the code behinds.  I was extremely dubious about Software Factories at first, but there might be some room for a software factory for ASP.Net that leads to better practices.  We'll see.

    If Jay had been building this functionality with Ruby on Rails (which already has that functionality btw), he wouldn't have had to go out of his way one single bit because Rails is inherently testable, and that's my whole point in this section.  We want ASP.Net to have the same level of testability that Rails does.  We should be asking Microsoft to move ASP.Net in a direction that enables us to write testable code without fighting the framework.

    I don't know how much say or influence I get with this MVP thingie, but the one single thing that I would beg Microsoft for in whatever is beyond Orcas is far more consideration for testability in the .Net framework.  It's the one area in particular where I think the .Net framework needs a lot of improvement.  ScottGu, since you're amazingly all seeing, are you out there?  Can we talk about testability in ASP.Net?  Can we jump testability over new wiz bangy RAD capabilities in the priority list?  Who's with me?

    I really think the .Net community needs to reexamine and debate the merits and appropriateness of the Visual RAD approach.  A lot of what makes ASP.Net WebForms hard to test is the extra complexity that's there to support design time controls, specifically the page event cycle.  RAD is doing more damage than good because the negative impact on maintainability/testability overwhelms the "write once" advantages of RAD.  Discuss.  

     

    My Stuff on Test Driven Development