A Vision for FubuMVC’s Component Model (gems, Nu, engines, slices, oh my…)

[25/02/10]

I’m banging this out fast and trying to think out loud.  Blame the lack of polish on that previous statement.  The whole point of this blog post is to elicit feedback and get ready for Pablo’s Fiesta this weekend (no crazy tax evader can stop the ALT.NET community by merely crashing a plane into the building).

Pablo’s Fiesta starts tomorrow night with the typical Open Spaces agenda creation.  Coincidentally, we’ve got several FubuMVC contributors coming into town and we’re going to take advantage of that to carry out some FubuMVC project business.  My main concern for the conference is to nail down our component story for FubuMVC.  First off, I want FubuMVC to have a fullblown “engine” or “slice” strategy that allows you to build and reuse vertical slices of an application across projects.  Secondly, we need an easy way to apply those “engines” to other places.  For those of you familiar with Rails and Merb, I’m wanting nothing less than a “gems” like solution for FubuMVC that allows a project team to quickly assemble project infrastructure and share substantial parts of an application architecture with as little friction as possible.  Right now, my focus is on the resurrected Nu project as a way to distribute and apply engines to your code tree packaged up as “Nug’s” (the Nu analogue to a gem).

 

To really make the usage and distribution of FubuMVC “engines” go well, I think we need to do be able to package / discover / distribute the following:

  • Libraries.  One of the things I hear from people is that they just think it’s too hard to piece together OSS tools (it doesn’t matter if you disagree with that statement, because many people *do* feel that way).  The very first step is to finally get a decent .Net OSS story around distributing components.  I want something like “gems install fluent-nhibernate” that puts the latest released version of Fluent NHibernate into my “tools” directory, and oh yeah, also gets the correct NHibernate binaries with all the little Castle and LinFu pieces that live underneath NHibernate in one go.  This is obviously pretty complicated when you think about versioning and dependency trees, but it’s also been done in other development communities and we can take a lot of inspiration from things like gems, Maven, etc.
    • We’ll have to effectively agree upon a standard folder layout for external tools so that Nu can scan
    • I’m fully aware of HornGet, but I do not see it as the right approach to this problem. 
  • Extensible Command Line tools.  We have several command line utilities at Dovetail for our localization subsystem (exporting/importing data, filling in missing localization keys, etc.) that could easily be useful on other projects.  Other folks are keen on building “scaffolding” approaches into Fubu   Nu is built around extensible command line tools and I think it could be a powerful way to distribute little project utilities as part of an engine/Nug package.
  • Project Files.  I think it’d be nice if when I installed the (not yet existent) “NHibernate QuickKit” engine with Nu and Nu could reach into my *.csproj files and add the right references for me in order to use the NHibernate features.  That’s a big can of worms, but I think it could reduce friction in using a lot of tools – especially tools that come with lots of assemblies (I’m looking at you nServiceBus).
  • Configuration.  Your engine could easily require some external configuration.  I know one of the first engines I’d like to see is a NHibernate starter kit that would give you a basic NHibernate setup and a simplistic Repository implementation – and NHibernate just doesn’t go without a connection string somewhere.  My thought is to standardize FubuMVC on the AppSettingsProvider model that Josh blogged about here
    • When a Nug is installed, maybe it could scan the new imported assemblies and find any new “Settings” classes needed for the new engine.  We could have it add the new properties to the appSettings file automatically with any default values.  I think this could help to make things like NHibernate integration easier
    • The standardized configuration model for things like file paths, Url’s, and connection strings would make it easier to share deployment recipes and infrastructure for staging code through different environments (dev to test to UAT to production).
  • Services.  A slice/engine may easily need to expose other services to the underlying IoC engine.  Fubu can only function with an IoC container.   It’s been a very important goal to me to ensure that Fubu is IoC tool agnostic (it’s not there yet, too many assumptions about StructureMap runtime characteristics that aren’t necessarily true of the other tools.  We’ll get there) and that Fubu makes no restrictions on *how* you can use your IoC tool (many of the “abstract away the IoC tool” strategies do an awful job on this score).  You already have some limited ability to register services in FubuRegistry.  The FubuRegistry.Include( other registry ) doesn’t merge the service registry yet, but will at some point.
  • Conventions.  Html conventions, behavior policies, Url/Route conventions, View conventions, you name it, all of it is reusable in FubuMVC.  I think it’d be nice to say “I wanna use the ‘DataAnnotations’ pack” and just like that, you get Html conventions applied to your project that read metadata off of the DataAnnotation attributes and apply that towards client side jQuery validation.  Today this is done with code in a FubuRegistry class to explicitly add conventions.
  • JavaScript libraries.  Look, it’s a rich internet world now and you almost have to use Ajax to create a compelling user experience.  There’s the whole jQuery ecosystem with more useful plugins than you can shake a fist at.  However, a lot of these plugins (jqGrid comes to mind) require some server side integration to really shine.  What if your “Nug’s” could contain both server side functions and custom JavaScript libraries?  When you download a Nug, any Javascript libraries will be pushed to where the main Fubu app can find those libraries. 
    • We have to determine a standard location for the JavaScript files
    • We need some sort of script manager piece in FubuMVC.UI that can load them
    • Maybe we minify them on demand?
    • I think it would be nice if custom Html Helper from external engines could quietly declare behind the scenes that “I need this JS / CSS file” and a <script> tag is added to the page if it isn’t already there
  • Packaged Views.  It would be nice is some engines could include packaged views for things like admin screens.  You can do this out of the box by using some sort of embedded views, but it’d probably be nice if we had a good way for an engine installation to copy the view files to a known location where you could modify or skin those views at will (in this case, the reusable view from the engine is mostly just a template).
  • Warmup / Deployment tools.  I’ve always admired things like Capistrano in the Ruby world.  If we standardized the FubuMVC code structure, maybe we could reuse project setup, automated build tooling, and deployment recipes across projects the way that Rails developers do.  Wouldn’t that be awesome.

 

