Two Views of Design

After watching Objectified again a few days ago I started formulating an idea of the concept of “Design”.

It seems to me there are two separate concepts of “Design” that have become mashed together.

The first concept, which to me is interesting but somewhat useless, is the idea of design as art or as artistic expression. There are plenty of designs that go by on Dornob which is art going for design. Many of the “designs” featured there are either making statements (such as the Nuclear War Shelving Units) or demonstrating technique (such as the laser-cut custom wall shelves) which are ultimately–if not useless, are at least impractical. Don’t get me wrong: I love these things. I love the floating bed concept, and the articles on vintage futurism is always very cool.

The second concept of design is a functional one. It is the idea of design as thinking through a problem obsessively–using various design patterns to decompose a problem (which is inherently a blank slate) and construct and test solutions which work even on the edge cases.

This sort of design is explained with the story in Objectified with the story of the Japanese-inspired toothpick, with the description of various design approaches (formal decomposition of a problem, the cultural or contextual symbolism of an item, and looking at the object within the larger contextual framework where it is placed or used.). It’s described by Jonathan Ives when he describes the design of the iPhone or the making of jigs to help cut a single component out of a block of aluminum. It’s shown when Bill Moggridge describes his early computer laptop design’s “pencil kick” component which kicks small objects out of the hinge.

It is this second concept of design which fascinates me–because to me, it’s about thinking the problem through.

Within my own realm, I’m fascinated by user interface design–which encompasses the realms of human interaction “language” (or the gestures and symbols used to consistently communicate with the computer), about the functional decomposition of a problem set into the hierarchy of components in that representation, and about the subtle (and non-subtle) cues that we use to guide a user to the relevant bits of information.

The current project I’m working on has two pieces–and I find it quite exciting. The first piece is a consumer-facing interface–it gives ad statistics to our advertisers. It’s an interesting project because the primary thing we’re trying to communicate is the power of our system and its usefulness in bringing you potential customer leads.

The second, and far more interesting component to me, however, is our back end administrative console. This is far more interesting because rather than the front end, whose purpose is in part artistic and artistic expression–making the data useful in a pretty way–it’s a far more functional interface.

And functional interfaces are exciting to me, because it requires bringing the full gamut of design tools to communicate the functional components of the interface in a way that is completely unobtrusive. It’s a thousand little decisions like the status light on the front of a MacBook Pro: when you need the information it’s there, almost as if it should be there, almost as if it was always there–but when it’s not needed, it quietly disappears: the calm, considered solution and not constant reminders of “the terrible struggles that we as designers and engineers had in trying to solve some of the problems”, as Jonathan Ives put it.

Animating an application.

I ran into a minor issue yesterday with an application I’m working on in my spare time. The application itself has a state machine underneath the surface which sends messages to the UI layer at certain state changes. One of those state changes triggers a UI animation to display the results.

And the animation was broken.

I found out why. In one execution path through the application, the same animation was being triggered twice. And when this happened, the animation was getting confused.

