JSON counterpoint

posted Feb 11, 2005
in XBLinJS

JSON is pretty cool for what it is; in a mix of dynamic languages where Javascript (most likely in a browser) is involved it may not be a bad choice. It's even a great choice if you're firing structured data back and forth from Javascript and something else.

But for it's "core competency" of interfacing with Javascript, I've found there is a better approach, though it may integrate JSON into the mix. Code is data and data is code; instead of transferring data, transfer code to replicate structures. There seems to me to be two basic techniques, each useful in their own way.

The first is to transfer only code. So, supposing you were going to replicate a graph structure, with nodes that have parents, and a string attached to them. This is what I might send to the browser upon the request for a particular document:

Node(ROOT, "document1", "My Document");
Node("document1", 1, "Section 1");
Node(1, 2, "Paragraph 1.1");
Node(1, 3, "Paragraph 1.2");
Node("document1", 4, "Section 2");
Node(4, 5, "Paragraph 2.1");

Behind the scenes, in the Javascript that was sent to the browser as part of the page, there is some global object that maps ids to nodes, and a Node function that takes the parent ID of the node, the ID of the current Node, and the text of the node, and does whatever processing is necessary. When you download Javascript like this, you're going to just eval it; don't fail to take advantage of the rich environment it is going to be running in.

The disadvantage is complexity. The advantage is of course power; while you could dump this structure out in pure JSON, you'd have dead data. If you're programming heavy-duty Javascript, you've probably got an object structure you want to put the data into. This makes that relatively easy.

It is also more maintainable in the long term, at least with appropriate discipline. (You have to have appropriate discipline no matter what, without it you've Already Lost(TM); I'm no fan of techniques that try to ignore that fact and just end up making things hard for everybody.) If you change something in the protocol, you have more places in the process to "hook into", a fact I've used to my advantage several times now. You don't have to have this mass of code that grovels over the JSON data structure and does all kinds of operations in one spaghetti pile, you can naturally partition it along the lines of what it is doing.

Alternatively, you could mix the two approaches. This is based on an existing application I have, using a factory function and some JSON-esque code (though it predates my hearing the term):

object = getObject("params");

object.children = {"plans": 3, "skus": 73};
object.metadata = {"human_name": "product", "order": "skus,plans"};

object.init()

object = getObject("config");
...

getObject is a factory function that returns some instance of a prepared class. The constructor of the class does little or nothing. I give it parameters as effectively JSON data. After that, I call an .init() function on the data, which goes through and post-processes it in the class definition. For instance, if "plans" referred to some other object, it might replace the 3 with a live reference to the indicated object. It can of course do anything it wants with the data, and it is still controlled by the class.

Note the re-use of the "object" variable. As part of either the getObject or .init() call, the object takes care of storing itself somewhere more permanently, perhaps in a global var as in the previous example. (One note if you get crazy with frames: If your global registry variable isn't going to clean itself out frequently as the underlying HTML page changes, be extra careful not to let the persistent registry become a memory leak.)

This does trend toward the "one massive lump of code" problem, but it does still provide a decent organization to the lumps of code.

JSON is cool and library support for it for as many languages as can play along is something that will, in general, enable web programmers to do better work faster. But it should generally be used not as a complete data transfer solution, but as a platform upon which to build richer representations without much more work. JSON libraries outside of Javascript should probably be built with this in mind; be sure to provide callbacks for library users to add their own initialization calls to the code. Yes, unless poked appropriately they should output "pure" JSON (like the examples), but all that is needed to greatly increase the value of the libraries is the ability to add simple assignment statements, pre-data code (like my getObject()), and post-data code (like object.init()). (You don't actually need to support my separate direct assignments to the members as I show; that's for historical reasons in my app.)

(Note the title of this post is "JSON Counterpoint"; think of it is the musical sense, not the more common usage of "disagreement".)

 

Site Links

 

RSS
All Posts

 

Blogroll