tsJensen

A quest for software excellence...

Learning from the Elevator State Machine Programming Test

In a recent job interview I was asked to build an elevator simulator. I was given the weekend to do it. I had never written a state machine before. It wasn't perfect but it passed all the tests I could come up with based on my own assumptions about the rules of behavior based on the following text from the interviewer:

Build an elevator simulator. It should have a UI that shows 5 floors, with the call buttons for each floor. The UI should also show the panel of buttons inside the elevator. As a user, I can press any floor call button (up or down), as well as elevator panel buttons to move the elevator. The elevator should move at a realistic speed (not just go instantaneously to the desired floor).

Evaluation criteria:

  1. Accuracy of the elevator state machine with various button-press scenarios.
  2. The object design of your project – how you organize the design into classes and their relationships, what design patterns you choose to use.
  3. Coding style and clarity.
  4. The UI doesn’t need to be fancy, but it needs to enable the functional requirements stated above. You can use any UI toolkit of your choice.
  5. The code should be written in C#.

Unfortunately, my assumptions were not the same as the evaluation team's assumptions, so they found some "bugs" in the behavior of my elevator. Honestly, I was not surprised. In fact, when I submitted the code, I had offered the following observations:

I did not spend much time refactoring or documenting, so you're getting to see the "first draft" of the code.

Some refactoring that I would do:

1. Create tighter assurances in the tests with required sequence of logged events rather. In running the tests, I took a shortcut and debugged through the tests to review the log entries from the state machine to verify the sequence of actions. This should be corrected.

2. Clean up each of the two state machines, AtFloor and Moving. To simplify, I might create one or two more state machine classes to make the logic rules easier to follow and remove some of the "if" fall through logic states.

3. Tighten up UI with view data model to reduce the clutter in the code or perhaps even rewrite the UI in WPF with an MVVM architecture. My choice of Windows Forms was based on time limitations and my limited experience with WPF.

4. Review and tighten up naming and coding conventions for improved readability.

The "bug" in the elevator was not the reason I did not get the job. Fortunately, the recruiter sent me the feedback she received from the interview team. This is rare. I found it helpful and will certainly take it into account in the future.

The positive and exciting thing about this entire experience was having a reason to write my first state machine in a fun exercise which I want to share with you here. This was certainly the most comprehensive programming test I've ever been given in conjunction with an interview. I applaud the employer for having such a thorough and extensive evaluation process. And I thank the interview team for their feedback. Such thoroughness really helps to determine whether a person will be a good fit for the team. And above all else, that fit is of paramount importance.

Please download the code and let me know what you think. There are clearly flaws, as I would expect of any code thrown together over a weekend, especially where the particular pattern being implemented is a first attempt. When I have time, I may want to pull this off the shelf and do the refactoring I suggested when I submitted the code. But first, I need to find an employer and settle down. I think that will happen soon.

ElevatorControl.zip (29.94 kb)

Moved from dasBlog to BlogEngine.NET

I bit the bullet today and moved from dasBlog to BlogEngine.NET after having upgraded my hosting account to .NET 4.0 and having way too many problems with my dasBlog install. I just exported the dasBlog content to BlogML.There are multiple posts about doing this.

The only thing I changed was the Global.asax code to create a permanent redirect for my dasBlog links out in the world to the BlogEngine.NET links using the following:

void Application_BeginRequest(object source, EventArgs e)
{
   HttpApplication app = (HttpApplication)source;
   HttpContext context = app.Context;
    
   // Attempt to perform first request initialization
   FirstRequestInitialization.Initialize(context);

   //redirect to ~/post/2012/03/30/DomainAspects+Inject.aspx
   //when url is ~/2012/03/30/DomainAspects+Inject.aspx
   if (context.Request.Url.AbsolutePath.EndsWith(".aspx"))
   {
      Match m = dateRegex.Match(context.Request.Url.AbsolutePath);
      if (m.Success)
      {
         string url = context.Request.Url.AbsolutePath;
         string dt = m.ToString();
         url = url.Replace(dt, @"/post" + dt);
         context.Response.RedirectPermanent(url, true);
      }
   }
}

static Regex dateRegex = new Regex(@"(?<!/post)/\d{4}/\d{1,2}/\d{1,2}/");

DomainAspects: Inject Fake PrincipalProvider and Avoid Fake HttpContext for Testing

