Dropbox Referrals and Google Adwords

My hosting company has been sending me promos for Google Adwords for years now, and the trick of buying an ad to get dropbox referral credit seemed like a low risk way to turn an already awesome free Dropbox account into an even awesomer free Dropbox account.

Before we get started I want to be clear that I know I am not the first person to think of this. In fact one of those articles is probably where I first heard of this scheme. I use Dropbox enough that I wanted more space, but not enough to justify the monthly expense, so I decided to give the Adwords route a try!

It turns out that this plan is plagued by two issues: 1. saturation, 2. indifference. The first people to do this probably did it about 5 seconds after the first company offered referral credit. Combine that with the popularity of Dropbox and you have a lot of people who have already done this or are doing it currently. The second problem is that people are freaking lazy. Look at this partial list of my referrals:

Dropbox referrals waiting for install

7 people who have waited days to install the Dropbox client. And there are 20 more people in that list who also haven’t completed the install process.

No install = No referral credit

I did take a queue from one of the articles and reached out to all of the no-install folks with a friendly little email, but so far none of them have budged. I would easily hit my maximum referral credit if even 1/5 of those folks would finish the setup. So was it worth it? Yes! In less than one week and for the low cost of $25 (plus the $100 Adwords credit) I now have an additional 11.5GB of Dropbox storage. And if some of those slackers finish the setup it could creep up another 4.5GB.

If you don’t already have Dropbox account feel free to sign up using my referral link, just make sure you actually finish the setup.

Refactoring with Class

If you ever want to know if you’re making progress on a skill, go back and look at your earlier work compared to your recent stuff. I was reviewing some of my old scripts on Github and I was surprised how simple and linear they are. They got the job done, but only just barely…

Now I’m not a full time coder, so I haven’t exactly gone pro since then, but I have moved from the ultra simple scripts of yore, to more intelligently formatted and reusable code.

Oh and classes, classes are cool.

Let’s look at a script I wrote not that long ago. It concatenates some CSV files together and gets them into the format I need them.

require 'csv'

courses = "courses.csv"

altered = []

CSV.foreach(courses, { :headers => true, :header_converters => :symbol }) do |course|
  altered << course.headers unless altered.size > 0
  course[:start_date] += "T01:00:01-6:00" unless course[:start_date].match(/T\d\d:\d\d:\d\d-/)
  course[:end_date] += "T22:59:59-6:00" unless course[:end_date].match(/T\d\d:\d\d:\d\d-/)
  altered << course

CSV.open(courses, "w+") do |csv|
  altered.each do |row|
    csv << row

teachers = "enrollments_t.csv"
students = "enrollments.csv"

CSV.open(students, "a") do |csv|
  CSV.foreach(teachers, { :headers => true, :header_converters => :symbol }) do |teacher|
    csv << teacher

sections = "sections.csv"

altered = []

CSV.foreach(sections, { :headers => true, :header_converters => :symbol }) do |section|
  altered << section.headers unless altered.size > 0
  section[:start_date] = ""
  section[:end_date] = ""
  altered << section

CSV.open(sections, "w+") do |csv|
  altered.each do |row|
    csv << row

teachers = "users_t.csv"
students = "users.csv"

CSV.open(students, "a") do |csv|
  CSV.foreach(teachers, { :headers => true, :header_converters => :symbol }) do |teacher|
    csv << teacher

Oh the horror. It does the job, but it has a lot of smells (and probably more then I even realize.) The most obvious is the duplication. Second (but related) is the complete lack of functions; if I need to concatenate more than just the four files I’d have to extend the script each time. Next is the most up to date version.

require 'csv'

FILE_TYPES = ["courses", "sections", "users", "enrollments"]

class CSVFixer

  attr_reader :rows

  def initialize(csvs_name)
    @csvs, @rows = [], []
    @csvs_name   = csvs_name
    @csvs        = get_csvs

  def get_csvs
    @csvs = Dir.glob("csvs/*#{@csvs_name}*", File::FNM_CASEFOLD)

  def read_csvs(csvs)
    csvs.each do |csv|
      CSV.foreach(csv, { :headers           => true, 
                         :header_converters => :symbol, 
                         :encoding          => "windows-1251:utf-8" }) do |row|
        @rows << row

  def write_csvs(folder, file_name)
    CSV.open("#{folder}/#{file_name}.csv", "w", 
             :write_headers => true, :headers => @rows[0].headers) do |csv|
      @rows.each do |row|
        remove_section_dates(row) if file_name == "sections"
        extend_course_end_date(row) if file_name == "courses" && row[:end_date] == "2013-12-14"
        csv << row

  def remove_section_dates(row)
    row[:start_date] = ""
    row[:end_date]   = ""

  def extend_course_end_date(row)
    # Horrible magic number change for Fall 2013
    row[:end_date] = "2013-12-25"

