Monday, May 12, 2014

Rethinking Introductions to Event Streams


While working through the errata in Dart for Hipsters, it has become pretty apparent that chapter 6, which introduces MVC in Dart, is not doing its job effectively.

In my defense, that is the front-line chapter that repeatedly saw the most updates as Dart moved through various event-based approaches to mouse and keyboard interactions before ultimately settling on a stream-based approach. I had thought I did a fair job of pulling the chapter through the various versions of Dart, but reading it through fresh eyes—especially with the errata feedback—it is clear that the narrative is not as effective as it should be.

I still like the overall approach, but I would like to see if I can cut some cruft from the specific implementation. Tonight, I hope to drop at least one import statement from the code in that chapter:
import 'dart:html';
import 'dart:async';
import 'dart:collection';
import 'dart:convert';
main() {
  // ...
}
This is relatively early on in the book, so the fewer the libraries, the fewer the concepts being introduced and the less discussion required to support the main narrative. Unfortunately, I am a bit of luck here. I need dart:html to gain access to DOM manipulation as well as to the HttpRequest class. Likewise, I need dart:convert to parse and stringify JSON data for a REST-like backend. That leaves me with dart:async and dart:collection.

The dart:collection library is an interesting option for chapter removal. It is there is make collections of MVC models easier to implement. That is nice, but it comes at the expense of addition background discussion of iterables. I can argue for retaining this in that MVC, by its nature, has a collection in it, so dart:collection probably will not look (at first) like a new concept to readers. So I table the removal of dart:collection for future investigation.

That leaves dart:async. I think that is mostly in there to support event-based discussion. Unfortunately I think this discussion is causing more trouble than it is worth—especially since the implementation is so similar to that of the stream-based implementation in a later chapter. So let's see what happens if I remove dart:async from the code...

Dang, it. When I do that, I get errors from the view, which is listening for events on the stream so that it knows when to update itself:
class ComicsView {
  // ...
  ComicsView({this.el, this.collection}) {
    if (collection == null) return;
    collection.onLoad.listen((event) => render());
    collection.onAdd.listen((event) => render());
  }
  // ...
}
Hrm... it seems like it might be really hard to implement MVC without some kind of events. In the main() entry point, I create a collection which can then broadcast its changes to the view (and any other interested parties) when things change internally:
main() {
  var my_comics_collection = new ComicsCollection();
  new ComicsView(
    el: document.query('#comics-list'),
    collection: my_comics_collection
  );
  my_comics_collection.fetch();
  // ...
}
Possibly the simplest conceptual approach would be a series of callbacks (I know, I know), but I am unsure how I could implement that in the above. If I define a local callback to be passed to ComicsCollection, how can it update the comics view when it is yet to be defined?

Ah, this is Dart, so lazy evaluation ought to serve nicely:
main() {
  var comics_view, my_comics_collection;

  my_comics_collection = new ComicsCollection(
    onLoad: ()=> comics_view.render()
  );
  comics_view = new ComicsView(
    el: document.query('#comics-list'),
    collection: my_comics_collection
  );
  my_comics_collection.fetch();
  // ...
}
By the time ComicsCollection does load, the comics_view will no longer be null and should respond to the render() method.

That will work, but does it suit the narrative? The only way to find out is to work through the remaining stream-based code and convert it to the equivalent callback-hell version. That is hardly ideal Dart code, but, if this approach suits the MVC chapter, it will certainly make the stream chapter that much more valuable.


Day #61

No comments:

Post a Comment