Tuesday, January 3, 2012

Ageing consumers and the UI balancing act

A few days ago I was listening to an episode of an Australian radio program Future Tense discussing the work towards and implications of increasing human lifespans (the episode is over a month old but I have a long podcast backlog). The program ends with an interview with Dr. Joe Coughlin, director of M.I.T.'s AgeLab. My ears perked up when he started talking about design:
Design is the language by which we speak to the customer. Now I'd love to give you a lecture that universal design, you know things that are easy to see, easy to read, and manipulate, is the answer for an ageing society.
It's certainly part of an answer, but universal design or simplicity for simplicity's sake, does not excite and delight the customer. You know the Baby Boomers have become the generation that they are because they've always demanded more, shiny and cool. Well universal design in general suggest that beige is a colour. I'm sorry, beige is not a colour.
As a Web application developer I hear the topic of accessibility come up every so often. In the discussions I've participated in, accessibility is usually thought of as designing for people with disabilities due to illness or an accident. With Web development being a relatively young industry, there are not many people working in it who are over 50 so few Web developers can relate to ageing-related accessibility at a personal level. However an ageing population means that the percentage of consumers who develop age-related usability issues will grow over time, and Web sites that can cater for that growing market will have a competitive advantage.

I'm not a User Interface person so I don't really know what I should be doing to make my Web interfaces more "ageing-friendly". As Dr. Coughlin points out, it's not simply a matter of making interfaces more "accessible". The Baby Boomers are sophisticated consumers that still expect to be excited and delighted even in accessible interfaces. Approaches such as "universal design" won't be enough to win them over.

All of this highlighted to me the many forces that designers need to be balanced when creating user interfaces. These forces are very different to those that need balancing when creating software (correctness, performance, security, and so on). I think my efforts would be better spent mastering the software development balancing act rather than add the user interface design balancing act to it. I do appreciate the work that goes into good user interface design: I just think it's not work I'm well suited for.



'via Blog this'

Monday, August 16, 2010

12 Ways Software Errors differ from Spelling Errors

[Note: I posted the following on my work team's blog earlier today. I started off with only 7 ways at noon, but came up with 5 more by the end of the day.]

Spelling errors are a simple and often humorous form of error that seems to be popular for introducing the topic of production errors. However I find that spelling errors and software errors differ in some very important ways.

The following is my own list of important differences between software errors and spelling errors.
  1. Software errors are usually dynamic (the software does something wrong) while spelling errors are always static (the spelling is wrong).
  2. Spelling is unambiguous: either a word is in the dictionary, or it is not.
  3. Spelling errors are trivial to reproduce.
  4. Once identified, spelling errors are usually easy to recognize as such.
  5. If different stakeholders disagree on the spelling of a word, you can resolve the conflict by going to the dictionary.
  6. You can usually ignore requests from a customer to spell a word incorrectly (after politely referring them to a dictionary, of course).
  7. The cost of correcting a spelling error in a draft document does not increase with the amount of time it spent there.
  8. After carefully correcting a spelling error, you can be supremely confident that the spelling of that one word is now correct.
  9. Repeated misspellings of the same word can be easily corrected with the "Replace All" word processor feature.
  10. It is easy to correct a spelling error without creating more spelling errors.
  11. Correcting a single spelling error does not cause a collection of seemingly unrelated spelling errors to vanish without a trace.
  12. There are many spell checking programs available to detect all your spelling errors for you. Software defect detection, however, is an undecidable problem: there cannot ever exist a program that will detect all software defects.
Can you think of any others? Post them in the comments!

P.S. This blog post has been certified by a spell checker as 100% free of spelling errors :-)

Saturday, February 13, 2010

Excellence is a better goal than best

One aphorism frequently cited in English is "Perfect is the enemy of the good". It's basic message is clear: perfectionism may initially result in improvements but it eventually becomes counterproductive. Unfortunately it is often misused in the workplace as an excuse for mediocrity: it becomes another way of saying "'good enough' is good enough".

Apart from the above-mentioned misuse, the truth of the saying seems fairly uncontroversial. After all, in a world of mortals perfection is never truly attainable. However a few months ago I decided to look for the origins of this saying and discovered a hidden controversy behind it, and with it a more subtle and deeper truth.

