Things Fit Together
Practical answers to impractical questions.
Thursday, October 13, 2011
New Pandora
I've been a happy and paying Pandora customer for years. I've discovered new bands, gone to unexpected concerts, and made unexpected friends at those concerts. It has affected my life consistently, positively, and non-trivially.
I'm just frustrated with "#NewPandora". There are basic requests and complaints that I have made and heard from other users year after year: What if we could make instrumental-only stations? Or vocal-only stations? What if we could add upvotes & downvotes to any song at any time, without having to wait for it to play? Stations tend to play 4-song blocks of similar music. What if we could see those blocks and skip over them if we don't like the aspects which chose them? What if we could pick and choose which Music Genome Project traits went into a station, allowing fine-tuned customization? What if we could scrobble our plays?
I'm not saying that any of these features necessarily should exist. Pandora is an admirably simple product. Obviously, if they implemented all (or even half) of the ideas in the above paragraph, it's likely that it would be a mess. Part of Pandora's beauty is that there aren't half a million things you can do. The "verbs" available have an attractive economy to them: you create stations. You upvote, you downvote. Sometimes you skip or snooze a song. That's it.
So what's the problem?
Over the past few years, I have seen Pandora roll out new projects with great fanfare. Pandora One. The desktop player. Mobile apps. And now "New Pandora". What bugs me is that they make huge deals out of inevitably expected changes, and then they don't iterate! The desktop player and mobile apps are still subject to almost the exact same flaws I experienced when I first started using them. Every time I pause the desktop player at the end of the day and come back tomorrow to resume, the track cuts off and I get a "Pandora is having trouble connecting to the internet, please click 'Retry' to try again" message. It's like clockwork. Why does it do that? Every time I want to move a song to a different station on the mobile app, I can't. It's not a feature of the Android app. Why can't I do that?
Instead we get New Pandora. Look, this is just a crotchety rant from an over-entitled user. Pandora doesn't owe me anything, and I know that. And New Pandora is great. You can click around the site without having to open new windows or wait for a flash loader to finish. But I still have to scramble to hit "Pause" when I open it while the desktop player is already going. And apparently now I can't bookmark stuff. They changed the meaning of the features: "Thumbs Up" doesn't just mean "this song is good for this station" anymore. It also (apparently) means "bookmark". That's not what I used bookmarks for. I used bookmarks when I heard a song that really resonated with me, that I wanted to check out later. Hell, sometimes I downvoted a song and then bookmarked it, because I liked it but it wasn't appropriate for the station! (On the mobile app, that's the closest you can get to "move to another station".) It wasn't broken--why did they try to fix it?
There are so many cool things Pandora could be doing with their product. If they had implemented just one of the inane features I listed above in the past however-many-years I've been a listener, I probably wouldn't feel the need to rant like this. But they just don't seem to be interested in really doing anything novel with their service. Instead they just want to keep obsessively polishing the same thing over and over again. I just don't get it.
Thursday, October 6, 2011
Tough Jobs
If you had asked me yesterday evening, "How will you feel when Steve Jobs dies?", I would probably have answered with something like, "Well, I'd feel like Apple lost a great innovator." Jobs was never someone who I considered an inspiration for myself. Mostly I was just annoyed that I had to deal with his fan club.
"I am truly surprised at how sad I am. Even if I disagreed on some of the decisions made by Apple... he was to me the most inspirational man alive. What a devastating loss."
"I want to make a ding in the universe."
Monday, August 8, 2011
method_missing considered harmful
Labels: programming, rubymethod_missing has many downsides:
- Your objects won't answer correctly when introspected with respond_to?, unless you override that too.
- Users of your code will not be able to see available methods when introspecting with Object#methods. This has the additional penalty of breaking tab completion in irb.
- Your objects are now hostile to being used with inheritance and mixins.
It's better to explicitly create the methods you want using metaprogramming.
class Foo
["one", "two", "three"].each do |num|
define_method "action_#{num}".to_sym do
puts "Now performing action #{num}!"
end
end
end
Now we can sensibly introspect into this object.
ruby-1.8.7-p334 :001 > f = Foo.new => #<Foo:0xb77b2408> ruby-1.8.7-p334 :002 > f.methods - Object.methods => ["action_one", "action_two", "action_three"]
Don't use method_missing to do metaprogramming. It's like writing an entire website in the 404-handler of a web framework.
Friday, August 5, 2011
Start developing for OS X in just 68 easy steps
- Go to Apple.com.
- Click "Buy Now" after configuring my new Air.
- Create an Apple ID username & password.
- Get a login prompt.
- Enter my Apple ID username & password.
- Enter my full name and address.
- Enter my payment information.
- Confirm payment. Wait for the laptop to arrive by Fedex. Admire the minimalistic box, and the frankly incredible fact that they put the optional video adapters INSIDE the vacuum-sealed box, neatly nestled in a nook beneath the manual.
- Turn on my new Air and go through the setup process.
- Enter my Apple ID username & password.
- Open the app store and type "Xcode" into the search box.
- Click "Buy Now" on Xcode and get a "Login" dialog at the top of the App Store app.
- Enter my Apple ID username & password.
- Get a popup: "This Apple ID has not been set up for use with the App Store. Please go to your Apple ID account page and enter the required information."
- Click the link in the popup, which opens the Apple ID Account site in my browser.
- Enter my Apple ID username & password.
- "An unknown error occurred."
- Refresh the page. The username & password input boxes are now gone.
- Copy & paste the URL into another browser.
- Still no input boxes.
- Clear my internet cache and refresh the page.
- Still no input boxes.
- Google "Apple ID Account" and click the first result. Now the boxes are back.
- Enter my Apple ID username & password.
- Accept the terms of service.
- Enter my full name and address.
- Enter my payment information.
- Get a confirmation dialog. Go back to the App Store app.
- Type "Xcode" into the app store search box.
- Click "Buy Now" and get a "Login" dialog at the top.
- Enter my Apple ID username & password.
- Get a popup: "This Apple ID has not been used with the App Store before. Please enter the required information."
- Accept the terms of service.
- Enter my payment information.
- Get a confirmation dialog. I am sent back to the App Store search results screen.
- Click "Buy Now" and get a "Login" dialog at the top.
- Enter my Apple ID username & password.
- The download begins.
- Leave the computer to complete the ~4GB download overnight.
- Come back in the morning. The computer went to sleep and stopped downloading.
- Restart the download. It finishes downloading.
- The Xcode app store icon now reads "Installed".
- Go to the mac "homebrew" website.
- Run the installation script, which produces an "Xcode is not installed!" warning.
- Ignore the warning because I just installed Xcode. Run "brew install tmux"
- Get an "Xcode is not installed! No such file or directory: /usr/bin/cc" warning.
- Run "which cc", no results.
- Run "which gcc", no results.
- Google "homebrew 'xcode is not installed'".
- Google "homebrew not detecting xcode".
- Google "os x lion homebrew".
- Ask in the "#machomebrew" IRC channel on freenode.
- Decide to open Xcode and figure out where it thinks cc is. Do a spotlight search for "xcode"
- See an "Install Xcode" entry, but no "Xcode" entry.
- Click "Install Xcode".
- Accept the terms and conditions.
- The installer sends me to the Apple ID Account page.
- Accept the terms and conditions.
- The Apple ID website asks me for more information so I can register as a developer.
- Enter "asdofhasdgoasdg" for my "Organization", because it's a required field and this is a personal laptop.
- Choose my primary industry. "Software" and "B2B" aren't on there. (I think I picked "Agriculture".)
- Choose what kind of apps I'm going to develop.
- Check the confirmation e-mail in my inbox.
- Copy & paste the confirmation code into the input form.
- Get a confirmation dialog. Go back to the Xcode installer.
- It spends a few minutes installing.
- Run "brew install tmux".
- Run "tmux" and have a beer.
Tuesday, June 14, 2011
When One Teaches, Two Learn
One of my favorite phrases is "when one teaches, two learn". There are lots of ways to interpret it, but one day I discovered that it can sometimes be applied quite literally.
Every once in a while I manage to convince one of my (incredibly patient) friends to let me teach them binary. Sometimes I have to bribe them with a couple of beers, but they all break eventually. Binary is a good "bite-sized" lesson that can be fully expressed and understood in less than an hour, and it poses some basic challenges for the educator. Since my day job involves very little direct pedagogy, I try to inflict it on my hapless acquaintances and loved ones to keep myself from getting rusty. (And to keep them on their toes.) Also, you will get a full range of enthusiasm in students, from "budding computer person who can't wait to find out" to "couldn't care less about this dumb math thing"; each extreme and everything inbetween subtly changes how the lesson will go.
One of the first steps towards learning binary is understanding some things about our own number system, decimal (or "base 10"), which we usually take for granted. Everyone knows that decimal numbers are expressed with 10 symbols (0 to 9) that represent bigger quantities the further they appear to the left in a given number. That is, a 9 in the "ones" column just means 9, while a 9 in the "hundreds" column means 900.
The way we get the value of these "columns" ("ones", "tens", "hundreds") is by counting how many positions to the left we have gone, and raising our "base number" to that power. Decimal is base ten, so the "tens" column is 10^1, the "hundreds" is 10^2, and so on.
But what about the first column? We actually start counting from 0, and anything to the zero power is 1. That's why the first column is always the "ones" column, no matter what number system we're in.
At this point in the lesson, my friend turned to me and said, "Why?"
I stopped in my tracks. "Why what?"
"You said 'anything to the zero power is 1'. Why is that?"
Suddenly, for whatever reason, I attained momentary insight into the inner workings of my brain. I felt my next sentence before it started to come out. I wanted to say, "Well, that's just how it works." Because that is just how it works. Right? I'm teaching, here! I'm supposed to have an answer, damn it. I'm supposed to know everything! I don't have a better answer, so the answer must be "That's just how it works."
Thankfully, that's not what I said. Thankfully, my ego blinked or sneezed or got distracted by something shiny, and released its grip on my self-delusional cognitive faculties just long enough for me to answer my friend honestly:
"I have absolutely no idea whatsoever."
Neither of us were satisfied with that answer, so we immediately opened up Wikipedia and went to the entry on exponentiation (of course, we searched for "power" and went from there, because who remembers a word like "exponentiation"?). The proof in the article didn't immediately click with us, but we clicked through to the linked article on empty products, and hailed the miraculous existence of the "Intuitive justification" section. When we both followed its mental example of a multiplication-only calculator that had to display a number when you hit "CLEAR", the reasoning for anything-to-the-zero-power being 1 made perfect sense to both of us, and helped us understand the original article's proof as well. We then continued with our original lesson.
When one teaches, two learn.
Friday, May 13, 2011
Do what you love, but don't be a bum
Marc Randolph, former CEO of Netflix, wrote today about "the spin". He contends that the line between "honest marketing" and "dishonest marketing" is determined by the boundaries of the marketer's own beliefs. He also touches on the subtle "anti-hucksterism" bias that is particularly noticeable in some parts of the software/startup world, offering his own belief instead, which is that marketing & product can only coexist: they need each other. I agree; ten thousand times, I agree!
All creative people--hackers, writers, painters--are tempted to engage in the conceit of "marketing avoidance". It is so easy, and feels so brave, to challenge the efficacy of such an enormous field: "Build it and they will come," we say! "Good ideas sell themselves!"
If only it were that simple.
Tuesday, May 10, 2011
Storing Hierarchical Relational Data with Nested Sets
Recently I have been working on a simple discussion board app. I decided to make replies hierarchical instead of linear, which is how most popular apps like phpBB and vBulletin do it.
Consider a post and a reply:
- We may experience some slight turbulence and then explode.
- I don't wanna explode!
Oracle gives us the handy "START WITH" and "CONNECT BY" clauses, which allow us to store our data like so:
| ID | Body | Parent |
|---|---|---|
| 1 | We may experience some slight turbulence and then explode. | NULL |
| 2 | I don't wanna explode! | 1 |
This data is easy to update, but we have to rely on the special SQL functions to query it meaningfully. The official term for this model is an adjacency list.
I have to keep my hippy license somehow, so I decided against Oracle for my forum app. I went instead with SQLite, since I hadn't really worked with it before. At first I was dismayed to find that no such recursive query functions existed, but there is another clever way of representing a tree in relational data called nested sets.