:: happy programmers


There is a line in a play that goes something like “what do we do, now that we are happy?.” It’s a tragicomic play, two people waiting for someone named Godot to come along. That’s the whole play: them waiting for Godot, who never shows up. He never comes, but the two men wait, nonetheless. A play about nothing, and because it has two acts, it’s a play in which “nothing” happens twice. Absurd, and yet, there is that line that sticks to you head: “what do we do, now that we are happy?”. Why would you need to do anything? Isn’t happiness the ultimate goal?

 “Hey, have you finished writing that rake task yet or are you still working on it?” 
Charles asked me, waking me up from my daydreams about a line in a play. Charles was my manager at a Ruby company.  
 “Yes!” I replied. 
 Charles smiled and went away. I’d beaten him in his own game of always answering an either/or question with a yes. 

 I’d been writing a script to update the values of all products and variants, but the script would fail every time I tried running it. I wasn’t sure what was going on, and Charles knew it. He usually didn’t put much pressure on anyone to get things done by a certain date, but this was something that Nikolai, the big bossman, was pressuring him to do, so he was asking me to do it. Fair enough, chain of command. 
 
I wasn’t very happy to be writing this script. It was something that could be done manually by people in the product team of the company. It would probably take less time to do it manually. Considering I had to write the code, test it, run it in staging – the copy version of the app that we use to test things –, wait for the next deployment of the real app, and then run it there again. Yeah, it would take longer. The way things were running at the company, this would take at least three or four days. Three or four days for a task that could be done manually in just a few hours. A task that would probably never be used, ever again. I wasn’t happy about this at all. I could feel the code dying, never to be used again, as I wrote it. 

 “Nikolai, hi, sorry, hi” I approached him like an idiot.
 “Yes?”
 “You know this script you asked me to write, you know, for the product team”
 “Oh, yes, have you done it?”
 “Well, no, not yet. You do realise that this code would never be used again and that I’m kinda of wasting my time. 
People at the product team could just update these values themselves.”
 “Yes, I know. Can you just do it, though?”
 “Really?”
 “Yes.”

 I walked back to my desk, slowly, like a donkey refusing to go up a hill, carrying the weight of a useless job. I was writing a type of script that Rubyists call a “rake task.” It’s something that you write to be used every now and again, something that changes or does something to some bits of data. It’s not something that you want inside your app as a normal function, because you don’t want other parts of the code base using it. You want to keep it separate, often in a folder called “tasks.” As I sat down to write the task, I immediately got distracted. I browsed the “tasks” folder, looking for a sub-folder to place my task in, found a file called “unfuck.” Interesting. 
 
The file had a series of smaller tasks, grouped together under the namespace “:unfuck.” When you actually run a task, it’s customary to add some lines that will show their current status. They’ll tell you at what stage they are at and let you know if things fail. If they do fail, they usually have no dangerous consequences, which is why they are so useful. By reading the code, I could see that some of them would tell you their current status by showing on your screen things like “Unfucking the adjustments for #{adjustment.adjustable.number}” and “Unfucking the totals for #{order.number}.” The tasks also had interesting descriptions like “Get rid of the table in the production database that shouldn’t be there” or “Unfuck orders that have the wrong adjustment amount.” What the (un)fuck what this?
 
As I scrolled through the file, I realized that someone had already been placed in the same mental head space that I was in. Someone else had already felt that they were writing stupid code, and decided to have some fun while. Why waste a beautiful name with a useless task? Why not call it by it’s real name and place in the namespace it deserves? The more I read the code, the more I was assured that this programmer and I shared similar feelings. I came across a comment that would only confirm my suspicions:

# This is the same logic that is in 
# app/services/refunds/line_item_refund_creator.rb
# but its not in a reusable state, 
# and I'm not refactoring the code
# for the sake of this rake task.

 “I’m not refactoring the code for the sake of this rake task” says it all. The person writing this is pissed off with the state of things, there is something that made them quite annoyed for having to write this task. Who was it? I opened the codebase on Gitlab, where the code was hosted, and searched through the history of changes in that file. I was looking for the person who’d made the changes to that specific portion of that file, the one that’d unfucked it all. What a surprise to find, in the history left behind, the name of Nikolai.
 