The solution, once I realized the problem (triggering an animation twice in rapid succession screws up the animation sequence) was simple: create a new event object which gets executed after the current event has completed processing in the event loop. In my case I set a flag which indicates if I’ve inserted my event to trigger my animation into the event loop, and when the animation is triggered, I clear the flag. (On the iPhone:

- (void)internalDoMyAnimation
{
	/* Trigger animation here */

	enqueueAnimation = NO;
}

- (void)doMyAnimation
{
	/*
	 *	We enqueue this for the next loop through the run loop to make sure we
	 *	only do this once. Two rapid calls to scrollToRowAtIndexPath animated
	 *	just confuses the animation code.
	 */
	
	if (enqueueAnimation) return;
	enqueueAnimation = YES;
	
	[self performSelectorOnMainThread:@selector(internalDoMyAnimation) withObject:nil waitUntilDone:NO];
}

The idea is simple: if for whatever reason -doMyAnimation gets triggered twice, the animation event will only be enqueued once. Parameters can be stored in the object itself, so if I have two ways to do the animation, I can trigger the correct behavior. And enqueueing the animation has the advantage of allowing the animation code to trust that the current application state has settled before actually doing something.

Every application framework allows an event to be inserted into the main (UI) thread: on Swing it’s SwingUtilities.invokeLater(Runnable doRun); on Windows it’s PostMessage(). Android is a little weird; you’d think Activity.runOnUIThread() would do the trick, but the class is executed immediately if triggered from the main thread by calling the Runnable’s run() method. Instead, you have to create a Handler when you create your Activity, and use Handler.post(Runnable r) to add the object to the message queue for that activity. (If only the activity would return it’s Handler…)

And in GWT (which I’m just now playing with) it’s DeferredCommand.runCommand(Command c).

Fun with GWT

Upgrading to v2.0 of GWT under Eclipse, here’s some of the things I encountered:

(1) For some reason my old 1.7.1 GWT projects are hopelessly broken; I can’t seem to debug them. Creating a new v2.0 GWT project seems to work fine. And I haven’t a clue as to why my v1.7.1 GWT projects, when I upgrade them to v2.0, refuse to debug: I’ve tried just switching the current GWT SDK, I’ve tried turning off and on GWT, I’ve tried blowing away the debug configurations–I’ve even tried recreating a new GWT project with the same source kit (which did work under v2.0’s debugger environment), then searching for differences.

Nothing.

The only workaround I’ve found is to create a new GWT project, and copy the sources across from the old GWT project.

(2) IE7 support for the new panel layouts is completely broken unless you change the DOCTYPE declaration from:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

to

<!DOCTYPE HTML>

Beats me why; I’m not into the finer points of HTML compatibility and doctype specifications. But once you make this switch, the new layout panels work as advertised.

The similarities between team architect and college professor.

I just spent the morning putting together a syllabus document describing the design parameters of the user interface I’m working on, complete with citations references to a number of research articles describing different aspects of visual design, usability and the importance of speed.

In the next few weeks I have members of a team I’m teaching building, which will be taught brought up to speed on what we’re doing.

The only thing that is missing are classes–and I’m sure if I offered to teach them (one every few weeks on different topics of usability), my manager would be elated.

Interesting observation about C++ operator overloading.

I don’t know why it didn’t dawn on me that this would work. After all, it’s not like I’ve been using C++ for the past 18-mumble-years. (Oh, wait; I have. Meh.)

So we define a class AClass, BClass and CClass such that AClass has an operator that converts it to BClass and CClass, and BClass has an operator that converts it to CClass. (Call AClass “integer”, BClass “double” and CClass “std::complex”.)

If we then define three operator + implementations:

AClass operator + (const AClass &a, const AClass &b);
BClass operator + (const BClass &a, const BClass &b);
CClass operator + (const CClass &a, const CClass &b);

Then we get automatic promotion to the appropriate type (AClass, BClass or CClass), regardless of what mixture of classes we use. Thus:

AClass a(5);
BClass b(3.3);
CClass c = a + b;

will set c = 8.3 + 0i.

I mean, this behavior makes complete sense. I just never thought of using this feature for my own code, until now.

Things that perplex me.

So the people I’ve worked with hate Eclipse because Eclipse insists upon imposing (by default) a standard project structure on a Java project.

It gets in the way and prohibits the flexibility necessary to get work done.

And they love Maven because it imposes a standard project structure on a Java project, so (to quote the Maven web site) as “to allow a developer to comprehend the complete state of a development effort in the shortest period of time.”

What the hell?

A useful little chunk of iPhone code.

This is something I hacked together for a program I’ve been tinkering with. Add this to your application delegate and it will trap uncaught Objective C exceptions, uncaught signals, and uncaught C++ exceptions (if you like messing around with Objective C++), and write a stack trace and detailed report which your application will offer to e-mail in the event that your program crashes in the field.

The preliminaries: the headers to add, global variables and the like:

#include <execinfo.h>
#include <exception>

/************************************************************************/
/*																		*/
/*	Globals																*/
/*																		*/
/************************************************************************/

static NSString *GBug;

/************************************************************************/
/*																		*/
/*	Crash Reporter														*/
/*																		*/
/************************************************************************/

static NSString *GetBugReport()
{
	NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
	NSString *dir = [paths objectAtIndex:0];
	return [dir stringByAppendingPathComponent:@"bug.txt"];
}

Note that this defines a function which saves any uncaught exceptions to a file ‘bug.txt’ on your phone. If this file is present the next time your application starts up, the user is presented with the option to e-mail the bug to you.

Now to catching uncaught Objective C exceptions:

/*	UncaughtExceptionHandler
 *
 *		Handle uncaught exceptions
 */

static void UncaughtExceptionHandler(NSException *exception)
{
	/*
	 *	Extract the call stack
	 */
	
	NSArray *callStack = [exception callStackReturnAddresses];
	int i,len = [callStack count];
	void **frames = new void *[len];
	
	for (i = 0; i < len; ++i) {
		frames[i] = (void *)[[callStack objectAtIndex:i] unsignedIntegerValue];
	}
	char **symbols = backtrace_symbols(frames,len);
	
	/*
	 *	Now format into a message for sending to the user
	 */
	
	NSMutableString *buffer = [[NSMutableString alloc] initWithCapacity:4096];
	
	NSBundle *bundle = [NSBundle mainBundle];
	[buffer appendFormat:@"PComp version %@ build %@nn",
			[bundle objectForInfoDictionaryKey:@"CFBundleVersion"],
			[bundle objectForInfoDictionaryKey:@"CIMBuildNumber"]];
	[buffer appendString:@"Uncaught Exceptionn"];
	[buffer appendFormat:@"Exception Name: %@n",[exception name]];
	[buffer appendFormat:@"Exception Reason: %@n",[exception reason]];
	[buffer appendString:@"Stack trace:nn"];
	for (i = 0; i < len; ++i) {
		[buffer appendFormat:@"%4d - %sn",i,symbols[i]];
	}
	
	/*
	 *	Get the error file to write this to
	 */
	
	NSError *err;
	[buffer writeToFile:GetBugReport() atomically:YES encoding:NSUTF8StringEncoding error:&err];
	NSLog(@"Error %@",buffer);
	exit(0);
}

This exception handler is called when you have an uncaught Objective C excption. This formats a bug report (note that I use build numbers in the info.plist file, under the key ‘CIMBuildNumber’), and writes the bug report both to the phone’s log and to the log file before force quitting the application.

Next, the signal handler:

/*	SignalHandler
 *
 *		Handle uncaught signals
 */

void SignalHandler(int sig, siginfo_t *info, void *context) 
{
	void *frames[128];
	int i,len = backtrace(frames, 128);
	char **symbols = backtrace_symbols(frames,len);
	
	/*
	 *	Now format into a message for sending to the user
	 */
	
	NSMutableString *buffer = [[NSMutableString alloc] initWithCapacity:4096];
	
	NSBundle *bundle = [NSBundle mainBundle];
	[buffer appendFormat:@"PComp version %@ build %@nn",
			[bundle objectForInfoDictionaryKey:@"CFBundleVersion"],
			[bundle objectForInfoDictionaryKey:@"CIMBuildNumber"]];
	[buffer appendString:@"Uncaught Signaln"];
	[buffer appendFormat:@"si_signo    %dn",info->si_signo];
	[buffer appendFormat:@"si_code     %dn",info->si_code];
	[buffer appendFormat:@"si_value    %dn",info->si_value];
	[buffer appendFormat:@"si_errno    %dn",info->si_errno];
	[buffer appendFormat:@"si_addr     0x%08lXn",info->si_addr];
	[buffer appendFormat:@"si_status   %dn",info->si_status];
	[buffer appendString:@"Stack trace:nn"];
	for (i = 0; i < len; ++i) {
		[buffer appendFormat:@"%4d - %sn",i,symbols[i]];
	}
	
	/*
	 *	Get the error file to write this to
	 */
	
	NSError *err;
	[buffer writeToFile:GetBugReport() atomically:YES encoding:NSUTF8StringEncoding error:&err];
	NSLog(@"Error %@",buffer);
	exit(0);
}

This more or less does the same thing, except for uncaught C signals.

And now C++:

/*	TerminateHandler
 *
 *		C++ exception terminate handler
 */

void TerminateHandler(void)
{
	void *frames[128];
	int i,len = backtrace(frames, 128);
	char **symbols = backtrace_symbols(frames,len);
	
	/*
	 *	Now format into a message for sending to the user
	 */
	
	NSMutableString *buffer = [[NSMutableString alloc] initWithCapacity:4096];
	
	NSBundle *bundle = [NSBundle mainBundle];
	[buffer appendFormat:@"PComp version %@ build %@nn",
			[bundle objectForInfoDictionaryKey:@"CFBundleVersion"],
			[bundle objectForInfoDictionaryKey:@"CIMBuildNumber"]];
	[buffer appendString:@"Uncaught C++ Exceptionn"];
	[buffer appendString:@"Stack trace:nn"];
	for (i = 0; i < len; ++i) {
		[buffer appendFormat:@"%4d - %sn",i,symbols[i]];
	}
	
	/*
	 *	Get the error file to write this to
	 */
	
	NSError *err;
	[buffer writeToFile:GetBugReport() atomically:YES encoding:NSUTF8StringEncoding error:&err];
	NSLog(@"Error %@",buffer);
	exit(0);
}

Which is the same thing for C++.

Next are the routines for hooking into uncaught signals:

/*	SetupUncaughtSignals
 *
 *		Set up the uncaught signals
 */

static void SetupUncaughtSignals()
{
	struct sigaction mySigAction;
	mySigAction.sa_sigaction = SignalHandler;
	mySigAction.sa_flags = SA_SIGINFO;
	
	sigemptyset(&mySigAction.sa_mask);
	sigaction(SIGQUIT, &mySigAction, NULL);
	sigaction(SIGILL, &mySigAction, NULL);
	sigaction(SIGTRAP, &mySigAction, NULL);
	sigaction(SIGABRT, &mySigAction, NULL);
	sigaction(SIGEMT, &mySigAction, NULL);
	sigaction(SIGFPE, &mySigAction, NULL);
	sigaction(SIGBUS, &mySigAction, NULL);
	sigaction(SIGSEGV, &mySigAction, NULL);
	sigaction(SIGSYS, &mySigAction, NULL);
	sigaction(SIGPIPE, &mySigAction, NULL);
	sigaction(SIGALRM, &mySigAction, NULL);
	sigaction(SIGXCPU, &mySigAction, NULL);
	sigaction(SIGXFSZ, &mySigAction, NULL);
}

Once an exception has been caught, it’d be nice to send it to you via e-mail. To do this, define the following Objective-C methods in your app delegate:

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex 
{
	if (buttonIndex == 1) {
		/*
		 *	Send an e-mail with the specified title.
		 */
		
		NSMutableString *url = [NSMutableString stringWithCapacity:4096];
		[url appendString:@"mailto:bugs@nowhere.meh?subject=Bug%20Report&body="];
		[url appendString:[GBug stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
		[[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];
	}
	
	[GBug release];
}

- (void)sendBugsIfPresent
{
	NSError *err;
	NSString *path = GetBugReport();
	
	GBug = [[NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&err] retain];
	if (GBug == nil) return;
	[[NSFileManager defaultManager] removeItemAtPath:path error:&err];
	
	UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Unexpected exception" 
			message:@"An unexpected exception was caught the last time this program ran. Send the developer a bug report by e-mail?" 
			delegate:self 
			cancelButtonTitle:@"Cancel" 
			otherButtonTitles:@"Send Report",nil];
	[alert show];
}

Remember to change the e-mail and the message that is displayed. This will display an alert to the user, and if the user selects “Send Report”, he’ll be dropped into the e-mail application to send the e-mail.

Of course you could do other things here, like upload via HTTP to some remote server. I like the e-mail approach; this way the user knows exactly what he’s telling you.

The -sendBugsIfPresent determines if a bug report has been written out, and if one is present, send it.

Now, once you’ve added this code, it’s simply a matter of wiring everything up to catch uncaught exceptions and alert the user if there was a crash the last time. To your -applicationDidFinishLaunching method add:

- (void)applicationDidFinishLaunching:(UIApplication *)application 
{
... Other initialization here ...

	/* Register for uncaught exceptions, signals */
    NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
	SetupUncaughtSignals();
	std::set_terminate(TerminateHandler);
	
	[self sendBugsIfPresent];
}

And that does it: we set up for uncaught Objective C exceptions, C++ exceptions and uncaught C signals, and we send a bug report if the last time we ran, we crashed.

Hope you find this as useful as I have.

Oh, and if you want to credit me with this, feel free–or not. (For the legally minded, I’m placing the above code snippets into the public domain. Just don’t sue me if it doesn’t work.)

An odd bug.

Found an odd bug tonight in an iPhone application I’ve been tinkering with.

The problem was that I had some code in a main UIViewController which was resizing the contents of it’s view. The code was being triggered by a button in another UIViewController which was placed in front of my main UIViewController through -presentModalViewController:animated:. And the code was crashing with a segment violation.

Some research later, and I figured out the problem: if you have a view controller representing a view hierarchy that is not currently on the screen (because it’s been kicked into the background by presentModalViewController), the view data structures can be unloaded from memory.

When this happens, calling [view bounds] on a view in your background view controller will crash, because the bounds is no longer present in memory.

Lesson: if a dialog or foreground view controller causes the background view controller to rearrange itself, you are better off detecting the change after the dialog or foreground view controller dismisses itself. In other words, only update views when they are visible.

Nouns, Verbs and UI Interface Design.

Excuse my ramblings.

Here’s a common mistake.

Say I’m building a client/server application. In attempting to understand the problem set I first design the back-end database layout, the data flow between systems, and the transformations (procedures, program statements) which perform the tasks that I need to use to achieve my system design.

The transformations then are mapped onto UI elements, so that the user can trigger these transformations by pressing a button or selecting a menu bar item, with the inputs and outputs of these transformations displayed in tables or custom views.

And we can call it a day, right?

Dear God, NO!!!

Of course you still need to design the back-end of the system, and how the data flows within the system. But users are not computer programs: most of us don’t think in terms of a sea of transformations that may apply against different data sets that can or cannot be grouped into larger transformation operations.

We think in terms of nouns, verbs and adjectives.

And user interfaces–at least when they’re done right–are not built in terms of transformation operations, but built in terms of the “parts of speech” that we understand, with the suitable “verbs” presenting themselves alongside the “nouns”.

I’m arguing for a deconstructionist perspective of design here: your interface will probably break down into a hierarchy of objects. In this hierarchy of objects you can discover the sub-objects and components which make up that object through “disclosure”: for example, double-clicking on a thing to open it, or pressing the disclosure button to reveal the sub-items in a list of items.

Actions that are appropriate to that object should be discoverable as close to that object as possible. The “verbs” (transformations) suitable for that object or it’s contained objects can be shown by updating a menu bar or having a small set of buttons associated with that item: in a sense, it’s a matter of balancing the atheistic of a minimal design with the need for discoverability: both work in favor of the user–with minimalism de-cluttering the screen from useless information, and discoverability showing the user (with subtle hints) how to perform an operation.

By associating the verbs with the nouns–the legal transformations with the objects they transform–we immediately move commands out of a global menu bar (where it’s unclear what may apply and why) and moving them with the objects that they operate on.

I like the [Edit] button on the iPhone and on the Address Book on the Macintosh: it helps balance the need of discoverability (how do I edit an entry? Hit the edit button) with minimalism (there isn’t a thousand edit boxes and icons on my main display confusing me). It adds a click to changing a record, of course–but the flip side is that this one click–this one moment in the user’s life–immediately makes it obvious what to do and how.

I also am starting to resent menu bars in general. In a perfect world they are the common verbs applicable to all (or almost all) nouns in the noun space of the application. But unfortunately most UI programmers use them as a dumping ground for noun-specific transformations, leaving the user to wonder why there are these twelve things that are always disabled. Most applications work with a menu bar because most applications operate on a very small uniform set of nouns. But with a more complex noun-space things become very messy very quickly.

It’s also why I’m very picky about the wording of menu items and the descriptions of objects in the documentation. Menu items should always be verbs: “Cut”, “Copy”, “Paste”, “Clear”, “Open”, “Close”, “Quit” are all direct verbs: “I copy this icon”, “I quit this application.” There are places where this is violated, and it sort of bothers me: in Safari the menu “User Agent” should in my opinion be “Set User Agent” (dropping the implied “to”). Of course sometimes the implied verb may be dropped, but I’ve never been quite comfortable with that: I’d rather have a sub-menu with a list of nouns buried under a menu item with the verb–using the submenu noun list as a modifier for the verb. (So: “Open >” pointing to a list of previous files, rather than a list of previous files.)

Of course, the idea is not to be strict about this–but to be clear: a new user should know if he selects a file it will open. Microsoft broke the contract of menu items as verbs with it’s quick open list in the File menu, and we’ve adopted it even though it’s bad UI design. But now everyone knows that “Open” is an implied verb, as is “Set”. *meh*

Overall I think the design of an application should be done both from the bottom up (data structures, then transformations, then presentation) as well as from the top down (user interface, then nouns and verbs, then map onto data structures and transformations). If we were to practice better design–and part of that is understanding the taxonomy of the nouns and verbs we are presenting to end-users–we could make user’s lives much easier.

And, as Apple has shown repeatedly with it’s Macintosh systems, iPhones and iPods, users will happily pay lots of serious money for systems which they perceive as easy to use.