Today I began playing with the DomainAspects project again and realized that my tests were breaking when I switched to the .NET 4.0 Framework. After a little research, it became clear. My test helper class in the previous version of DomainAspects committed a Class A coding misdemeanor. It relied on reflection to set the value of a private member on object returned by an internal method in the Thread class.

In my own defense, I did not write that code. I borrrowed it from somewhere online to allow me to set the HttpContext even when there really isn't one available when I run my tests. This was clearly bad form and came back to bite me. So I decided to eliminate the need and just added a facility in my DomainFactory class to substitute one or more of the Windsor components used by the DomainFactory.Create<T> method which is wrapped in an IDisposable via the DomainProxy<T> class being used in the tests.

Here is the simple addition to the DomainFactory. Note that we must remove these components in reverse order and then add them back since there are dependencies involved. Also note that this method will fail if you have already created an instance of a domain interface using the proxy or factory class.

/// <summary>
/// Replaces default aspect oriented operations components with client supplied components.
/// Used for testing or customizing operations withing the factory IoC container.
/// </summary>
/// <param name="principalProviderType"></param>
/// <param name="operationAuthorizerType"></param>
/// <param name="operationAuditorType"></param>
/// <param name="operationInterceptorType"></param>
/// <exception cref=""></exception>
public static void SubstituteComponents(
	Type principalProviderType = null, 
	Type operationAuthorizerType = null, 
	Type operationAuditorType = null)
{
	//set default types where param is null otherwise check for proper interface
	if (principalProviderType == null)
		principalProviderType = typeof(PrincipalProvider);
	else if (principalProviderType.GetInterface(typeof(IPrincipalProvider).FullName) == null)
		throw new ApplicationException("principalProviderType is not of type IPrincipalProvider.");
		
	if (operationAuthorizerType == null) 
		operationAuthorizerType = typeof(OperationAuthorizer);
	else if (operationAuthorizerType.GetInterface(typeof(IOperationAuthorizer).FullName) == null)
		throw new ApplicationException("operationAuthorizerType is not of type IOperationAuthorizer.");

	if (operationAuditorType == null) 
		operationAuditorType = typeof(OperationAuditor);
	else if (operationAuditorType.GetInterface(typeof(IOperationAuditor).FullName) == null)
		throw new ApplicationException("operationAuditorType is not of type IOperationAuditor.");


	if (container.Kernel.RemoveComponent("OperationInterceptor")
		&& container.Kernel.RemoveComponent("OperationAuditor")
		&& container.Kernel.RemoveComponent("OperationAuthorizer")
		&& container.Kernel.RemoveComponent("PrincipalProvider"))
	{
		container.Register(
			Component.For<IPrincipalProvider>()
				.ImplementedBy(principalProviderType)
				.Named("PrincipalProvider")
				.LifeStyle.Transient,

			Component.For<IOperationAuthorizer>()
			.ImplementedBy(operationAuthorizerType)
			.Named("OperationAuthorizer")
			.LifeStyle.Transient,

			Component.For<IOperationAuditor>()
			.ImplementedBy(operationAuditorType)
			.Named("OperationAuditor")
			.LifeStyle.Transient,

			Component.For<OperationInterceptor>()
			.Named("OperationInterceptor")
			.LifeStyle.Transient);
	}
	else
	{
		throw new ApplicationException("SubstituteComponents failed due to invoked component dependencies.");
	}
}

Once the new method was added to the DomainFactory class, I removed the TestHelper.cs file which included this very naughty code which fails in .NET 4.0 because the implementation of the Thread class changed and the GetIllogicalCallContext internal method went away.

//broken in .NET 4.0 - GetIllogicalCallContext does not exist in Thread class anymore
public static void SetCurrentContext(string fileName, string url, string queryString, FakePrincipal principal)
{
	var context = CreateHttpContext(fileName, url, queryString);
	context.User = principal;
	var result = RunInstanceMethod(Thread.CurrentThread, "GetIllogicalCallContext", new object[] { });
	SetPrivateInstanceFieldValue(result, "m_HostContext", context);
}

Now that the offending code is gone, the RegistrationServiceTests test class is broken as you see below:

[TestInitialize]
public void Initialize()
{
	//set up a fake http context with fake IPrincipal
	string[] roles =
		{
			 "Admin",
			 "User",
			 "Local Office"
		};
	TestHelper.SetCurrentContext(new FakePrincipal("Fake", "testuser", true, roles));
}

I replaced that code with this:

static bool isInitialized = false;

