Hugoware

The product of a web developer with a little too much caffeine

Archive for December 2009

Minimize Context Switching

with 2 comments

I very rarely get to work on only a single project at a time when I’m writing code. Normally I have a couple projects going on at work plus a few extra at home. Add in a few blog posts and bug fixes in the mix and it starts to get really difficult to remember where you were at when you sit down to start working. Most people refer to switching between projects as context switching which normally has a very expensive cost in mental resources.

However, it really doesn’t have to be that way. You can minimize, and sometimes completely eliminate, the cost associated with context switching. Here are some ways I have found that has transformed my ability to work on multiple projects at once.

Minimize Complexity, Increase Clarity

Whenever I’m talking code with other beginning developers, this is the first point I start with. Complexity and clarity is one of the most difficult battles for a developer since the definition of ‘complex’ and ‘clear’ constantly changes.

Remember when reading contents a text file was difficult for you to understand? Now you can write an entire content management system in a single lambda expression. The perception of complex code diminishes over time for a developer but complexity of code never changes (too philosophical?)

The point is that just because you can understand large chunks of code doesn’t mean that it isn’t complex. Large blocks of code require a lot of time to read and comprehend, even if they are well documented — which adds significant context switching costs. Here are a few of the main points I like to discuss.

  • Always use clear names for classes, functions and variables — You’ll never regret naming a function employeeTotalSalary instead of just x
  • Keep functions short and specific. Limit the responsibility of a function to a single purpose. If you have a function that has multiple steps, then it ought to be in its own class.
  • Using named enumerated types as a return value from a function are often more clear than other responses such as booleans or nulls.

Be Consistent

Another point is to keep the way you code your project consistent. If a style of an project changes from class to class and function to function, then you can expect the cost of context switching to be dramatic.

For example, what if you chose to return ‘null’ in functions that encountered an error — but for only half of your project. Then, the other half of the project you threw exceptions. Each time you opened that project you would be forced to read code and remember all of the little details for each class and function you were working with.

On the other hand, if you were consistent with your approach, then after the first error you encountered you would remember how to deal with the rest of the project without needing to open a single file.

  • Be consistent with your approach to handling errors, passing arguments, cleaning user input.
  • Remember the ‘DRY’ Principle — Repeated code leads to inconsistent code. If you’re doing it more than once then you need to move your code into a single, well named function.

Test Driven Development

I’m not a huge advocate of Test Driven Development – I don’t think it solves nearly as much as many people suggest it does. There is a lot more to if an application is working than a series of tests can prove (for example, a website and browser rendering issues). However, TDD can go a long way to make you confident that your changes aren’t breaking existing functionality.

Because a single change could potentially break an entire system, you can’t just modify some code and then hope for the best. Instead, you have to spend a lot of time reading code and finding possible errors and then testing them.

Even if you aren’t an expert at the methodologies behind TDD, using Tests in a project is a great way to minimize the context switching costs. You can focus on making a change and verifying that you didn’t break any existing functionality.

  • Using tests is a good way to minimize context switching because you don’t need to understand the project to make a change.
  • You don’t need to be an expert to write tests — Just spending an afternoon researching TDD can go a long way

Don’t Stop Here Though…

Context switching is a difficult thing to deal with, but reducing complexity and improving your confidence in a project is a great way to make switching between projects easier than before.

These are just a few ideas that I wanted to type about tonight. I have a lot of other suggestions that I share with developers that I’ve learned over the years. Additionally, there is a lot of great information about managing code complexity on the web.

If you aren’t doing anything to reduce the complexity of your projects then you can always expect your context switching time to be a difficult transition — but the good news is that it doesn’t take much to reduce that cost and make your life easier.

Advertisements

Written by hugoware

December 28, 2009 at 12:19 am

Undo, Redo and Whatever… From A Web Application

with 2 comments

Long ago a brilliant developer invented the Undo command — probably one of the most important features to be added in computing history. It seems funny to me that today, in 2009, it is still a very rare feature to find on a website. This isn’t to say no one is doing it but more that it isn’t a common feature to find.

