Send to Kindle

Tuesday, July 29, 2014

Minimum Viable Reactor Pattern (in a Reactor Pattern)


After last night, I believe that I finally have good handle on what the Reactor Pattern is. I also have a decent implementation to illustrate the pattern in Dart (at 039b2b0b3b in the git repo). But it is a bit obtuse.

I patterned the code after the original implementation from the paper that introduced the Reactor Pattern. As the paper noted, the pattern does not apply directly to a single threaded environment like Dart. It does not help that Dart itself is based on the Reactor Pattern. Even so, I think that I have Dart code that mimics the spirit, if not the exact implementation, of the implementation from the paper. But how much, exactly, of that spirit is really necessary?

After some thought, I think I can get rid of two things: a “re-imagining” of select() and the use of Dart isolates. Neither removal is a slam dunk—both serve multiple purposes in the sample code. But both also introduce additional concepts into an already concept-laden design pattern. If I have learned anything in my writings, it is that pretty much everything can (and should) be sacrificed at the alter of minimizing the number of concepts. So let's slaughter a couple of sacrificial concepts and see if I am rewarded...

First up is removing the Dart isolate code, which can been see on the very first line of the main entry point:
main() {
  // Spawn the message sending isolate and set its receive port as the source of
  // the fake select() messages
  Isolate.spawn(messageSender, connection());

  // Create (and register in constructor) event handler
  new LoggingAcceptor();

  // Reactor “loop” (handleEvent is recursive)
  new InitiationDispatcher().handleEvents();

  // NOTREACHED
  return 0;
}
Part of the benefit of using an isolate here is that communication takes place over “ports” which sound very much like the networking ports from the original C++ example. The comparison is not exactly one-to-one, however, and the send vs. receive ports can be confusing:
void messageSender(SendPort server) {
  var logClient = new ReceivePort();
  server.send({'type': 'log_connect', 'value': logClient.sendPort});
  logClient.
    first.
    then((SendPort s1) {
      // Send messages to the connected “application“ port
    });
}
The isolate was introduced to solve a problem that it did not actually solve. I kept it for the “ports,” but perhaps streams would suffice? It is impossible to escape streams in Dart, so using them here would hardly count as a new concept.

The problem is that, in order to mimic the network nature of the Reactor Pattern sample, I need different connections for different services. I had not realized it, but the isolates fit this fairly well. I can convert to streams, but the change does not seem to improve the readability of the example that much:
void messageSender(StreamController server) {
  var logClient = new StreamController();
  server.add({'type': 'log_connect', 'value': logClient});
  logClient.
    stream.
    first.
    then((StreamController s1) {
      s1.add({'type': 'log', 'value': 'howdy'});
      s1.add({'type': 'log', 'value': 'chris'});
      server.add({'type': 'log'});
      // ...
    });
}
Even with isolates, the send and receive ports are ultimately streams themselves, so maybe this pure stream approach is the best option. Still, actually using the companion nature of send and receive ports lends itself to networking discussion. I will have to think about this.

OK, so with the isolates removed, next up is the select() re-imagining. This is a tough thing to remove because it as the heart of the Reactor Pattern. The real select() call is responsible for demultiplexing systems calls likes TCP/IP server connections, network messages, and system I/O. Ultimately these system messages go into a queue that can be processed via select() calls inside of the reactor loop. In both the article and my sample code, this takes the form of the handleEvents() method of the dispatcher:
class InitiationDispatcher implements Dispatcher {
  // ...
  handleEvents() {
    var event = select().fetch();
    if (event == null) { /* Jump to next loop to select again... */ }
    events[event.type].forEach((h)=> h.handleEvent(event));
  }
}
My select() is not even a real function—it just returns an object whose fetch() method behaves like the real select(). I ought to remove it just for that bit of confusion, but… this fake select() does have the advantage of being a very explicit Queue of events:
class Select {
  StreamController<Map> connection;

  static final Select _select = new Select._internal();
  factory Select()=> _select;
  Select._internal() {
    connection = new StreamController();

    connection.
      stream.
      listen((m) {
        add(new MessageEvent(m['type'], m['value']));
      });
  }

  Queue<MessageEvent> queue = new Queue();

