Jeremy D. Miller -- The Shade Tree Developer

Sponsors

The Lounge

News

Advertisement

Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
Thoughts on Building Pluggable Frameworks

I'm about to start building a new pluggable framework for my new project.  I've built several over the years, but I've found that my approach is much different now than it was five years ago.  Before I start, I thought that it might be worthwhile to jot down what I think about building a framework. 

  • If you're a real developer with blood pumping through your veins, building a pluggable, whitebox framework is about the most fun you can possibly have at work.  I used to call designing a framework my mad scientist mode.  I do think that feeling of creative joy probably explains much of the harmful overdesign being done out there.
  • The mechanics of a pluggable framework are easier than ever because you can just grab an IoC/DI tool off the shelf (like StructureMap) to handle the plugin's and configuration.  As a matter of fact, I would almost go farther and say that I would almost automatically use an IoC tool for any nontrivial enterprise system.
  • Watch out for Architect Hubris.  The idea that you can foresee all possible points of divergence ahead of time is flawed.  You need to be tailoring your framework to providing value in exactly the way that the business functionality requires.  The best way to ensure that your framework fits its actual usage is to grow the framework organically as you develop real functionality.  In Ordering Software Construction Tasks, I tried to argue that the strategy of building the architectural framework first, then developing the actual business functionality second can easily be a delayed timebomb.  Getting the perfect design upfront can be a boon, and sometimes you'll be right, but on the whole you're going to be better off measuring your design as you go with real world feedback. 
  • Where do you need to put the extensibility seams?  I say let automated testing be your guide.  It gets blurred by the word "Test," but Test Driven Development is a design technique.  In my experience, the places where it's convenient to put a seam for the sake of writing small, concise, isolated tests are likely to be the exact same places where it's valuable to have an extension point later.  I don't design my code upfront for extensibility anymore, but my code is much more extensible.  If nothing else, a class structure that is hard to test is a pretty good indicator that extension will be difficult.  Extensibility will most reliably follow by focusing hard on keeping class responsibilities cohesive and loosely coupled.
  • One of the pieces of advice I try to give out about building frameworks is to put off the configuration mechanism at first.  My theory is that it's better to concentrate at first on the classes that do the real work first.  I say this for a couple reasons:
    • It's easy to get bogged down in designing the configuration strategy first
    • Sometimes building the "worker" classes in the middle will give you plenty of insight into how the configuration needs to work.  Starting in the middle can help you prevent churn and often lead to a simpler configuration mechanism.
    • You definitely want your framework to be decoupled from the configuration.  My strong advice is to build an internal model representing the configuration of the framework.  I think you have much more flexibility later, and easier testing upfront, if you completely decouple the end functionality of the framework from its configuration.  Starting with the configuration first can easily leave you too tightly coupled to the configuration.
  • Do hide the smelly, complicated details of your internal model from the consumers of your framework.  That was a lesson I learned the hard way from early versions of StructureMap.
  • The framework I'm starting on this week has some pretty stringent requirements for ease of configuration.  I still think I want to start in the middle with the classes that do the work, but I think that I will tackle the configuration schema or DSL as early as possible.  Bellware gave me an idea about more or less letting the tester define the syntax and format of the configuration as part of creating acceptance tests.  I'm definitely going to give that some serious thought.
  • How do you configure your framework?  One easy path is to just use StructureMap or Castle Windsor and use their configuration mechanisms right out of the box.  I know in my case that strategy would easily lead to some very verbose Xml descriptions with repetitive data, so another layer of abstraction might be valuable.  One of my thoughts for the new Fluent Interface API in StructureMap is that you could use that as a base for creating your own application specific plugin configuration.  For my new project I'm thinking about these alternatives (strangely enough, I think StructureMap 2.0 usage is a given):
    • A new Fluent Interface API written in C# that sits on top of StructureMap.  We're expecting the configuration to change frequently, and the personnel doing the configuration aren't necessarily hard core developers.  I think we're already ruling this one out, but I might resuscitate the idea for StoryTeller later.
    • Create a terse Xml format specific to the framework that would probably still feed StructureMap to minimize the amount of "builder" code later and provide easier paths to adding extensions.  Xml is always a good fallback position, but a proliferation of angle brackets and readability don't always go hand in hand.  All the same, you know that's where we'll end up.
    • Create a new DSL with BOO scripts or Ruby/RubyCLR.  I'll admit that's just the inner geek in me wanting to do that, but it might be a very viable option.  I'm not confident about being able to sell that though.
    • This is out of left field, but I think it's perfectly viable.  Use the FitnesseDotNet engine to parse out HTML tables.  Leaning on the DoFixture, you can cheaply build little languages quickly.  That also comes with a cool advantage of being ready made for automated testing.
    • Create an administrative tool.  Blackhole here we come.  In a way, I think it's nearly a mark of failure if your framework's configuration is only usable with a GUI designer. 