Using Lambdas For Undo Actions

In .NET you can use Lambdas to create a function and pass it around like an argument and then that argument can then be invoked at a later time in a different place. That said, with a little careful planning and a few correctly stored Lambdas, you could have a working ‘Undo’ model in your ASP.NET web sites For this example I’m going to use MVC but this would really work anywhere.

Warning: This is very crude code, more of a proof of concept, so you probably don’t want to use it in your projects as is.

Let’s start with an abstract controller that contains our Undo handling code.

[UndoController.cs]

using System;
using System.Web;
using System.Web.Mvc;

namespace UndoAction {

	//class that supports an undo action
	public class UndoController : Controller {

		#region Constants

		private const string SESSION_UNDO_ACTION = "Session:UndoAction";
		private const string SESSION_UNDO_MESSAGE = "Session:UndoMessage";
		private const string TEMP_DATA_UNDO_MESSAGE = "UndoResult";
		private const string DEFAULT_UNDO_MESSAGE = "Previous action was undone!";
		private const string DEFAULT_MISSING_UNDO_MESSAGE = "No actions to undo!";

		#endregion

		#region Undo Action Container (Session)

		//contains the current undo action
		private static Action _UndoAction {
			get {
				return System.Web.HttpContext.Current
					.Session[SESSION_UNDO_ACTION] as Action ;
			}
			set {
				System.Web.HttpContext.Current
					.Session[SESSION_UNDO_ACTION] = value;
			}
		}

		//the message to return in the view data for this action
		private static string _UndoMessage {
			get {
				return System.Web.HttpContext.Current
					.Session[SESSION_UNDO_MESSAGE] as string ;
			}
			set {
				System.Web.HttpContext.Current
					.Session[SESSION_UNDO_MESSAGE] = value;
			}
		}

		#endregion

		#region Setting Undo Actions

		/// <summary>
		/// Applies an undo action
		/// </summary>
		protected void SetUndo(Action action) {
			this.SetUndo(DEFAULT_UNDO_MESSAGE, action);
		}

		/// <summary>
		/// Applies an undo action with a return message for the user
		/// </summary>
		protected void SetUndo(string message, Action action) {
			UndoController._UndoAction = action;
			UndoController._UndoMessage = message;
		}

		/// <summary>
		/// Performs the undo action (if any) and saves the message
		/// </summary>
		protected void PerformUndo() {

			//check if there is an action
			if (UndoController._UndoAction is Action) {

				//perform the action and save the message
				Action action = UndoController._UndoAction;
				action();
				this.TempData[TEMP_DATA_UNDO_MESSAGE] =
					UndoController._UndoMessage;

				//and clear out the previous information
				UndoController._UndoAction = null;
				UndoController._UndoMessage = null;

			}
			//just save a generic message
			else {
				this.TempData[TEMP_DATA_UNDO_MESSAGE] =
					DEFAULT_MISSING_UNDO_MESSAGE;
			}

		}

		#endregion

	}

}

Basically, we create an abstract Controller that allows us to set an Undo action using a Lambda. You can also set a message for to return to the user that sumarizes what the action had done. This example uses a couple Session variables to hold the parts of the undo action, except I recommend that you create an actual class to house all of the information.

Next, let’s look at how we would actually use this controller.

[HomeController.cs]

using System;
using System.Collections.Generic;
using System.Web.Mvc;
using System.Linq;

namespace UndoAction {

	//example of using undo actions
	public class HomeController : UndoController {

		#region Constants

		private const string SESSION_LIST_CONTAINER = "Session:ListContainer";

		#endregion

		#region Properties

		//a simple list of items for the list
		public static List<string> ListContainer {
			get {
				List<string> container = System.Web.HttpContext.Current.Session[SESSION_LIST_CONTAINER] as List<string>;
				if (container == null) {
					container = new List<string>();
					System.Web.HttpContext.Current.Session[SESSION_LIST_CONTAINER] = container;
				}
				return container;
			}
		}

		#endregion

		#region Actions

