Tuesday, May 4, 2010

Simplicity vs Capability

Generally speaking, the greater the capability to be built into a hardware object, the more complex the interface will need to be. Yet simplicity-of-use is a very desirable feature. Capability and simplicity are two forces that need to be balanced in design. Complexity is related to quantity. Fewer items = simpler.

To squeeze the greatest amount of capability out of the fewest items, choose items that matrix. Consider cars, for example. We could have 6 models and 6 colours. If each model is available in each colour, we have 36 different things (6 models x 6 colours) which can be known by knowing only 12 things (6 colours + 6 models). If we also offer a manual or automatic transmission for each model, we have 72 variants (6x6x2), defined by 14 items (6+6+2). And so it goes. As long as the items matrix, we get more possibilities for fewer items.

The items in the example are properties of the object Car: .model, .colour, and .transmission. These are independent variables. The simplest, most powerful object interface will result from a collection of properties that are independent variables.

This idea works as long as there are no exceptions. If one particular model is not available in one colour, the simplicity is lost. As a rule, exceptions are bad news.



Sunday, May 2, 2010

More Generalities

So where to start when designing hardware objects? My approach has been to look around at what has been made so far, starting with the simplest and most common devices. For instance, lighting control. There is the ubiquitous light switch, can't get much simpler than that. In terms of objects and their properties:

Light.on = 1; // turns the light on
Light.on = 0; // turns it off

The next most common lighting controller is the dimmer. It might be implemented like this:

Light.brightness = 50; // set light brightness to 50%
Light.brightness = 0; // set light brightness to 0% (turn it off)

(and so on)

Clearly the "brightness" property can be used to implement the "on" property. Say you want to be able to set the brightness with a slider, and then switch the light on (to that brightness) or off, using a switch.

You could write some code:

int curSwitch = 0; // variable storing switch state, connect to switchChange() event
int curSlider = 100; // variable storing slider position, connect to sliderChange() event

void setBrightness()
{
Light.brightness = (curSwitch == 1) ? curSlider : 0;
}

void switchChange(int state)
{
curSwitch = state;
setBrightness();
}

void sliderChange(int percent)
{
curBrightness = percent;
setBrightness();
}

There is no problem per se, but the hardware object could easily be doing more of the work. By implementing the .on and .brightness properties separately, this same effect can be created by simply setting properties in response to change events.

void switchChange(int state)
{
Light.on = state;
}
void sliderChange(int percent)
{
Light.brightness = percent;
}

My point: when designing hardware objects the goal is not to eliminate redundancy to create a minimal object. The goal is to design an interface that implements common behaviours, offloading these from external processes.