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

October 2008 - Posts

  • A Quick StoryTeller Update

    I announced the StoryTeller reboot a couple weeks ago.  I had a couple people email me about it, or volunteering to help.  I didn’t respond (I’m sorry) because I didn’t know quite how things were going to go.  I think I can finally say that I’m confident that StoryTeller is on a good path and start thinking about other contributions.  At this point, I’m able to author tests against our system at work and I’ll be able to demo the testing engine at KaizenConf this weekend.

     

    Here’s what I’ve got so far.  It’s very rough, but it’s a start.  I’m deviating a lot more from Fit than I had thought I would, but it’s still easiest to describe the functionality in terms of Fit analogs.

    Terminology:

    • Test – duh.
    • ITestContext – the state of the currently executing test.  My main vehicle for maintaining state during a test.  One of the gripes about Fit is the clumsiness of maintaining state in a test across multiple Fixture classes.  I think I’ve generally alleviated that problem with StoryTeller.  ITestContext is also more or less a service container for the test infrastructure.
    • Step – A test is composed of steps.  The “Step” in StoryTeller is a logical operation in the test, or group of operations.  A Step does not necessarily equate to a single table row in Fit.  In the StoryTeller model, a single Step might equate to a half dozen lines in the rendered test output.  For example, editing my application’s Address form requires 6-7 different actions for filling in different textboxes and selecting dropdown values, but you always have to do these 6-7 things at a time, so it’s a single Step.  I think this is hugely important in making StoryTeller test authoring more mechanically efficient that Fit.
    • Grammar – The fundamental unit of test execution and expression.  Each Step is processed by a single Grammar in the test execution based on the Step’s “grammarKey.”  It is possible to create a CompositeGrammar to group related Grammars into a coarse grained unit.  A TableGrammar is a special kind of Grammar that allows you to recreate a ColumnFixture from Fit in StoryTeller for example driven tests.
    • Fixture – A class that provides one or more Grammars.  Unlike Fit, a Fixture in the StoryTeller architecture can mix table and flow driven grammars in a single class for easier coding and state sharing.

     

        public interface IFixture

        {

            string Name { get; }

            IEnumerable<IGrammar> Grammars { get; }

            IGrammar FindGrammar(string key);

            void ForEachGrammar(Action<string, IGrammar> action);

        }

     

     

    ColumnFixture Analog

    The thing that Fit is best at is table driven “example” tests, or the Row style tests in MbUnit.  Unlike Fit, the StoryTeller analog can just be a method instead of a completely separate class.  Any simple Grammar can be exposed as a TableGrammar.  Here’s an example of turning a normal method into a TableGrammar:

            [ExposeAsTable("Add numbers", "Rows")]

            [return: AliasAs("sum")]

            public int AddNumbersTogether(int x, int y)

            {

                return x + y;

            }

     

    It’s limited to a single return value at the moment (a serious limitation), but that’s a lot less code than the Fit equivalent.  The ExposeAsTable attribute just says “this method is a table grammar.”  The AliasAs attribute is just helping to fine tune the test rendering.  Don’t worry, it’s not crazy with attributes, but I am using some to control formatting.

     

    DoFixture Analog

    This was actually my very first use case for the new engine.  The DoFixture allows you to do flow based testing.  At its simplest, just write public methods on your Fixture class:

        public class AddingFixture : Fixture

        {

            public AddingFixture()

            {

                // This creates a TableGrammar using the AddNumbersTogether2() method

                Grammar("AddNumbersTable").IsTable("Add some numbers together and see what happens").TheInnerGrammar

                    .Is(FindGrammar("AddNumbersTogether2"));

            }

     

            [ExposeAsTable("Add numbers", "Rows")]

            [return: AliasAs("sum")]

            public int AddNumbersTogether(int x, int y)

            {

                return x + y;

            }

     

            [return: AliasAs("sum")]

            public int AddNumbersTogether2(int x, int y)

            {

                return x + y;

            }

        }

    Any public methods will be picked up as Grammars.  In addition, there is the beginning of a DSL for programmatically defining Grammars.  Here’s a real life example from our AddressFixture that tests our Address CRUD and Query web pages:

            public AddressFixture(ApplicationDriver driver)

            {

                _driver = driver;

     

                // More or less script how the Address screen is edited in one logical step

                Grammar("EditAddress").IsScreenEditor<EditAddressViewModel>("Edit Address").WithPrefix(x => x.Address)

                    .Enter(x => x.Address.Address1)

                    .Enter(x => x.Address.Address2)

                    .Enter(x => x.Address.City)

                    .Select(x => x.Address.StateOrProvince)

                    .Enter(x => x.Address.PostalCode)

                    .Select(x => x.Address.Country)

                    .Select(x => x.Address.TimeZone);

     

                // Check all the values saved to the database

                Grammar("CheckFields").IsCompositeTitled("Verify Persisted Fields")

                    .LoadThisObject<Address>()

                    .VerifyPropertiesOf<Address>(x =>

                    {

                        x.Check(o => o.Address1);

                        x.Check(o => o.Address2);

                        x.Check(o => o.City);

                        x.Check(o => o.StateOrProvince);

                        x.Check(o => o.PostalCode);

                        x.Check(o => o.Country);

                        x.Check(o => o.TimeZone);

                    });

     

                // Create a new Address object and persist it

                Grammar("DefineAddress").IsCompositeTitled("Address in the Model Is")

                    .SaveNewObject<Address>(x =>

                    {

                        x.SetAllPrimitivePropertiesSpecificToThisType();

                    });

     

                // Create and persist multiple Address objects

                Grammar("AddressList").IsToSpecifyTheListOf<Address>();

     

     

            }

     

    I should point out that quite a bit of that stuff above is Dovetail-specific language for our application architecture. 

     

    RowFixture Analog

    Very frequently, you need to verify a set or list of values against an expectation.

                // This Grammar clicks the "Save" button expecting input validation failures

                // and validates the displayed validation failures against an expected

                // list, displayed as a table like the Fit RowFixture

                Grammar("ClickSaveUnsuccessfully").IsVerifySetOf<ValidationError>("Clicking Save should fail with validation errors", x =>

                {

                   x.Before((step, context) =>

                   {

                       clickSave(context.Retrieve<ScreenDriver>());

                       var notifyDriver = context.Retrieve<NotifyDriver>();

                       context.CurrentObject = notifyDriver.GetErrors();

                   });

                })

                .MatchOn(x => x.Field)

                .MatchOn(x => x.Message);

  • StructureMap 2.5 is Released!

    As of, oh, whenever SourceForge ends up cooperating and uploading the file, StructureMap 2.5 is officially released! The binaries are available for download now at http://sourceforge.net/projects/structuremap. For the first time in quite a while, the binary release includes a new CHM file for all of the public facing API. 

    So, what does the release mean?

    The documentation is unfortunately not complete, but I wanted to make the release now as effectively putting a stake in the ground and saying "from this moment on, I commit to maintaining *this* public interface and all changes from here on out will be backwards compatible with the 2.5 release." I'm working diligently on the documentation. You can browse the documentation work in progress here.  In the meantime, please ask any StructureMap questions in the google group for StructureMap

    To be upfront, I’ve treated the 2.5 release as my Python 3000 release, meaning that I’ve taken every opportunity to clean up the API and blow away some unfortunate trash in the code.  This release marks nearly a fullblown re-architecting of the StructureMap internals, and that new architecture has largely been responsible for the explosion in functionality in this release.  All of this does mean that some existing API’s introduced in 2.0 for the Registry DSL are already gone.  I’ve learned a lot about writing internal DSL’s with C# in the meantime.  That learning, combined with all the new language goodies in .Net 3.5, have led to a somewhat different Registry DSL, but one that I hope will be easier to read and more discoverable once you stop yelling at me for changing it ;-)

    Unfortunately, this release has taken so long that Jimmy Bogard openly mocks it as the “Duke Nukem Forever” release.  I saw the news the other day about Guns & Roses finally releasing Chinese Democracy, and I knew that I *had* to get this thing out.

    If you happen to be at QCon San Francisco in November, come to my talk and you’ll hear all about the 5 years of hard lessons I’ve learned from doing and redoing StructureMap.  If you’re at KaizenConf this week, go to Chad Myer’s talk and you’ll hear quite a bit from the internal DSL angle.

     

    The new functionality in StructureMap 2.5:

    • Completely revamped Assembly scanning options
    • Cleaner, more predictable way to initialize a Container.  StructureMapConfiguration is now deprecated, please use ObjectFactory.Initialize().
    • Optional setter injection
    • All new abilities to query the configuration of a Container
    • The ability to use StructureMap with ZERO Xml or attributes by default
    • The ability to add services at runtime. You can now programmatically add an entire Assembly at runtime for modular applications that might not want all services to be loaded at startup.
    • An auto mocking container based on Rhino Mocks 3.5. I was a doubter on the validity of AMC, but I'm sold now that I've used it
    • Contextual object construction
    • More sophisticated auto wiring rules
    • Supporting NameValueCollection and IDictionary types
    • Far more extensibility
    • Interception and post processing hooks for you AOP enthusiasts. StructureMap will NOT include its own AOP engine, but will allow you to use the runtime AOP technique of your choice.
    • More configuration options in both Xml and the Fluent Interface. Completely revamped the Registry DSL.
    • More options for modular configuration (mix and match Xml configuration or Registry's at will) -- which basically had to trigger:
    • Completely revamped diagnostics, including the Environment Testing support
    • Transparent creation of concrete types that are not explicitly registered
    • Create objects with explicit arguments passed to the container
    • Use the underlying Container independently of ObjectFactory
    • Pluggable auto registration with your own custom Type scanning policies
    • StructureMap is now strong named (thanks to Steve Harman)
    • Pull configuration from the App.config (thanks to Josh Flanagan)
    • Generics fixes (thanks to Derrick Rapp)

     

    Anyway, I've got some documentation to go write.  Watch the blog for a lot more content on StructureMap usage.  We’ve added some other functionality at work that hasn’t gotten into the trunk, but I’m putting the kibosh on new code until the documentation and website is completely overhauled.

  • Initializing and Configuring a StructureMap Container

    More dribs and drabs of StructureMap documentation.  I've gotten quite a few questions over the difference between Initialize() and Configure().  I hope that this will help with that confusion.  Another goal is to present the Initialize() method.  StructureMapConfiguration has turned out to be a near disaster and is now deprecated in the trunk.  Initialize() was created as a (hopefully) less confusing alternative.  It definitely solves the problem of ordering calls.

     

    The recommended mechanism for initializing the Container or ObjectFactory is the Initialize() method.  The Initialize() method is new for StructureMap 2.5, and largely driven by (my current love affair with Lambda's) the confusion and misuse of StructureMapConfiguration.  StructureMapConfiguration is still supported, but it is deprecated in the code and will be eliminated in a future release.  Initialize() is a Nested Closure that gives you a chance to express directives telling the Container how to construct itself and add one or more sources of configuration. 

            public Container(Action<ConfigurationExpression> action)

            {

                var expression = new ConfigurationExpression();

                action(expression);

     

                construct(expression.BuildGraph());

            }

    Typically, you would make a single call to the Initialize() method at application start up (Global.asax for web application, or the main routine for a desktop application).  The Container (ObjectFactory is simply a static wrapper around a single Container) is completely initialized and configured by the Initialize() method in one atomic action.  Any successive calls to Initialize() will effectively wipe out any existing configuration and effectively restart the Container.  Here's a sample usage of Initialize():

                ObjectFactory.Initialize(x =>

                {

                    x.UseDefaultStructureMapConfigFile = true;

     

                    x.AddRegistry(new CoreRegistry());

                    x.AddRegistry(new SearchRegistry());

                    x.AddRegistry(new WebCoreRegistry());

                    x.AddRegistry(new WebRegistry());

                    x.AddRegistry(new RuleRegistry());

                });

    Inside the Initialization() method you can declare directives against an InitializationExpression object.  The InitializationExpression object has these methods for all all the possible configuration directives.

     

        public interface IInitializationExpression

        {

            // Directives on how to treat the StructureMap.config file

            bool UseDefaultStructureMapConfigFile { set; }

            bool IgnoreStructureMapConfig { set; }

     

            // Xml configuration from the App.Config file

            bool PullConfigurationFromAppConfig { set; }

     

            // Ancillary sources of Xml configuration

            void AddConfigurationFromXmlFile(string fileName);

            void AddConfigurationFromNode(XmlNode node);

     

            // Specifying Registry's

            void AddRegistry<T>() where T : Registry, new();

            void AddRegistry(Registry registry);

     

            // Designate the Default Profile.  This will be applied as soon as the

            // Container is initialized.

            string DefaultProfileName { get; set; }

     

            // ... and the Registry DSL as well

        }

     

     

    Adding Configuration to an Existing Container

    In contrast to Initialize(), the Configure() method allows you to add additional configuration to an existing Container or ObjectFactory.  Think of this scenario.  You're building a composite application that contains multiple modules spread over several assemblies, but you might not want to load any of the configuration or types for a particular module until it's requested by the user.  In that case, you can use the Configure() method like this:

                // This code would add any configuration from

                // Registry classes found in the

                // assembly named 'MyApplication.Module1'

                ObjectFactory.Configure(x =>

                {

                    x.Scan(scan =>

                    {

                        scan.LookForRegistries();

                        scan.Assembly("MyApplication.Module1");

                    });

                });

    To summarize, Initialize() completely resets the configuration of a Container, and Configure() is purely additive.  If Configure() should happen to be called before Initialize(), it will set up the Container with the configuration in the Configure() call.  Configure() offers a subset of the Initialize() method (it leaves out the directives for the StructureMap.config file), and it also includes the entire Registry DSL.  You can take advantage of that fact to add a few types or instances at a time:

     

                ObjectFactory.Configure(x =>

                {

                    x.ForRequestedType<ISomething>().TheDefaultIsConcreteType<SomethingOne>();

                });

     

  • Embedding StructureMap configuration into the App.config file

    The System.Configuration namespace in the .Net framework provides a lot of functionality for caching and encrypting configuration.  To take advantage of this functionality StructureMap offers an option to embed configuration directly into the App.config file (web.config for web development).  Just add a section for StructureMap like this:

    <?xml version="1.0" encoding="utf-8" ?>

    <configuration>

      <configSections>

        <section name="StructureMap" type="StructureMap.Configuration.StructureMapConfigurationSection,StructureMap"/>

      </configSections>

     

      <StructureMap>

        <!-- Put StructureMap configuration here -->

      </StructureMap>

    </configuration>

    Then you need to explicitly tell ObjectFactory to use this configuration:

                ObjectFactory.Initialize(x =>

                {

                    // Tell StructureMap to look for configuration

                    // from the App.config file

                    // The default is false

                    x.PullConfigurationFromAppConfig = true;

    &            });

  • The StructureMap.Config File

    More docs.  I’m working on it.

     

    In the beginning, StructureMap configuration began and ended with a single file named "StructureMap.config" in the application base folder that contained StructureMap Xml configuration (in short, wherever your App.config file would go).  Today, the default behavior is that StructureMap will automatically read in configuration data from the StructureMap.config if it is found when either ObjectFactory.Initialize() is called, or the first time that a service is requested from ObjectFactory.  You can technically use only the StructureMap.config file and completely forgo the the usage of any programmatic bootstrapping.

    You can override the default behavior for the StructureMap.config file.  If you want to make the StructureMap.config file mandatory, you can do this:

                ObjectFactory.Initialize(x =>

                {

                    // We put the properties for an NHibernate ISession

                    // in the StructureMap.config file, so this file

                    // must be there for our application to

                    // function correctly

                    x.UseDefaultStructureMapConfigFile = true;

                });

    At other times you might want to force ObjectFactory to ignore the StructureMap.config file even if it does exist.

                ObjectFactory.Initialize(x =>

                {

                    x.IgnoreStructureMapConfig = true;

                });

  • Contest to create the best definition of 'DSL'

    There's a catch though.  You have to speak as if you were Justice Gray.  A winning entry must contain words like metrosexual or reference hair products.  A winning entry may also simply make the average person very uncomfortable and make you wonder if it's NSFW or not.  Ok, ready, go.

    This is all to help Chad come up with a better title for his KaizenConf talk.

  • The Shade Tree Halloween Special

    Years ago, SD Magazine used to feature a section in the October issue on software horror stories.  In honor of one of my favorite (since departed) publications, I’d like to continue the Halloween traditions by reliving some of the worst screwups and dumbest decisions made in the career of yours truly.  Since I moved back to Austin, I’ve started meeting some of my friends from a previous job in what I’d put forward as the worst software organization I’ve ever been associated with.  They’ve been kind enough to remind me of some of these episodes.

    • What do you mean, backup?  I started my career as an engineer in Houston, but promptly got into project automation writing shadow IT apps for my old engineering team.  My first job was writing a tool that could trouble shoot an extremely problematic data exchange.  I solved the problem more or less by writing a system that worked in parallel, but worked correctly, and compared my results to the actual results of the real system.  It was a complete success.  My first programming triumph.  The engineering teams wanted access to the correlation reports themselves, so I then added an ASP application that would allow users on the engineering projects to kick off the data comparisons.  On my box.  On my puny Compaq workstation running underneath my desk.  Which was so overworked by my little shadow IT application that it threw a head through the hard drive.  The hard drive that had the only copy of the code.
    • Sev 1 Trouble Tickets?  I’ve got your ticket right here.  On my very first big project, and as a lead no less, I decided that it would be a cool thing if we automatically sent a trouble ticket to support if our application logged an error.  Sounds good, except we didn’t really specify which errors sent the tickets, and how many times.  On the first day it rolled out, in a day that was otherwise very successful, we experienced a minor configuration flaw that caused the application to write an excep tion record to a table in the database. 
      • Which caused an After Update trigger to fire. 
      • Which created and posted a trouble ticket to support in a stored procedure. 
      • With the dreaded Sev 1, OMG the factories are down!, kiss your raise goodbye level. 
      • Every 5-10 seconds or so as the polling thingie encountered the exact same innocuous problem
      • About 300 times until we fixed the configuration
    • Integration by Hook or Crook.  Of everything I’ve ever done, the one thing that embarrasses me more than anything is my first big integration project.  We needed to integrate with an externally facing B2B server.  I was offered a choice by my buddy who was in charge of the B2B infrastructure.  We could either do it by MQ Series that neither one of us had ever used, or we could just use a queuing table in my Oracle database with nice simple mechanisms that we all understood.  I naturally said that I’d man up and do MQ Series.  We were already using the built in job scheduling in Oracle and Java Stored Procedures, so I just assumed that we’d use JMS inside the Oracle database.  All the samples looked very simple, but it turned out that we had to be running the Oracle database under a certain configuration and the DBA’s were adamant that they weren’t able to effect that change late in the game.  For a variety of reasons (ignorance, technical limitations, and haste), we ended up:
      • Having a stored procedure called from Oracle’s job scheduler on a polling interval…
      • Do an Http post to an ASP page on our website…
      • Which would gather up the correct data from our database and post to yet another web page on another server (because, surprise, we couldn’t make DCOM work consistently)…
      • Where that ASP page would call a COM component that could finally put the data into MQ Series queue
      • Of course, we had good instrumentation and distributed transactions throughout – NOT!
      • It was just a little bit buggy in production ;-)
    • SetConnectionString.asp.  I have a really bad taste in my mouth from all of the times I’ve had to interact with centralized architecture teams.  Nothing will freeze my blood in fear more than hearing the phrase “you have to use our standard framework for Logging / Persistence / Security / Etc. from our architecture team.”  I’ve had that feeling reinforced at 6-7 different places, but it started with a simple tool we had to use from our architecture team to store database connection strings.  It was kind of a pre-DPAPI implementation where the data was encrypted in the registry using some sort of NT user information as the key.  Basically , the only NT user that could read or write to the registry settings was the currently logged in user.  Great for security, but the registry settings corrupted every couple days.  There wasn’t a useful tool for setting the connection string in the first place, so I wrote an ASP page that would let you type the connection string into a textbox, then submit the data to the server where the connection string would be written into the registry under the correct user name.  Because this was one of those incompetent shops with horrendous configuration management policies, we inevitably had to play the “is it pointed at the right database?” games.  I naturally changed my SetConnectionString.asp page to show you the current connection string.  I’m sure you know what happened next.  That page managed to get deployed to production.  A couple years after I left, they did some sort of security scan that scanned a web page and tried to access each page automatically to verify that it was secured.  Somehow, this security scan submitted the form with a blank connection string and effectively broke the application.  The mission critical, shut the factory down application.
    • Workflow?  Nobody has ever done Workflow before like me.  One of the things we needed to do was provide some workflow capabilities for supply chain dispute resolution between us and our supply chain partners.  As one of the architects on the project, I was tasked with determining a strategy for this functionality.  I naturally decided that we should code it ourselves, because, you know, there’s only a half billion existing 3rd party workflow tools out there.  I delivered a working solution and more or less on time – at the cost of my sanity, mental health, and respect of my development team.  At its peak the system had 70+ metadata tables that could be, or had to be, configured to make the system.  Let’s just say that the system was a bit over-engineered.

     

     

    Next week I’ll have more fun by talking about the ones that I only observed, and another about the horror stories inflicted upon me by someone else – usually one of those centralized architect types ;-)

  • Our “Opinions” on the ASP.NET MVC (Introducing the Thunderdome Principle)

    I’ve got my asbestos underwear on, so flame away…

     

    So many of us are so thrilled at seeing an official Front Controller / MVC framework for ASP.NET development that I think we’ve forgotten to ask ourselves “Is this thing any good?”  In *my* opinion, if you look at the ASP.NET MVC framework as a complete framework to be used out of the box, the MVC framework isn’t very good at all.  However, as a set of fairly loosely coupled classes that you can use to build a highly productive, specialized MVC stack for your specific application needs, the ASP.NET MVC framework is perfectly fine.

    Basically, my issue with the MVC framework is that I think it falls far short of Ruby on Rails in terms of productivity enhancing features and testability.  Specifically, I think the MVC framework – out of the box – has failed by not embracing the Rails mantras of Opinionated Software, Convention over Configuration, the  DRY Principle, and Testability support.  That’s okay though, because we’ve found it relatively simple to cherry pick the pieces of the MVC that we wanted (routing, some of the ActionResult classes, and the WebFormsEngine) to form the core of the MVC framework that we wanted.  After deciding that we would use the MVC framework (why we chose the MVC over Rails and MonoRail is a different discussion), Chad & I immediately proceeded to develop a set of “opinions” on how we wanted our architecture to work and built up some infrastructure around the MVC to make these “opinions” become true.  We’re doing a joint presentation at KaizenConf called Using and Abusing ASP.NET for Fun and Profit that’s all about our particular usage of the ASP.NET MVC framework.  As a preview of that talk, and for those of you who won’t be in Austin for KaizenConf, here are the “opinions” that we’ve adopted.

    Our guiding principles have been heavily influenced by Rails.  We’re using Convention over Configuration as much as possible, and we’re adamant about DRY.  We’ve deviated from Rails by trying to use the strengths of C# 3.0 rather than trying to make C# act like a half-assed version of Ruby.  To that end, we very heavily use Expression’s, Lambda’s, Object Initializers, and Generics.

    Opinions

    • The “Thunderdome Principle” – All Controller methods take in one ViewModel object (or zero objects in some cases) and return a single ViewModel object (one object enters, one object leaves).  The Controller classes will NEVER be directly exposed to anything related to HttpContext.  Nothing makes me cry like seeing people trying to write tests that mock or stub that new IHttpContextWrapper interface.  Likewise, Controller methods do not return ViewResult objects and are generally decoupled from all MVC infrastructure.  We adopted this strategy very early on as a way to make Controller testing simpler mechanically.  It’s definitely achieved that goal, but it’s also made the Controller code very streamlined and easy to read.  We’ll explain how this works at KaizenConf.
    • Controllers should have no knowledge of the View.  View’s should have no knowledge of the Controller.  They only share the Model class, period.
    • Controllers should be thin.  The only job of a Controller action is to translate the model coming in to the proper service calls and to create the output model object.  All responsibilities for business logic are done by delegating to non-UI service classes.  In other words, business logic does NOT go into a Controller.
    • No slinging around HashTable’s, IDictionary’s, or magic strings.  All of these things are error prone and make development harder than strongly typed parameter objects.  Instead, we…
      • …say that all navigation is done by an Expression like:  <%= this.LinkToAction<HomeController>(c=>c.Index(), UserMessageKeys.MAIN_HEADER_TEXT) %>.  The actual implementation is half convention, and half configuration of controller “aliases.”  This choice does not lock you into making all url strings an exact representation of the controller name and method name.
      • …as I said earlier, all Controller actions are invoked by passing in a single parameter object
      • …allow no direct access to HttpContext collections.  In the very rare case we need to access something in HttpContext, we use a wrapper interface that expresses that need in terms of our application.  Dependency Injection is used to get the HttpContext wrappers to the Controller classes that need them.  See this post from Jimmy Bogard for another example.
    • All View’s are strongly typed View’s (ViewPage<T>, where T is the ViewModel that comes out of a Controller action).  This is somewhat necessary because of the Thunderdome principle, and also enables the bullet point below…
    • All html form elements are built by Expressions with our own html helpers like this:  <%= this.TextBoxFor(m => m.Site.Identifier)%>.  This has worked out very well because:
      • It makes screen synchronization simpler by binding the element names to the actual properties of the Model object.  With a little code generation, we’ve basically made the effort to synchronize data between the view, the Request.Form, and the internal Domain Model objects a miniscule part of the development effort.
      • This cuts down on mistakes from misnamed elements or mangled string key values on the server side
      • It’s enabled automated testing of the screens.  We can address screen elements in tests by a strong typed Expression as:  DropDownFor(x => x.Site.Status).HasOptionValues(Given.StatusList);
      • We have access to the underlying PropertyInfo while we’re building textbox’s and dropdown’s and the like.  We’re just starting to take advantage of this to intelligently set restrictions on what type’s are valid in the html elements.  We’re also tying into our validation attributes to automatically mark fields that are required and set some client side validation rules on the html elements.  Sooner or later, we’ll also tie in tooltip values into the html controls.  And all of this comes without adding any more code on the actual View. 
    • Server side markup is never intermingled with client side JavaScript.  It is our opinion that this all too common technique leads to unreadable code and eliminates the ability to TDD the client side JavaScript.  This:  callFunction(‘<%=Model.Variable%>’) is not allowed.  If server side data needs to be passed to client side JavaScript, we do that by writing “var something = <% =Model.Variable%>.” 
    • View’s should be very simple.  If you’re using an if/then statement or some sort of looping expression, you’re doing something wrong.  Conditional logic belongs in the Controller or in JavaScript libraries that can be tested with QUnit.  No, or minimal, logic in the View’s reduces errors by moving logic out of hard to test code and into easier to test code – and yes, I’m declaring that JavaScript is easy to unit test.  Tag Soup can be avoided.  We tend to move looping constructs into our own partial implementation like:  <%= this.RenderPartialForEachOf(m => m.Solution.Resolutions).Using<EditResolution>()%>.  In that block of code, EditResolution refers to an ASCX control, and m.Solutution.Resolutions is a property of type IList<Resolution>.  This statement will iterate over the list, and render a partial view for each Resolution object.
    • All Domain Model classes are identified by a single numeric property called “Id” (enforced with a layer supertype).  Nothing uncommon about that opinion, but it does eliminate repetition in the code by allowing us to reuse a lot of code for finding objects and Url routing between different types of Domain Model objects. 

     

    Other Stuff We’re Doing

    • We use QUnit quite extensively and I’m thrilled with it as a tool.  We try to treat our JavaScript work as “real” coding and apply the same quality requirements to JavaScript as our C# code, and that means TDD.  We’ve found that many things are easier to unit test and build with jQuery / QUnit rather than server side markup and NUnit.
    • We do have a way to test View’s in isolation with WatiN.  We can set up the input Model class in memory, then render that Model with a View and make assertions on how the View was rendered.  Rails has support for this very thing, and I’ve always wanted this ability.  This hasn’t been as useful as I thought it was going to be once we adopted the rules about simplicity in the View’s and started using the QUnit / jQuery combination.  In order to make this ViewContext work, however, we had to forgo all usage of the built in HtmlHelper’s because of some unfortunate coupling to HttpContext.
    • We’re using Fluent NHibernate for configuration.  We’re about to remove some of the explicit configuration in favor of the convention based mapping.  At this point, we’re completely generating the database with NHibernate’s HBM2DDL tooling.  The database is just flowing out of the Domain Model for the time being (until we have a need to optimize the default DDL).  We have added some conventions to Fluent NHibernate to tie our validation attributes into the DDL generation.  DRY baby.  The lesson we can take out of Rails success is DRY.  It’s just that the shape of DRY code is a bit different in the .Net world.
    • We have a custom BDD style “Context” abstract class for our Controller actions.  Because of the “Thunderdome Principle,” it’s simply a matter of defining the input model, running the method, then doing state-based assertions against the output model.  No HttpContext.Request.Form setup, and no scraping data out of a weakly typed ViewResult after the fact.  This “Context” class also uses the StructureMap AutoMocker behind the scenes to cut down on the overhead of setting up tests.  Here’s an example of that context in action testing a service class:

    [TestFixture]

    public class When_yanking_a_workflow_item :

        ActionContext<WorkflowService, YankRequest, WorkflowActionResult>

    {

        private User theCurrentUser;

        private Queue theOriginalQueue;

     

                                                      // Defines the method

        public When_yanking_a_workflow_item() : base( (x, input) => x.Yank(input))

        {

            UseInMemoryRepository = true;

        }

     

        // Set up the context

        protected override void beforeEach()

        {

            theCurrentUser = new User().WithId(4);

            WorkflowItem theCase = new Case().WithId(1);

            theOriginalQueue = new Queue{Name="OriginalQ"}.WithId(5);

            theCase.Enqueue(theOriginalQueue);

     

            // Setup the input model

            Given = new YankRequest

                        {

                            CurrentUser = this.theCurrentUser,

                            Item = theCase

                        };

        }

     

        [Test]

        public void the_owner_should_be_changed_to_the_current_user()

        {

            // The first access of the "Output" property

            // runs the Controller action and caches the return

            // value of the Controller action

            Output.Item.Owner.ShouldBeTheSameAs(Given.CurrentUser);

        }

     

        [Test]

        public void it_should_no_longer_be_assigned_to_a_queue()

        {

            Output.Item.Queue.ShouldBeNull();

        }

     

        [Test]

        public void the_item_and_the_queue_and_the_log_should_be_saved()

        {

            TheLastTransactionWasCommitted()

                .TheSavedObjectsWere(Output.Item, theOriginalQueue, Output.Item.LastAction);

        }

    }

     

    In Closing

    Please don’t think that I’m saying that the ASP.NET MVC is bad, because it’s not.  I just think that the MVC out of the box is too “bland” and wishy washy.  If you’re going to use it for anything bigger than a handful of screens, I’d highly advise you to add some of your own application specific sauce.  I think we can agree that Microsoft couldn’t make the MVC framework opinionated without pissing off 3/4’s of its users (just think, if they were to build in direct support for persistence they’d have to use Linq to SQL or the messy tool that shall not be named, neither of which I would consider to be acceptable).  Making the MVC opinionated, and hence more productive, is going to be left to the community and to each organization.

  • Using the StructureMap Container independent of ObjectFactory

    More dribs and drabs of StructureMap 2.5 documentation.  At the pace I'm on, I do believe that Duke Nukem Forever will be released tomorrow night. Knock on wood.

    New to 2.5 is the ability to create an instance of the underlying Container class independent of the static ObjectFactory class (actually, you always could do this, but it's much easier in 2.5).  The IContainer interface has roughly the same methods as ObjectFactory (the only major difference is that ObjectFactory.GetNamedInstance<T>(name) is IContainer.GetInstance<T>(name) )  You can build a Container with a single Registry object:

     

                var container = new Container(new BasicActionRegistry());

     

    Or more commonly, you can build the Container in a manner very similar to the ObjectFactory.Initialize() method.  One of the constructors for Container takes in an Action<ConfigurationExpression> expression that can be used to configure the Container in one atomic action like this code below:

     

                var container = new Container(x =>

                {

                    x.Scan(scanner =>

                    {

                        scanner.Assembly("StructureMap.Testing.Widget")

                    });

     

                    x.ForRequestedType<Rule>().TheDefault.Is.OfConcreteType<ColorRule>()

                        .WithCtorArg("Color").EqualTo("Blue");

     

     

                    x.IncludeConfigurationFromConfigFile = true;

     

                    x.AddConfigurationFromXmlFile("ExternalFile.xml");

                });

     

    The ConfigurationExpression class is a Registry, so you can use all of the Registry DSL in the Lambda expression passed into the Container constructor.  In addition to the Registry DSL, you also have these options:

     

     

            bool IncludeConfigurationFromConfigFile { set; }

            void AddRegistry<T>() where T : Registry, new();

            void AddRegistry(Registry registry);

            void AddConfigurationFromXmlFile(string fileName);

            void AddConfigurationFromNode(XmlNode node);

     

     

    These other options will allow you to add configuration from additional Registry classes, the StructureMap section in the App.config file, or other Xml files.

     

    Lastly, you can create a Container directly with a no argument constructor, then use the Inject() methods or later use the Configure() method.

     

            [Test]

            public void Add_an_assembly_on_the_fly_and_pick_up_plugins2()

            {

                var container = new Container();

                container.Configure(

                    registry =>

                    {

                        registry.Scan(x =>

                        {

                            x.AssemblyContainingType(typeof (IService<>));

                            x.AddAllTypesOf(typeof (IService<>));

                        });

                    }

                    );

     

                IList<IService<string>> instances = container.GetAllInstances<IService<string>>();

                instances.Count.ShouldBeGreaterThan(0);

            }

  • Profile’s in StructureMap

    This feature has been in StructureMap from the very beginning, but I don’t think that I’ve ever documented it very well.  More docs:

    From the very beginning, StructureMap has supported the ability to define a named set of default instances called a "Profile."  The Profile feature was originally meant to be a quick way of switching the connection mode of a smart client application from connected to disconnected modes.  In practice, it's more commonly used as a way to migrate configuration between environments or for creating alternative deployment configurations.  My team uses the Profile feature in our system as a quick way to collapse our entire distributed application into a single AppDomain for easier testing and debugging.  Our "InMemory" profile is defined like this:

                // Using this Profile configures our application to

                // run completely inside a single AppDomain

                // In production the application will consist

                // of the website and 2-3 external windows

                // services

                var repository = new InMemoryRepository();

                CreateProfile(IN_MEMORY_PROFILE, x =>

                {

                    x.For<IRepository>().Use(repository);

                    x.For<IEventPublishingService>().Use(new InMemoryEventPublishingService(repository));

                    x.For<IUserMessagePublisher>().UseConcreteType<InMemoryUserMessageQueue>();

                    x.For<IUnitOfWork>().UseConcreteType<InMemoryUnitOfWork>();

                });

    In the code, we can switch the application to the in memory mode by calling the SetDefaultsToProfile() method on the Container (or ObjectFactory.Profile = CoreRegistry.IN_MEMORY_PROFILE):

                // This is actual code from a test harness class we use

                // for integration testing

                IContainer container = createContainer(new RuleSet[]{ruleSet});

                container.SetDefaultsToProfile(CoreRegistry.IN_MEMORY_PROFILE);

  • Using StructureMap 2.5 to scan all assemblies in a folder

    In a magical confluence of events, I’m free from all parental and spousal responsibilities today and I’m trying to use the day to write StructureMap docs.  Hopefully, this is the first post of several today.

    This is the very last (or next to last) feature to make it into the StructureMap 2.5 release that Josh added last week to support an extensibility need that we have at Dovetail.  From the documentation:

    StructureMap 2.5 has a brand new capability to auto register types in all assemblies in a given folder path.  My current project is using this feature for our extensibility mechanism.  For customer-specific deployments, we need to add business rules and even all new screens and features to our application that can be discovered at runtime -- without changing our core code.  Our design calls for all extensions to be created in separate assemblies.  On application startup, our system will look for all assemblies in a well known folder and use StructureMap to scan these assemblies for the extensions that will be specified in Registry classes.  Our bootstrapping looks like:

                Scan(x =>

                {

                    // I'm telling StructureMap to sweep a folder called "Extensions" directly

                    // underneath the application root folder for any assemblies found in that folder

                    x.AssembliesFromPath("Extensions");

     

                    // I also direct StructureMap to add any Registries that it finds in these

                    // assemblies.  I'm assuming that all the StructureMap directives are

                    // contained in Registry classes -- and this is the recommended approach

                    x.LookForRegistries();

                });

    Note in the code above that I made an explicit call to "LookForRegistries."  Scanning for Registry's is no longer active by default.  This is a breaking change from the 2.4.9 preview release. 

    You can also filter the assemblies based on a Predicate like this:

                Scan(x =>

                {

                    // This time I'm going to specify a filter on the assembly such that

                    // only assemblies that have "Extension" in their name will be scanned

                    x.AssembliesFromPath("Extensions", assembly => assembly.GetName().Name.Contains("Extension"));

     

                    x.LookForRegistries();

                });

  • Test Automation Brain Dump

    I’m working to revamp our test automation strategy this week and next.  By test automation here I’m referring to full or partial stack tests that exercise the application from website to database and back again rather than just the normal TDD/BDD testing.  As I work today I’m going to jot down notes here and dump it out later.  Stream of consciousness here we come:

    • Test automation is hard.  You’ve got to be committed to using it to really make it work.  I don’t think you can succeed by only doing automated testing at the end of the project.
    • Integrated testing will catch different types of errors than unit tests.  You still want to do unit testing first though.
    • I don’t see how you can possibly make test automation work in the large scale without very close participation from the actual development team.
    • I look at automated testing as a way to find, remove, and prevent problems in the codebase.  It’s not an end all, be all mechanism by itself to prove that the application code works correctly. 
    • My very strong opinion is that Whitebox tests provide a much, much higher reward to effort ratio than Blackbox testing.  I think the people who only accept the results of blackbox tests are only considering the usage of tests as a way to verify the correctness of the system rather than just another mechanism to remove problems in the system.
    • The software design matters a lot.  Good separation of concerns type qualities enable a lot more chances fo