		//shows the list of items
		public ActionResult Index() {
			return this.View(HomeController.ListContainer.OrderBy(item =&gt; item.ToLower()));
		}

		//adds an item to the list
		public ActionResult Add(string phrase) {

			//format the value
			phrase = (phrase ?? string.Empty).Trim();

			//add the item if it isn't there yet
			if (!HomeController.ListContainer.Any(item => item.Equals(phrase, StringComparison.OrdinalIgnoreCase)) &amp;&amp;
			    !string.IsNullOrEmpty(phrase)) {
				HomeController.ListContainer.Add(phrase);
			}

			//return to the list view
			return this.RedirectToAction("Index");

		}

		//removes an item from the list
		public ActionResult Delete(string phrase) {

			//make sure the item even exists first
			if (HomeController.ListContainer.Any(item => item.Equals(phrase, StringComparison.OrdinalIgnoreCase))) {

				//since it exists, save the logging message
				this.SetUndo(
					string.Format("Restored '{0}' to the list!", phrase),
					() => {
						HomeController.ListContainer.Add(phrase);
					});

				//and then actually remove it
				HomeController.ListContainer.Remove(phrase);

			}

			//return to the main page
			return this.RedirectToAction("Index");

		}

		//tries to undo the previous action
		public ActionResult Undo() {

			//attempts to undo the previous action (if any)
			this.PerformUndo();

			//return to the main page
			return this.RedirectToAction("Index");
		}

		#endregion

	}

}

This controller allows the user to manage a simple shopping list with an Undo action to allow them to restore a deleted item. It is some ugly code, but you get the idea on how it works.

The important thing you should note is that the Lambda doesn’t refer to the instance of the class (this) but instead that the list is a static property. This is important to keep in mind as you develop something like this. When you create the Lambda action, you can’t refer to the instance that it was created in. Instead, you need to work with static properties.

Finally, let’s look at the ViewPage that is used in this example.

[Index.aspx]

<%@ Page Language="C#" 
	Inherits="System.Web.Mvc.ViewPage" %>
<%@ Import Namespace="System.Collections.Generic" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<title>Shopping List</title>
	</head>
	<body>
		<% IEnumerable<string> list = this.Model as IEnumerable<string>; %>
		
		<h2>Shopping List</h2>
		
		<p><% =this.Html.ActionLink("Undo Previous Action", "Undo") %></p>
		
		<% if (this.TempData["UndoResult"] is string) { %>
		<p><em><% =this.TempData["UndoResult"] as string %></em></p>
		<% } %>
		
		<hr />
		
		<table>
		<% foreach(string item in list) { %>
			<tr>
				<td><% =this.Html.Encode(item) %></td>
				<td><% =this.Html.ActionLink("Remove", "Delete", new { phrase = item }) %></td>
			</tr>
		<% } %>
		</table>
		
		<hr />
		
		<form action="<% =this.Url.Action("Add") %>" method="post" >
			<strong>Add an item:</strong>
			<input type="text" name="phrase" />
			<input type="submit" value="Add" />
		</form>
		
	</body>
</html>

The ViewPage itself is nothing fancy — If you’re working in a project you should create a strongly-typed view but in this example we just read the information we need and go on.

Using The Page

Below are a few screen shots of what happens as the user makes changes to the page. This example starts with a list of a few different items.

After removing an item from the list (the ‘Orange’) pressing the ‘Undo Previous Action’ button will restore the item. The custom message that was added is displayed (from the TempData field).

If you press the ‘Undo’ button again there aren’t any actions waiting anymore and the default message is displayed instead (no actions waiting).

Things To Consider

This code is just a sample of how you could implement and Undo function into your web applications. Here are a few things that you might want to keep in mind before starting something like this.

  • Make sure that your Undo command doesn’t cause you to duplicate code. In this example, the undo command uses a different ‘Add’ approach than the actual ‘Add’ action on the controller. This could result in duplicated code or incorrect results.
  • Determine if you can queue up ‘Undo’ commands. This example can only do one action at a time, but you could potentially create a Stack of actions that are executed in the reverse order that they were added.
  • Could you use the same concept to ‘Redo’ a command after it has been undone?
  • Be careful with your context – Don’t use ‘this’ inside of your Undo Lambdas.

