Tuesday, May 5, 2009

How do you document an options Object?

In JavaScript APIs and libraries, you can make a constructor or function more flexible and easy to use by having developers pass in an object of additional options.

Here's an example of a badly designed constructor that doesn't take advantage of this feature - the final 5 arguments are all optional, but yet, location must be passed in if the developer wants to specify hobbies.

EvilPerson(name:String, location?:String, age?:Number, job?:String, hobbies?:String);

When used, it's hard to understand what this constructor is doing:

var evilPerson = new EvilPerson("Taz the Haz", null, null, "Annihilator", "Blowing stuff up");

Here's an example of a well designed constructor that makes developers specify the absolute core information, and then pass everything else via an options object:

GoodPerson(name:String, options:Object);

When used, it's very obvious what options we're setting:

var goodPerson = new GoodPerson("Snuggly Muggly", {job: "Cuddler", hobbies: "Spooning"});

So, most people are in agreement that this is a good technique, but there's one problem: there's no standard on how these options objects should be documented.

In the JavaScript Maps API, we give the objects a class name, link to the class reference from the constructor, and then list the keys there. The advantage is that we can refer to these objects in the developer's guide or forum by name, the disadvantage is that we list a class in our reference that developers cannot actually instantiate, and that can be confusing.

The screenshots below are from the GMarker and GMarkerOptions reference.

In the Maps API for Flash, we turned those name objects into actual classes that developers must instantiate. This is good for documentation, but does perhaps bloat our API and make constructors more verbose.

The screenshots below are from the Marker and MarkerOptions reference.

In jQuery UI, every widget gets its own single-page documentation, with "Options" being a section along with "Events" and "Methods". There is no actual reference for the widget constructor itself, presumably because every widget's constructor takes only an options object. This likely works for jQuery UI developers as they're accustomed to this convention, but I personally found it confusing that there was no constructor reference.

The screenshots below are from the Dialog reference and options section.

In Dojo API, the reference for many of the Dijits specify that they take an Object for additional parameters, but they don't actually make it clear what can be passed into that object. My best guess is that the fields listed in the "Properties" section can all be passed in. This is probably once again a convention that seasoned Dojo developers are accustomed to, but arguably pretty confusing for a new Dojo developer.

The screenshots below are from the Dialog reference and the properties section.

In the Gears API, none of the constructors take a options argument, but there is something somewhat analagous: objects passed into event callbacks. In this case, Gears documents the object entirely inline with the reference. This technique has the advantage that everything about the function and the object are in one place - and the disadvantage that there's not a great way of referring to that specific event callback object elsewhere (besides saying "the object that the onerror function passes back").

The screenshot below is from the WorkerPool reference.

All of these styles have their pros and cons - and there's no one technique that satisfy our goals, like being easy for newbies to understand easy to refer to elsewhere in the documentation. What do you think? Have you seen a documentation that does it better, or do you think one of these techniques is clearly superior?


Dr Nic said...

I don't like documentation that pushes the options key:value descriptions into a new section of the docco. Perhaps this sort of behaviour extends from giving them "class names" like GMarkerOptions.

As you started with, think of the API: we're using an Object just to make our API more effective, so the documentation should describe this relationship inline with the rest of the method's definition

Roman Nurik said...

Here's how I do it:


Pamela Fox said...

Thanks for the feedback, guys.

Roman, I really like that style, thanks for the pointer.