Posts Tagged ‘Design’

The Russian Doll Approach to Web Services

Here's an anecdote for the WTF inbox. I assure you this is very real, but I cannot divulge any of the specifics.

Some time ago a friend of mine was talking to a web services vendor, who was explaining his versioning scheme. The vendor's approach was to make all of the web service functions accept a single parameter describing the function being called, and the version of the function requested. Prototypically:

public object Foo(FunctionCallInfo)

And what is FunctionCallInfo, you ask? Why, it is a strict XML document adhering to a schema that he would provide.

My observation, which my friend also arrived at independently, was that this person was basically creating an implementation of web services inside of web services. So nat'ralists observe, a flea / Hath smaller fleas that on him prey.

XML: the cause of, and solution to, all of your development problems.

What would do in this situation?

Faking Multiple Inheritance with Event Handlers

I'm going to take a page from the Book of Darrel and post some design patterns whenever I realize that I'm using them. I'd like to be careful because I think that there are a few camps when it comes to design patterns:

  1. Design patterns are very important, very specific, and are a great thing to quiz people about in an interview.
  2. Design patterns are more of a feel thing, something that is figured out when you're factoring code. There is no way you will not discover these on your own, if you are experienced and smart.

I lean to the second category. The quizzers tend to be solipsists and may know little else (you'll see the same attitude with plenty of other development topics).

Now that you know how to take my writing about design patterns, let's suppose that you want to make a Windows form that becomes a little translucent when it is inactive. That may or may not be annoying, but there is a very straightforward way to make it happen:

// Form that becomes transparent when it is inactive
public class Foo : Form
{
    private const double c_InactiveOpacity = 0.25d;
    private double _prevOpacity;

    protected override void OnDeactivate(EventArgs e)
    {
        _prevOpacity = this.Opacity;
        this.Opacity = c_InactiveOpacity;
        base.OnDeactivate(e);
    }

    protected override void OnActivated(EventArgs e)
    {
        this.Opacity = _prevOpacity;
        base.OnActivated(e);
    }

    public Foo()
    {
        _prevOpacity = 1.0d;
    }
}

Which works fine, unless you want TWO forms that do that, the second with a special base class not related to the heirarchy of the first.

public class Foo2 : SpecialForm
{
    // criminy
}

This conundrum could be resolved in a few ways:

  1. Ctrl+C, Ctrl+V.
  2. Multiple base classes.
  3. What I am going to call the "Extender Pattern."

If you picked the first option, I think it'd be better for both of us if you unsubscribed from my feed. The second option would work fine, but CLR languages don't support it. Some days this bothers me, but most days I think it's a good thing. Especially when I factor a solution that is just as elegant.

I'm calling that solution the "Extender Pattern" without bothering to find out if anyone has used this term to describe anything else. As I explained above, this is more about artistic sensibility than it is about hard rules and book learning. Not that I'm anti-book learning.

The basic idea is this: you have a set of components that support certain properties, methods, and events. The forms, in this case. You add in to the mix a set of small objects whose only responsibility is to wait for events from the components and make very directed changes to them.

So here is such a class for the problem stated above:

// Alters the target form's transparency level
// when it is activated/deactivated.
public class TransparencyExtender
{
    private Form _target;
    private double _prevOpacity;
    private const double c_opacity = 0.25d;

    public TransparencyExtender(Form target)
    {
        _target = target;
        _prevOpacity = target.Opacity;
        target.Activated +=
             new EventHandler(Activated);
        target.Deactivate +=
             new EventHandler(Deactivate);
    }

    void Deactivate(object sender, EventArgs e)
    {
        _prevOpacity = _target.Opacity;
        if (_prevOpacity >= c_opacity)
        {
            _target.Opacity = c_opacity;
        }
    }

    void Activated(object sender, EventArgs e)
    {
        _target.Opacity = _prevOpacity;
    }
}

Given this, we can write our forms very easily:

public class Foo : Form
{
    private TransparencyExtender _tExt =
        new TransparencyExtender(this);
}

public class Foo2 : SpecialForm
{
    private TransparencyExtender _tExt =
        new TransparencyExtender(this);
}

Keep in mind that I am not claiming that this is original. It's really the same as a small secondary base class in C++. However, I think there's value in looking at the same problem in different ways.

In a real application I'm working on, I've written a handful of other window/control styles that can be applied and removed on the fly or from the designer. Again, not original, but I like my little framework. Perhaps I'll post this someday, or turn it into a product.

I like event/message-driven programming the more I try to use it. I'm using Windows Forms as an example here, but it would be wrong to assume that's the only place this could be applied. I've done the same kinds of things in ASP.NET.

Exploit Natural Mappings in Interface Design

The on-screen guide for my Direct TV box looks roughly like this:

DirectTV blows

The control on my remote that causes the current channel to move up and down looks like this:

DirectTV blows

If the problem here is obvious to you, you too may have a future in user interface design. If you thought to yourself, "hey, they screwed up an obvious natural mapping," then you are probably already involved on some level.

Just to make it perfectly clear what I am talking about, the orientation of the controls are out of whack. From my perspective, the channels increase going down on the screen but going up on the remote. The fact that the two don't match causes me to change the channel up when I meant to change it down, and vice versa, pretty much constantly.

You might call me a moron, and most days you might be right, but not here. This design is broken. It should do what I want without requiring me to stop to think about it.

It's amazing that decades after the publication of The Design of Everyday Things that it is still possible for a well-funded company to make this mistake. This company has enough money to buy the NFL through 2010, but apparently it isn't able to find a decent interface designer.

Thinking Better Tech Designs

Where I work, there are programmers of widely varying skill levels all working on a single project. Some pieces tend to get behind, and some finish much more quickly. There are a seemingly endless number of integration problems. I am daily pondering what the differences are in the way people develop, and how I can communicate good ideas in a way that will help people reach that “eureka” moment where they get it.

Generally speaking, I’ve been pretty bad at it. I’ve tried explaining inheritance with stories, shaking people by their collars, etc, nothing really seems to work. The result is that people write code the way they always have: messy, hard to understand, hard to transfer to another owner, hard to change without creating new bugs.

Today this SLAR on System::Console got me thinking. Particularly, this line:

This class is a classic example of “design in reverse.” Before we designed this class we knew what we wanted the Hello World example to look like:

Console.WriteLine ("Hello World");

Well, there it is. That might be my own “eureka moment.” Write an API for yourself as you go. For every task you have to accomplish, ask yourself this:

If I had access to an oracle that could do my task for me, how would I want to use it?

Then start building that oracle. It’ll have steps that seem hard too, but use more oracles and more black boxes.

Another important point is to avoid thinking about code as much as you can.

Now, there are (obviously) a lot of steps between being a programming neophyte and being in the top few percent of software engineers. Most people need to get a lot of bad code out of their system before they’re much good. And this is certainly an oversimplification of thinking like a good developer.

Thinking of the best questions to ask your oracles can be a subjective, soft science too–but hopefully this is a decent starting point.