def make_folder
  folder_name = Time.now.strftime("%Y-%m-%d %H%M%S")
  while File.exists?(folder_name)
    sleep 1
    folder_name = Time.now.strftime("%Y-%m-%d %H%M%S")


  return folder_name

output = make_folder

FILE_TYPES.each do |type|
  fix = CSVFixer.new(type)
  next if fix.rows.empty?
  fix.write_csvs(output, type)
  puts "Processed #{fix.rows.length} rows for #{type}.csv"

So this version is 20 lines longer, but it adds so much goodness in those 20 lines. First, a class is used to declare and make accessible the commonly needed functions, and a CONSTANT holds the names of files (that are now DIR::glob-ed for). This means that I can now make the entire tool also process groups.csv but just adding "groups" to the FILE_TYPES array. I can also concatenate any number of partial files, so if I have users.csv, users1.csv, users2.csv and users3.csv, it will read in all the lines and cram them into one (UTF-8!!) file.

This little tool still isn’t perfect. It assumes the files are formatted correctly (they come from a machine source so that’s fairly likely) and it does use a magic number, but all in all it’s infinitely more extensible and reusable the the original iteration.

The time I spent writing this little utility didn’t just save me many hours of boring (and error prone) manual concatenation of files, but my coworkers got to benefit from using it while I was away from the office.

One Month with the Crabby Wallet (Updated!)

Crabby Wallet logo

I backed the ultra-minimalist Crabby Wallet on Kickstarter and (sort of) patiently waited for it to be released. Now that I’ve been using it for a month I’ve formulated some opinions on it.

I’m a big fan on minimalist and utilitarian things. The wallet I’d been carrying (a tired leather front-pocket affair that was seriously worn out) needed to be replaced and that’s when I found the Crabby Wallet. But what is it?

It’s an elastic band. There’s really no other way to describe it. I suppose it might be more accurate to say it’s an elastic band with an elastic band around it. The body of the wallet is a big fat elastic loop sewn on three sides, and it has an elastic band that wraps around it to hold the cards you put into it.

When it first arrived it was so tight that the five cards I put into it bowed slightly. Now it’s a little more relaxed but it’s still very difficult to pull the end cards out, and basically impossible to get the middle card out without removing the lot. It’s secure; no doubt about that.

I do love how compact it is. When I first started using it I kept thinking it wasn’t in my pocket (which was nerve wracking for a bit), but it’s nice how light and thin it is. It also forces you to only carry the essentials. I was decent at this anyway with my front pocket wallet, but now I carry next to nothing and I like that.

My one small side complaint is this: I carry two RFID enabled cards for work and in my old wallet I could just tap the wallet against the sensor and they’d work, but in the Crabby Wallet they are so close to each other that they interfere. It’s not the wallet itself because either one alone works fine. Not a problem everyone would have, but I do need to find a good solution since getting cards in and out quickly is difficult.

Overall I’m pretty happy with it. Once I solve my RFID problem I think I’ll be good with this wallet as long as the elastic holds out. How durable it is will take time to determine.

UPDATE 2013-11-03

So this happened about a week ago:

Busted Crabby wallet

which is annoying because I haven’t used the key loop even once. Although it could just be a one-off defect and isn’t necessarily a product flaw, I’m overall not in love with this wallet enough to break in another one and find out. Fortunately the good people at their support desk walked me through returning the wallet and getting a refund.

Rejoining the Open Source World

Github logo

After entirely too long since my last git commit -m "Initial Commit" I’ve finally rejoined the OSS community!

I’ve dabbled with code for several years now but it’s not something I do full time, or even for pay (directly.) Oddly, I actually am fulfilling the dream of every teach-yourself-to-code startup and using code not to become rich and famous, but to make my life easier. I make little scripts here and there to make myself or my colleagues more efficient, but I don’t write what most developers would consider “real software”.

