Tuesday, September 25, 2012

Keeping server and client side in sync - enforcing contract compatibility

In our project which is an ASP.NET MVC application, quite a lot of features are implemented at the client side, with JavaScript, which is talking with the server using JSONs. Besides the web client, we have a mobile client application, which is driven by the separate API, provided by the same MVC application, a bit WebAPI style, again using JSONs. No rocket science.

As all of these three parts are growing and changing quickly (sometimes way too quickly), we were struggling with incompatibility between what the JavaScript or mobile client expects to receive and what the server is returning, due to the changes not being applied on both sides. Refactorings, functional changes or even correcting a typo affected these server-client interactions. Changing a property name is so easy with ReSharper that we're often not taking enough attention to spot possible impact at the borders between the layers. What's worse, we're relying heavily on the default model binding behavior of ASP.NET MVC - this means that even parameter names in action methods became part of our public API that we need to take care of. And by taking care I mean either not ever changing once-published name, or update all the possible clients together with the server-side backend deployment (that includes forcing all mobile app users to upgrade - nightmare!).

We decided we need a cheap, reliable and universal method that prevents unintended changes in our public contracts - action names, parameter types and names, returned types structures, names of properties etc.

Good and well maintained suite of integration tests will probably do the job, but unfortunately we still don't have one (and we're not the last ones, are we?). And I suppose the suite would be quite huge to cover good range of unintentional changes we can possibly introduce. Second thought was to implement some quirky tests that would use reflection to go through the codebase and fail if the implementation differs from what we expect. But it would be better to invest that considerable amount of time needed to write these kind of specifications in writing real integration tests.

Finally we took a simpler approach. We decided to be more explicit in what is our external API and what is not. We've created a binary contract definition using few steps. Let's see it on this simple example:

public class StadiumController
{
     public ActionResult GetByCapacity(int? minCapacity, int? maxCapacity)
     {
          var min = minCapacity ?? 0;
          var max = maxCapacity ?? int.MaxValue;
          return Json(Stadiums.Where(x => x.Capacity >= min && x.Capacity <= max));
     }
}

1. enclose the input parameters of action methods in "input model" classes

public class StadiumByCapacityInputModel
{
     public int? MinCapacity { get; set; }
     public int? MaxCapacity { get; set; }
}

public class StadiumController
{
     public ActionResult GetByCapacity(StadiumByCapacityInputModel input)
     {
          var min = input.MinCapacity ?? 0;
          var max = input.MaxCapacity ?? int.MaxValue;
          return Json(Stadiums.Where(x => x.Capacity >= min && x.Capacity <= max));
     }
}

2. change the return types of action methods to "output model" classes

public class StadiumByCapacityInputModel
{
     public int? MinCapacity { get; set; }
     public int? MaxCapacity { get; set; }
}

public class StadiumOutputModel
{
     public string Name { get; set; }
     public int Capacity { get; set; }
}