A Google search revealed that the quote originated from the French philosopher Voltaire. As you might expect, the English quote is a translation. The original words were "Le mieux est l'ennemi du bien." I do not know French, but apparently the words "le mieux" (translated as "perfect" in the popular aphorism) is more literally translated as "the better" or "the best". As is common in such situations, debates abound over Voltaire's intended meaning of his words and which translation most accurately conveys that meaning.

I prefer the translation "The best is the enemy of the good". It may sound very similar to the common translation, but there is a subtle difference. While perfection is clearly unattainable, "the best" appears to be more within reach. However it is this attainability that makes it more dangerous than perfectionism.

When we strive for quality (good), we frequently encounter choices on how to proceed. At the beginning it is usually easy to identify the "better" choice, however as progress is made this becomes more difficult. The difficulty arises because at higher quality levels the choices tend to trade off one aspect of quality for another, so value judgments must be made as so which trade-off is the "better" one to make. Such value judgments are by their nature subjective and if there is disagreement a lot of energy can be expended in resolving the differences of opinion. In my experience, such disagreements almost always occur before "the best" is reached.

So if mediocrity is unacceptable, perfection is unattainable, and "the best" is too costly, what should we aim for? My answer is excellence. Once we learn to recognize excellence in our own work and the work of our peers, it becomes more productive to stop at "excellent" than to continue towards "best".

All this hit me recently while working on Model-Glue. I have been contributing to the Model-Glue project for a few months now and was recently accepted as a member of the development team. The two members I have been working the most with are Dan Wilson and Ezra Parker. Both are skilled coders and I am grateful for them giving me the chance to be the worst in their band.

We are working on finalizing a maintenance release and Ezra was assigned to fix an outstanding bug. He implemented a proposed fix and posted it with a request for feedback. I was a bit busy at the time so it was a few days later before I replied with an alternative approach that I had in mind that addressed a concern he had. I also offered to implement my idea if he were interested. In his response to my reply Ezra said:
If you'd like to create another patch for this ticket, feel free. I'm all for going with whatever fix works best, so if your idea turns out to be the better one, then we should probably implement it. That said, I performed some load testing tonight, and I'm not currently convinced that the attached patch causes any decrease in real-world performance.
Ezra wrote a good implementation, created unit tests for it which his fix passed, and performed load testing that confirmed that his fix offered good performance. In short, his work was excellent.

Sorry Ezra, but I must disagree with you on going with whatever fix works best. I've decided to not implement my idea. Why should I mess with your excellence?

PS. Excellence is not always the best or most important goal. Less is often a more important goal than excellence. Sometimes worse is better. And as strange as it may sound, sometimes sucks is a better release point than excellent (an idea Google seems to have embraced).

Wednesday, January 6, 2010

Thread-safety of integer counters in ColdFusion

I was a quite floored this morning when I discovered that Ben Nadel had taken some comments I made regarding thread safety on his blog post on ColdFusion 9 caching and used it to write an entirely new blog post on the AtomicInteger Java object.

In the first post, Ray Camden commented that he thought there might be a race condition in the array loop in Ben's code sample. I later chimed in, expressing my opinion that the race condition was not in the array loop but in the ID generator, and the latter could be fixed with an AtomicInteger object. Ben followed up by saying a named cflock would also work, and I replied that it would interesting to compare the performance of the two techniques.

Any of you who are followers of Ben Nadel's blog know that he is an irredeemable empiricist. He rarely accepts theories on how programs work without first testing them with his own experiments. His intellectual curiosity and honesty makes his blog a joy to read, and I find there is always something to be learned from his experiments.

Apparently my final comment on Ben's caching post caught his attention, as he made it into the topic of a new blog post on AtomicInteger. It was awesome to see him put enough thought into the topic to whip up a performance test and then share his thoughts on the topic and the test results on his blog.

While I enjoyed reading his new blog post, I decided that his experiment needed to be taken a little further. There were two issues that Ben's experiment did not address:
  1. The experiment was single-threaded, so it did not test the performance of the counters when shared by multiple threads;
  2. The experiment did not compare the thread-safety of the two approaches against the control case (no locking).