Another architectural issue is how the externalized engines are discovered by FubuMVC.  Right now, you have to explicitly add things to a FubuRegistry class.  I think we also need to consider some sort of dynamic discovery of the external addin’s.  It could just be a known folder that we scan at application startup, a partial class in your top level web project that could be auto-generated, an Xml/Json file listing the class names of FubuRegistry types to load as engines or something else I haven’t considered yet.  I’m leaning towards the scanning model, but I’m all ears.

 

The core architectural philosophy of FubuMVC is composition.  It’s completely wrapped around IoC service composition, the code basically follows the S.O.L.I.D. ideas for object responsibilities so there’s a lot of seams, and everything is swappable (think “sharp tools”).  Conventions can be packaged up and reused across projects.  Vertical slices of the application can be packaged and reused across applications by the FubuRegistry concept.  The thought right now is to keep a pretty spare core MVC infrastructure in the core assemblies and add additional UI magic in external assemblies that can be optionally added into your project.  The Html conventions feature was already developed in this way.  In the next 3-4 months I know where adding new facilities for localization, validation, and some more Html conventions on top of those things – but none of it will come out of the box.  The “tinker toy” approach gives us a huge advantage in being able to adapt FubuMVC for totally new scenarios and reuse code and avoid the original Rails problem of “use my opinions or go home,” but…

How the bleep is the average team going to be able to assemble all these little pieces and get them to work together without losing all their hair?

 

My personal goal for FubuMVC is to get that question answered – and I’m hoping that Pablo’s Fiesta moves the conversation.

A Vision for FubuMVC’s Component Model (gems, Nu, engines, slices, oh my…)


Archives


Web Forms Routing in ASP.NET 4

[28/02/10]

At our first Sarasota Web Developer Group meeting we discussed several of the new enhancements in ASP.NET 4 Web Forms. One of my favorite enhancements is the new routing features which are very similar to the ones I have enjoyed so much in ASP.NET MVC.

 

Register Routes

This is old hat for those using ASP.NET MVC. Just register your routes at application startup. Rather than your endpoint being a controller, however, you associate a physical page as the handler of the request.

 

public class Global : System.Web.HttpApplication
{
    void Application_Start(object sender, EventArgs e)
    {
        RegisterRoutes(RouteTable.Routes);
    }

    void RegisterRoutes(RouteCollection routes)
    {
        routes.MapPageRoute(
            "Contact_Details",                  // Route Name
            "Contacts/Details/{id}",          // Url and Parameters
            "~/Contacts/Details.aspx"     // Page Handling Request
            );
    }
}

 

In this case we are telling the routing engine 3 things:

  • Name of the Route: Contact_Details
  • The Route: Contacts/Details/{id}
  • The Physical Page Handling the Request: Details.aspx

 

Notice the id parameter ( route value ) which will be the id of the contact to display in the details page.

 

Expression Builders for Creating HyperLinks, etc.

With ASP.NET MVC we have strongly-typed View Helpers to help generate links. With ASP.NET 4 Web Forms you utilize Expression Builders to create links such as:

 

<asp:HyperLink
    NavigateUrl="<%$RouteUrl:RouteName=Contact_Details, id=1 %>"
    runat="server">John Doe
</asp:HyperLink>

<asp:HyperLink
    NavigateUrl="<%$RouteUrl:id=1%>"
    runat="server">John Doe
</asp:HyperLink>

 

We can explicitly specify the name of the route or let the routing engine figure out the correct route based on the parameters.

 

Getting RouteData from the Page

