It’s probably me, but I’m having a hard time dealing with data as arrays and hashes…
Here’s what you get in just about every programming language nowadays:
- variables (which is simply keyed access by name)
- simple scalars, such as ints, floats, and strings
- indexed aggregation, i.e. arrays:
blah[index]
- tagged aggregation, i.e. structs:
blah.property
- arbitrarily nested combinations of the above
JavaScript structs are called objects and tag access can be blah.tag
or blah['tag']
.
It would seem that these are all one would need, but I find it quite limiting.
Simple example: I have a set of “drivers” (JavaScript modules), implementing all sorts of functionality. Some of these need only be set up once, so the basic module mechanism works just fine: require "blah"
can give me access to the driver as an object.
But others really act like classes (prototypal or otherwise), i.e. there’s a driver to open a serial port and manage incoming and outgoing packets from say a JeeLink running the RF12demo sketch. There can be more than one of these at the same time, which is also indicated by the fact that the driver needs a “serial port” argument to be used.
Each of these serial port interfaces has a certain amount of configuration (the RF12 band/group settings, for example), so it really is a good idea to implement this as objects with some state in them. Each serial port ends up as a derived instance of EventEmitter, with raw packets flowing through it, in both directions: incoming and outgoing.
Then there are packet decoders, to make sense of the bytes coming from room nodes, the OOK relay, and so on. Again, these are modules, but it’s not so clear whether a single decoder object should decode all packets on any attached JeeLink or whether there should be one “decoder object” per serial interface object. Separate objects allow more smarts, because decoders can then keep per-sensor state.
The OOK relay in turn, receives (‘multiplexes”) data from different nodes (and different types of nodes), so this again leads to a bunch of decoders, each for a specific type of OOK transmitter (KAKU, FS20, weather, etc).
As you can see, there’s sort of a tree involved – taking incoming packet data and dissecting / passing it on to more specific decoders. In itself, this is no problem at all – it can all be represented as nested driver objects.
As final step, the different decoders can all publish their readings to a common EventEmitter, which will act as a simple bus. Same as an MQTT broker with channels, with the same “nested key” strings to identify each reading.
So far so good. But that’s such a tiny piece of the puzzle, really.
Complexity sets in once you start to think about setup and teardown of this whole setup at run time (i.e. configuration in the browser).
Each driver object may need some configuration settings (the serial port name for the RF12demo driver was one example). To create a user interface and expose it all in the browser, I need some way of treating drivers as a generic collection, independent of their nesting during the decoding process.
Let’s call the driver modules “interfaces” for now, i.e. in essence the classes from which driver instances can be created. Then the “drivers” become instantiations of these classes, i.e. the objects which actually do the work of connecting, reading, writing, decoding, etc.
One essential difference is that the list of interfaces is flat, whereas a configured system with lots of drivers running is often a tree, to cope with the gradual decoding task described a bit above.
How do I find all the active drivers of a specific interface? Walk the driver tree? Yuck.
Given an driver object, how do I find out where it sits in the tree? Store path lists? Yuck.
Again, it may well be me, but I’m used to dealing with data structures in a non-redundant way. The more you link and cross-link stuff (let alone make copies), the more hassles you run into when adding, removing, or altering things. I’m trying to avoid “administrative code” which only keeps some redundant invariants intact – as much as possible, anyway.
Aren’t data structures supposed to be about keeping each fact in exactly one place?
PS. My terminology is still a mess in flux: interfaces, drivers, devices, etc…
Update – I should probably add that my troubles all seem to come from trying to maintain accurate object identities between clients and server.