Anyways, just an interesting concept to share. This approach requires a lot more thought but could pay off in the end.

Do you have a web application that could benefit from an ‘Undo’ command?

Written by hugoware

December 21, 2009 at 12:03 am

Speaking Of Code

with 2 comments

So as it turns out there are a couple guys that work at my company that are going to school for computer programming. I was helping them with homework a week ago and I suggested we start a weekly code discussion in one of the conference rooms. I even invited my new assistant.

Tonight was the first meeting and it was great. I talked with them about language choices, writing readable code and just general programming practices.

For a long time now I’ve been pretty much a solo programmer — I only got an assistant in the last few months. But lately I’ve really been trying to reach outside that bubble and connect with more developers. I’ve even tried enlisting other people to help me with projects simply because I want to collaborate with more than one developer.

If you aren’t already communicating with other developers then you need to, even if it is only on a virtual level (like Twitter or blogs). However, getting a group of developers in front of a whiteboard for a causal chat is probably a hundred times better.

It probably isn’t that hard to find a few developers near you — They don’t even need to be very experienced. Just gather a group of people and come up with something for them to do…

For example, here are a few of the ideas we came up with…

  1. Review Code
    Each person in the group starts a small, personal project that they work on in their spare time. Each project is reviewed by the group in the next meeting. We can try and help them solve the problems they are having or simply perform an informal code review on their project.
  2. Team Project
    Start a medium sized project that the whole team can work on. Introduce the rest of the team to source control and explain how it works. Assign responsibilities to each team member and discuss, as a team, what role should accomplish.
  3. Let Everyone Teach
    Have each person teach something new they learned that week. It doesn’t even need to be the same language that everyone else is using. Take this as an opportunity to let some of the less experienced members explain what they know.

You can be a great developer without doing something like this but I personally recommend it. The internet makes it easier than ever to contact people that you would have never had the chance to meet — but why not try to meet some of the local developers while you’re at it.

Written by hugoware

December 16, 2009 at 1:15 am

Meanwhile, Back At CodePlex…

leave a comment »

Just a quick update — I’ve been working on Flow Based MVC Controllers some more and hope to do a blog post about them in the next couple days…

For now, I’ve moved some of my other MVC projects onto CodePlex so there is a better home for them (than my own website of course :))

Mvc Content Marker

A few months ago I wrote some code that allowed you to write to different parts of the page using inline code — You probably know it isn’t easy to add a stylesheet or script to a different part of the page since after render code has finished you can’t go back and write over it.

This code makes it so you can place a marker on the page and then write back to it no matter where you are at. It also supports forward looking markers (meaning markers that haven’t been added to the page yet) so it makes it easy to add scripts to the footer of your page from higher up in the document.

As it turns out Spark has something similar to this — but if you aren’t ready to jump into Spark then this still might be handy for you. (Spark is cool, don’t get me wrong though)

Mvc WebForm

Mvc WebForm does exactly what you think it does — It lets you place a WebForm inline with your Mvc code. I isn’t perfect at all and in all honestly was just to see if it was possible. As it turns out you can have basic event handling, button clicks, data grids — whatever — and it works directly in your Mvc Views. Neat stuff even if it is evil.

I expected to be shunned by the development community with this but surprisingly I got several ‘thank you’s and ‘good job’s — Funny how that works out sometimes.

Written by hugoware

December 7, 2009 at 10:16 am

Flow Based MVC Controllers

with 2 comments

I’ve been working on a project lately that has required that a controller follows a series of logical steps before it reaches the end. I don’t want users to access the last step until earlier steps have finished. The process also branches into separate paths depending on their selections.

One of the things that bugged me is I hated having so much logic devoted to checking to see if steps had been done before I continued. For example, checking if an image had been uploaded OR if they selected one from a gallery. Most likely I could simply create a property that checked for the state of things, but I wanted to come up with a reusable way to manage the flow of a controller.

The Flow

