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

Inversion of Control with the Plugin Pattern

(IoC) is an old principle in object oriented programming, but it’s gotten a lot of buzz the last couple of years because of the proliferation of Dependency Injection (DI) tools and articles.  Dependency Injection is a significant flavor of the broader Inversion of Control principle, but it’s not the whole enchilada.  IoC is an important technique to make your code easier to test with TDD, but the other major benefit is extensibility.

Inversion of Control is also known as the “Hollywood Principle” – “don’t call me, I’ll call you.”  In short, this principle applies when you create classes that are passive, i.e. they do not direct the executing flow of the code.   It also applies to classes that are ignorant of the services that act upon them instead of directing the services themselves.

The original usage of the term Inversion of Control referred to the creation of reusable whitebox frameworks that could be extended by creating plugin classes.  The general idea being that you extend the existing behavior of a framework by creating a class implementing an interface from the framework.  Your new class doesn’t call the framework; the framework code calls the new class. 

The Plugin pattern as described by Martin Fowler in the PEAA book is a common pattern.  I went looking for examples today and found several just by looking in my current project and at tools that we use every day.  CruiseControl.Net is a very “pluggable” framework.  CC.Net has to work with multiple source control systems (Subversion, CVS, Perforce, etc.), different build tools (NAnt or MSBuild), and different strategies for publishing build results.  A former colleague has been setting up a CC.Net server against a CC/Harvest (unusable pile of manure) source control repository.  CC.Net doesn’t support Harvest out of the box, but it’s not a show stopper.  Just create a class that implements CC.Net’s ISourceControl interface and configure CC.Net to call the new class in the CCNet.config file.
 

<cruisecontrol>

  <project name="StructureMap">

    <webURL>http://localhost/ccnet/Controller.aspx?_action_ViewProjectReport=
true&amp;server=local&amp;project=StructureMap</webURL>

    <triggers>

      <intervalTrigger seconds="60" />

    </triggers>

    <modificationDelaySeconds>10</modificationDelaySeconds>

 

    <!-- Configure the connectivity to Subversion ISourceControl plugin and establish the working directory -->

    <sourcecontrol type="svn">

      <executable>c:\program files\subversion\bin\svn.exe</executable>

      <trunkUrl>file:///C:/PersonalProjects/StructureMapSVN</trunkUrl>

      <workingDirectory>C:\PersonalProjects\StructureMap-Working</workingDirectory>

      <autoGetSource>true</autoGetSource>

    </sourcecontrol>

           

    <!-- Configure the NAnt builder block -->

    <build type="nant">

      <executable>C:\PersonalProjects\StructureMap-Working\bin\nant\nant.exe</executable>

      <baseDirectory>C:\PersonalProjects\StructureMap-Working</baseDirectory>

      <buildFile>cruise.build</buildFile>

      <targetList>

        <target>cruise</target>

      </targetList>

 

      <buildTimeoutSeconds>1500</buildTimeoutSeconds>

    </build>

 

    <!-- Merge in test results from the NUnit tests -->

    <tasks>

      <merge>

        <files>

          <file>C:\PersonalProjects\StructureMap-Working\results\*.xml</file>

        </files>

      </merge>

    </tasks>

 

    <publishers>

      <xmllogger />

    </publishers>

 

  </project>

           

</cruisecontrol>

 

My StructureMap tool has a couple of plugin patterns to extend the basic framework with additional options.  I wanted multiple options for project configuration.  Simple projects would probably just use the basic XML configuration in the project path.  Larger multi-server applications might push a team to use a central database or some sort of LDAP tree structure to store the configuration in a common place.  StructureMap uses classes that extend the MementoSource abstract class to fetch configuration data for instance graphs.  To create and use a new means of configuration I first create a new class that inherits from MementoSource and override the virtual and abstract methods.  StructureMap is directed to use the new MementoSource in the StructureMap.config file in the project directory.
 

<StructureMap>

  <!—Configure this PluginFamily to use an XmlFileMementoSource that pulls configuration from an Xml file named “FullTesting.XML” -->

  <PluginFamily Type="StructureMap.Testing.Widget.Column" Assembly="StructureMap.Testing.Widget">

    <Source Type="XmlFile" FilePath="FullTesting.XML" XPath="Columns" NodeName="Columns" />

  </PluginFamily>

</StructureMap>

Here are some other examples of the Plugin pattern:

  • Log4Net provides extensible logging options.  If none of the two dozen or so built in logging storage mechanisms fit your needs, you can happily create a custom implementation of the IAppender interface for customized logging.
  • It’s very straightforward and often advantageous to create custom tasks to use in NAnt build files. 
  • The Provider model in .Net 2.0 is an example of the Plugin pattern (and the Service Locator variant of Dependency Injection).   

 

The Open/Closed Principle

 

“Software entities (Classes, Modules, Functions, etc.) should be open for extension but closed for modification.”

 

This sounds like a contradiction at first glance, but it’s not.  As explained by Robert Martin here, the Open/Closed Principle (OCP) pushes you to design software in such a way that new functionality can be added to system by creating brand new code rather than modifying gobs of existing code.  The thinking behind the OCP is to make a system easier to change by leaving currently working code alone, or at least minimizing the amount of code modification needed to add the new behavior.  An abstracted Plugin pattern is one of the best ways to follow the OCP. 

 