Ben had already done the heavy lifting, so all I had to do was add the thread code and the no-locking case. I changed the tests so that each test created 10 threads, and each thread incremented the shared counter 100,000 times. The correct final result of each test would then be 10 * 100,000 = 1,000,000. However if the counter experienced any race conditions, some of the increments would be lost and the final result would be less than 1,000,000.

Since blogger.com does not offer a good way to include long code snippets in a blog post, I decided to publish the code on pastebin. You can check it out on http://cfm.pastebin.com/f18eee642

The performance part of my new test matched Ben's results:

Named CFLOCK Test: 22,807 ms
AtomicInteger Test: 2,403 ms
No-Locking Test: 2,574 ms

I was a little surprised that the no-locking test was slightly slower than the AtomicInteger test. I can only guess that AtomicInteger offers a speed benefit over ColdFusion's ++ operator that outweighs its thread-safety overhead.

The thread-safety part of my new test, on the other hand, completely blew my mind:

Expected final counter value: 1,000,000
Named CFLOCK final counter value: 1,000,000
AtomicInteger final counter value: 1,000,000
No-Locking final counter value: 497,246

The final counter value of the thread-unsafe test was half that of the thread-safe tests. That means that with 10 concurrent threads, approximately 50% of the shared counter increments were lost due to race conditions!!! It turns out experiencing race conditions with the ColdFusion ++ operator was much more likely than what I originally thought. Empirical testing FTW!

Thanks again to Ben Nadel for inspiring me to take this investigative journey and share it with others.

Sunday, December 13, 2009

ColdFusion shared scopes and race conditions

In a recent Google Group thread discussing the Singleton design pattern, Phillip Senn asked whether the application scope needs to be locked in onApplicationStart. Ray Camden answered with the following:
You don't need to lock if you let them run "normally." If you run the methods manually (many people will add a call to onApplicationStart inside their onRequestStart if a URL param exist) then you may need a lock. Of course, you only need a lock if you actually care about a race condition. 99% of the code I see in application startup just initializes a set of variables.
Ray's comment about not needing to lock when onApplicationStart is invoked implicitly during the application start event is completely correct. However, things get a little more complicated when you directly invoke the same method. Not only does it create race conditions, but the race conditions it creates are often not easily solved by cflock.

Let me explain with a story. Once upon a time a CF coder wrote some application initialization code that looked like this:
application.settings = {};
application.settings.title = "My application";
application.settings.foo = 42;
application.settings.bar = 60;
application.settings.baz = false;
To allow these settings to be reloaded, the coder added the following to onRequestStart:
<cfif StructKeyExists(url,"init") and url.init eq "abracadabra">
<cfset onApplicationStart() />
</cfif>
This worked fine in development and testing and so was deployed to production.

The application was successful and its usage grew. The original coder moved on to other projects and the maintenance was handed off to a new coder. Many months later the new coder noticed something. Occasionally, when the maintainer used the init=abracadabra parameter to reset the application variables, he would see errors pop up in the error log at the same time. The errors looked something like this:
Element BAR is undefined in APPLICATION.SETTINGS
The source of the error was not isolated to a single place in the code; it occurred in many different places in the application. The element also changed: sometimes it was BAR, other times it was BAZ or FOO or TITLE. The only thing in common to all the errors was APPLICATION.SETTINGS.

The coder couldn't see any pattern to the errors and so wrote it off as an anomaly; either an obscure bug in ColdFusion or some server misconfiguration. The errors continued but not frequently enough for end-users to really notice and complain about it.

Some time later, a project to add enhancements was approved for the application and another coder was brought in to assist the maintainer. The new coder is a bit of a "guru" and knew something about race conditions. When the code guru saw the strange errors he quickly identified the source of the problem: the initialization code contained a race condition.

By initializing the application.settings variable with an empty structure, there was a short period of time when the structure did not contain the title, foo, bar, or baz members. This is not a problem during the application start event because the event occurs before any normal request processing, but it is a problem if the same code invoked directly. If any other request thread tries to access one of those members after the re-init has created the structure but before it has assigned a value to that member, an error will occur.