So here is an example of what kind of flow would go through this. This controller allowed a customer to provide a custom image or choose one from a gallery. The requirements at the end change depending on what a user selects.

Right now I’ve only developed some rough code — but here is a basic idea of how the flow can be controlled automatically.

The Basics

This first example shows the basic idea behind identifying a method as requiring a step to complete. An attribute can be applied to


//for now, the flow process uses extension methods instead of an inherited class
using MvcFlow.FlowExtensionMethods;

//A controller for MVC
public class ShopController : Controller {

    //required override to check steps automatically
    protected override void OnActionExecuting(ActionExecutingContext filterContext) {
        //extension method to check an action in the flow
        this.ProcessStep(filterContext);
    }

    //this step has no requirements so it can be browsed to at any time
    public ActionResult Index() {
        returns this.View();
    }

    //this has no requirements but it does APPLY a step if the validation is successful
    public ActionResult ValidateUser(string username, string password) {
        if (this.PasswordIsCorrect(username, password)) {

            //an extension method to update the steps for the flow
            this.ApplyStep(Steps.UserValidated);
            return this.RedirectToAction("SelectType");
        }
        //if the process doesn't apply the next allowed step then it can't proceed
        else {
            return this.RedirectToAction("Index");
        }
    }

    //this step cannot be executed until Steps.UserValidated has been applied
    //which is done in the successful validation step
    [StepRequires(Steps.UserValidated)]
    public ActionResult SelectType() {
        return this.View();
    }

    //snip...

The important thing to notice is that there are only three things required to make this process work.

  • Override the OnActionExecuting method to perform the validation. By overriding this step we can make sure an action is allowed to be executed — and if not, redirect the user.
  • Add an attribute to describe step requirements. The attribute StepRequires allowed us to define what steps must have been completed before they can execute this action.
  • Apply steps after successful validations. If requirements have been met then the step can be saved and a new set of actions will open up.

Removing And Branching

Here is another example of the code that shows how flow can be managed…


//snip...

//this step requires validation has happened -- but it also removes if 
//they have selected certain future steps. This means if someone browses back
//to the page then they are required to answer the question again
[StepRequires(Step.ValidatedUser)]
[StepRemoves(Step.SelectCustom | Step.SelectGallery)]
public ActionResult ChooseType() {
    return this.View();
}

// BRANCH 1
// Custom --------------------------

//Applies the SelectCustom option -- but also removes the option for
//the other branch (if it was even found)
[StepRequires(Step.ValidatedUser)]
[StepRemoves(Step.SelectGallery)]
public ActionResult SelectCustom() {
    this.ApplyStep(Step.SelectCustom);
    return this.RedirectToAction("UploadImage");
}

//This step requires that both the validation and select custom steps have been applied
[StepRequires(Step.ValidateUser | Step.SelectCustom)]
public ActionResult UploadImage() {
    return this.View();
}

// BRANCH 2
// Gallery --------------------------

//Applies the SelectGallery option -- but also removes the option for
//the other branch (if it was even found)
[StepRequires(Step.ValidatedUser)]
[StepRemoves(Step.SelectCustom)]
public ActionResult SelectGallery() {
    this.ApplyStep(Step.SelectGallery);
    return this.RedirectToAction("ShowGallery");
}

//This step requires that both the validation and select gallery steps have been applied
[StepRequires(Step.ValidateUser | Step.SelectGallery)]
public ActionResult ShowGallery() {
    return this.View();
}

Unfortunately, the attributes are a bit difficult to read but the general idea is to break the flow of the controller into two parts — each existing separate from each other but within the same controller.

You’ll notice in these steps we can use our enumerated type to create more than one requirement for an action (for example Step.ValidatedUser | Step.SelectCustom ). We can also use the RemovesStep attribute to automatically move back the current point of the flow.

Too Confusing?

I wrote a lot of the code to do this process today but I’m looking for some thoughts about this process. Is this too much work? Too confusing? Not really helpful?

Do you spend enough time managing flow in your applications that a framework like this could help?

Written by hugoware

December 2, 2009 at 10:05 pm