  void add(MessageEvent e) { queue.addLast(e); }
  MessageEvent fetch() {
    if (queue.isEmpty) return null;
    return queue.removeFirst();
  }
}
That said, streams themselves are decent demultiplexers. So perhaps I can get rid of all of the Select queuing stuff and replace it with a simple stream?
StreamController _connect;
connect() {
  if (_connect == null) {
    _connect = new StreamController.broadcast();
  }
  return _connect;
}
The main() entry point and the message sending code does not have to change, but, unfortunately, the actual handleEvents() method that is called in the heart of the reactor is not longer a loop or a recursive function. Instead, it just becomes a stream listener:
class InitiationDispatcher implements Dispatcher {
  // ...
  handleEvents([int timeout=10]) {
    connect().
      stream.
      listen((event){
        print('[handleEvents] ${event}');
        events[event['type']].forEach((h)=> h.handleEvent(event));
      });
  }
}
At this point, the sample code is no longer demonstrating the Reactor Pattern. Instead it is a roundabout way to illustrate that Dart is using the Reactor Pattern under the covers. Even worse, I cannot send the messages ahead of time since they will no longer queue. Instead I have to further deviate from the example in the original paper and move the message sending after the dispatcher is created:
main() {
  new LoggingAcceptor();
  new InitiationDispatcher().handleEvents();
  messageSender(connect());
}
That is not a show stopper, but the lack of an actual loop (or recursive function) probably is.

So in the end, last night's isolate and fake select() code was probably fairly close to what I need. There is still some code that I might clean up in there, but maybe not as many concepts as I had thought.


Day #137

Monday, July 28, 2014

Deep, Isolated Reactors in Dart


I think that I have decent sample code the Reactor Pattern in Dart. Furthermore, I think I have a decent explanation for why I cannot get closer to the C++ implementation in the original paper. I think, I think, I think… What I know is that I usually get into trouble when I think.

To have a better idea that I have replicated the spirit, if not the exact details, of the pattern described in the original paper, I would like to establish two communication channels between my isolate message sending code and the reactor loop from yesterday:
main() {
  // Spawn the message sending isolate and set its receive port as the source of
  // the fake select() messages
  var res = new ReceivePort();
  Select.source = res;
  Isolate.spawn(messageSender, res.sendPort);

  // Create (and register in constructor) event handler
  new WordAcceptor();

  // Reactor “loop” (handleEvent is recursive)
  new InitiationDispatcher().handleEvents();
}
Aside from the shenanigans with the select(), this looks very much like the main loop presented in the paper. The “word acceptor” waits for the reactor to inform it of new word sending connections, at which point it creates an instance of a “word handler” which simply prints words to STDOUT.

The problem with my current implementation is that I have the acceptor doing everything. Instead, it should follow the paper more closely—at least if I hope to better appreciate the implications. So I start with a much simpler WordAcceptor class:
class WordAcceptor implements EventHandler {
  WordAcceptor() {
    new InitiationDispatcher().registerHandler(this, 'word_connect');
  }

  void handleEvent(connection) {
    if (connection.type != 'word_connect') return;
    new WordPrinter(connection.value);
  }
}
As in the source paper, this registers itself with a singleton instance of the initiation dispatcher. It is looking to accept incoming connections (connections in this setup come from a separate isolate of code) with a type of word_connect. That is, it is accepting “word” client connections.

The initiation dispatcher invokes the acceptor's handleEvent() method whenever such an event occurs. I will supply a value of a “receive port.” The port in this case is a connection back into the calling isolate—a way to communicate back with the isolate. That value is supplied to the WordPrinter which, until now, has not been pulling its weight.

The WordPrinter will mimic the functionality of the Logging_Handler from the paper. I will not have the low-level C interfaces into network devices, but it can use the isolate ports as a substitute:
class WordPrinter implements EventHandler {
  SendPort sendPort;
  ReceivePort receivePort;

  StreamSubscription handle;

  final timeout = const Duration(milliseconds: 2);

  WordPrinter(this.sendPort) {
    new InitiationDispatcher()
      ..registerHandler(this, 'word')
      ..registerHandler(this, 'word_close');
    // ...
  }
  // ...
}
Like the WordAcceptor, the WordPrinter needs to register itself with the reactor's dispatcher. In this case, it will handle word connections (to signal when words are available to be read) and word_close connections (to signal that there are no more words).