[TestInitialize]
public void Initialize()
{
	if (!isInitialized)
	{
		isInitialized = true;
		//only do this once per test/process run
		DomainFactory.SubstituteComponents(typeof(FakePrincipleProvider));
	}
}

And created the new FakePrincipleProvider class to create and deliver the IPrincipal as required by the IPrincipalProvider:

public class FakePrincipleProvider : IPrincipalProvider
{
	FakePrincipal principal;

	public IPrincipal GetPrincipal()
	{
		if (principal == null)
		{
			string[] roles =
			{
				 "Admin",
				 "User",
				 "Local Office"
			};
			principal = new FakePrincipal("Fake", "testuser", true, roles);
		}
		return principal;
	}
}

And now my tests pass again because my IoC container is passing along the FakePrincipleProvider to my OperationAuthorizer class.

There will be more to come with DomainAspects soon.

DomainAspects_v1_2.zip (2.97 MB)

ASP.NET MVC 4 Beta Released

I’m excited to watch the rollout of ASP.NET MVC 4 Beta and looking forward to finding the time and a good solid project to take advantage of the new mobile support and Azure SDK.

Here’s a basic list of what’s new.

  • ASP.NET Web API
  • ASP.NET Single Page Application
  • Enhancements to Default Project Templates
  • Mobile Project Template
  • Display Modes
  • jQuery Mobile, the View Switcher, and Browser Overriding
  • Recipes for Code Generation in Visual Studio
  • Task Support for Asynchronous Controllers
  • Azure SDK

I want to hear your ASP.NET MVC 4 stories. Let me know what you think about it. You may get a chance to deep dive before I do, given my current project priorities.

Situational Intelligence Leads to Certainty and Confidence

I like this quote from General Stanley McChrystal on crisis communication:

“I think when any leader faces crisis, this is true on the battlefield but I think it's also true in other areas as well, one of the things you fear most is not understanding the situation. And I think it's that uncertainty that actually is most unsettling to many leaders and causes them to be undermined in their confidence.”

Understanding the situation. If you lack context. If you lack critical knowledge. You cannot effectively lead. First, seek to understand. Listen and absorb. Contemplate. Then, and only then, act.

Goal Oriented Meetings in Software Development

I’m fascinated with the subject of meetings. It is a topic of discussion across the wide webbed world. There are nearly as many opinions on this subject as there are stars in the sky. So adding my own here cannot possibly disrupt our little corner of the multiverse, nor will it likely establish a new or even affect an existing trend. But before I bore you with my own opinion, let me share with you some links to some very cogent resources that have helped me, in addition to my own years of experience, to form my opinions here.

  • Firemen, donuts and meetings – Seth Godin: “Don’t bother to have a meeting if you’re not prepared to change or make a decision right now.”
  • Reduce Meeting Time by 30 Percent – Max Isaac: “Prior to the meeting, send an email with the proposed Purpose, Process and Preparation, and attach documents that should be reviewed.”
  • Meetings frustrate task-oriented employees – American Psychological Association: “…people high in accomplishment striving, who tend to be highly task and goal oriented, were most negatively affected by meetings...
    ...people who participate most in meetings, such as those who identify themselves as upper-level management, tend to view them most favorably...solely because they get to talk a lot, they inevitably miss other key pieces of meeting effectiveness, including their ability to successfully lead the meeting.”
  • Why Goal-Oriented Requirements Engineering – Yu & Mylopoulos: “The identification of goals naturally lead to the repeated asking of "why", "how" and "how else" questions... Stakeholders also become more aware of potential alternatives for meeting their substantive goals, and are therefore less likely to over-specify by prematurely committing to certain technological solutions.” (This paper is not about meetings but contributes to the opinions expressed below.)
  • Goal-Oriented Idea Generation – multiple authors, taken from summary of results: “The goals obtained from the ideas have high quality. During the activities for grouping ideas, it was frequently observed that the stakeholders could find their misunderstandings and tried to resolve them. As a result, the obtained goals were based on the consensus and the agreement of all of the stakeholders.” (Again, this is not about meetings but contributes to my ideas on the subject.)

It has been my experience that any form of software development, including my personal favorite: behavior driven design/development first introduced by Dan North, generally requires more than one person in the process. There is at least a user and a programmer, at least for any software that one might be paid to produce. And where there is more than one person in a process, there is the inevitability of a meeting.

The real question is what is the nature of the meeting. And by nature I mean how will it be planned and conducted, and what if any follow up will occur as a result of the meeting.

