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:

http://www.c42.in/a_url_is_an_interface/
(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 rubymonk.com (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.


zero to emacs in under 5 minutes

You want to write Clojure. You want to write it in Emacs. Here's how.

1. Grab Leiningen.

mkdir -p ~/bin
cd ~/bin
wget https://raw.github.com/technomancy/leiningen/stable/bin/lein
chmod +x lein
echo 'PATH=$PATH:~/bin' >> ~/.profile
lein self-install

This will get you leiningen, Clojure's build tool.


2. Grab Clojure.


cd ~/code
lein new my-first-clojure-project
cd my-first-clojure-project
lein deps
`lein deps` will bring down a local copy of Clojure. Look in ~/code/my-first-clojure-project/lib !


3. Grab swank-clojure.


lein plugin install swank-clojure 1.4.0
This gives you the `clojure-jack-in` command in emacs. It's your samurai sword.


4. Grab a healthy .emacs config.

mv ~/.emacs ~/.emacs.bak
mv ~/.emacs.d ~/.emacs.d.bak
git clone git@github.com:c42/dotfiles.git
ln -s dotfiles/emacs.d ~/.emacs.d


5. Grab an emacs.

Ubuntu: https://launchpad.net/~cassou/+archive/emacs
OS X: http://emacsformacosx.com/emacs-builds/Emacs-pretest-24.0.94-universal-10.6.8.dmg

Running emacs for the first time will automatically install all the packages you need. Now run your first emacs repl!
M-x clojure-jack-in

TADA!

finger brains


Okay, so now I'm back on my own computerand it's a race against myself. Crap. I still seem to be making mistakes. I guess I just can't type all that well when I've had ad couple. Shit.
Well, this is all I can think of so I'm going to stop typing in 3 2 1....
My housemate Nikhil (and not my other housemate Nikhil) and I had a typing race on our two respective keyboards. It lasted only a few seconds. We were racing ourselves to test the keyboards (MacBook Air vs. ThinkPad 410-something-something). We each preferred each other's machines but I would only trade this for an X1 covered in leather. Our conversation led to a cross-comparative question "why should I care about my typing speed?" to which was returned one of my favourite stories:
Duke Huan was in his hall reading a book. The wheelwright P'ien, who was in the yard below chiseling a wheel, laid down his mallet and chisel, stepped up into the hall, and said to Duke Huan, "This book Your Grace is reading--may I venture to ask whose words are in it?"
 "The words of the sages," said the duke.
 "Are the sages still alive?"
"Dead long ago," said the duke.
"In that case, what you are reading there is nothing but the chaff and dregs of the men of old!"
"Since when does a wheelwright have permission to comment on the books I read?" said Duke Huan. "If you have some explanation, well and good. If not, it's your life!"
Wheelwright P'ien said, "I look at it from the point of view of my own work. When I chisel a wheel, if the blows of the mallet are too gentle, the chisel slides and won't take hold. But if they're too hard, it bites in and won't budge. Not too gentle, not too hard--you can get it in your hand and feel it in your mind. You can't put it into words, and yet there's a knack to it somehow. I can't teach it to my son, and he can't learn it from me. So I've gone along for seventy years and at my age I'm still chiseling wheels. When the men of old died, they took with them the things that couldn't be handed down. So what you are reading there must be nothing but the chaff and the dregs of the men of old."
Wait. Maybe I meant to read him the one about the buckle-maker who focuses so intently on his craft of making buckles that he couldn't see anything else. It wouldn't be the first time I've confused them. Anyway, if you can't type in one continuous stream (higher speeds are largely irrelevant but a 100wpm minimum wouldn't hurt), you're losing little tiny brain spasms to figuring out which keys to hit. These little tiny brain spasms could be helping you figure out what `self` is in the median of your code while trying to remember how to write a class method which generates class methods in Ruby. Because that's how brogrammers like you and me get our tickles. These little tiny brain spasms are basically the opposite of sleep. Shoot them down with your giant space laser-equipped pelican-shaped airship! And then just run under Bowser because you don't actually have to kill him. The beautiful Mavis Beacon awaits on the other side.

Programming is for girls!

My buddy Anne recently posted some of her favourite articles on the subject of women in Computer Science. I wrote an article last year which presupposed her question, "Programming is for girls?" My answer? Programming is for everybody!

Granted, not everyone who writes an Excel macro will be so enamored with their creation that they feel the need to master Haskell. The wonderful thing about Computer Science today is that they could. Thanks to the tiny (almost negligible) barrier to entry, the only thing left to tackle is the stigma.


Programming is already social. I prefer pair programming because I'm ADHD and it's the only way I can ever accomplish anything. But I also get to hang out with friends all day as a side benefit. Code is literature, a communication medium. It's fascinating that our little code-robots do something but it's a great deal more important that it speaks to people.

But: Not every software company is an inherently social environment. Yet.

Programming is already creative. In many ways, it's a purely creative endeavour. Outside the speed of light, there aren't many limitations placed on the raw imagination in a world of code.

But: Many software projects are still about doing the same old thing to a different piece of data.

Programming is already sexy and relevant. Startups are sexy by their very nature. Everyone knows what you're talking about if you say you work for Google or Apple. Most people you know already have a phone they've used to install software while they ride the bus.

But: Not everyone gets to work for a startup or Apple.


You can't have it all but you can certainly have most of it. Think your job isn't sexy? Automate the boring parts or quit. It's a seller's market these days. Try out a new technology, if that excites you. Talk to your coworkers. Work with them directly. Find a broader solution to an entire category of problems. Send your resume to that one company you think is really kicking ass.

There is a real spectrum of significance to the machines we build and the companies we build them for. Create some partial orderings to demonstrate this to yourself. Which is more significant? Clean water or banking? Auto insurance or rice? Diabetes research or zinc? Middle school education or vodka? Public transportation or plywood?

Not everyone considers the world in the same way and most of us will change our opinions over the course of our lives... but some parts of our society have obvious gravity. If you're already in software, let that gravity pull you in. If you're considering a career in software, contemplate the fact that a career in software really means a career in any field you want: from water purification to zinc froth flotation.

Girls, software is already sexy. Get on the trolley.

Clojure Macros: How Evil?

Dan asked me at the Chicago Clojure Meetup this week if Clojure macros tend to send developers into the death spiral of metaprogramming Ruby's various hooks did when we first discovered those.

tl;dr: no.

The canonical example of evil Ruby metaprogramming is everyone's favourite this-will-trim-8-lines-of-code hack: strings to method names. Have you ever written something like this?

x.send("#{a}_#{b}")

Sure you have. It's okay. We've all sinned. Are you prevented from doing this sort of thing in Clojure? Nope. No more than you are prevented from doing it in Java. But in Clojure and Java, the apparent innocence of Ruby's `send` method is revealed to be a sham: Reflection feels bad in these languages.

All of Ruby's other metaprogramming hooks have something in common: define_method, const_get, method_missing, every flavour of eval, monkey-patching... and all their friends... happen at runtime.



The behaviour of my first few Clojure macros confused me because I was accustomed to Ruby's runtime powers. Clojure's macros are expanded, go figure, at macro expansion time. As such, they have a few interesting and related properties:

  • macros feel like adding a feature to the language
  • ruby metaprogramming feels like mutating the language
  • macros cannot use runtime data to generate dynamic code
  • ruby metaprogramming requires runtime data to generate dynamic code
  • macros require a new way of thinking about code generation
  • ruby metaprogramming is just a higher-level imperative layer 
Macros also have a very clear usage pattern (see Christophe's wonderful (not= DSL macros) presentation from the first ClojureConj):

data formats > functions > macros

This is to say: Build your functions on top of your data. Build your macros on top of your functions. Macros should always be a convenience rather than a requirement. This one little rule is often enough to remind yourself that "write a macro!" usually isn't the solution you're looking for.

We're probably better off to avoid comparing Ruby's metaprogramming facilities with macros at all. It makes more sense to compare Ruby's hooks to Clojure's reflection and Ruby's eval to Clojure's eval -- neither of which I've seen used in a production Clojure application. Macros actually stand out on their own, since Ruby doesn't have an equivalent feature.

Can you still write a steaming pile of magic in Clojure? Of course. Once you suffocate your desire for elegance, you can reflect and eval and macro your way into a painful and confusing labyrinth of obfuscated code just as you can in any other modern language. But Clojure's libraries and language features usually display enough power on their own that you aren't tempted to shortcut your way into an impenetrable structural abstraction. At least, I haven't seen it yet.

Open Letter to Pascal

My friend Pascal recently asked me what books I would recommend he read to learn the basics of programming. He'd been looking into it for a while but simply couldn't decide where to start, given the multitude of programming books available.

I'd be the last to claim I've swum a majority of the book lagoon, but I have found over the years that the majority of programming books are neither timeless nor all that well-written. Pascal's response seems obvious, in retrospect: if I could start it all over, what would I read?

In Pascal's case, I'd recommend The Structure and Interpretation of Computer Programs. As a Math teacher, he should find the calculus-based examples in the early chapters relatively easy -- if not downright intuitive. SICP is easily the richest and most thoughtful programming book I've ever read. Were it not for all the math it assumed familiar to the reader, I'd recommend it to everyone above and beyond all other texts in the discipline.

For everyone else (myself included), I'd put The Little Schemer at the top of the list, quickly followed by The Seasoned Schemer and The Reasoned Schemer. The books are a joy to read thanks to their peculiar style and between them convey many of the ideas SICP presents as a more traditional academic text.

Why not Learn to Program or Learn Java in 21 Days?

Most introductory programming books and online tutorials (even Why the Lucky Stiff's Poignant Guide to Ruby, in all its humour and beauty) make a grave mistake in their introduction to programming: They misrepresent syntax as the first principle of writing code.

If the first chapter of your introductory literature explains the representation of strings and numbers in [insert-your-language-of-choice-here], you've already started your reader off on the wrong foot. Worse yet, there's a temptation to teach new programmers about variables, mutation of state, and side-effects -- such as printing to the console.

One does not require dozens of books and years of practice to understand the essence of writing software. But in my case, it took as much to unlearn the bad habits taught by my first texts.

FlyMake does not like JRuby

JRuby often works out-of-the-box wherever MRI does. FlyMake is not one of those cases.

Flymake expects a particular format for error messages returned from the interpreter: MRI error messages. Charlie and Friends have decided the MRI error messages can be a bit opaque, and upgraded them to something a little more readable. Sadly, this breaks anything attempting to parse those messages.

Gaz and I decided to try switching things back to MRI so we could get our syntax errors highlighted in emacs. Lo and behold! Everything's happy again. As an added bonus, you don't need to wait for JRuby (and thus, a JVM) to start up every time FlyMake runs.

You can grab our changes with our latest emacs-starter-kit: https://github.com/drwti/emacs-starter-kit

If you're using Phil Hagelberg's emacs-starter-kit, make the appropriate change to starter-kit-ruby.el:

- (list "ruby" (list "-c" local-file))))
+ (list "/usr/bin/ruby" (list "-c" local-file))))

Enjoy!