You can access the RouteData from the Page by accessing the Page.RouteData Property, which is just a convenient access point to RequestContext.RouteData. Here are a couple of ways to get the id from the route to display the proper contact given its id:

 

public partial class Details : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        var id = Page.RouteData.GetRequiredString("id");

        var id2 = Page.RouteData.Values["id"];
    }
}

 

RouteParameter for use with DataSources

If you are displaying the contact in a DetailsView, for example, you can use the new RouteParameter with your DataSource to get values from the route as such:

 

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" 
    SelectMethod="FindById" TypeName="Contact">
    <SelectParameters>
        <asp:RouteParameter Name="id" RouteKey="id" Type="Int32" />
    </SelectParameters>
</asp:ObjectDataSource>

 

Binding your DetailsView to the ObjectDataSource will now cause the contact to be displayed appropriately.

 

Response.RedirectToRoute and RedirectToRoutePermanent

A lot has been mentioned about using Response.RedirectPermanent for SEO, but even cooler is Response.RedirectToRoute and Response.RedirectToRoutePermanent for working with the new routing engine. Below I am specifying the route name and passing in any route values where necessary when redirecting:

 

Response.RedirectToRoute("Contact_Details", new { id = 1 });

Response.RedirectToRoutePermanent("Contact_Details", new { id = 1 });

 

Conclusion

Lots of really neat things in ASP.NET 4 and ASP.NET 4 Web Forms. I am going to continue to post a few more we discussed during the first meeting.

For those interested, the second meeting of the Sarasota Web Developer Group will discuss a number of interesting topics: Leveraging ASP.NET MVC - Web Forms - DynamicData - Castle ActiveRecord.

 

David Hayden

 

Introduction to the Reactive Extensions for JavaScript – Creating Observers

[27/02/10]

Looking back to the previous post, we covered how we create observable sequences, the producers of our data.  We have quite a number of ways of creating these outside of events which we covered earlier.  Now that we have these observable sequences, now what?  We need to address the consumer side of this producer/consumer story in the form of an observer.

Before we get started, let’s get caught up to where we are today:

Creating Observers

Let’s go back to the Observer pattern definition once again before we get started.  The idea here is that we have an object, called the Observable (or Subject) which keeps a list of its dependents, the observers, and notifies each of them automatically of any state changes.  In the case of the Reactive Extensions for JavaScript, we’re talking more about observable sequences.  As we discussed last time, the Observer has three parts:

  • OnNext – when a new value is produced
  • OnError – when an exception occurs
  • OnCompleted – when the observable sequence terminates

When creating an observer, we should take all three into account and how we’re going to handle them. 

In order to attach these observers to our observable sequence, we can invoke the Subscribe method on our observable while passing in our observer.  And when we’re no longer interested in the subscription to the observable sequence, we can detach by calling Dispose on the result of the Subscribe method.

New Observer via Create

Let’s get started in creating an Observer by looking at the Observer.Create method.  This method takes in three functions, one for the OnNext, one for the OnError and finally one for the OnCompleted.  This function returns to us an Observer which we can then use for subscribing.

Rx.Observer.Create(
    function(next) { ... }, // OnNext
    function(err)  { ... }, // OnError
    function()     { ... }) // OnCompleted
);

Once we have an Observer, we can then attach to the Observable using the Subscribe method which takes our Observer.  When we call Subscribe, we get back a disposable object with a single Dispose method which allows us to detach from the Observable.

Observable {
    Subscribe : function(observer) { ... }
}

One of the best ways I find to explore a new API is to write tests to show the expected behavior.  By writing these, I have a comprehensive view of what each method does, especially if the code didn’t come with the tests already.  So, let’s create a few tests to show the behavior of creating an Observer and then subscribing to an Observable sequence.  I’ll use QUnit to write my tests, and in particular, the asynchronous test feature due because we are testing asynchronous callbacks.

The first test will be to check the OnNext function parameter on Observable.Create.  In this case, I’ll assert at the single value in my observable sequence is the value I receive when OnNext is invoked.

asyncTest("Observer should observe OnNext", function() {
    var observable = Rx.Observable.Return(0);

    var observer = Rx.Observer.Create(
        function(next) {
            equals(0, next);
            start();
        },
        function(err) { },
        function() {});

    observable.Subscribe(observer);
});

The next test, I will make an example on how my OnError function parameter will work.  In this case, I’ll have an Observer throw an exception via the Throw method and my OnError function check the message and assert that it’s the same as my error that I threw.

asyncTest("Observer should observe OnError", function() {
    var someError = "FAIL!";

    var observable = Rx.Observable.Throw(someError);

    var observer = Rx.Observer.Create(
        function(next) { },
        function(err) {
            equals(someError, err);
            start();
        },
        function() {});

    observable.Subscribe(observer);
});