The sendPort is the mechanism by which this printer can communicate back to the isolate sending words to be printed. The WordPrinter only needs to send a means for the isolate to send words directly back to the WordPrinter. This is very much in the spirit of the Logging_Handler establishing a server connection for clients once the Logging_Acceptor receives a connection request. The WordPrinter establishes a local port via which a client (the message sending isolate) can send data.

To accomplish this, the WordPrinter needs its own receive port. So I add that in the constructor:
class WordPrinter implements EventHandler {
  // ...
  WordPrinter(this.sendPort) {
    new InitiationDispatcher()
      ..registerHandler(this, 'word')
      ..registerHandler(this, 'word_close');

    receivePort = new ReceivePort();
    sendPort.send(receivePort.sendPort);

    handle = receivePort.
      asBroadcastStream().
      timeout(timeout, onTimeout: (_){ handle.pause(); }).
      listen(write)
      ..pause();
  }
  // ...
}
The timeout and the pause are how I hope to better mimic the Reactor Pattern's usage of select() in C++. When data is ready to be read in the C++ version, the Reactor signals the concrete event handler to read as much data is available for non-blocking read. It then yields control back to the reactor so that it can wait for more data—either from the same connection or from somewhere else. This is the very heart of the pattern, so it seems useful to try to simulate it here.

So I pause the listener on the stream as soon as it is established so that control can go back to the reactor loop, which will wait until it sees a word event. When it does, this dispatcher invokes handleEvent(), which resumes the subscription handle, which reads all data available on the stream, sending it to write()::
class WordPrinter implements EventHandler {
  // ...
  void handleEvent(event) {
    if (event.type == 'word') {
      read();
    }
    // ...
  }

  void read() {
    handle.resume();
  }

  void write(word) {
    print('[WordPrinter.read] $word');
  }
}
With that, I think I have a decent replication of the spirit of the Logging_Handler class from the paper, but now in Dart.

To call this code, I use the isolate's sendPort to send the word_connect message. The WordAcceptor then creates a WordPrinter which replies back with a send port of its own:
main() {
  // Spawn the message sending isolate and set its receive port as the source of
  // the fake select() messages
  var res = new ReceivePort();
  Select.source = res;
  Isolate.spawn(messageSender, res.sendPort);

  // Create (and register in constructor) event handler
  new WordAcceptor();

  // Reactor “loop” (handleEvent is recursive)
  new InitiationDispatcher().handleEvents();

  // NOTREACHED
  return 0;
}

void messageSender(SendPort port) {
  var wordSender = new ReceivePort();
  port.send({'type': 'word_connect', 'value': wordSender.sendPort});
  wordSender.
    first.
    then((SendPort s1) {
      s1.send({'type': 'word', 'value': 'howdy'});
      s1.send({'type': 'word', 'value': 'chris'});
      port.send({'type': 'word'});
    });
}
Once the WorkPrinter's send port comes back, I can send as many words as I like. To actually tell the reactor that non-blocking data is ready, I send a connection of type word.

And that actually works. The reactor sees the messages, triggers the handle_event() methods in its registered event handlers, which eventually results in the right connections and ultimately words being printed. It even works if I delay sending some of the words (and then send a follow-up word connection):
$ ./bin/reactor.dart
[handleEvents] word_connect
[handleEvents] word
[WordPrinter.read] {type: word, value: howdy}
[WordPrinter.read] {type: word, value: chris}
[handleEvents] word
[WordPrinter.read] {type: word, value: delayed}
[WordPrinter.read] {type: word, value: howdy}
[WordPrinter.read] {type: word, value: chris}
[handleEvents] word_close
To be sure, this is a loooong way to go to print out words, but it does a decent job of capturing the intent of the Reactor Pattern in Dart. Of course, Dart itself is a Reactor Pattern, so absolutely none of this is needed. But it was still fun to implement.



Day #136

Sunday, July 27, 2014

Isolated Reactors in Dart


I am having a devil of a time implementing the Reactor Pattern in Dart.

