defining the interface for rubymonk

Discussing an interview I had yesterday --quite interesting when delivered with Aninda-- with a non-technical friend, we stumbled on the fact that everything in Computer Science is an interface. From the moment you differentiate data from code, which wasn't immediately obvious to even the first computer programmers twiddling individual bits....

Everything you build in software is defined by an interface. These are the boundaries, but they're also where the magic happens.

Here are some interfaces:
(We'll come back to this.)

$ ps aux | grep clojure

At this point, I had to stop to explain how a function works. Does this help? (Hey Blogger or Google or whoever the heck is in charge: why can't that image be an SVG?)

Objects are the next interface to consider. They are a bundle of functions. Actually, they're more complex than that. They are a bunch of closures... actually, dispatching closures. (Okay, I've lost my non-technical friend at this point. Oh well.) There are other ways of looking at them, but we'll take the perspective of the function, which we already agree is quite simple. To the function, the object looks like a set of rules about how one defines interfaces with functions. Objects can be made of functions but it's not quite so the other way around (though the object may consider this point contentious or even academic). The function doesn't care. To him, an object is just a cluster -- however small -- of functions who have been told in advance that part of how they behave must change, because of the way they were set up... this time, at least. And what's worse, just because an object has been set up -- it won't necessarily stay that way! Yikes. Looking at it from the outside, the function pities the object. The function can choose to behave this way but the default position of the function is, "I never change!" The object changes himself (or worse, allows other, unknown objects to change him). It takes some work for the function to behave so sloppily; you need multiple functions -- and functions returning functions, no less (as a type's constructor returns a function whose sole purpose is dispatch based on the type of the first parameter and the name of the second -- usually with these parameters taking special positions, like first_is_an_object.second_is_a_method. I digress.). Such effort forces a conscious choice on the part of the person writing that function. "This risk is worth it!" you say, and an interface of your choice, with complexity of your choice, emerges.

Finally, at the top of this scale are languages. They themselves are composed of functions and objects. In fact, most compilers and interpreters for languages can be thought of as pure functions: I give you the language, you give me the binary, assembly, bytecode, or runtime language (JS, these days). This is the most complex interface. Usually, a human still speaks to this interface. In 2012, this interface is fully-manual. These humans are called programmers. And the best of them will make it their task to automate away their own job. But, as of 2012, programs that write programs are risky and difficult. Automation can be seen on any of these other scales (functions and data) without writing your own macro or yet another compiler or parser. Choose a language which gives you this option when you have no other choice, but be careful to wield such a weapon when you see no other way out. Otherwise, it is a simple interface you want.

Kitty pointed out to me that I haven't called out a very important point: All these interfaces are fundamentally the same. They accept some input and produce some output (even if that output is a side-effect). Objects are built of functions, and they're both built of languages. And the languages are built of objects and functions. What differentiates each one is the mental energy required to contend with the interface's complexity. Stateless interfaces -- such as immutable objects, pure functions, and HTTP -- are always easier to understand because there are fewer balls in the air. The "given" of given-when-then doesn't apply if there's nothing to set up. There's only when and then.

This makes the interface for RubyMonk interesting. There is of course a very cute visual style to (yeah, we love it too), but the real interface is the user's interaction with the mentor -- how we evaluate their progress and the programs they write. How we assert that something they've done is correct -- because the programs they write are data to us. As we teach more complex concepts, this interface itself will become increasingly complex by its very nature. Or, perhaps, we will realize the beautiful intrinsic quality of data that is code and code that is data, leading us to discover an elegant solution to the automation of the Hacker Mentor.