On the third day of class, we learned a term called “yak shaving”. The idea is that you want to do something, let’s say change a lightbulb, but that ends up requiring you to do something else, which in turn requires you to do something else, which requires you to do something again… After diving into subtask after subtask, eventually you find yourself shaving a yak when all you wanted to do was change your lightbulb!
Etymology: the term is thought to have been coined at the MIT AI Lab circa 2000, as inspired by an episode of Ren & Stimpy. Here are some definitions from various sources: MIT, Urbandictionary, Seth Godin (who helped popularize the term)
I didn’t think much about the term until pretty recently. In the last 2 weeks or so, as I’ve been diving heavily into code, I’ve found myself shaving yaks constantly – I can see why it’s a “thing” in programming now!
Case in point – the jukebox. As my teammates can attest, I’ve been building a command-line interface jukebox which when given a list of songs, will retrieve the songs’ artists and genres, and allow the user to browse or choose by category and select a song to “play” (it only displays the song & doesn’t actually play it yet, haha). Well technically, this was an assignment everyone had to do, but since I liked the idea I decided to take it a lot further. (Also, to order to generate a song list, we parsed a directory for mp3 files and built a library of artists, songs, and genres)
My current version of the CLI jukebox can not only browse by “artist”, “song”, or “genre”, but it can also search by artist, song, or genre, and whatever the results are of the current search or browsing results, you can keep entering input to further filter results, as well as choose a result by number (thanks Ning for some of the inspiration!)
Here are some examples of yak shaving while making the CLI jukebox:
- In order to get the program to understand so many different kinds of user inputs, I ended up having to learn regular expressions (Rubular is awesome!). Specifically, valid commands that the program understands are stored in class constant:
This allows for the program to understand the input “artist(s)”, “song(s)”, “genre(s)”, as well as the input “artist [name or number]”, “song [name or number]”, “genre [name or number]”.
Here is what my code for seeing whether or not a valid command is recognized looks like:
This doesn’t work though. After some banging my head on the wall, I ended up reading the “grep” documentation in the Ruby Enumerables module, and discovered the problem:
1 2 3 4 5 6 7 8
Simple enough. We open the class and give it a new method grep2:
1 2 3 4 5 6 7 8 9 10 11
- After creating this program on my own computer, I wanted to import this to the web so that it could run as a CLI “web app” over the internet. I was inspired by a few command-line interface websites: xkcd, goosh, After many futile attempts at finding an answer which made me question my google-fu, I finally found something reasonable which had been staring at me in the first page of google results: a Ruby gem called Rack Webconsole! After installing, more banging my head on the wall and finagling, I finally got it to work:
Now I need to learn how to get “puts” and “gets” to work in the webconsole interface instead of on the server-side console:
1 2 3 4 5 6 7 8 9 10 11 12 13
Enjoying the view and striving for the destination
There’s always more to learn, and to do something I thought would be so simple ended up requiring hours and hours of banging my head on the way. However, in retrospect it was all a great learning experience and helped me become a better coder, as I suspect yak shaving can oftentimes be.
It’s the journey that matters, not the destination. However, a program that doesn’t work right isn’t useful either. So I guess both are important – enjoy the view along the way, but to learn the most, don’t stay satisfied until you reach the destination.