Truth be told, I do not have to implement it in Dart since Dart is itself built on the Reactor Pattern. Even so, I would like to try my level best to get a reasonable facsimile of it going. The effort itself so far has been illuminating. I had not previously really understood it—that is I could not teach it to someone else. But I would like to get it running for a more pragmatic reason: it would provide insight on how (and if) to include concurrency patterns in the forthcoming Design Patterns in Dart. And, for better or worse, I opted for the Reactor Pattern as my test case.

The problem is not the implementation of the reactor loop:
main() {
  _startRandomMessageSender();

  // Create (and register in constructor) event handler
  new WordAcceptor();

  // Reactor loop...
  for(;;) {
    new InitiationDispatcher().handleEvents();
  }
}
The problem is not even event handlers like the WordAcceptor above, which follows along with the original Reactor Pattern paper by creating new object that then listen for the actual words being sent into the reactor loop.

The problem is getting the messages into the reactor loop. Messages sent before the loop are properly queued and properly processed by the loop. But, once the loop is running, nothing else in the Dart program will run. The loop is so tight that asynchronous code is never given a chance to be executed by Dart's own reactor loop. This, it would seem, is one of the hazards of attempting to build a Reactor Pattern on top of another Reactor Pattern.

But I think the problem might be better phrased as that of a single threaded execution environment, which Dart is. Or, more precisely, Dart's isolates are single threaded. But nothing is preventing me from spawning a second isolate. So that is just what I do. Spawn the message sending function in its own isolate so that it can send messages regardless of what the main isolate is doing:
// ...
import 'dart:isolate';
main() {
  var res = new ReceivePort();
  select().from = res;
  Isolate.
    spawn(messageSender, res.sendPort).
    then((_){
      // Create (and register in constructor) event handler
      new WordAcceptor();

      // Reactor loop...
      for(;;) {
        new InitiationDispatcher().handleEvents();
      }
    });
}
And… this has no effect whatsoever.

Well, it has some effect. The message sending code is now reached and can even be delayed. But the problem remains back in the main code isolate. The reactor loop is so tight that it prevents any other activity from reaching the top of Dart's internal reactor loop.

Oh, and in case anyone thinks like me, no, scheduleMicrotask() is not the answer. Unless the question was, ”how do I exhaust VM memory really, really fast?” Again, the main thread of execution never stops evaluating the for loop long enough to ask what the next microtask or regular event task might be.

So, I think I have to abandon trying to implement this exactly as done in the paper. The for loop prevents any events from outside the loop from being executed, which means that any asynchronous code (like the Future-based isolates) will never been seen.

So I convert the handleEvents() call that used to be inside the loop to a recursive function call. I call handleEvents() once:
main() {
  var res = new ReceivePort();
  Isolate.
    spawn(messageSender, res.sendPort).
    then((_){
      // Create (and register in constructor) event handler
      new WordAcceptor();

      // Reactor “loop”...
      new InitiationDispatcher().handleEvents();
    });
}
Then change handleEvents() to a recursive call (adding a Timer delay for good measure):
class InitiationDispatcher {
  // ...
  handleEvents([int timeout=0]) {
    var event = select().fetch();
    if (event == null) {
      Timer.run((){this.handleEvents();});
      return;
    }
    events[event.type].forEach((h)=> h.handleEvent(event));
  }
}
And that does the trick. I can now send any messages in from the message sending isolate that I like. I probably do not even need the isolate any more.

I think this still honors the spirit of the Reactor Pattern, but I am not 100% positive. I am also not entirely sure what all of this would buy me. The code is hard to follow as-is—hardly sufficiently illustrative to belong in a book. But it feel as though it add a lot of ceremony on top of something that Dart just gives us out of the box. Perhaps that is the point. If nothing else, this has given me additional information on which to ruminate.


Day #135

Saturday, July 26, 2014

(Not Quite) Simulating Select for a Dart Reactor


I still hope to build an illustrative implementation of the Reactor Pattern in Dart. The ultimate goal is to begin to understand the right abstraction level which Design Patterns in Dart should approach concurrency patterns (or if it even should include them). Many concurrency patterns come baked into Dart (as does the Reactor Pattern), so it is very much an open question if I ought to cover them. Still, it is worth exploring…

