Showing posts with label Design. Show all posts
Showing posts with label Design. Show all posts

At developer summit in Stockholm a couple of weeks ago I attended a great talk by Jim Webber titled "Guerrilla SOA". On one slide he listed some causes for why SOA and ESB solutions quickly degrade to a pile of spaghetti.  One of the causes was that developers take:

"The Path of least resistance for individual applications"

This line really resonated with how I feel, not in a SOA scenario but for application architecture or just code in general. When you write code you constantly fight either your own design/architecture or some framework and what many developer end up doing (including me sometimes) is taking the path of least resistance, and depending on the application design this might often not be the right path.

Ayende had a post a couple of days ago about zero friction & maintainability in which he writes:

"As it turn out, while code may not rot, the design of the application does. But why?

If you have an environment that has friction in it, there is an incentive for the developers to subvert the design in order to produce a quick fix or hack a solution to solve a problem. Creating a zero friction environment will produce a system where there is no incentive to corrupt the design, the easiest thing to do is the right thing to do.

By reducing the friction in the environment, you increase the system maintainability"

A big goal when designing an application or framework should be to make the path of least resistance the right path. This is of course easier said than done and I think you will never get the perfect design where every right way is the easy way. So when we head down the path of least resistance knowing it is the wrong way, why do we do it? It could be time constraints, plain laziness or some other hurdle. When making the decision it is important to weigh in possible future problems and maintainability issues that could potentially be very costly.

Well that is all I had to say about this for now, stay away from the path of least resistance (unless it is the right path!).

In most applications you usually store and cache some user information in a session object. Most actions are dependent on this information, which means that many services require this information. This problem can be solved using different approaches. What I usually end up with is creating a user ticket class which holds maybe a subset of the user information (or the complete user class) and other session specific information. The simplest approach is then to pass this object along to each service / method that needs it:

public class WishListService
{
  private IWishListRepository wishListRepository;

  public WishListService(IWishListRepository wishListRepository)
  {
    this.wishListRepository = wishListRepository;
  }

  public void AddToWishList(IUserTicket ticket, Product product)
  {
    // handle all the important stuff
  }
}

The problem with this approach is that all callers need to fetch the user ticket. If you have deep method stacks and the deepest component needs the session information then all methods needs to pass the object along.

A sometimes nicer approach is to let the components fetch the session information on their own (through an interface):

public class WishListService
{
  private IWishListRepository wishListRepository;
  private ITicketAccessor ticketAccessor;

  public WishListService(IWishListRepository wishListRepository, ITicketAccessor ticketAccessor)
  {
    this.wishListRepository = wishListRepository;
    this.ticketAccessor = ticketAccessor;
  }

  public void AddToWishList(Product product)
  {
    IUserTicket ticket = ticketAccessor.Current();
    // handle all the important stuff
  }
}

This approach makes the component easier to use and the method calls are simpler, dependencies to the session (ticket) information is handled by the ITicketAccessor which can be inject by a IoC container.

Another approach is to have a static RuntimeContext class which static properties to access the session information from anywhere in your application:

public class RuntimeContext
{
  private const string KEY_TICKET = "RuntimeContext.Ticket";        

  /// <summary>
  /// Used to access the ticket for the current request
  /// </summary>
  public static IUserTicket Ticket
  {
    get
    {
      // try local execution context first
      IUserTicket ticket = Local.Data[KEY_TICKET] as IUserTicket;
      if (ticket != null)
        return ticket;

      // try session
      if (Local.RunningInWeb && HttpContext.Current.Session != null)
      {
        ticket = HttpContext.Current.Session[KEY_TICKET] as IUserTicket;
        // cache in local 
        if (ticket != null)
          Local.Data[KEY_TICKET] = ticket;
      }

      return ticket;
    }
    set
    {
      Local.Data[KEY_TICKET] = value;

      // store in session if running in web 
      if (Local.RunningInWeb)
      {
        HttpContext.Current.Session[KEY_TICKET] = value;
      }
    }
  }
}

The Local class in the above code is an abstraction over HttpContext.Current.Items and Thread data depending on if the code is being run in web context or not. This last approach is very easy to work with but you have less control over where and how the data is accessed.

There is also Thread.CurrentPrincipal which is a good to use, especially for user authorization. I am not sure which of the approaches I like more, the second one is probably the best one from a purist / TDD point of view. I will post a question in the ALT.NET mailing list to find out what solutions smarter people than me have arrived at.