A story on composable systems

<warning>This is a long post that attempts to describe a positive experience leveraging multiple frameworks</warning>

TL;DR. Static Typing / IoC == AWESOME FLEXIBILITY

Recently while working at Dovetail I had the absolute pleasure to provide a solution to a customer request. We were adding SAML authentication to our product, and we wanted to provide an extensibility point to handle unknown users. By default the product would show a not authorized screen if we encountered a valid SAML assertion referencing an unknown user. This was pretty easy to setup, but as I said, we really wanted this to be extensible. What I wanted to support was redirecting the user to a different page, maybe one that a customer has specified which would give the user the information needed to request access to our application through the approved channels. That would have been pretty easy with just a configuration entry, but we decided that really wasn’t enough. We also wanted to be able to handle a request to make a user right there. Well, now we need the ability to execute some code, a configuration file isn’t going to handle that very well. Even if we kept the config file approach we would have to redirect the user to somewhere else in the app, and then figure out how to shuffle all of the required data around. :( It just didn’t feel like a solid solution.

Thankfully, FubuMVC, Bottles and StructureMap came to the rescue. FubuMVC gives us controllers that can easily take dependencies on services (nothing to fancy here, you can do this in ASP.NET MVC too). So our SAML Authentication controller (or action in Fubu land) takes in a service that acts as a policy (SuccessfulSamlAssertionPolicy) it takes a valid SAML assertion, and attempts to locate the user in the database, if it finds them, the policy logs them in, and then redirects the user to the home page. If we can’t find the user, then we invoke the UnknownUserPolicy (another service/policy thing which is injected in the SuccessfulSamlAssetionPolicy) the default implementation of this policy simply redirects them to an error page of ours, but since it’s a interface/class pair, we can easily swap that out. This is where IoC/DI/StructureMap make things really nice.

So, the above may seem a bit complex (I definitely didn’t explain it that well). So lets break it down and make it concrete. I have an interface that looks like this

public interface UnknownUserPolicy
{
    //FubuContinuation is a way to redirect the user
    FubuContinuation HandleUnknownUser(SamlAssertion assertion);
}

we ship with the following implementation

public class DefaultUnknownUserPolicy : UnknownUserPolicy
{
    public FubuContinuation HandleUnknownUser(SamlAssertion assertion)
    {
        return FubuContinuation.RedirectTo<LoginController>(c => c.Login(null));
    }
}

Super easy code, nothing too hard here. We wire it up in StructureMap using a convention, so there is really nothing else to show. Now, lets imagine we have a customer, that doesn’t want them redirected to the login page, they should instead go to: https://silly.corporate.subdomain.company.com/request_access.cfm . Using StructureMap, this is as easy as registering our policy later in the container (after the default registrations) by adding a line like this:

For<UnknownUserPolicy>().Use<CompanyXUnknownUserPolicy>();

That will override the default policy and boom! We have just customized our application for this one customer. So that’s great and all – but I want that in only ONE deployed instance of the application. I do not want to modify the base product for this customer, and this is where Bottles comes to my rescue. :)

Bottles is a framework for assisting us in loading dynamic code in a controlled and predictable manner. Its built with an IoC container in mind, but is completely agnostic of them and FubuMVC entirely. When our application starts up, we go through all the usual stuff for a .Net / IoC project. We initialize logging, spin up our container, blah, blah, blah. The one new step that we add with Bottles though, is to run through every discovered Bottle, and look for ‘StructureMap Registries’ and load them into the container. Now, a bottle is pretty much a glorified zip file holding .Net assemblies — among other things. The bottles, being a separate file from the base product, can be used to modify our existing application. In this case, we have a Customer Bottle that does one thing. It executes that above piece of SM registration code to override the base UnknownUserPolicy. :) WIN.

So, by putting all of these various tools, patterns, and frameworks together, we were able to build a solution that allows for a lot of customizability, does NOT require us to change our base product (would have loved to have had this at the bank), and I think truly encapsulates the changes that customizations for a customer can bring into one easily deployable unit.

There are a LOT of things going on in this post, we have programming to interfaces, we have making small classes that do one thing well, we are using IoC, we are using a web framework that makes redirecting deep in the bowels of the app easy and testable, we have composition, dynamic code loading and a lot of ‘abstractions’ (Yup, learned about those at a young age ;) ). Using all of these has allowed us to add a lot of seams to our application, and it’s this kind of power that keeps our application nimble and easily customizable for any customer.

About Dru Sellers

Sr. Software Engineer at Dovetail Software.
This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Anonymous

    :)
    You aren’t the only one.

    Bottles (a simple packaging concept [a zip file]) + dependency management + a loading mechanism. StructureMap does the scanning (not bottles).

    Therefore it is not like MEF.

  • Anonymous

    Sounds cool Dru!
    I read about Bottles on some other blogs as well. Is it similar to MEF in that it can dynamcially load assemblies that export specific interfaces? I thought  StructureMap already had that capability. Sorry if my question doesnt make sense. trying to wrap my head around bottles :)

  • Anonymous

    We have extensive testing in place. Every commit is tested against over 2,000 unit tests, 300+ end to end tests, and customer specific test runs as well. On top of that we have tests for each sellable combination of the product.

  • Khalid Abuhakmeh

    @chadmyers:disqus  Yeah I think that might not make sense to do that unless you were building the next wordpress or similar CMS.
    @drusellers:disqus I guess my concern is how do you test different modules for different clients. I’d love to see how that is done. Might be a lot to track. @Rauhr:disqus mentions logging which is probably what you do. What does your build and deployment process look like?

    I’m very intrigued.

  • http://chadmyers.lostechies.com Chad Myers

    Also, we generally don’t load bottles at runtime, only at deploy time. It is possible to drop a Bottle into a running app’s deployed folder, but we don’t do that. 

  • Anonymous

    What specific concerns do you have Khalid?

  • Anonymous

    FubuMVC provides comprehensive logging on when bottles are loaded, what order they were loaded, and the time it took to load them. FubuMVC also provides a web interface to view the logs directly from the application. 

    There are hooks to add your own logging. Bottles also provides directed acyclical dependency graph to ensure bottles with dependencies get loaded in the correct order. 

  • Khalid Abuhakmeh

    Bottles sounds really cool, but how do you handle or address system stability when loading dynamic bottles. Do you have a lot of logging code and fail safes built around loading bottles?