Stop making things better

September 14th, 2008

Sometimes I think we should never improve anything.

Every time we add goodness to an app or library someone gets hurt in the fall-out. Some unexpected side effect causes pain in userland (which is a place of many wails at the best of times). I swear it’s not our fault. OK, let me rephrase that. I suggest that occasionally we’re not to blame. Users have a way of finding a product’s one unsupported feature (which we maintain is actually a minor unfixed bug) and using it to power their entire business model. So when we fix the bug at last we’re surprised to get a call from an irate person called Bob enumerating a number of interesting and anatomically implausible plans he has to improve us, should we decide not to roll things right back.

Sorry Bob, but by then it’s too late. You can never take it back. At least four users will have launched new enterprises that depend utterly on the fix. And so the cycle of pain and recrimination rolls on.

This week I played Bob and spent some time in a userland hell of my own making. It’s a long story, actually, that starts here.

Back in the days of PHP 5.1 the language had a slightly odd feature. PHP provided a magic __toString() method that looks promisingly like the Java equivalent. The promise here is clear enough. Where a class wraps a string, it looks as if you should be able to implement __toString() and have the string value substituted when an object instance is used in a string context. And, yes, for this:

class wrapper {
    function __toString() { return "I'm a wrapper\n"; }
}
$wrapper = new wrapper();

Then

print $wrapper;

outputs

I'm a wrapper

Trouble is, if you place the object reference in a string, then you get something else entirely. This:

print "explain: $wrapper\n";

outputs:

explain Object id #46

Now, its obvious that this is one of those ‘features’ that will just go away one day. It’s just a loophole waiting to be closed. So of course I made significant parts of a project dependent upon it. Because I’m a user. I realized that you could use stringified object references as array keys:

$list["$wrapper"]

resolves to

$list["Object id #46"]

Neat.

But also quite stupid. Because when PHP 5.2 came along the loophole was closed, and suddenly

$list["$wrapper"]

resolved to

$list["I'm a wrapper\n"]

which is no longer guaranteed unique (not that the original behavior was in all circumstances, but that’s a different story). Much fixing of bugs ensued.

Fast forward a year. The team saw that this nifty string behaviour worked as expected, and it was good. Looking through our codebase our aesthetic sensibilities were offended by clumsy constructions like this:

print "adding value ".$mywrapper->toString()." here";

So over time we implemented __toString() methods and cleaned up clumsiness thus:

print "adding value {$mywrapper} here";

All was well. All unit tests passed. All regression tests passed. QA were happy. The release went out. With three layers of testing like this, surely little can go wrong. My laugh is bitter and hollow.

Someone ran our code against PHP 5.1. Files named Object id #45.db started appearing on the filesystem. Users were greeted: Hello Object id #36. Fatal errors appeared, some immediate, others as bad values were pulled from a database and slotted into confused and panicking code.

In fixing this, my first approach was a slack-jawed drool of an idea. I tried to chase down each error. This fly-fishing strategy failed utterly, mainly because the errors were not always obvious. There’s nothing about

print "adding value {$mywrapper} here";

that’s obviously wrong unless you know what kind of value $mywrapper holds. This statement produces garbage, but it does not generate a nice easy exception. After a full day of bug hunting I went home smelling of fail. The next morning, though, I switched from fly fisherman to trawler. Actually the best platform to catch these errors is PHP 5.2, because it’s here that you know that __toString() will be invoked. It was simply a matter of adding a stack trace and a die() statement to each of these methods, in order to catch all the invoking code. Every time the system died, I followed the stack trace and replaced the old inelegant explicit toString() call. When my unit tests all finally passed, I switched back to PHP 5.1 to confirm that all worked as expected.

So what have I learned? If I were smart I’d take this away:

1. Test against every major version and platform you purport to support. Virtualization can help here.
2. Don’t exploit side effects and undocumented features in a language, library or app. They are voodoo and will eat your soul sooner or later.
3. Don’t use new features if you want to support platforms on which they won’t work. Or if you do, then degrade gracefully.

If you find this bloody obvious, then woohoo for you. Personally I need the occasional reminder.

Alternatively, of course, I could choose blame the PHP team for my own shortcomings. The problem with open source products though is that there’s often no one person you can to shout at. Anyway if you lurk on php-internals you’ll find that they’re far too busy shouting at each other to tolerate any userland bolshiness.