Posted 04-04-2007 8:03 PM by Jeremy D. Miller

[Advertisement]

Comments

Ayende Rahien wrote re: Thoughts on Building Pluggable Frameworks
on 04-04-2007 9:19 PM

> Create a new DSL with BOO scripts or Ruby/RubyCLR.  I'll admit that's just the inner geek in me wanting to do that, but it might be a very viable option.  

Obviously that would be my choice.

> I'm not confident about being able to sell that though.

That one is an issue, for some reason. No one has a problem with > 200 Kb of XML Configuration, but they have a problem understanding if/else if it is not syntax colored and in VS.

What kind of information do you need to put in the configuration is key here.

One of the reasons that Binsor is making life simpler is that I don't need to put things like: "Foo.Bar, Assembly, Culture=Neura..." all over the place.

This works really well for configuring an IoC, because it is mostly about dealing with types, and that is something that Boo is very good about.

Rinat Abdullin wrote re: Thoughts on Building Pluggable Frameworks
on 04-05-2007 2:30 AM

> Create an administrative tool.  Blackhole here we come.  In a way, I think it's nearly a mark of failure if your framework's configuration is only usable with a GUI designer.

Why not let Structure Map handle the configuration management as well? I think something like the GUI designer for the Microsoft Enterprise Library could do the trick and still stay extensible and reusable.

David Hayden wrote re: Thoughts on Building Pluggable Frameworks
on 04-05-2007 9:02 AM

"Where do you need to put the extensibility seams?  I say let automated testing be your guide."

You hit the nail on the head. In the past I have been king of overarchitecting a framework or library by adding extension points based on speculation because I feared it would be difficult to add those extension points later. I tried to predict the needs of the business from a crystal ball :) It turns out that writing tests flushed out the extension points on their own and made the framework more adaptable to future needs.

chris donnan wrote re: Thoughts on Building Pluggable Frameworks
on 04-05-2007 11:01 AM

Another important aspect to 'pluggable frameworks' is that the 'base cases' are real easy, and the harder stuff is pluggable along the desired 'seam'. TDD is the de-facto guide, but also knowing how to enable a point of extensibility is key.

-Composed Strategies

-Template Method/ Inheritance

-Delegate based APIs (think List's generic search stuff and friends)

-Contain and delegate/ decorators

I agree that IoC is a huge key to truly 'pluggable frameworks', but even without a DI container, it is pivotal. Use of 'sensible defaults' for the 'injectable' constructor args/ properties. The sensible defaults enable the 'seams' to only be visible when you look close - or you need to 'get in there'. Do not forget the sensible defaults :)

Also - TDD as a guide ensures that the base cases 'look right' are 'easy' and 'simple'. DI can sometimes complexify usage scenarios if you do not do TDD to 'see your way' and if you do not provide sensible defaults. Using a DI framework is helpful, but I usually try to evolve my APIs WITHOUT them 1st, then look @ the DI framework as a configuration mechanism to keep the couplings out of the code and act as an elaborate scenario based builder. The API should certainly be usable and trim without the DI framework IMHO.

My 2 cents;

-Chris

58bits - Tech - Application Block Software Factory - Sample App wrote 58bits - Tech - Application Block Software Factory - Sample App
on 07-03-2007 5:07 PM

Pingback from  58bits - Tech - Application Block Software Factory - Sample App

Add a Comment

(required)  
(optional)
(required)  
Remember Me?