After last night, I have the dispatcher and event handler interfaces fairly well defined as:
abstract class Dispatcher {
  void handleEvents([int timeout=0]);
  void registerHandler(EventHandler);
  void removeHandler(EventHandler);
}

abstract class EventHandler {
  void handleEvent(type);
  get handle;
}
The Dispatcher class serves as the interface for the InitiationDispatcher in the original paper. Similarly, EventHandler has the same structure as the interface in the paper.

From there, things got a little more difficult for me—party because Dart is single threaded and already built on the Reactor Pattern but mostly because I still lack a deep understanding of the pattern. In the end, I was able to somewhat demonstrate the pattern with a STDIN KeyHandler:
main() {
  // Create (and register in constructor) event handler
  new HandleKey();

  // Reactor loop...
  for(;;) {
    new InitiationDispatcher().handleEvents();
  }
}
STDIN is a poor way to demonstrate a demultiplexing pattern since only one thing can be sent to it at a time. Also, the simple implementations of STDIN block in Dart, which rather defeats the purpose of the tight event loop. So let's see if I can come up with a more illustrative example.

I start by defining select() as a Queue on which I can push “system events”:
class Select {
  static final Select _select = new Select._internal();
  factory Select()=> _select;
  Select._internal();

  Queue queue = new Queue();

  void add(String type) { queue.addLast(type); }
  SystemEvent fetch() {
    if (queue.isEmpty) return null;
    return queue.removeFirst();
  }
}

select()=> new Select();
The Select class is a singleton, so whenever new stuff is pushed on there, it is pushed onto the same queue. Hopefully this will mimic the system() call built into Linux sufficiently for my purposes.

The handles that are read from (and written to) after an OS select have an ID. I again try to mimic that:
class Handle {
  static int nextNumber = 1;
  static Map<int,Handle> lookup = {};

  int number;
  String type;
  var stream;
  Handle(this.type, this.stream){
    number = Handle.nextNumber++;
    Handle.lookup[number] = this;
  }
}
Instead of storing the ID in the operating system, I am storing it in the class itself for later lookup.

The other side of the equation is building an “acceptor” and “processor” pair. This is not strictly necessary for demonstrating the Reactor Pattern, but it follows the original paper closely and—hopefully—will help me better understand things.

First up the acceptor, which accepts “word” connections:
class WordAcceptor implements EventHandler {
  WordAcceptor() {
    new InitiationDispatcher().registerHandler(this, 'word');
  }

  void handleEvent(event) {
    if (event.type != 'word') return;
    new WordPrinter(event.handleId);
  }
  get handle;
}
As with other reactor event handlers, it registers itself with the dispatcher and then handles events by creating a processor instance—in this case a simple word printer that will print the message to STDOUT. Yes, I am going a long way simply to print things out...

The process reads from simple streams:
class WordPrinter  {
  int handleId;
  Handle handle;

  WordPrinter(this.handleId) {
    handle = Handle.lookup[handleId];
    read();
  }

  void read() {
    handle.stream.listen((word){
      print('[WordPrinter.read] $word');
    });
  }
}
Hopefully streams will serve as a nice stand-in for reading from low-level sockets.

Finally, I change the reactor loop to listen for “word” connections and start up a message sender:
main() {
  _startRandomMessageSender();

  // Create (and register in constructor) event handler
  new WordAcceptor();

  // Reactor loop...
  for(;;) {
    new InitiationDispatcher().handleEvents();
  }
}
But here, I am stumped. The reactor loop is too tight for my fake file system streams to be processed. I am effectively blocking in the reactor loop. I can get the message acceptor to fire because it adds to the System queue that is inside the reactor loop. But streams are outside of it.

I could probably replace the streams with something that also gets placed onto the system queue (or something similar). But I am still stumped about how to simulate random data coming in over time. If I try a Timer.run() in the _startRandomMessageSender():
void _startRandomMessageSender() {
  // ...
  new Timer(
    new Duration(seconds: 1),
    () { print('yo'); )
  );
}
Then the print statement is never reached. Again, the reactor loop is too tight. And if I cannot print something 1 second later, how can I send messages to processors?