Bad Meetings: Vague, Purposeless, Meandering Time Wasters
The world of software developers could fill terabytes of hard disk space with examples of meetings that were a complete waste of time, ineffective, resulted in no change to the status quo nor the discovery of anything that was not already immediately discoverable in an issue or project tracking system.

Rather than go through any of these bad examples in detail, I will simply summarize that these meetings most typically include in the email invite only a vague subject line, a time and place, a dial-in number for remote attendees, and by virtue of the most commonly used tool to send the invite, a list of attendees, most often the entire team. Too many of these meetings and your organization has fallen hopelessly into the “Meaningless Meetings Machine.”

Goal Oriented Meetings: Purpose Driven, Limited, Action Packed
The very best meetings I have ever attended or conducted (yes, I’ve conducted my share of bad meetings too) have had the following qualities:

  • Goal oriented – the agenda focuses on stated goals. (See Mark Schiller’s cogent treatment in Fixing IT Productivity Destroyers.)
  • Limited scope – the time and agenda are limited to specific related goals.
  • Parking lot – good but unrelated ideas go into a “parking lot” to be discussed at another time and often in a different forum.
  • More listening (less talking) – participants listen carefully with their full attention and speak only when they have something relevant to contribute or need clarification in order to make a decision or understand an action item being assigned to them. And NEVER, NEVER, NEVER do participants rudely talk all at once.
  • Previous action items related to goals on the agenda are reviewed in summary fashion – discussion is limited to reporting outcomes and/or impediments that require attention by the group. This does NOT mean that the group attempts to resolve these impediments during the meeting. They are noted and may generate an action item for a participant, but under NO CIRCUMSTANCES will the meeting get side tracked to solve the problem in the moment.
  • Goals drive actions – starting with diverging opinions and working toward consensus in these steps:
    • affirming the goals are properly stated
    • identifying actions required to achieve the goals
    • identifying (or getting volunteers) to take those actions
  • Decisions are made – work toward a consensus but have a meeting leader who can make a final decision right there, right now, after having considered the input of meeting participants. Perfect consensus is not the goal. Decision and action from team input and reasonable discussion is sufficient. (And as Seth points out, don’t bother having a meeting unless you are prepared to change your mind. If you have already made your decision, just announce it, assign the tasks and follow through—don’t waste your team’s time with a meeting to maintain the illusion that you care about what others think—they know you don’t.)
  • Minutes, including action items and commitments, are recorded and published post haste. They are also maintained in a team public place such as a wiki or project portal for reference and follow up.

Goal Oriented Meetings Foster Better Software Development
I included some links already that talk about goal oriented requirements engineering and behavior driven development (BDD). In Dan North’s treatment of BDD, he presents two single sentence templates for defining each of the requirements of any software system. With my own explanations, they are:

To define a feature or user story:

As a [X], I want [Y], so that [Z].

Where [X] is the role of a user, [Y] is the feature, and [Z] is the benefit or value (the goals) of the feature.

And to define the acceptance criteria for that story:

Given [some initial context—the givens], when [an event occurs], then [ensure some outcomes].

The outcomes to be assured also define the goals of the user specifically within a certain behavioral or system state context.

When the goals of stakeholders are clearly understood and can be codified in a manner such as the BDD form, the development team can move forward more quickly and with greater confidence. And when meetings are equally focused on goals and achieving them, meetings will be an asset rather than a liability. And your team will have a much greater opportunity to succeed.

Enterprise Content Management for the Win in 2012

December was an interesting month with multiple pieces on the chess board moving all at once insuring an interesting and exciting new year for me. And that new year is upon us. I picked up my copy of CIO Insight magazine, the November/December 2011 issue, this morning and read with delight the article entitled Where the IT Dollars Are Headed in 2012.

One passage in the study mentioned in the article (included in the print version and linked to online) caught my eye:

“Elsewhere in enterprise applications, collaboration, and content and project management are rapidly gaining popularity, which makes sense given the new mobile opportunities for these categories. Collaboration and content management are seeing increases in 2012 over 2011 of roughly 10 percentage points in the number of organizations budgeting; and among those that already were spending in these areas, budget growths are averaging 14.6 percent and 7.3 percent, respectively—both significantly higher than 2011’s growth.”

I have a recently renewed and very keen interest in the potential growth of the enterprise content management market. And I will blog more about this in the coming weeks which are sure to open up new opportunities for personal and professional growth.