Saturday, May 14, 2011

TEAM.Commons: MVC + Single Responsibility Principle (SRP) = Single Action Controller

Since a long time ago I've been concerned about the increasing size and complexity of our ASP.NET MVC controllers: we have been clearly going against the Single Responsibility Principle.

UPDATE:

an improved version of this implementation is available here.

Common controllers

This is some sample code to illustrate how one of our typical controllers looked like:

using MyCompany.MyProject.Models.Author;

namespace TEAM.MvcSACDemo.WebUI.Controllers
{

  public class AuthorsController : Controller
  {

    // Dependencies (smell: too many dependencies)
    protected readonly IDbSessionFactory DbSessionFactory;
    protected readonly IIndexQueries IndexQueries;
    protected readonly IEditQueries EditQueries;

    // Actions
    // Smells: too many methods; too many qualifications in the classes' names)
    public ActionResult Index(AuthorsFilterDataModel filter) { ... }

    public ActionResult Create() { ... }

    public ActionResult Insert(AuthorInsertDataModel newAuthor) { ... }

    public ActionResult Edit(long id) { ... }

    public ActionResult Update(AuthorUpdateDataModel) { ... }
  }
}

The violation of the Single Responsibility Principle should be obvious.

Our new approach


My initial thought was to change the rule we have been using to create a controller, which is one controller per entity, and find some other rule that produces more controllers with less actions while keeping or increasing the organization level.

A few days ago I stumbled on this post by Derek Greer, and immediately asked my friend Yaniel Díaz help me to develop this idea. After a couple of iterations we had a couple of classes and extension methods that will let us (and also you if you like) implement Single Action Controllers keeping must of the nice ASP.NET MVC conventions.

First, let's see how do Single Action Controllers look like:

using MyCompany.MyProject.Models.Author.Index;

// Name your namespace after your controller.
// This works very nicely with the directory structure you create in your project.
namespace TEAM.MvcSACDemo.Controllers.Author
{
  // Name your class after your Action and inherit from SingleActionController
  // You could choose to name it IndexAction instead
  public class Index : SingleActionController
  {
    // Only one dependency
    protected readonly IIndexQueries IndexQueries;

    // One single action (notice the use of namespace to remove extra qualification in the classes' names)
    public ActionResult Execute(FilterDataModel filter) { ... }
  }
}

And this is how it all looks in the Solution Explorer:


Except for the "Author" and "OtherEntity" nested folders, it's all like "traditional" MVC.

Using it in your application


All the required classes are available in the TEAM.Commons package under the TEAM.Commons.Web.MVC.SingleActionControllers namespace. TEAM.Commons is also available as a NuGet package, which is the preferred way to share code these days.

After you install TEAM.Commons in your solution (or copy the code you need), you must register your routes using the custom SingleActionControllerRoute:

public static void RegisterRoutes(RouteCollection routes)
{
  routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
  // Best practice to avoid MVC handling the favicon request
  routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.ico(/.*)?" });

  // Only change the original MapRoute by our MapSingleActionControllersRoute
  routes.MapSingleActionControllersRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "Author", action = "Index", id = UrlParameter.Optional },
    new { }
  );
}

and then register SingleActionControllersFactory as the ControllerFactory:

// You must pass the fully qualified name of the assembly
// and the namespace of the controllers. 
// In future versions we'll simplify this step.
ControllerBuilder.Current.SetControllerFactory(new SingleActionControllerFactory(Assembly.GetExecutingAssembly().FullName, "TEAM.MvcSACDemo.Controllers"));

The internals


Thanks to ASP.NET MVC design we just had to implement a custom ControllerFactory, a custom Route and a custom base class for controllers.

Check the source code at the TEAM.Commons repository. It should be self-explanatory and could give you ideas about how to do it yourself in case you don't want to use TEAM.Commons.

Conclusions


The implemented solution is not perfect and I'm sure it could be improved, but we needed to go back to SRP in our controllers as soon as possible. I'll update this post when we find a new solution.

I hope you find this as useful as we do :-)

Friday, March 25, 2011

Unobtrusive and useful Google Chrome plugins for developers

There are zillions of plugins for Google Chrome, and several of them are developer-oriented. However, some of these plugins interrupt my usual workflow, or make Chrome slow and unresponsive, or are simply not well tested and crash.

These are the plugins I've found to be more useful:

Monday, March 21, 2011

TEAM.Commons published as a NuGet Package

NuGet is a nice tool to share code (source or compiled).

I've published TEAM.Commons as a NuGet package in http://nuget.org/List/Packages/TEAM.Commons. With this step it's much easier to use this set of classes: just type Install-Package TEAM.Commons in your NuGet console.

Saturday, March 12, 2011

Unobtrusive jQuery UI (jquery.ui.unobtrusive)

I am very enthusiastic about unobtrusive JavaScript. It's a design pattern and usual warnings apply:
  • It doesn't apply to every scenario.
  • It will hurt if you use it wrong.
  • Long etc.
Very short version of this post

I hope someone creates a complete jquery.ui.unobtrusive plugin. Since I'm a developer I have already started one at:
https://bitbucket.org/rodolfograve/jquery.ui.unobtrusive

The bad news is that I'm not an expert JavaScript nor jQuery developer, so I'm sure the quality of what I'm doing can be greatly improved. It will be great if someone with more expertise could continue this work or start his own and make it public.

Long version

I think unobtrusive JavaScript solves several old and current problems:

  • How do we make advanced HTML + JavaScript stuff from server-side code?
  • How do we reuse JavaScript code that interacts with the elements of a page?

Until now I've seen incomplete and ugly approaches (the latter is obviously a personal opinion):
  • Don't do advanced HTML + JavaScript from server-side code at all and create custom JavaScript code for each page you have.
  • Generate small pieces of script from server-side code, intermingled with the final HTML code (outside the head tag), and handle elements' IDs and classes.
With unobtrusive JavaScript we have a new great approach: generate HTML attributes in your tags and let your unobtrusive scripts do their science (I appreciate science more than magic).

This new approach is:
  • Flexible: you can use whatever you like to generate the attributes (ASP.NET MVC HtmlHelpers, your own framework, write attributes by hand in your HTML, etc).
  • Testable: unobtrusive scripts can (or even must) be developed as reusable components, with their own tests (JavaScript as a Framework).
  • Readable: your HTML code will declaratively express what it does (no need to look IDs nor classes in JavaScript files).
No more obscure separation between the appearance and the behavior. This separation is good and encouraged, but it's much better without the "obscure" feature added by current implementations (you must look your IDs or CSS classes in your JavaScript code to know what's going on with an HTML element).

<html>
  <head>
<script type="text/javascript">
  $(document).ready(function() {
    $("myDatePicker").datepicker({
      showOn: "button",
      buttonImage: "../themes/mytheme/calendar.gif"
    });
  });Notice this piece of script usually is in another file (even worst).
</script>
  </head>
  
  Lots of stuff, and then hidden some where in the page:

  <input id="myDatePicker" name="myDatePicker" type="text" >

With unobtrusive JavaScript you keep the separation at the implementation level, and avoid the separation at the code level.

<input type="text" ui-datepicker="true" ui-datepicker-showOn="button"
                                             ui-datepicker-buttonImage="../themes/mytheme/calendar.gif" >

This last code looks much better to me and I wish we soon have the unobtrusive "mapper" of the most popular JavaScript frameworks out there.

What do you think?