Bleh. This may be the hazards of attempting to simulate the Reactor Pattern on a platform that itself implements the Reactor Pattern. But, I think it may be more a matter of rethinking how I want to simulate the low-level handles. I will ruminate on this some more and approach it fresh tomorrow.



Day #134

Friday, July 25, 2014

The Reactor Pattern in Dart


I purposefully did not include the phrase “object oriented” in the title of Design Patterns in Dart. The reason, of course, was that I hope to explore others software design patterns in the book. Some of the patterns that most interest me have to do with concurrency—not because that is where the action is in Dart, but because I am so weak with them.

Let me start by stating that I do not really understand the difference between the actor model, the reactor pattern, regular old events, or the observer pattern. It is not that I have no idea, but rather that I know that I lack the understanding to be able to teach them or their differences. This is why I hope to include them in the book.

Part of the challenge before me is that Dart is built on many of these patterns. Normal operations under Dart occur in an event loop that (I believe) is the reactor pattern. Isolates are built on the actor model. Streams support publish and subscribe. And so forth. So how do I discuss these patterns when they are the building blocks of the language? I really have no good answer to that question, but I have an idea how I can start thinking about them.

So tonight, I implement the Reactor Pattern as described by Douglas C. Schmidt in his Reactor paper. Since the reactor pattern is running underneath in Dart itself, this may be a little weird, but I'm going to try it anyhow.

I start with the main dispatcher as:
class InitiationDispatcher {
  var events = {};

  static final InitiationDispatcher _dispatcher =
    new InitiationDispatcher._internal();

  factory InitiationDispatcher() {
    return _dispatcher;
  }

  InitiationDispatcher._internal();

  registerHandler(eventHandler, eventType) {
    events.putIfAbsent(eventType, ()=> []);
    events[eventType].add(eventHandler);
  }

  removeHandler(eventHandler, eventType) {}

  handleEvents([int timeout=0]) {
    // ...?
  }
}
Most of that is just setting up a singleton per the article. I will worry about removeHandler() another day. I am not quite sure how to handle events just yet, so I leave that open for a bit. I do know how to register a new handler—for a given type of event and corresponding handler object, I add the object to the list of handlers for that type. Adding objects instead of functions is different than the normal event listeners to which I am accustomed, but I roll with it here.

Then the handle event class is a simple keyboard reader:
import 'dart:io';
import 'InitiationDispatcher.dart';

class HandleKey {
  HandleKey(){
    new InitiationDispatcher().registerHandler(this, 'key');
  }

  handleEvent(eventType) {
    if (eventType == 'key') {
      print('[handled] $handle');
    }
  }

  get handle {
    return stdin.readLineSync();
  }
}
As in the paper, I exploit the singleton nature of InitiationDispatcher to get the one instance and register this new keyboard handler when it is constructed. I am still struggling with the Dart equivalent for a “handle” from the paper. Here, I start with reading from STDIN. If nothing else, this will give me something with which to experiment.

Finally main:
#!/usr/bin/env dart

import 'package:reactor_code/InitiationDispatcher.dart';
import 'package:reactor_code/HandleKey.dart';

main() {
  new HandleKey();

  for(;;) {
    new InitiationDispatcher().handleEvents();
  }
}
I create an instance of the HandleKey class (which registers itself with the reactor dispatcher). Then I enter into the infinite loop that tries to handleEvents().

And I remain stumped here on how to handle events in the reactor loop without stealing data from the actual handler—how can I see that there is stuff to be read from STDIN, but not actually read it? Not knowing what else to try, I define handleEvents() as:
class InitiationDispatcher {
  // ...
  handleEvents([int timeout=0]) {
    var line = stdin.readLineSync();
    print('[handleEvents] $line');
    events['key'].forEach((h)=> h.handleEvent('key'));
  }
}
The important part is that handleEvents() tells the appropriate handlers to do their things (the last line of the method). But actually waiting for an event blocks until a line is ready from STDIN—defeating the entire purpose of the Reactor Pattern. Still, for tracer bullet purposes, it works. If I type 1, 2, 3, 4, and so on, I get:
$ ./bin/reactor.dart
[handleEvents] 1
[handleEvent] 2
[handleEvents] 3
[handleEvent] 4
[handleEvents] 5
[handleEvent] 6
The first event triggers the dispatcher. The second triggers the actual handlers.