“Can you just do it, though?” 
 Yes Nikolai, I sure can write this rake task for you. 

 Jim Weinrich created Rake in 2009 and it has since become one of the staples of Ruby programming. It’s always there, you use it all the time. I’d wager good money – I’ll eat my own hat, as my old mentor used to say – that “rake db:migrate” is the most written set of characters in the history of Ruby. Rake is part of every Ruby application's ecosystem, it’s always there. Boring, nothing new, furniture, part of the landscape. That's why it's especial; rake is one of the things Rubyists take for granted.
 
Jim wrote, when Rake was launched, that he never intended to write the program in the first place. He didn't think it was particularly useful, and probably wasn't going to be interesting to anyone. At the time, he was writing programs that help you put together a software library. Programs called “build tools.” They contain the steps to build a large chunk of software in a safe way. Why? To avoid resorting to human memory to remember which bits go first and which ones go second. You can’t build a house roof first, you have to lay the foundations. Build tools contain the intructions that tell the computer what to do to build a specific house, I mean, a specific software library. Believe it or not, programs have loads of things that they depend on, and you have to stack them together in a nice way. To do that, Jim used what everyone was using at the time: Make. Make was created at Bell Labs in 1970, and shipped during the first version of UNIX (1). It uses Makefiles, files that describe how each part of a program should be compiled and in which order. When you run Make, it follows those instructions, and packages your library into binary. 
 
"All I can say is that Why's onion truck must by (sic) been passing through the Ohio valley.” Jim writes in a copy of the anouncement of Rake, “What am I talking about?… A Ruby version of Make" (2).  He had the idea to create Rake because he kept finding the same problems with Make. He had to use a Ruby script to do work around those problems, and thought it would be nice to just be able to use Ruby inside a Makefile. He gave it a go. "I showed the code to my coworker and we had a good laugh” Jim writes. “It was just about a page worth of code that reproduced an amazing amount of the functionality of Make. We were both truly stunned with the power of Ruby." (3) Jim created Rake in 2009, just 5 years before he passed. (4) With more than 500 million downloads, Rake is the the 10th most downloaded Ruby gem. Rails is number 40. (5)
 
Rake is built on a clever computational model: dependencies. Programs dependend on other programs to run, and they need to make sure those other programs - their "dependencies" - are working well before they themselves start running. Rake deals with this through the idea of "task." A task is "the basic unit of work in a Rakefile. A task has a name, a set of prerequisites, and a list of actions to be performed." (9)  A typical Rakefile will have tasks that dependend on one or more dependencies. Everytime a task is "invoked" - the term used by many programmers to give their actions a hint of magic - it checks which other tasks it dependes on. 
 
A Rake task relies on Ruby's quintessential structure, the block, to enclose the code it needs. But the interesting thing is that the specific order in which each dependency is built might not matter. “Few people that knock up a build script realize they are programming in funky computational model," writes Fowler (7). The computer will decide, while running the task, what it will do first, and this uncertainty Fowler calls “funky.” Jim Weinrich didn’t invent this model in Rake. Make has it too, and so do other build tools. These “funky” build tools share yet another trait: conceptually, they are all Domain Specific Languages or DSLs. They are a tool built for a very specific thing, and only usable for that thing, like a Mac’s thunderbolt cable. 
 
The problem with Make and other build tools is that their uniqueness is perhaps too unique. You’re bound to that DSL, you can’t use functions and calls from a different DSL, let alone a different programming language, within it. Rake, however, is a little bit different. Rake is also tailored to a specific problem, but Rake is cosmopolitan and well-travelled. Rake has been to Japan and it now speaks Ruby. Rake is made out of Ruby, it’s like a little dialect of Ruby, a dialect that you mumble as you write the code that will execute that useless task that Nikolai asked you to do. 
 But if Rake is basically just Ruby, what makes it so special?
 
 Many months after I’d finish writing the task that Nikolai wanted me to write, I was looking through the actual code that Jim wrote for Rake. I was prompted to do this by a comment made by one of the first Ruby programmers outside of our company that I reached out to. I came across a list of projects on machine learning written in Ruby (8), and found his project, Rley (9). As it sometimes happens with publicly available source code, the owner of the project didn’t reveal who they were and simply went by the name “FamishedTiger”. I eventually managed to contact the secretive tiger, and what followed was a long exchange of emails and interviews about his program, natural language processing, and machine learning, but also about Ruby and what it means to create beautiful ruby code. We exchanged long emails about the history of programming languages and I even sent him a draft of one of my academic papers on the anthropology of programming. He didn't particularly liked the paper, but our conversation went on, and he wrote one day on the topic of which Ruby programs or libraries he found the most beautiful. "I was always seduced by gems / libraries that provided a DSL (Domain-Specific Language) that helped programmers to express their intents in Ruby in a fluent way" he wrote. He pointed out the simplicity of something like Sinatra and emphasized how much he loved Rake.