I used to think that the OCP was only important for systems that really needed a lot of extensibility, but I’ve found that following the Open/Closed Principle helps make code that can evolve inside of an incremental design process.  You don’t necessarily have to use a Plugin pattern class that’s loaded via reflection and configuration to get the benefits of the OCP.  You do, however, have to follow the Dependency Inversion Principle to reap the benefits of the OCP.

 

My CodeBetter neighbor David Hayden has a good discussion on the OCP here.  The OCP is also easier to achieve by following the Single Responsibility Principle.

 

A Word of Caution

 

Don’t use a Plugin pattern until it’s really necessary.  Speculative usage of the plugin pattern everywhere you think you’ll need flexibility later is a quick path to a sclerotic, over-designed application that nobody wants to work with.  Not that I've ever been guilty of that.  The Plugin mechanism creates more indirection in your code.  That leads to additional intellectual overhead trying to understand what’s happening in your code base.  I’m tangentially involved with a code base that extensively uses classes loaded by reflection.  The end result in this case is simply an application that is harder to debug and trace (and impervious to ReSharper code navigation).  If you’re using the plugin pattern, I’d recommend using an existing tool like StructureMap to take advantage of the diagnostics and troubleshooting features.

 

One of the most wrong-headed sentenced in all of software development is “let’s build the framework first, and then the application will be easy.”  No, no, no.  I’m never going to be a part of (or be the cause of) this exercise in stupidity ever again.

 

 

 

My next two posts will talk about using Inversion of Control for improved testability and using Dependency Injection as a crucial technique for TDD.



Comments

Christopher Steen said:

.NET CF, AxHost, and PDC [Via:
windowsmobile ]
ASP.NET 2.0 Beta2 to RTM changes
[Via: Jackie Goldstein...
# September 14, 2005 12:51 AM

Jeremy D. Miller -- The Shade Tree Developer said:

Inversion of Control (IoC) is an essential tool for any software designer’s design toolbox because it’s...
# September 20, 2005 3:52 PM

Mohammed Amin said:

Could anybody tell me if they were able to use NANT to get the latest code from CC harvest. I am trying to automate our build process and am unable to get the latest code from CC Harvest using NANT. Thanks in advance

Amin
# October 19, 2005 1:08 PM

Jeremy D. Miller -- The Shade Tree Developer said:

It’ll never be the most commonly used pattern in your design toolbox, but I’ve occasionally had good...
# November 7, 2005 12:22 AM

Jeremy D. Miller -- The Shade Tree Developer said:

StructureMap is an open source tool I’ve written for Dependency Injection support in .Net.&amp;nbsp; This...
# November 18, 2005 9:40 AM

Jeremy D. Miller -- The Shade Tree Developer said:

Inversion of Control (IoC) is an essential tool for any software designer’s design toolbox because it’s...
# January 18, 2006 4:12 PM

Jeremy D. Miller -- The Shade Tree Developer said:

This past Saturday was the Austin Code Camp.&amp;nbsp; I had a great time and the general consensus was that...
# March 6, 2006 8:32 AM

Nicolai's Blog said:

&quot;One of the most wrong-headed sentenced in all of software development is “let’s build the framework first, and then the application will be easy.”  No, no, no.  I’m never going to be a part of (or be the cause of) this exercise in stupidity ever
# June 16, 2006 7:37 PM

Jeremy D. Miller -- The Shade Tree Developer said:

The slide deck and sample code from my StructureMap talk last night is available from the ADNUG downloads...
# July 11, 2006 10:52 AM

Rodel E. Dagumampan said:





&quot;One of the most wrong-headed sentenced in all of
software development is “let’s build the framework...
# July 18, 2006 4:53 AM

Rodel E. Dagumampan said:

&quot;One of the most wrong-headed sentenced in all of software development is “let’s build the framework
# August 7, 2006 3:02 AM

Jeremy D. Miller -- The Shade Tree Developer said:

Between being extremely short handed at work, tech' reviewing a new book, a
possible book proposal...
# August 7, 2006 4:51 PM

Jeremy D. Miller -- The Shade Tree Developer said:

Between being extremely short handed at work, tech&#39; reviewing a new book, a possible book proposal

# September 1, 2006 2:33 PM

Jeremy D. Miller -- The Shade Tree Developer said:

My employer, Finetix , added my blog to their main feed and my most recent post at the time just happened

# January 9, 2007 12:00 AM

Jeremy D. Miller -- The Shade Tree Developer said:

It took long enough, and I&#39;ve had a pretty good stream of people asking for this, so here it is:

# April 2, 2007 10:28 AM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add

About Jeremy D. Miller

Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy previously worked as a systems architect building mission critical supply chain software for a Fortune 100 company and learned agile development practices as a .Net consultant at ThoughtWorks, one of the pioneers of agile development. Jeremy is the author of the open source StructureMap (http://structuremap.sourceforge.net) tool for Dependency Injection with .Net and the forthcoming StoryTeller (http://storyteller.tigris.org) tool for supercharged FIT testing in .Net. Jeremy's thoughts on just about everything software related can be found on his weblog "The Shade Tree Developer" at http://codebetter.com/blogs/jeremy.miller, part of the popular CodeBetter site. Jeremy is a Microsoft MVP for C#. Check out Devlicio.us!

This Blog

Syndication

News

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

About Me

"Best Of" Compendium

StructureMap (Dependency Injection for .Net)

StoryTeller (Supercharged Fit)

Build your own Cab

TestDriven

MVP