sbgui, stickleback’s web interface extension to be documented at last

September 3rd, 2008

I think that core stickleback is pretty nifty in itself, and it’s proved its worth quietly powering applications for a couple of years now. It’s been partially documented outside of Yahoo! both here and in the pages of php|architect.

In the real world most PHP coders want to see web-oriented applications and APIs. In fact sbgui, stickleback’s Web extension, has been round for well over a year, but it’s been used internally and barely documented.

I’ve just submitted a short article to php|architect that could change that. I’ve also been busy writing internal documentation that I hope to get out on to YDN in due course.

sbgui is a lightweight and easy plugin-based framework for building Web-based interfaces. It makes it easy to build a presentation/command layer for an application, and it makes it even easier to extend.

Watch this space.

sbws to bring web services to stickleback, other stickleback plans

August 13th, 2008

As I reported over at openr3.com, stickleback is set to acquire a new extension. sbws will manage a pluggable RESTful Web Services interface. It’s written by fellow sb developer Steve Webster, and marks the third major extension to the stickleback plugin engine after sbcli (pluggable command line interfaces) and sbgui (pluggable web interfaces).

Also entering the planning stage are a couple of major new features. First off we want to provide plugin managment tools using the stickleback engine — these will allow plugin authors to generate the boilerplate code and XML required in setting up a pluginset, for example.

Secondly, we plan to incorporate an object persistence layer into stickleback. Once this is in place you will be able to use stickleback to create web interfaces at the front end and to save out domain objects at the back.

More soon.

OO and request superglobals

July 25th, 2008

David A. Spitzley posted a question in a comment regarding superglobals:

I’ve got a relatively basic question which wasn’t addressed in your book, but which seems important in dealing with Object Oriented programming in PHP: the superglobals. Do you have any advice on using $_POST and $_SESSION (for example) without breaking OO design principles?

I thought I’d answer it in the main blog, since I haven’t posted for such a long time (php|architect piece, also actually writing fiction believe it or not, etc etc).

Actually in Chapter 12 I provide an example of working with the $_REQUEST variable. The trick is to wrap the variable with a class.

I usually create a Request class which can be configured to accept $_POST or $_GET data, but is also savvy enough to work in an CLI context and acquire its data from $argv. In this way I can test run web apps from the command line. The wider system works perfectly happily in this context, since it deals with a Request object and not the superglobals the class hides behinds its interface.

This mechanism is also fantastic for testing. Your Request object can be charged with values in your test class’s setup() method, and you can test for your expected results.

Another benefit of maintaining a Request object is that it makes it easy to implement the Intercepting Filter pattern. The Request can be interrogated, and its values amended by gatekeeper components that clean up incoming data prior to the command stage.

Of course this doesn’t prevent the problem of rogue components directly manipulating your superglobal (which could happen if your system supports foreign plugins) — but I don’t see this as a huge issue. You probably got first bite of the cherry in any case, and your code won’t be working with the corrupted variable.

It Stops Here

April 21st, 2008

In some ways I miss spam. Of course I loathe it, and I believe that if there’s a hell, there’s a special part of it set aside for the evil Viagra-peddling scumbags that blight our inboxes. But now that I’ve filtered most of it out, it becomes starkly apparent how few actual real people want to mail me on a daily basis. I used to cycle through through screen after screen of penile bling painrelief awfulness and hate every second, but at least there was the possibility, the merest chance, that someone had decide to publish that short story, or offer me a fantastic tech book deal. Nowadays I must come to terms with my relative unpopularity at a single glance.

Nevertheless, I thought I’d release my mail quarantine package for any other sufferers who happen to use a procmail-like mail filter. It’s called ISH (for It Stops Here), and it works for me.

stickleback tricks part 2: providing default functionality for an extension point

March 22nd, 2008

In part 1 of this short series I looked briefly at mechanisms for passing parameters to plugins. In this piece I’m going address another of Jun’s points. This time: how to provide a default implementation of certain extension point interface functions.

First, let’s break down what we want to achieve here. stickleback defines its extension points in two ways. Firstly an extension point is associated with a plugin in XML metadata, that is via the <epoint> element in the sbplugin.xml file which must be present in a pluginset. The second aspect to an extension point is its interface. It is this that enforces the functionality that an extending plugin must provide. Here is the extension point interface in my ongoing example:

interface DoThisPleasePlugins extends stickleback_Plugin {
    function sayHello( $requiredvalue );
    function sayGoodbye();
}

Now all plugins that extend the MyAppPlugins host plugin along the DoThisPleasePlugins extension point are forced to support sayHello() and sayGoodbye(). In a non-trivial example though, it’s likely that you’ll want to provide some core functionality for your plugin authors above and beyond the simple interface they must implement.

Let’s say, for example, that you would like to provide an extendable implementation of the DoThisPleasePlugins interface. The functionality I provided for the someone plugin last time looks like it might be generically useful. By making it available as the optional default behavior for all plugins I can save a lot of duplication. By convention, I use the name of the extension point interface followed by Impl — short for implemented or implementation. Here is DoThisPleasePluginsImpl class. I drop it into the MyAppPlugins directory.

abstract class DoThisPleasePluginsImpl implements DoThisPleasePlugins {

    function sayHello( $requiredvalue ) {
        $this->doPrint("$requiredvalue\n");
    }

    function sayGoodbye() {
        $reg = stickleback_PluginRegistry::getInstance();
        $desc = $reg->getPluginDescriptor( $this );
        $bye = $desc->parameter("goodbye");
        $this->doPrint((is_null( $bye ) ? "goodbye" : $bye)."\n");
    }

    abstract function doPrint( $str );
}

Note that I would usually name a class in a pluginset directory as if the pluginset were its package. So I could have called this class MyAppPlugins_DoThisPleasePluginsImpl — but that’s such a mouthful, that I’ve decided to forego the convention. stickleback does not enforce any naming conventions for classes or extension points, and it doesn’t care where a class or interface is found, so long as it is found. It makes sense though to put a stub plugin in the relevant pluginset directory for ease of distribution.

So The functionality here should be familiar from part 1. sayHello() requires a value, and sayGoodbye() acquries a value via a parameter in the sbplugin.xml file. The difference is that I’ve moved it into an abstract base class. Notice also that I’ve deployed the template method pattern. In other words both my implemented methods call an abstract method: doPrint(). This is a typical trick. It allows common behavior to be shared, but requires extending classes to provide their own implementation of a small part of the shared workflow.

Now that I’ve provided an abstract base class, the someone plugin can be much simplified:

require_once( "MyAppPlugins/DoThisPleasePluginsImpl.php" );

class someone extends DoThisPleasePluginsImpl {
    function doPrint( $str ) {
        print "someone says $str";
    }
}

So now, instead of implementing the DoThisPleasePlugins extension point interface, all the someone plugin class has to do is to extend the DoThisPleasePluginsImpl class. I could choose to override sayHello() or sayGoodbye(), but in this case all I do is implement the doPrint() method. In this way we can vastly simplify the process of building a plugin for our users. In fact, when building pluggable applications I almost always work in this way, providing much default functionality. Of course a plugin author could chose to provide their own implementation — that’s their privilege, but design your abstract plugin stubs right, and most plugin authors will gladly use them.

Finally, then, here is the script’s new output:


$ php MyApp.php
someone says wotcha
someone says cheerio

stickleback tricks part 1: passing parameters to plugins

March 21st, 2008

Commenter Jun posted a really handy set of questions about stickleback. These questions were posed off the back of my stickleback quickstart articles, so I’ll extend the code I used there.

So, to kick off, how can we provide additional input parameters and objects to the extender plugin?

The simplest way of doing this of course is for the extension point interface to demand input values through type hinting. This forces the host plugin to provide the required parameter on calling the plugin’s implemented method. First of all I amend the interface that enforces the extension point so that sayHello() requires an argument:

interface DoThisPleasePlugins extends stickleback_Plugin {
    function sayHello( $requiredvalue );
    function sayGoodbye();
}

Then I implement my extender plugin so that it respects the new interface. Note that the new argument in the sayHello() declaration is not the only change here. The DoThisPleasePlugins interface now extends from stickleback_Plugin — this means that any class that implements DoThisPleasePlugins is automatically of type stickleback_Plugin — this will become significant later on.

class someone implements DoThisPleasePlugins {

    function sayHello( $requiredvalue ) {
        print "$requiredvalue\n";
    }
    //....

Finally any client must now provide an argument when it calls DoThisPleasePlugins::sayHello(). Here’s and amended version of MyApp::execute().