Finally, in my last example, let’s create a simple test to show off the OnCompleted behavior.  In order to do so we’ll create an empty observable which should not yield any values and instead only invoke the OnCompleted.  Then we’ll create an Observer which has the test logic in the OnCompleted function parameter.

asyncTest("Observer should observe OnCompleted", function() {
    var observable = Rx.Observable.Empty();
    
    var observer = Rx.Observer.Create(
        function(next) { },
        function(err) { },
        function() {
            ok(true, "True when invoked on complete");
            start();
        });

    observable.Subscribe(observer);
});

Creating Observers this way is good for reusability, especially if you wish to attach to any number of observable sequences.  But, we’re not tied to having to create them via Create, there are other ways.

Overloading Subscribe

In addition to creating an Observer via the Create method, we also have shortcuts which allow us to create an Observer on the fly with the Subscribe method.  In addition to the Subscribe which takes an Observer, we have three other overloads which can take functions for our OnNext, OnError and OnCompleted.  The first overload takes a function for OnNext, where the next takes a function for OnNext and OnError, and finally the last overload takes functions for all three, the OnNext, OnError and OnCompleted.

Observable {
    Subscribe : function(
                    function(next) { ... })

    Subscribe : function(
                    function(next) { ... },
                    function(err)  { ... })            
                    
    Subscribe : function(
                    function(next) { ... },
                    function(err)  { ... },
                    function()     { ... })
}

This function, just as above, will create a disposable object for us which allows us to unsubscribe at any time via the Dispose method.

Unsubscribing

As I’ve stated earlier, one of the great things about the design of Rx for JavaScript is that it’s quite easy to both subscribe and unsubscribe from an observer.  The design of Rx for JavaScript follows very closely to the design of Rx for .NET including subscribing and unsubscribing.  Let’s step through an example of how we can use the Dispose method on our subscription.  In this instance, we’ll have two observers, and after the first value has been produced, we unhook the first observer and continue listening on the second.  We’ll assert that indeed the first has been unhooked while the second continues to listen.

asyncTest("Dispose should unhook observer", function() {

    var nextValue = 0;
    var observable = Rx.Observable.FromArray([1,2,3]);

    var disp1 = observable.Subscribe(
        function(next) {
            nextValue = next;
        });
    var disp2 = observable.Subscribe(
        function(next) {
            disp1.Dispose();
            equals(1, nextValue);
            start();
        });
});

Such scenarios could be quite helpful in unhooking events when others happen, such as mouse events, keyboard or even AJAX requests.  We’ll cover some of those scenarios in upcoming posts.

Conclusion

So, now we’ve covered the basics of creating Observable sequences and Observers and subscriptions.  Now that we have some of the basics what else can we do with it?  That’s where some of the LINQ combinators come in handy and we’ll pick that up next time.

This of course is only scratching the surface of what capabilities this library has and there is much more yet left to cover.  The question you’re probably asking now is where can I get it?  Well, for that you’ll have to stay tuned.  I hope to have more announcements soon about its general availability.

What can I say?  I love JavaScript and very much looking forward to the upcoming JSConf 2010 here in Washington, DC where the Reactive Extensions for JavaScript will be shown in its full glory with Jeffrey Van Gogh.  For too many times, we’ve looked for the abstractions over the natural language of the web (HTML, CSS and JavaScript) and created monstrosities instead of embracing the web for what it is.  With libraries such as jQuery and indeed the Reactive Extensions for JavaScript gives us better tools for dealing with the troubled child that is DOM manipulation and especially events.

Certified Scrum Product Owner Training class on May 24, 2010 in Boulder.

[26/02/10]
Certified Scrum Product Owner Training class on May 24, 2010 in Boulder.

[26/02/10]  - The usefulness of interaction tests, or “How to question the method”

[26/02/10]  - Castle Project code organization

[26/02/10]  - Scrum Challenge #1 OVER: Scrum is…

[25/02/10]  - A Vision for FubuMVC’s Component Model (gems, Nu, engines, slices, oh my…)

[25/02/10]  - The Exec Problem

[25/02/10]  - 3 Days To Go!

[25/02/10]  - Random Thought Scrum Challenge – #1

[24/02/10]  - DevTeach Toronto 2010 Ultimate Edition

[23/02/10]  - Introduction to the Reactive Extensions for JavaScript – Creating Observables

[23/02/10]  - Sarasota Web Developer Group - MVC and ASP.NET 4 From Scratch

[22/02/10]  - How I Stole an Office and Fixed Our Daily Scrum

[22/02/10]  - CST Application Process Improvement Community

[22/02/10]  - Scrum Alliance National, USA: Managing Director

[22/02/10]  - 10 Things I Hate About Agile Development!

[21/02/10]  - XP Day Suisse, Geneva, 29 March 2010

[21/02/10]  - In Praise of Middle Management

[20/02/10]  - Why use Event Sourcing?