I cannot but consider it as a masterpiece. The much regretted Jim Weirich created a tool that surpassed the original C Make by making rakefiles just Ruby files. As C (and C++) we can express dependencies in our projects and still use the full power of the Ruby language. He could achieve this thanks to the malleable Ruby syntax.

 I understood what he was saying, but I couldn’t feel it. I couldn’t really explain why Rubyists loved it so much. It wasn’t just because it was useful, I thought, there had to be something else. It must be something in this idea of the “task”, I thought. “Task” looks like a lot of things do in Ruby: something important that opens up a block. A keyword that unfucks the door to another dimension. I rumaged through Rake’s code and found a file with something called “Rake::DSL.” This must be it. (10) The file describes what Rake is, its main components, how to write a Rakefile, and how to run them. The file is long, with loads of comments, but the key to understand it lies at the very end of the file. There, Jim wrote:

# Extend the main object with the DSL commands. 
# This allows top-level calls to task, etc. 
# to work from a Rakefile 
# without polluting the object inheritance tree.

self.extend Rake::DSL

 A simple line that goes “self.extend Rake::DSL.” It takes Ruby by the hand and asks, “could you please add my dialect to your program? It literally says please extend yourself with the language of Rake. In other words, would you allow us to say ‘task’ every now and then?” The expression "self.extend Rake::DSL" cements Jim's cleverness. More than cleverness, perhaps, it is this type of thing that makes Ruby code looks so powerful and, most of all, it it this kind of thing that makes Rubyists happy programmers.

 In 2008, a year before the release of Rake, David Flanagan and Matz published "The Ruby Programming Language." It came in a particularly crucial point in the development of Ruby, the troublesome crossing from version 1.8 to version 1.9. To this day, some 14 years later, Matz still refers to this epoch as the moment he was most afraid that the community would break up in two - the ones using the 1.8 version and the ones using the 1.9 one. In their book, Flanagan and Matz describe how domain-specific-languages (DSLs) work in Ruby. It reads as a description of what Rake would be when it was released a year later. DSLs use blocks “as if they were keywords” (11) – they have first-grade properties. DSLs extend the Ruby syntax “in ways that make programming easier” they write.  This is what Rake does, turning a “task” into something you can use anywhere. By extending the main object of a program to include the methods defined in it, Rake makes it easier for programmers to write tasks. Rake and other DSLs makes the life of the programmers easier. They make programmers happy. They don't necessarily chuckle when they use Rake, but I’d like to think that most Rubyist as least smile when they read Rake’s code for the first time, as I did. 
 
But if reflection and meta-programming are tools to make programmers happy, they don't make the computer happy at all. As Matz often says, optimizing for happiness is opposed to optimizing for the compiler, meaning: the more DSL-like techniques you inject in your programs, the more things need to be checked when your program is running. The more you create special syntax like Rake’s “task”, the less efficient your computational process will be. And compilers hate that. Compilers want to be as efficient as “machinically” possible. Well… maybe not the compilers themselves, but certainly the people who design compilers and work to make Ruby as efficient as it can possibly be.

 When I started my research, Charles told me I should speak to someone called Chris. They’d gone to university together, and Chris was quite involved in the Ruby community – he was writing a compiler for it. I hesitated in contacting Chris right away because I wanted to build my connections in the community one-by-one. Charles didn’t have Chris’ contact, they hadn’t kept in touch, so I would need to send him a cold email. I hate sending cold emails even more than I hate receiving them. This time, I did it, and Chris’ reply was interesting. 
 
"Developers get tons of these survey invites” he wrote. “I’ll say yes since you look like a legitimate researcher and I’ve very interested in human aspects of Ruby, but if you’re wondering why you get low uptake it’s because we get spammed with these things all the time." I replied saying that it wasn’t a survey at all, that I wanted to have an in-depth chat about his life as a Ruby dev. That didn’t help much, and I considered giving up. I’m so glad that I didn’t. Not only Chris and I had a great chat, he ended being a great supporter of my research, encouraging me every step of the way. 
 
Even so, the beginning of our chat was tough. I introduced myself, explained the research, as I always do, and tried to break the ice by referring to Charles and mentioning that they both had gone to university together. 
 