Being the wannabe that I am, I tend to follow the culture and was recently inspired by this article, and to that end I’ve published my first bit of code in ages on Github. It’s not much, but it makes my life and my coworker’s lives a lot better.

Unfortunately, since I wasn’t practicing good git fu and living the open source life, only this most recent version exists; my journey to this point is uncharted. That is a mistake I won’t be making anymore!

Thoughts On Auto-Graded Assessments

All of the major Learning Management Systems have some sort of assessment tool. It’s a staple of traditional education to, at some point during a class, present students with a list of roughly 25 multiple choice questions to evaluate their mastery of the material. In the bad old days these had to be marked by hand, then later educators were blessed (and students were cursed) by scantrons that could be graded by machine, and for the last decade and a half computer based assessments have become very popular.

Computer based assessments have all of the perks of paper multiple choice tests; easy to grade, familiar format, uniform, as well as the central perk of scantrons; automatic grading, and they have the added bonus of not wasting paper! Another amazing benefit is decentralized delivery, students don’t have to be present to take an assessment.

What I find odd is the main complaint against auto-graded, computer based, assessments is how easy it is to cheat. “Students can use their notes,” faculty cry out, “and how do we even know who is really taking the assessment?!” These are legitimate concerns, and quelling them has created an entire industry of remote proctoring (which I believe is effective) and anti-cheating software (which I know is ineffective). I think the solution isn’t Orwellian monitoring of student activities, but to reconsider how auto-graded assessments are utilized.

Let’s assume for some reason you can’t give up auto-graded assessments and go to a completely assignment/project based grading scheme; how can you more effectively use auto-graded assessments? A typical course is comprised of a large number of low-value assignments and a small number of high-value assessments. Instead, consider a large number of short, open note (yes, seriously), low-value quizzes, and a few high-value assignments/projects. With this model you encourage frequent review of course content, and can make it even more frequent by allowing students multiple attempts. Making quizzes open note encourages review of notes and course texts. For the instructor it keeps the amount of hand graded work to a manageable level, which can be critical in ever larger and larger courses. It also takes the stigma off of out of class, unproctored, assessment; in an online course it’s crucial that students can be assessed remotely, but in hybrid and face to face courses it frees up classroom time for group work, labs, or other projects by making quizzes an outside class assignment.

The above model won’t work for every course, and it’s far from the only alternative assessment model, but the notion of removing some of the prestige from assessments and placing it instead on assignments/projects is worth considering. Online and time-shifted assessments are a very convenient tool for instructors but it requires a shift in thinking as well. Long gone are the days of standing in front of the blackboard while students carefully circle letters or fill in bubbles. The improvement in technology isn’t just an opportunity to save time and paper, but an opportunity to rethink how we assess student learning.

Most Successful Tweet

As of the time of this writing my most successful tweet is one where I admitted a stupid mistake I made that was apparently quite relatedable. It’s been retweeted over 20 times earned a handful of favorites, and even started a few nice conversations. I think I may have even gained a follower or two.

To be fair, it only got that attention because a certain Jeff retweeted it.

Be that as it may, it was still nice to see that all of the replies and reactions were people who shared similar experiences. No negativity, just empathy. It seems doubly approproaite when you consider Stack Exchange is all about saying “I don’t know how to do this!” and strangers coming together to say “Here’s how!”

If you’re curious; this was the stackoverflow post in question.

The Bleeding Edge

Ready for some Inception? Good.

I read this post which took special note of this comment from this blog post. The sentiment is that there are just too many great frameworks, best languages, and general new hotness to ever feel on top of things. The comment:

I agree, I can’t keep up, I just finished learning backbone.js and now I’m found out on that it’s old news, and I should use ember.js, cross that, it has opinions, I should use Meteor, no, AngularJS, no, Tower.js (on node.js), and for html templates I need handlebars, no mustache, wait, DoT.js is better, hang on, why do I need an HTML parser inside the browser? isn’t that what the browser for? so no HTML templates? ok, DOM snippets, fine, Web Components you say? W3C are in the game too? you mean write REGULAR JavaScript like the Google guys? yuck, oh, I just should write it with CofeeScript and it will look ok, not Coffee? Coco? LiveScript? DART? GWT? ok, let me just go back to Ruby on Rails, oh it doesn’t scale? Grails? Groovy? Roo? too “Springy?” ok, what about node.js? doesn’t scale either?? but I can write client side, server side and mongodb side code in the same language? (but does it have to be JavaScript?) ok, what about PHP, you say it’s not really thread safe? they lie?? ok, let me go back to server coding, it’s still Java right? no? Lisp? oh it’s called Clojure? well, it has a Bridge / protocol buffers / thrift implementation so we can be language agnostic, so we can support our Haskell developers. Or just go with Scala/Lift/Play it’s the BEST framework (Foresquare use it, so it has to be good). of course we won’t do SOAP and will use only JSON RESTful services cause it’s only for banks and Walmart, and god forbid to use a SQL database it will never scale I’ve had it, I’m going to outsource this project… they will probably use a wordpress template and copy paste jQuery to get me the same exact result without the headache and in -half- quarter the price

