Saturday, August 22, 2015

Polymer web components and Dart

A couple of weeks ago I finished reworking the Polymer and Dart Codelab example SPA produced by the good people at Google demonstrating the use of the 0.5 release of Polymer. After looking it over, I determined it would make a good general template for the creation of CRUD clients for various REST APIs. In other words, it's a great little example of a single-page app (SPA) to perform the standard operations - create, read, update and delete (CRUD) - in the browser.

I forked the Github repository and issued a pull request. I'll try to remember to include a link here when I get around to deploying it on App Engine.

But I dreaded the idea of having to reproduce the entire project for each REST API - or, more accurately, service - for which I want to provide a browser UI. So the task became how to minimize the repetition involved in creating a CRUD client for an API service. Note that the concept of web services isn't exactly required at this point in our discussion. The data could also come from a local file or AJAX request.

Subclassing Polymer custom components

At the 0.5 milestone, Polymer supports the subclassing of custom components. What this means, exactly, is somewhat unclear, as evidenced by the dropping of its support in the 1.0 release. But I was intrigued with the possibility of abstracting out the CRUD boilerplate and getting some nifty custom web component polymorphism action. I was somewhat successful.

First came the task of determining what the base class(es) would contain. All conceivable, at least to me, interactions with a collection of objects consist of our basic CRUD operations. Therefore, a base class called ItemElement was created. ItemElement would consist of the following:

  1. An instance of the model class Item, item
  2. Stubs, at least, for the CRUD methods read() and update()
Since the other CRUD methods, create() and delete(), are natural as members of a collection class, the ItemList class was created for them. ItemList contains, at a minimum, the following members:

  1. A list of Item instances, items
  2. Stubs, at least, for the CRUD methods create() and delete()
At this point, much of the implementation of Codelab, CodelabElement and CodelabList could be moved into the Item, ItemElement and ItemList classes, respectively. And so it was, leaving only calls to the base class implementations in the Codelab classes.

Next steps

With the success of this basic refactoring, I have stepped back to consider what to do next. Some targets are obvious, such as the difficulty in controlling the placement of HTML elements in the Codelab components. When a base class contains HTML elements, interspersing HTML elements into them from within subclass components is tricky and largely undocumented outside of a brief discussion of the <content> and <shadow> elements on the Polymer website. One is left with the idea that a great deal of flexibility can be leveraged from these. But how?

The next candidate for refactoring consists of removing the form classes ItemForm and CodelabForm contained in the files item_form.[dart/html] and codelab_form.[dart/html] It looks to me that these four files can be easily eliminated from the project by factoring their contents into the ItemElement class. Since the custom Polymer component <item-element> contains logic to control the display of an item based on whether it is being edited, the <item-form> component appears to be at best a convenient abstraction and at worst a design flaw.

Finally, adding the calls to a Codelab web service is on this list of enhancements. This presents particularly attractive possibilities for refactoring. Initial experiments indicate that large portions of the REST API interaction can live in the base classes ItemElement and ItemList. This should be most enjoyable and I expect to report back how Dart made doing this a pleasure.

No comments:

Post a Comment