on protocols: a “Fun JS” follow-up

When I gave my “Functional JavaScript” talk at BurlingtonJS last week, the last portion was focused on protocolsmixins[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]

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 birthDate or 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.

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.

Taking your same data — your Review and Book objects 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 update or isValid or something like that. And maybe something like ValidationProtocol can be exactly the same in both places, but PersistenceProtocol needs to be a little different. Maybe it’s PersistenceProtocol that mixes in the update function, 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.

Hopefully these examples (the code from my talk and the gist for this post) convey how wonderfully simple and yet powerful protocols/mixins are. They may be a bit contrived, but the fact that they’re so “simple” is a feature. And this is what I’ve realized +1 week after I gave the talk in the first place: I kept fretting over how simple (“Too simple?”) they were, thinking “There must me more to it than this!” — but that was exactly the opposite reaction. There wasn’t anything else to it; there shouldn’t be anything else to it. This is what I love about protocols/mixins. Breaking down the operations into petite, elementary functions — really getting it down to the essence and then seeing how that essential version can be applied anywhere it’s relevant. It’s a beautiful bit of craft, and one that serves as a great bridge between the functional and object-oriented worlds that JavaScript sprawls all over.

I used the term “protocols” throughout my talk, not realizing until later that Fogus (in his book Functional JavaScript) had dropped the term (which I’d seen in early drafts) in favor of “mixins”. I think this makes a lot of sense, as the former comes with some baggage, while the latter is a term that more by-trade JavaScript developers are probably familiar with. At any rate, I mentioned in the talk that you could “sort of” use the terms interchangeably w/r/t/ JavaScript. Anyway: for the rest of this blog post, I’ll be sticking with protocols. [↩]

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.) [↩]

With the aside that (“of course”) there really isn’t any such thing as “classical inheritance” in JavaScript but the prototypal inheritance in JavaScript is close enough that we can get away with calling it that if it makes you more comfortable. [↩]

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… [↩]

Buy my book!

Beginning with the basics of PhantomJS, this book will dive into its core modules and guide you through how to solve real-world testing problems. This book explores a variety of test automation tasks, including executing JavaScript unit tests with the Jasmine, QUnit, and Mocha frameworks; functional tests with tools such as Selenium, Capybara, and CasperJS; performance analysis with tools such as YSlow; and much more.