I feel you Eran, I really do.

Being new to the dev world this is frightening because apparently you’re never completely on top of things, but more importantly it means I can stop worrying about being on the newest, bestest, greatest hotness and just ship something.

Ruby Kernel#Sleep

While reviewing the answer on a stackoverflow question I posted I learned a very cool Ruby Kernel method: sleep.

Kernel#Sleep does pretty much what the name implies; it pauses the interpreter for an indicated amount of seconds (or forever if no value is passed in). By itself this wasn’t obviously useful to me. Why, I thought, would I want to make my code slower and delay results and prevent interaction? Well if you reviewed the code in the answer above you’d see this:

Thread.new do
  loop do
    if WAYS[:updated] != (mtime= File.mtime(WAYS[:file]))
      WAYS[:all].replace File.readlines(WAYS[:file]).map(&:chomp)
      WAYS[:updated] = mtime
    sleep 5 # seconds

The significant bit there is Thread.new do. That bit initiates a new Thread and runs the code within, while allowing the main thread to continue executing code. Now that the sleep is happening in a separate thread you can probably think of plenty of jobs you might want to delay or run on a schedule.

When I think about code I think about speed and optimization, but in this case it was delay and pacing that made my app work.

I Don't Know What That Means

While browsing Hacker News I happened upon this post about 5 pre-interview questions to weed out subpar developers. From the article:

Here are the first few questions we ask, and we estimate maybe only 1 in 200 software developer job applicants can give accurate, clear and concise answers to all these questions:

  1. Explain public.
  2. Explain private.
  3. Explain protected.
  4. What is an abstract class?
  5. What is an interface?

Most software developers can fumble out some sort of passably adequate answer to at least two of these questions. Very, very few can give accurate, clear and concise answers to all five questions.

I am the 99%. Not only would I be unable to give clear and concise answers, I wouldn’t be able to answer several at all. That’s ok though because I can learn what these things are, and then I won’t look the fool.

Off to Google!

My first though was “Oh! It’s a Java thing, not a Ruby thing,” but that seemed a little slack in the research department so I adjusted my search. This time I read through a well written blog post on the subject, as well as several stackoverflow posts from equally confused rubyists. One lead me to a Wikipedia article on Duck Typing that was slightly off the original path, but useful and interesting nonetheless. So what’s the point of the story? If you’re going to be serious about learning to code (or learning anything, really) you have to be willing to follow “I don’t know what that means,” with “so I better find out.” Also, thanks to stackoverflow I now know this is a thing.

Development From The Sidelines

At a certain conference last week (which I was fortunate enough to speak at I sat in a meeting of the Sakai technical committee. These are the people who drive Sakai. Not just the deciders but the doers. Being new to developing, it was particularly fascinating to see such a large group, all with different backgrounds, incentives, priorities, and views, come together to have these discussions. Sakai is an open source project, so while anyone can contribute there still has to be some kind of governing body.

The meeting was not brief, but real work got done the entire time. Decisions made and committed to (digital)paper, action items decided on and names attached to them. This was not a feel-good theoretical discussion about software, these were decisions that will likely effect the day to day work of these developers and many others for weeks or months to come.

It was inspiring to listen and learn, and I was very humbled that I was allowed to be a part of the meeting. The welcoming environment was clear from the word go; when I walked in and there were no chairs empty Dr. Chuck immediately said “Grab a chair from next door and come in!” Although I didn’t contribute anything (except a sarcastic fist shake and a smile when Ruby devs were joked about) I learned a lot about what writing software, especially OSS, in a large group is like. There was lively debate, and some people ended up disappointed if their view didn’t win the majority, but everyone still works hard and contributes.