So I sort of have a Reactor Pattern in Dart. But it would be nicer to have one that did not block and that better mimics handles and select() from the paper. I do not necessarily need low-level I/O or networking access to accomplish this, but what I have now is insufficient. I will ruminate on that (or if someone has suggestions?) and pick back up tomorrow.


Day #133

Thursday, July 24, 2014

Logarithmic Scales: For When the Winner is That Big


Up tonight: whatever breaks when I try my all-encompassing, Design Patterns in Dart benchmarking suite on a different pattern. I have been building it out on code for the Visitor Pattern and I think it is finally ready (more or less). So let's see what happens when I pull it back into the code for the Factory Method Pattern.

Note: the code is located at https://github.com/eee-c/design-patterns-in-dart. The current HEAD points to bec37fd41e.

What I found in the Visitor Pattern code was that the benchmark numbers were dependent on the number of times that a particular pattern was run through a loop. This could be specific to patterns that work on node structures like then Visitor Pattern. But for all I know, different approaches like storing a list of Factories in a Map might also be influenced by the number of times through a loop. There is only one way to find out…

I start with a little code re-organization. I think I have settled on storing the preferred solution directly in the lib directory of the particular pattern being explored while alternatives go in lib/alt. After that, I create a separate benchmark script for each approach in the tool directory:
$ tree tool
tool
├── benchmark.sh
├── benchmark.dart
├── benchmark_map_of_factories.dart
├── benchmark_mirrors.dart
└── packages -> ../packages
I also create a mostly-configuration benchmark.sh Bash script file that pulls in common code to run each of those Dart scripts. And it all works pretty brilliantly. Except for the 2 errors per script that cause each benchmark to crash:
Unhandled exception:
FileSystemException: Cannot open file, path = '/home/chris/repos/design-patterns-in-dart/factory_method/tool/packages/args/args.dart' (OS Error: No s)
#0      _rootHandleUncaughtError.<anonymous closure>. (dart:async/zone.dart:713)
...
The solution is fairly simple, though it does expose yet another gap in my thinking—this time regarding Dart Pub packages. Before moving the benchmarking code into a common package location, it was a development dependency for the Visitor Pattern code:
name: visitor_code
dev_dependencies:
  args: any
  benchmark_harness: any
That is no longer needed directly by the pattern code—the common benchmarking code parses command-line arguments now. Only it is clearly not being pulled into this factory method “application.” The factory method application depends on the common dpid_benchmarking package:
name: factory_method_code
dependencies:
  browser: any
dev_dependencies:
  dpid_benchmarking:
    path: ../packages/benchmarking
And dpid_benchmarking does depend on args:
name: dpid_benchmarking
dev_dependencies:
  args: any
  benchmark_harness: any
So why doesn't args get pulled into the application as well?

The answer is simple, really. It is a development dependency of dpid_benchmarking. In other words, it will get installed when used by other applications or packages (like my factory method code). As a development dependency, it is only installed when working directly with the package—when developing it in isolation.

This is not completely obvious. I had not given this much thought, but I realize now that I expected this package's development dependencies to be installed by my application's development dependencies. Somewhere in the back of my mind I was expecting the development dependency on dpid_benchmarking to pull in dpid_benchmarking's development dependencies as well.

Now that I have exposed this flawed thinking, I acknowledge that it was erroneous. Development dependencies are for single package development only. Hopefully I will remember that.

That issue aside, everything else just works. I get nice graphs that seem to prove that the number of times that a Factory Method implementation is used has no impact on its performance:



It may be a little hard to see, but there is a number associated with the “classic” subclass implementation of the Factory Method pattern—it is just really small compared to the other two approaches. For this, I tell gnuplot to plot the y axis logarithmically:
set style data histogram
set style histogram clustered
set style fill solid border
set xtics rotate out
set key tmargin
set xlabel "Loop Size"
set ylabel "┬Ás per run"

set logscale y

plot for [COL=2:4] filename using COL:xticlabels(1) title columnheader
That gives me:



