protocols 1 as a functional programming technique that you can use to imbue your objects with behaviors in an ad hoc (“at runtime”) fashion. I would like to say that I represented the topic fairly well, but couldn’t shake the feeling that I wasn’t doing it justice.2 Afterward (the next day?) I had a conversation with a colleague that helped me to think of some scenarios that would have better conveyed the beauty and the power of mixins. Though I won’t dive into all of those situations, I’ll outline the one that stuck with me.
an aside: summarizing my summary of protocols from my talk
The short-short version of what I had to say re protocols to the BurlingtonJS crowd: use protocols to extend objects and give them behaviors without resorting to classical inheritance.3
I invoked a couple of Fogus quotes to help me prove my point:
Specialized data types should be, well, special.
This is our justification for creating constructors to use as wrappers around our object data. We have
instanceof in our tool kit; why not use it if it’s appropriate?
Sometimes behaviors are just behaviors.
Translation: your methods don’t always need to have special “type” information to do what they need to do. A hypothetical
getAge method (furnished, of course, from some
AgeMathsProtocol) could be on any kind of object, assuming that the object can fulfill the expected contract (e.g., by having a
publicationDate or some such thing). Why confine your date math to some specific inheritance chain by binding
getAge to the prototype on some constructor function?
…well-designed APIs are meant to compose and should abstract the details of intermediate types.
And this I used as the basis for the rest of my protocols discussion. That we could create protocols that have well-defined contracts and that were flexible enough to attach to (just about) any object to create these extremely rich and expressive objects with gloriously composable APIs.
And then I just gave them…
protocols are awesome, really!
I don’t mean to be down on my
ToStringProtocol example. It got some nods in the room, some comments afterward, and I think (generally) speaking did manage to illustrate the major point I was trying to make: that you could certainly start with “naked” objects and apply functions via protocols/mixins without needing those functions to be “there” in there first place (i.e., from the original prototype on the constructor). I used
toString because it was something that everyone in the room would be familiar with, and because I could show how one small function (with just a little supplementary data) could be applied to two different objects right then and there at runtime.4
And/but/so that’s nice… but show me something more powerful?
As I mentioned earlier, it was in a follow-up conversation that some alternatives were suggested that would have helped illuminate this.
My friend Dave suggested the following: (paraphrasing)
Taking your same data — your
Bookobjects from the Goodreads API — let us assume that you have a Node.js app on the back-end and a single-page-app on the front-end running something like Backbone or Angular. In both cases you’re dealing with the same data — converted from that awful Goodreads XML into a more palatable JSON. And maybe you have some shared code between your server and your client that those model objects need to talk to. It’s always a call to
isValidor something like that. And maybe something like
ValidationProtocolcan be exactly the same in both places, but
PersistenceProtocolneeds to be a little different. Maybe it’s
PersistenceProtocolthat mixes in the
updatefunction, which on the front-end is packaging the data and posting to a REST end point but in Node.js-land it needs to talk to Mongo.
Shorter version? Share code, but just enough code; mixin the rest.
I pictured something along the lines of this:
In a way, this flips the crux of my protocols discussion on its head. Instead of passing around one protocol to use on different objects, we have an object in multiple environments with different versions of the protocol getting mixed in accordingly. And once again: there are a couple of different ways of tackling this problem (e.g., little libraries that take the model objects as arguments) but there are plenty of arguments in favor of doing it this way… Maybe you want to have some idiomatic way of dealing with your model objects. Maybe you have other little libraries that assume these methods are available on these model objects. Maybe you just like this particular style.
- As an aside: one of the lessons I learned from my talk that night was to be confident in the way that you talk about the subject matter. Don’t be arrogant, but don’t apologize and mumble into the mic about how you’re sorry that you’re not doing it justice. (Even if you are.) If you need to make self-deprecated jokes, and that’s just part of your established sense of humor, then fine; but don’t mince over how you’re not blowing anyone’s mind. (And/but this is a whole blog post in and of itself. And I’m not writing that one. Not tonight.) [↩]
- And yes: we had the discussion about how it’s ultimately a style thing — a question of “what do you need? what makes sense here?” And how the same thing could have been applied N different other ways… [↩]