public class StadiumController
{
     public IEnumerable<StadiumOutputModel> GetByCapacity(StadiumByCapacityInputModel input)
     {
          var min = input.MinCapacity ?? 0;
          var max = input.MaxCapacity ?? int.MaxValue;
          var stadiums = Stadiums.Where(x => x.Capacity >= min && x.Capacity <= max);

          return stadiums.Select(x => new StadiumOutputModel() 
          {
               Name = x.Name,
               Capacity = x.Capacity
          };
     }
}

3. extract interfaces from the controllers

public class StadiumByCapacityInputModel
{
     public int? MinCapacity { get; set; }
     public int? MaxCapacity { get; set; }
}

public class StadiumOutputModel
{
     public string Name { get; set; }
     public int Capacity { get; set; }
}

public interface IStadium
{
     IEnumerable<StadiumOutputModel> GetByCapacity(StadiumByCapacityInputModel input);
}

public class StadiumController : IStadium
{
     public IEnumerable<StadiumOutputModel> GetByCapacity(StadiumByCapacityInputModel input)
     {
          var min = input.MinCapacity ?? 0;
          var max = input.MaxCapacity ?? int.MaxValue;
          var stadiums = Stadiums.Where(x => x.Capacity >= min && x.Capacity <= max);

          return stadiums.Select(x => new StadiumOutputModel() 
          {
               Name = x.Name,
               Capacity = x.Capacity
          };
     }
}

4. move these interfaces and input/output models far from the controller so that ReSharper-driven refactorings do not affect it - to the separate "contract" libraries.

5. include the libraries as referenced DLLs in our project

6. tweak ASP.NET MVC's default ActionInvoker to handle non-ActionResult return types (not needed with ASP.NET Web API - the actions in Web API controllers by design return POCO objects)

Now we treat the contract libraries like separate projects. We actually keep them in Libs folder and check it in to our main project as binaries, but just having it in a separate solution will do the job. The solution for contract library is configured so that the built output files go directly into the Libs folder, what is not possible without manual check-out of the previous binaries. This guarantees that no one checks in any changes in contract code without the new contract binaries and it also raises the level of explicitness. We've effectively made the development around contracts more difficult to ensure that all the changes done in contracts definitions are made deliberately and with proper consideration.

Whenever someone breaks the contract requirements (without modifying the binary contract properly), the project just doesn't compile - either the interface is not implemented or there is some kind of type mismatch. Moreover, having the contract definition in a separate physical project makes managing, documenting or versioning easier.

There is one thing that may seem to be a serious downside. We need to map our input model classes from contract to some "real" domain objects from the main codebase in order to use it. And the same with return types - we often need to map domain objects back to match types defined in the contract. It is a lot more fuss, but again - it makes the contract very explicit and visible. Easy cases of mapping can be handled with the tools like AutoMapper. More complicated cases may exist when the codebase starts to differ from the contract and we need to keep backward compatibility (like when the clients are mobile apps). In that cases again - it's even better to have all the transformations explicit and in one place and the mapping code becomes more helpful than annoying.

Saturday, September 22, 2012

Non-ActionResult action return type in ASP.NET MVC

In ASP.NET MVC, there's quite silly behavior when the controller's action method returns type that is not ActionResult-derived. The default ActionInvoker, which is responsible for invoking action code and interpret its result, checks if the returned instance is ActionResult and if not, returns plain string representation of the object (type name by default):

protected virtual ActionResult CreateActionResult(
    ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue)
{
    if (actionReturnValue == null)
    {
        return new EmptyResult();
    }

    ActionResult actionResult = (actionReturnValue as ActionResult) ??
        new ContentResult { Content = Convert.ToString(actionReturnValue, CultureInfo.InvariantCulture) };
    return actionResult;
}

I can see no real-life scenario in which ToString result returned as plain content can be useful. This in practice means that in ASP.NET MVC we're forced to use ActionResult or its derived types. This is especially annoying when you want your action method to be defined in an interface or used somewhere as a delegate.

The issue was solved much better in ASP.NET Web API - the actions in Web API controllers by design return POCO objects that are serialized correctly before sending it to the wire depending on the request and configuration - as XML, JSON etc.

To achieve similiar result in "normal" MVC controllers, let's replace the default ControllerActionInvoker right after creating the controller - in ControllerFactory - with our derived implementation that just overrides the virtual CreateActionResult method:

public class MyControllerFactory : DefaultControllerFactory
{
    public override IController CreateController(RequestContext context, string controllerName)
    {
        var controller = base.CreateController(context, controllerName);
        return ReplaceActionInvoker(controller);
    }

    private IController ReplaceActionInvoker(IController controller)
    {
        var mvcController = controller as Controller;
        if (mvcController != null)
            mvcController.ActionInvoker = new ControllerActionInvokerWithDefaultJsonResult();
        return controller;
    }
}

public class ControllerActionInvokerWithDefaultJsonResult : ControllerActionInvoker
{
    public const string JsonContentType = "application/json";

