Notes on what it’s like to write code.
Today, I raced back into Ruby’s arms.
It’s hard to believe, but the end of the semester is drawing near, and so CS50 (the intro to computer science course I’m taking at Harvard) is winding down, too. Well, “winding down” would probably be an overstatement; there’s a lot of work left to do! But lectures have finally broken free of the thicket of C, and this week’s problem set will be our last. After that, there’s just one more quiz and the final project.
The final project. The specification explains: “All that we ask is that you build something of interest to you, that you solve an actual problem, that you impact campus, or that you change the world. Strive to create something that outlives this course.” I’ve built apps before, but something feels different about the prospect of this one. It might be my great love for the course; it might be the element of communal experience; it might be that CS50 itself feels like a rite of passage. It might be that in the past, apps I’ve built have always felt hacked together—hanging by a thread. This one might, too, but I’ll understand the threads so much better. I’ll see how they come together.
For a long time, I’ve imagined that I’d build my final project for iOS. The promise of being able to experience something I built on my phone just seemed impossibly cool. But after spending some time with Apple’s iOS documentation this weekend, my heart fell. In spite of my newfound (relative) comfort with C—a close relative of Objective-C, the language iOS apps are written in—the tutorials still felt insurmountable. This could be for a lot of reasons, but I have a feeling that Xcode's cryptic interface contributed mightily.
So I backed up. I remembered RubyMotion, a “toolchain” that lets you write iOS apps in Ruby that then compile to Objective-C. Also, if the screenshots are to be believed, it lets you circumvent Xcode. Hallelujah! Seems great. The only problem is that it costs money. I visited their website for the dozenth time, and this time noticed that they were willing to discuss student discounts for those who wrote in. I wrote in. I still hope to hear back; I’d love to try it out. But in the meantime, my mind started spinning on alternatives.
The idea for the alternative I’m running with arrived unbidden, as most good ideas do. This is how it came about:
This coming Thursday, I’m traveling to Berlin—for the first time!—to visit friends at SoundCloud. I’m so, so excited for this trip. One reason: I’ve been recording daily, private audio messages to Erik using SoundCloud’s iPhone app for the past year (now up to 321 tracks totaling over 75 hours), so SoundCloud means a lot to me; this will be like a pilgrimage to the mothership. Another reason: I’ve never been to Germany, and haven’t been to Europe at all in almost eight years. Also: I’ll get to hang out with David!
So over the weekend, looking forward to the trip, I decided it was high time to follow more people on SoundCloud. My primary one-to-one use case means that I haven’t played around with many of the site’s social features, and I wanted to take those for a whirl by filling out my network a bit. The only question: how?
I was running errands while mulling this over, so I pulled up the SoundCloud app on my phone and decided to just start searching for the names of bands and musicians I like. But—well—that didn’t seem very thorough. So I opened up Rdio (my primary music app) and started scrolling through the artists in my “collection”—a list of albums stored in my account, originally built off of my iTunes library (which is itself now in deep storage on an external hard drive…Rdio and sites like HypeMachine and SoundCloud serve all of my day-to-day music needs, and SSD storage space is precious). It’s a long list; my iTunes library was huge, holding almost a decade’s worth of accumulated tracks. When I saw an artist that rang a bell as a solid favorite, I’d toggle over to the SoundCloud app on my phone and search for that artist’s name. But the hit rate was disappointingly low, and I soon grew frustrated with the workflow. This seemed like the kind of repetitive work a computer could be doing…
A computer could do this!
And that means I could make a computer do it.
The idea started to shudder to life in my mind. What if…matching?…Rdio…SoundCloud…APIs?…this must already already exist?…shouldn’t it be built in to SoundCloud?…but…well…it sounds fun.
My mind careened onto other topics, then veered back, then kept careening. Later that evening, back in front of my computer, I decided to give iOS development one more shot. I got stuck on some Xcode setting and felt totally defeated. Eventually, I went to sleep.
Today, Erik and I got to talk in real-time for the first time in a while; he was at RubyConf in Colorado for the second half of the week, and we typically rely on time-shifted methods (like my SoundCloud audio messages) during the workweek anyway. We talked about all kinds of things (including the lightning talk he gave on the T gem, his open-source command-line power tool for Twitter), but eventually ended up at the question of my final project.
I presented the options. Option 1: I attempt an iOS app, but I somehow have to figure out all of iOS development in two weekends, since I’ll be traveling for most of the rest of November and the CS50 fair (where we exhibit our apps) is on December 10. Or, Option 2: I explore this Rdio/SoundCloud idea in Ruby (a familiar language) and focus on making the interface cool. But…that didn’t feel like quite enough. I’ve mashed APIs together before; for a project last spring, I at one point had Stripe, Twilio, and MailChimp all hooked up at once. So where was the challenge befitting a semester of hardcore computer science?
Erik’s suggestion: focus on the algorithm. What if instead of straight matching—”you listen to this artist on Rdio, here’s that same artist on SoundCloud”—the app used Rdio artists-in-collection as revealed preference inputs to a suggestion algorithm for new, up-and-coming artists to follow on SoundCloud?
Now that was interesting. I could feel myself getting more excited. I’ve never tried to write a real algorithm, though I’ve gotten close in my work with databases. When I interface directly with databases, it’s usually about pulling all the fields I think might be useful, exporting to a spreadsheet, then messing around in Excel til the data starts to make sense. The prospect of writing an algorithm tugged at those same detective instincts, but went beyond. Rather than figuring out how to make sense of the data in one particular configuration, I’d be trying to figure out how to make sense of the data across all users and all cases, and to present the results of that sense-making in a usable form. When I mess with data in Excel, I’m the intended audience; by putting data through an algorithm, it expands the possible audience to—well, anyone.
So, that’s the going idea. That’s what I’ll be working toward. But this is one of my favorite things about coding: glimpsing the end goal let me see all the hurdles standing in the way—stretching out to the horizon—and gave me the energy to start jumping them, one by one.
Obstacle #1: I wasn’t actually sure what Rdio’s API looked like. I’ve used SoundCloud’s API for projects in the past (here’s one example), so I felt pretty confident that I’d be able to get what I needed from that side. But Rdio’s API was a total mystery. And, weirdly, I haven’t seen many people tap it for projects. That could just be a sample error (I only follow so many people on Twitter, so I only hear about so many hackathon projects), or it could be that Rdio just doesn’t have a big presence at hackathons, or it could be a lot of other things. But that relative void made me wary, so I decided to investigate Rdio’s API first, to make sure it had what I needed.
I found Rdio’s developer page just by searching for “rdio api,” and quickly realized that I would need to apply for an API key. I was a bit worried that a human would need to review my application, so I resigned myself to a couple-day wait. But fortunately, the process was automated; my application was approved instantly. I browsed the documentation just enough to reassure myself that the API was, indeed, quite extensive. And then it was time to rush off to lunch.
When I came back from lunch, I hit obstacle #2: finding the right Ruby gem.
The hazard—and joy—of programming in the GitHub era is that for any given API, there might be lots of ways to access it in your language of choice. Companies will often release an official “wrapper” for their API that makes it nicer to interact with their data through Python, or Java, or—my favorite—Ruby. But that wrapper (called a “gem” in the context of Ruby) may or may not be the nicest one: some kind soul out there in the world might have taken it upon themselves to make an even better one. There’s really no way to know until you start looking. And, unfortunately, the company’s documentation will not always give you the answer you seek.
In the case of Rdio’s API, I started out on the straight and narrow. Well, I thought it was the straight and narrow. I typed `gem install rdio` at the command line, kind of expecting that to be the canonical one. Simplest name, most canonical; makes sense. Sadly, as I soon discovered, the gem hadn’t been updated in a while…and didn’t behave exactly as I expected. It might actually be fine, but I veered away before answering that definitively, because a closer look at Rdio’s documentation told me that what I really wanted was Rdio-Simple, a family of wrappers developed by Rdio itself and hosted on GitHub.
Except…did I really want it? The syntax seemed kind of horrible—not Ruby-like at all—and I was having trouble getting it to do what I wanted. Again: maybe it’s fine. I didn’t push it far enough to know for sure. What I do know is that I got frustrated and went on a last-ditch quest to find something better. To do that, I went straight to the source: GitHub.
GitHub explains itself as a place for “social coding,” and it meets that definition, certainly. But it can also act like magical toolbox: every time you go there, the available tools have gotten better and shinier in your sleep. I say “act like” because in reality, it’s not magic at all: it’s a result of the efforts of hundreds of software developers, working out in the open, giving their creations back to the community. What makes GitHub so great is that those creations are made instantly usable and instantly discoverable—so instantly that as soon as you find the tool that does what you need, you can’t imagine how you ever lived without it.
So, I went to GitHub and typed into the search box: “rdio”. Rdio’s official rdio-simple repository did show up first. But a few lines down, something caught my eye: a different gem by AnilV, titled “rdio_api”. I went to the gem’s page, skimmed the README, and noted that its author cited the Twitter gem as inspiration. Erik’s one of the Twitter gem’s primary maintainers, and so I’ve seen first-hand all of the care that’s gone in to designing it well. This seemed like a good sign. I installed the gem and revised the few shreds of code I’d written up to that point, trying to use the gem the way I thought it should work. I ran the program and…it didn’t break! The gem worked the way I wanted it to! I didn’t have to bend to its will, or bend it to mine; it already fit my will like a glove.
That’s one of the nice things about open-source: sometimes it’s not about what version is better or worse, but about which one matches your built intuition. The rdio_api gem matched mine, and so I ran with it.
I figured out how to get artist names from Rdio; then figured out how to input those names as search terms to SoundCloud; then figured out that if I ranked the results from SoundCloud by number of followers, I got a reasonable approximation of the “most legit” account matching any given artist’s name. I started printing those results to the command line, but then realized that scrolling up and down through Terminal would be a pain; printing the results to a CSV (which I could then open in Excel) would be way more usable. So I got that working, and then watched with glee as my spreadsheet filled up with permalinks to artists’ pages. I hit a few snags—I periodically got 503 error codes from SoundCloud, and discovered that SoundCloud couldn’t seem to handle colons as search input. (My iTunes library was voluminous enough that it included a couple of artists with this issue, including the mysteriously-named P:ano.) But overall: it worked. It worked! The basic idea worked.
With the data in a handful of spreadsheets, I started exploring—clicking permalinks that seemed promising and, on a meta level, trying to develop some intuition for what datapoints I was privileging when deeming permalinks as “promising,” so that I could build that into a future algorithm. I ended up following about 45 new accounts (you can see all of them here), very few of which I would discovered without this exercise. A few highlights:
- Olafur Arnalds makes serene, dreamlike music. At least one of the tracks appears to be a true improvisation—not just a polished, finished track. I always like it better when artists show their work.
- The way I was sorting showed me that Vagrant Records is actually home to several artists I love, including Edward Sharpe and The Magnetic Zeros and School of Seven Bells. Since Vagrant lists those artists in its profile, SoundCloud search picked up on the connection and returned Vagrant’s account as a result. And now I’m following them, which means I’ll get to trust their taste further.
- It seems improbable that this Owen Pallet account is legit, but I loved hearing the demo version of “Tryst with Mephistopheles”—a song I listened to every morning, for a span of months, when I lived in San Francisco.
- Lykke Li!
Now that I’ve cleared many of the hurdles, I can’t wait to start building out the app itself—tweaking the algorithm, generalizing the code to work for more users than just me (probably by enabling authentication), figuring out how to present it all. But underneath that anticipation, there’s also ecstatic satisfaction. There’s nothing quite like bringing an idea to life in an afternoon, and I never get that feeling more reliably and more acutely than when I’m working with code.
And I’d say that the prediction/wish I made last week is holding truer than I imagined: “I don’t think I knew how good I had it with Ruby…but I also never knew what it was capable of (or what I was capable of). So that’s the bet I’m making: two months of alternately infuriating and satisfying hand-to-hand combat with C followed by a lifetime of harmonious cooperation with Ruby and whatever comes next.” Ruby is awesome. It’s so good to have it back. I’ll never take it for granted again.
What else? So many things!
While debugging with Erik today, we took a detour into talking about SOLID principles of object-oriented design—specifically, the Liskov Substitution Principle, which states that “objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program” I actually had a bug that related to that principle, so it proved a good learning moment. In the process, I learned about Barbara Liskov—a computer science pioneer, now at MIT. New goal: meet Barbara Liskov before I leave Boston/Cambridge!
Exploring SoundCloud, I ran across this Four Tet remix of Ultraísta’s “Smalltalk,” (warning: it’s great), which reminded me of this Twitter exchange with Patrick and Buzz, wherein Buzz noted that “Objective-C actually shares one of the same ancestor[s] as Ruby (Smalltalk),” and Patrick recommended Squeak as a way to play with Smalltalk today. Still need to dig in to all the links they suggested, but that thread is one of the many that feels more woven into my life lately.
I’m still making progress through Seymour Papert’s Mindstorms, which I picked up from the library after taking heed of Bret Victor's strong recommendation in his post on “Learnable Programming.” The book is sort of about LOGO (the programming language with the turtle), but mostly about learning. A few passages I’ve loved recently:
Of all ideas I have introduced to children, recursion stands out as the one idea that is particularly able to evoke an excited response. I think this is partly because the idea of going on forever touches on every child’s fantasies…
…what is important when we give children a theorem to use is not that they should memorize it. What matters most is that by growing up with a few very powerful theorems one comes to appreciate how certain ideas can be used as tools to think with over a lifetime. One learns to enjoy and to respect the power of powerful ideas. One learns that the most powerful idea of all is the idea of powerful ideas.
An important component in the history of knowledge is the development of techniques that increase the potency of “words and diagrams.” What is true historically is also true for the individual: An important part of becoming a good learner is learning how to push out the frontier of what we can express with words.
And, finally, there was this: an artifact of today’s remote pair programming date with Erik, the moment where I excavated all the way to the bottom of an object’s ancestry.