So how did the guru fix the race condition? The naïve approach would be to simply put a cflock around the call:

<cfif StructKeyExists(url,"init") and url.init eq "abracadabra">
<cflock scope="application" type="exclusive" timeout="60">
<cfset onApplicationStart() />
</cflock>
</cfif>

However, to making this work would also require a read lock around every single access to the application.settings structure! A painful approach to say the least.

The guru knew a better way. He made some simple changes to the initialization code:

var settings = {};

settings.title = "My application";
settings.foo = 42;
settings.bar = 60;
settings.baz = false;

application.settings = settings;

Voila! By initializing the settings structure in a local variable and only assigning it to the application scope after it is fully initialized, the original race condition disappeared. No locking required!

The fix was deployed and the no trace of the error was ever found again.

Some time later, another coder noticed that he was seeing a similar problem in his application, except his errors were in the session scope and they occurred much more frequently.

The CF guru rolled his eyes. "Here we go again," he thought to himself...


Sunday, October 11, 2009

Model-Glue: Event result handlers

One feature of Model-Glue that seems to frequently trip newcomers is the <result> tag. I tend to call these result handlers, to distinguish them from results issued by controller methods.

A result handler is used in a event handler to specify which event(s) should be processed after the current event. A named result handler is fired only when a controller issues a result of the same name during the event, while an unnamed or default event handler is "always" fired and does not require an explicit result from a controller (except under certain situations that I will explain in this post).

However, a Model-Glue result handler has two quite distinct behaviours depending on the value of the redirect attribute:

  • When redirect="true", processing of the current event is stopped and the event queue is discarded. The framework then issues a to the target event. By default the event state is preserved and is available in the target event, but this can be overridden by adding preserveState="false".
  • When redirect="false" or is unset, the target event is added to the event queue. Because an event handler may have more than one <result> tag, an event handler may add more than event to the queue. After all matching <result> tags have been processed, the framework invokes the handler for the next event in the queue.
The basics of the <result> tag is explained in the Section 5 of the Model-Glue Quickstart.

A Model-Glue newcomer is likely to first think of <result> as a kind of GOTO statement and may not realize that multiple events can get queued by an event handler. In a recent post to the Model-Glue mailing list, a developer wondered why the following event handler did not work as expected when an error result was issued:

<event-handler name="signup">
<broadcasts>
<message name="doSignupForm" />
</broadcasts>
<results>
<result do="page.index" />
<result name="error" do="signupform" />
</results>
</event-handler>

What was happening of course is that both "page.index" and "signupform" were being added to the event queue. In this case the developer was seeing the view rendered by page.index, but the final rendering would depend on how the two target event handlers were written.

There are two solutions to this. One solution suggested by another member of the mailing list is to have the controller method issue a success result when there is no error:

<event-handler name="signup">
<broadcasts>
<message name="doSignupForm" />
</broadcasts>
<results>
<result name="success" do="page.index" />
<result name="error" do="signupform" />
</results>
</event-handler>



Another solution is to use redirect="true" to imbue the error result with the expected GOTO-like behaviour:

<event-handler name="signup">
<broadcasts>
<message name="doSignupForm" />
</broadcasts>
<results>
<result do="page.index" />
<result name="error" do="signupform" redirect="true" />
</results>
</event-handler>

One interesting feature of redirect result handlers that I've discovered is that they fire immediately upon a controller method issuing them. This means that any controllers that are waiting to process the current or subsequent message broadcasts in the current event will not be executed.

For example, let's say you wanted to use a message broadcast to log successful signups. One approach would be to add a second broadcast to your signup event:

<event-handler name="signup">
<broadcasts>
<message name="doSignupForm" />
<message name="log"> <argument name="message" value="Signup success" /> </message>
/broadcasts>
<results>
<result do="page.index" />
<result name="error" do="signupform" redirect="true" />
</results>
</event-handler>

If the error result uses redirect="true", this will work as intended because an error result would interrupt the event processing so that the log message would not be broadcast. If the redirect="true" is removed, the log message would be broadcast even on error results.