    protected override ActionResult CreateActionResult(
        ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue)
    {
        if (actionReturnValue == null)
            return new EmptyResult();

        return (actionReturnValue as ActionResult) ?? new ContentResult()
        {
            ContentType = JsonContentType,
            Content = JsonConvert.SerializeObject(actionReturnValue)
        };
    }
}

This simple implementation just serializes the returned objects to JSON, but it's easy to implement something more sophisticated here, like content negotiation patterns like Web API has. Feel free to use it and extend it if you find it useful - I've published it as a Gist for your convenience.

Saturday, September 15, 2012

NHibernate LINQ Pitfalls: Too many joins with deep conditions

Although I've just discussed whether NHibernate became obsolete, it doesn't mean that I'm no longer maintaining or developing applications that use it. It'll take at least few years to completely phase it out and in the meantime we still have some problems with it and we still need to know how to use it.

One of recent surprises we had with NHibernate was when querying the database using LINQ provider and condition in our query was checking a reference value not directly in queried object, but in another object it references (yes, I know it is breaking the Law of Demeter), like this:

var firstQuery = sess.Query<RootNode>()
    .Where(x => x.Child.GrandChild.Id == 42)
    .FirstOrDefault();

The condition on GrandChild uses its key value only, so looking at the database tables, joining the GrandChildNode is not needed - all the information used by this query sits in RootNode. Surprisingly, NHibernate 3.2 not only joins GrandChildNode, but also joins RootNode for the second time, only to completely ignore it. That makes 4 tables total.

However, when we change the way we're looking for a grand child and use proxy object created by ISession's Load method, we get expected and optimal query with only 2 tables joined.

var secondQuery = sess.Query<RootNode>()
    .Where(x => x.Child.GrandChild == sess.Load(42))
    .FirstOrDefault();

This bug was already found and is fixed in version 3.3 (and surprisingly, was not present in 3.1) - so it affects only NHibernate 3.2. But I think it's worth mentioning as it may have potentially large performance impact if you're using that version.

Friday, September 7, 2012

Is NHibernate dead?

Before discussing the question from the title, let me answer another one: Is this blog dead? Definitely no. Summer time distracted me a bit, but I'm hoping to get back to writing now :)

So it's more than half a year since I've concluded my series about NHibernate's mapping-by-code. The series is still surprisingly popular, there are quite a lot of hits from Google every day. I've also just reached 50 upvotes at Stack Overflow in a question about where to find some docs and examples for mapping-by-code. Thanks for this!

Quick googling for "mapping by code" and skimming through NHForge website convinced me that still there is nothing better available in the topic. Moreover, none of the bugs I've encountered half a year ago made any progress - all issues left unresolved and unassigned back then are in the same state right now. These facts are a bit sad, as I saw the mapping-by-code feature as quite revolutionary and shaping the future of NHibernate.

Well, and here comes the question - maybe there is no future? Maybe everything what is needed in the subject of object-relational mapping is already there and no development is needed? Ohloh stats notice some development in NHibernate project, but the pace is rather slowing down. No new releases are planned according to the roadmap on issue tracker. There are 25 issues classified as "Critical" unresolved, oldest waiting for more than 20 months by now. The development in a third-party ecosystem has already stopped - see the Ohloh graphs for NHibernate.Contrib or Fluent NHibernate, to name the most significant ones.

In my opinion, the reason for NHibernate's agony is simple. It was already discovered many times that applications nowadays are mostly web-based, read-intensive, not so data-centric and not consisting complicated data manipulation as few years ago. With the advent of mature NoSQL engines - free, easy to use and full of neat features - like RavenDB and - on the other side - with lightweight ORM-like tools like Dapper or Simple.Data, that cover at least 95% of ORM features needed to effectively handle newly-designed relational databases, we just don't need to use such a big and heavy tool like NHibernate.

Legacy databases are still a niche for NHibernate, for sure, but how many legacy databases that are not OR-mapped yet we still have out there? And for fresh developments, I'd say that unless you're designing some kind of specific data-driven application, it is more effective (both in terms of development effort and performance) to stick with either NoSQL or some lightweight ORM instead of NHibernate.

NHibernate is a great tool, but time goes by pretty quickly. The context of our work changes from year to year and even good tools some day must be superseded by better ones, that are more suitable for nowadays needs. And I think that day for heavy, multi-purpose ORM's like NHibernate has just come.