“I don’t remember him” Chris said, his face staring at me through our Zoom call. I had no intention of talking about programming and happines with Chris. I don't think I'd even heard the phrase "optimize for happiness" at that point - it was very early on in my research. Chris and I talked about many things, including his trajectory as a developer  and how he was pulled back from his career in the armed forces because his work on compilers got some attention. He decided to focus on programming languages that, for various reasons, were harder to optimize. These languages, often called “dynamically-typed” languages or interpreted languages, don’t rely on compilers. Compilers are like a pre-flight check. They are programs that check if your program can fly relatively well. They don’t guarantee that there won’t be any turbulence – that’s out of a compiler’s hands – but they will tell you if the type of wheel you are using is not appropriate for that plane. The things is that some programming languages don’t really allow for pre-flight checks. They don’t know what their programs are made of until they are actually flying. 
 
“What is this “wheel” made of, Ruby?” might ask a humble pre-flight compiler.
 “I don’t know, I haven’t used it yet.” Ruby replies. 
It could be rubber, might be steel, possibly wood. I guess we’ll have to fly and see.” 
 “What if it’s rubber?”
 “Well, then we make sure the landing strip is made of tarmac.”
 “What if it’s steel?”
 “Wa-a-ater, maybe?”
 “Ok, but what about wood? How do we land on wooden wheels?”
 
 “The problem with Ruby” Chris said “is that is has a lot of ‘what ifs’.” What if a function hasn't been used yet during this run time? What if it has, but some other method has changed its meaning since the program started? Such "what ifs" are costly in terms of performance – it takes a while to check them – and these performance penalties come directly from Ruby's idea of "optimizing for happiness.” Comes from this idea that things are malleable, changeable, that each Rubyists does things a little bit differently, that there are a lot of domain-specific-language, loads of metaprogramming. Loads of Rake-like things.
 “Does that bother you Chris, as someone trying to optimize things?”
 “What?”
 “That the Ruby community likes those things that make the life of a compiler harder?”
 “Not at all. That’s just idiomatic Ruby, it’s the way people write it. I don’t feel the community should change its ways. It all springs from the fact that Ruby embraces the chaos.”
 
Ruby embraces the chaos. A community in which (almost) everything goes in terms of programming. Things that make up the chaos and complexity of Ruby. People that use the language as they understand it. If people want cake, let them eat it. We'll deal with the crumbs at compiler level.
 
 Like the line from that play, the beginning of Jim Weinrich's announcement of Rake stuck in my head for while:

Ok, let me state from the beginning that I never intended to write this code. I'm not convinced it is useful, and I'm not convinced anyone would even be interested in it. All I can say is that Why's onion truck must by (sic) been passing through the Ohio valley.

 What was he on about? What does a truck full of onions belonging to someone named “Why” would have anything to do with him writing software? I assumed that “Why” referred to why_the_lucky_stiff, the legendary Ruby programmer (12), but the rest was a mystery. 
 I did what I seldom do. I went on Twitter looking for answers. 
 I posted a link to Rake’s announcement and asked if any Rubyists would know what "Why's onion truck" was about. I tagged a few people, and Brittany quickly replied, saying that Nick Schwaderer would be the person to ask. He came back quite quickly, in a short burst of tweets.

ooh now this is an interesting curiosity

why’s famous ruby guide included an onion. the idea was that the poignant ruby should make you weep, if not the onion would help.

which is where I first went with this. everyone is getting into ruby, onions flinging about everywhere

But there's something wrong with this assumption.
THIS COMMIT IS FROM 2003
And the poignant guide was a 2005 publication.
so unless there was an earlier reference, I'm slightly stumped

my gut says that it is in line with some whimsical phrasing of the time, and why was very active on ruby talk and message boards, and maybe he got swept up in the excitement, and this is how he phrased it
(also Jim lived in the ohio valley I believe)

 I have a very hard time using social media, the anxiety of it all, but this time it went great. Jim lived in the Ohio valley, and maybe Why had been messaging on RubyTalk about trucks and onions. Nick put it all together. Why's truck drove past the Ohio valley, the onions made Jim cry, tears fell on his keyboard, and boom, Rake was written. 
 Onion tears, coding tears, tears of joy. 
 I guess that’s what we do when we are happy.
 We write tasks that Nikolai make us write so we can unfuck someone else’s problems.
Back