Any way that you look at it, the class subclass approach is the clear performance winner. There may be some maintainability wins for the other approaches, but they would have to be significant to warrant using them over the subclass approach. Even when compiled to JavaScript:



I think that will close out my initial research into object oriented design patterns for the book. I may investigate some concurrency patterns tomorrow. Or it may be time to switch back to Patterns in Polymer.


Day #132

Wednesday, July 23, 2014

Varying Only the Import in Dart


Tonight, I explore a new kind of Dart refactoring: varying the import statement.

This occurs in the benchmarking code for the Visitor Pattern as part of my research for the future Design Patterns in Dart. I have three different approaches that I would to compare. After refactoring and refactoring and refactoring, I am finally down to very slim scripts that only vary by the implementation code being imported (and the name of the benchmark):
$ diff -u tool/benchmark.dart tool/benchmark_single_dispatch_iteration.dart
--- tool/benchmark.dart 2014-07-23 23:11:55.933361972 -0400
+++ tool/benchmark_single_dispatch_iteration.dart       2014-07-23 23:12:45.545363182 -0400
@@ -2,12 +2,12 @@
 
 import 'package:dpid_benchmarking/pattern_benchmark.dart';
 
-import 'package:visitor_code/visitor.dart';
+import 'package:visitor_code/alt/single_dispatch_iteration/visitor.dart';
 
 main(List<String> args) {
   BenchmarkRunner.main(
     args,
-    "Classic Visitor Pattern",
+    "Nodes iterate w/ single dispatch",
     _setup,
     _run
   );
The BenchmarkRunner.main() method signature is a little ugly, but aside from the minor quibble I feel pretty good about this. Except…

There are two dozen lines of code that follow this that are exactly identical in each of the three benchmark scripts. The setup and the actual code that is executed is 100% duplicate between the three files. It looks something like:
var visitor, nodes;

_setup() {
  visitor = new PricingVisitor();

  nodes = new InventoryCollection([mobile(), tablet(), laptop()]);
  // Add more sub-nodes to complexify the structure...
}

_run(loopSize) {
  // nodes used
  // visitor used
  // (nodes accept visitor a bunch of times)
}
I am creating a closure over visitor and nodes so that they can be shared between the setup and benchmark runner when executed by BenchmarkRunner.

What is important to me in this case is that the PricingVisitor and InventoryCollection classes have the same name, but are defined differently by the three different imported packages in the three different scripts that I have.

This is almost certainly unique to benchmarking considerations, but still, how can I move this duplicated code out into a single file that can be shared? Dart parts will not work because the file containing the common setup and run code would have to be the main file and only one of the three implementations could be part of it. Conditional imports do not work in Dart.

Unfortunately, I am more or less stumped on a good way to do this. Dart is not meant to used like this (I'm not sure any language is). That said, I can come up with something that works. I have to use the Factory Method pattern to create the visitor and the node structure (I also have to pull in makers for the nodes within the structure). In the end, the overhead does not seem to save much in the way of lines of code:
import '_setup.dart' as Setup;

main(List<String> args) {
  Setup.visitorMaker = ()=> new PricingVisitor();
  Setup.inventoryCollectionMaker = (items) => new InventoryCollection(items);
  Setup.mobile = mobile;
  Setup.tablet = tablet;
  Setup.laptop = laptop;
  Setup.app = app;

  BenchmarkRunner.main(
    args,
    "Classic Visitor Pattern",
    Setup.setup,
    Setup.run
  );
}
What I do gain is the ability to keep the test setup and running logic in one place: _setup.dart. And in there, I simply define top-level variables to support the Setup.XXX setters:
library visitor_setup;

var visitorMaker;
var inventoryCollectionMaker;
var mobile;
var tablet;
var laptop;
var app;

var visitor, nodes;

setup() {
  visitor = visitorMaker();
  // ...
}
// ...
I am not satisfied with that, but it does have the advantage of keeping the common logic in one place. At the risk of rationalizing this too much, I note that the 6 Setup assignments are only needed because I am using 4 node types to intentionally create complexity in the data structure being tested.

I will leave this as “good enough” for the time being. Using this on other design patterns will ultimately decide if this approach is usable. So I will pick back up with that tomorrow.



Day #131