    function execute() {
        $reg = stickleback_PluginRegistry::getInstance();
        $desc = $reg->getPluginDescriptor( 'MyAppPlugins' );
        $plugins = $desc->getExtendingPlugins( "DoThisPleasePlugins" );
        foreach ( $plugins as $plugin ) {
            $plugin->sayHello( "wotcha" );
            $plugin->sayGoodbye();
        }
    }

I pass the string “wotcha” to the plugin. Here’s what we get when run the application:

$ php MyApp.php
wotcha
goodbye

Really, this is just standard coding — which is no surprise, since stickleback uses object-oriented features of PHP such as interfaces, type hinting and inheritance.

You can however use stickleback itself to parameterize plugins. This is particularly useful since a single plugin class can be used in multiple plugins. By passing different values to your plugin objects through the sbplugin.xml document you can construct plugins objects that behave in varying ways.

Here is plugins/someone/sbplugin.xml .

<?xml version="1.0" standalone="yes"?>
<pluginset
    name="someone"
    xmlns='http://developer.yahoo.com/xmlns/stickleback/sbconfig'>
    <plugin name="someone" type="someone">
        <honors plugin="MyAppPlugins" epoint="DoThisPleasePlugins" />
        <param name="goodbye" value="cheerio" />
    </plugin>
</pluginset>

As we’ve seen this pluginset defines a single plugin, someone which extends its host MyAppPlugins at extension point (ie interface) DoThisPleasePlugins. I have added a single line:

        <param name="goodbye" value="cheerio" />

By the magic of stickleback, this parameter becomes available to a plugin’s descriptor. A plugin can easily get access to its own plugin descriptor, and through that can acquire any parameters. Here’s the someone class:

class someone implements DoThisPleasePlugins {

    function sayHello( $requiredvalue ) {
        print "$requiredvalue\n";
    }
    function sayGoodbye() {
        $reg = stickleback_PluginRegistry::getInstance();
        $desc = $reg->getPluginDescriptor( $this );
        $bye = $desc->parameter("goodbye");
        print (is_null( $bye ) ? "goodbye" : $bye)."\n";
    }
}

In MyApp I passed a string name to stickleback_PluginRegistry::getPluginDescriptor() but the method also accepts an plugin object — allowing plugins to acquire their own descriptors with ease. At the time of this writing a plugin must implement the stickleback_Plugin class for this to work, but this requirement will probably be relaxed in future versions. The someone plugin is now parameterized. Any value addded to the relevant plugin/param element in sbplugin.xml will be picked up by someone::goodbye().

Here’s the full output now:

$ php MyApp.php
wotcha
cheerio

Next stickleback trick? I’ll show you how to save duplication by providing a default implementation for an extension point.

openr3: a new r3 site

February 23rd, 2008

Although it’s a pleasure to blog about my projects at Yahoo! they do somewhat dominate these pages at times. In order to encourage an open source community around these tools, a group of us are building a resource and information site over at openr3.com. There is very little there at the time of this writing, but we have a bunch of potential contributors, and a lot to talk about. We should be getting input from core developers, and I hope from some of the many web developers who use r3. This power user perspective has been missing from getinstance, and from other articles, and I hope it will set openr3.com apart.

A side effect of all this is that these pages will be freed up for more general content. More stick man cartoons anyone? Suit yourself.

r3 on Yahoo! Developer Network

February 14th, 2008

My project at Yahoo! is r3 — a flexible tool for localizing sites, configuration files and applications (across markets, cobrands, languages, or anything you like really). When we learned that Yahoo! was happy to support the release of certain properties to the open source community we were quick to volunteer r3 and stickleback (the plugin engine which drives r3’s interfaces and much else besides). We got the go-ahead after some scrutiny, and have lurked in the softest of launches for many months now.

Yesterday, though, we went official. You can now find full documenation at developer.yahoo.com. There are some more details in Norm’s announcement on the YDN blog.

Behind the scenes at the moment we’re labouring on some major new features. A vastly improved UI for one thing, some Web Services support, and mutable dimensions — a major new release is expected in about a month (though you’ll probably see point releases sooner).

no comment

February 7th, 2008

Roger Lancefield who left a really nice comment about PHP Objects Patterns and Practice in these pages recently posted a yahoosoft logo on his blog. Since I am officially barred from advancing any substantive opinion on the topic I’ll confine myself to two points:

  1. microhoo sounds better
  2. I for one welcome our new overlords