To get the correct behavior for a non-redirect result you must put the log broadcast in the target event. You may need to define an intermediate event for this. Here is an example:

<event-handler name="signup">
<broadcasts>
<message name="doSignupForm" />
</broadcasts>
<results>
<result name="success" do="signupSuccess" />
<result name="error" do="signupform" />
</results>
</event-handler>

<event-handler name="signupSuccess" access="private">
<broadcasts>
<message name="log">
<argument name="message" value="Signup success" />
</message>
</broadcasts>
<results>
<result do="page.index" />
</results>
</event-handler>
In this case I had to use a named result handler for success so that it would not be fired on error. I also declared the target event handler as private: this is to prevent anyone from triggering the event externally.

For the signupSuccess event handler I would make one more change. If a user signs up successfully and then triggers a browser reload, I do not want to process the signup event again. To prevent this, I could change the final result handler to a redirect:

<event-handler name="signupSuccess" access="private">
<broadcasts>
<message name="log">
<argument name="message" value="Signup success" />
</message>
</broadcasts>
<results>
<result do="page.index" redirect="true" />
</results>
</event-handler>
With this change, a user who successfully signs up would end up at index.cfm?event=page.index instead of index.cfm?event=signup. A browser reload at that point would simply reload the main application page instead of repeating the signup processsing.

Sunday, August 30, 2009

Challenging Ourselves with Progressive Enhancement

Introduction


Most Web coding these days is a jumbled mess of HTML, CSS, and JavaScript. I was starting to believe that this was simply an ugly truth I had to live with, but then I learned about progressive enhancement. Progressive enhancement (PE for short) is a Web design strategy that uses web technologies in a layered fashion to separate the jumble and provide universal access to basic content and functionality while also providing an enhanced experience for those with more capable browsers and bandwidth.

Following PE requires some discipline. I and many other long-time Web developers have gotten used to using presentation markup, inline styling and scripting because we started at a time when there was no other way to provide a suitable user experience. However, browser technologies have matured to the point where the developers are now usually holding back the technology rather than the other way around.

With this in mind, I wanted to come up with a few simple rules for guiding Web developers towards this new approach. My idea is to offer a series of challenges, where each challenge involves implementing some common Web development task while being restricted to a set of rules to steer the developer away from obsolete techniques and towards PE. My intent is to offer a way to gently introduce the practice of PE to Web developers (including myself).

The Challenge


The Progressive Enhancement Challenge consists of four rules and three levels. The rules enforce separation of the layers while the levels enforce the progressive construction of those layers.

The Rules

  1. All markup must be well-formed.
  2. Transitional or other pure presentation markup must not be used.
  3. Inline styles or scripting must not be used.
  4. All links to external stylesheets and client scripts must be within the document head.

The Levels


Each level must maintain all the levels below it, so levels must be constructed in order and higher levels must not break lower levels.

Level 1: Function

The application must provide all required functionality even when client scripting and/or CSS is disabled or not available.

Level 2: Presentation

The application's presentation should be enhanced with appropriate styling.

Level 3: Interaction

The application's client-side behavior should be enhanced with appropriate scripting.

Conclusion


If you're not familiar with current Web technologies, some of the rules may seem impossible. For instance, Rule #3 prohibits the use of HTML event attributes such as onload or onclick. The Progressive Enhancement alternative to event attribute is to use unobtrusive JavaScript techniques such as jQuery event handler functions. Likewise, most other popular techniques prohibited by the rules have better alternatives that are well support in all the major modern browsers.

The goal of this challenge is to push us to become better Web developers. As such, it is merely a means to an end, and not an end unto itself. While I'd like to see this create a little friendly competition between developers, the last thing I want is for people to take this too seriously. If you try to use progressive enhancement for real work and find yourself in a situation where sticking to these rules is proving too difficult, don't sweat it; your page won't crumble to dust if you break a rule here or there. And please, please don't create or put any badge graphics on your Web pages claiming they are Progressively Enhanced!

Stay tuned for some PE challenge exercises coming to this blog Real Soon Now(tm)!