derwiki

Dec 31 2011

Setting yourself up to achieve New Year’s resolutions

It’s that time of year again — the time to trick yourself into setting a new year’s resolution that you already know you have a good chance of not seeing through. And let’s face it: it’s probably a hard resolution for you to achieve.  If not, you wouldn’t be selecting it for a new year’s resolution. While it’s entirely true that you don’t have to rely on new year’s resolutions for self improvement, you can use the opportunity to set a very clear goal to achieve over the next 365 days.

While it’s easy to focus on just one new year’s resolution, there are drawbacks. If you’re too ambitious, you’re setting yourself up to fail at your one resolution. On the other hand, it’s easy to sell yourself short with a resolution that’s not putting you a little outside of your comfort zone. This year, I’ve come up with seven resolutions with various degrees of impact and difficulty. 

Starting with the most important resolution, I’ll add the next resolution every two weeks until I’ve tried incorporating all of them into my life. This will be less overwhelming than seven resolutions at once, and will allow for a two week acclimation period per resolution. After the initial two week period, I can decide if the resolution is worth continuing.

If this sounds interesting to you, I encourage you to try it! I’m including my list of resolutions to help you brainstorm. Feel free to steal! They are:

Minimize possessions
Pro: A less cluttered life is a more focused life.
Pro: Easy to quantify “in vs out” flow.
Con: Could get rid of something actually important in a haste to get rid of something.
Con: Could encourage “hoarding” items to get rid of one at a time instead of large groups.
Thoughts: Practice as “get rid of something when I get something.” Some sort of document or simple web app to track new things and things I’ve gotten rid of. Create a staging area and purge items once a week.
Metric: New items are +1 points, getting rid of items is -1 points. Achieve 0.  Don’t count disposable things like food or bathroom supplies.

“Six-pack abs” (or similar exercise related goal)
Pro: It’s only going to go downhill as I get older, start from as far uphill as possible
Con: Very easy to give up, daily progress hard to monitor
Thoughts: It’s easier to monitor input (X sit-ups) versus output — track that instead. Gadgets or web sites could help make it exciting, just like the Kindle did with reading.
Metric: Empty stomach waist measurements or some sort of timed holding, “how long can you hang from a bar and keep your abs tensed”

Have a conversation with a stranger every day
Pro: Forces conversation with a more diverse group of people
Con: Might be less rewarding if it ends up feeling forced
Thoughts: Could be as simple as small talk with the person at the market.
Metric: Binary, dead simple. Start day with a coin in the right pocket and move it to the left after having a conversation with a stranger (hat tip to the Boy Scout “Do a Good Turn Daily” mnemonic)

Perform daily reflection, no matter how short
Pro: Reflection leads to deliberate practice and inevitably self improvement
Con: Easy to not do on leisure/vacation days
Thoughts: Should be easy to input/record from a phone or a computer — and should also be easy to backfill from written down reflection if unable to input on phone or computer.
Metric: Binary again. No day should be empty.

Blog more
Pro: More thought is required to write about something than to read about it
Pro: Blogs for Causes could help with technical recruiting
Pro: Potential income from Amazon Affiliate program
Pro: Popular articles are rewarding
Con: Unpopular articles are a bummer
Con: Time sink potential
Thoughts: This document is in itself a blog post. And I’ve found it useful. Keep a list of topics to write about and pick the best one each week.
Metric: At least one blog post per week.

Deliberately practice one Vim tip of the week
Pro: Compounding efficiency gains — continually do more in less time
Pro: Good fodder for “Blog More”
Thoughts: Knowing ones tools well is the mark of a master craftsmen and programming is a craft. Could expand to Vim plugins after core functionality. Add dry-erase trim sticker around laptop monitor so I can write the TOTW in the laptop screen border.
Metric: This will be a littler harder to measure. A tip for each week can be recorded (or blogged about), but measuring how much I actually use it will be harder. There might be a way to extract command use frequency from Vim.

Use Gmail labels better
Pro: A little more organization up front pays in dividends for
Con: Could easily go over the top
Thoughts: Set a maximum of two labels, only allow more as an exception
Metric: For a given week, divide the number of received messages by the number of labels. This seems a bit tenuous as a metric.

Not all resolutions are made equal in terms of difficulty, payoff, or ease of tracking. Even the most well intentioned resolution can fizzle if you don’t have a reasonable way to track your progress. If you follow a two week implementation cycle like I’m going to, it makes sense to start with the “lowest hanging fruit” goals — if for no other reason than to build momentum. My prioritized list is:

  1. Blog more
  2. Perform daily reflection
  3. Conversations with strangers
  4. Minimize possessions
  5. Six-pack abs
  6. Deliberate Vim practice
  7. Gmail labels

Being the computer nerd that I am, I plan to track my progress in a git repository that I keep on Github. This makes my promise public, which is a strong motivating factor for me. This can be as little as a sentence (e.g. did 30 sit-ups) or as long as a few paragraphs (i.e. self reflection). I plan to store the data in YAML so that it will be easy to calculate simple metrics.

This project is somewhat inspired by an earlier blog post I wrote about making daily progress toward personal productivity. While a good idea (I’ve ended up with a super helpful base set of productivity gains that I can easily clone onto a new computer), my goal of one commit a day was a bit ambitious. It turns out some days, I use the tools I’ve written effectively and don’t need to come up with new ones.

Thanks to Sajan and Josh for reading drafts of this post.

Comments (View)
Nov 07 2011

Testing Bulk Mailers in Rails

Building large email systems is a little different than other systems because the #1 priority is that you don’t accidentally send out emails. At the same time, you still need to profile and test it like you would any large scale system to look for flaws or bottlenecks. It’s very helpful to build in hooks to override certain aspects of delivering a campaign. Let’s start with a basic code snippet that sends an email campaign:

def deliver_all(users)
  users.each {|user| deliver user.email}
end

The first thing you’ll want to do is try out this method — but user shouldn’t receive an email. We can improve deliver_all with an options hash that takes an optional email override:

def deliver_all(users, options={})
  users.each {|user| deliver options.fetch(:email_override, user.email)}
end

This gets us two things. First, you can pass in {:email_override => nil} and have your mailer bail just before sending if the recipient is nil. You can also pass in your own email address to test that the email shows up in your inbox and looks correctly. But, if you have a lot of users, you might end up with a lot of email. deliver_all can be improved again with an optional limit:

def deliver_all(users, options={})
  (options[:limit].nil? users : users.first(options[:limit]).each do |user|
    deliver options.fetch(:email_override, user.email)
  end
end

We use the conditional on options[:limit] to .each over the entire list or just the first options[:limit] number:

deliver_all(users, :email_override => ‘user@example.org’, :limit => 1)

If you’re delivering emails asynchronously, it can be hard to tell if a bug is in the email itself or just the asynchronous deliver mechanism. It’s best to eliminate async sending as a failure point as early as you can, and we can improve deliver_all to quickly switch between the two:

def deliver_all(users, options={})
  (options[:limit].nil? users : users.first(options[:limit]).each do |user|
    deliver_method = options[:sync] ? :deliver : :deliver_async
    send deliver_method, options.fetch(:email_override, user.email)
  end
end

Based on the value of options[:async], we switch between two different delivery methods. An end to end test that sends one email synchronously to an email address you specify is as simple as:

deliver_all(users, :email_override => ‘user@example.org’, :limit => 1, :sync => true)

and calling it for real to actually send to your users would still be:

deliver_all(users)

Let’s look at another way you might have solved this problem:

def deliver_all(users, options={})
  if options[:limit]
    users.first(options[:limit]).each do |user|
      email = options.fetch(:email_override, user.email)
      if options[:sync]
        deliver email
      else
        deliver_async email
      end
    end
  else
    users.each do |user|
      email = options.fetch(:email_override, user.email)
      if options[:sync]
        deliver email
      else
        deliver_async email
      end
    end
  end
end

Other than not being DRY, this seems like a reasonable approach. However, using the same ‘test’ and ‘production’ methods end up going down two completely different code paths. Setting a :limit takes you down the first if-branch and setting :sync takes you down another if-branch. It’s entirely possible that the (:limit, :sync) code path is bug free, but the `production` code path could still be hiding bugs because its code path is not exercised. Because of this, it’s important that the hooks you build in for testing the campaign use as many of the same code paths as the production call would use. In the example above, you’d most likely be iterating and testing using the (:limit, :sync) code path and just be diligent that anything you fix in the test branch also gets fixed in the production branch. That ends up being extra information to juggle in your head as you’re building, and it’s easier to just eliminate that as a source of problems.

Comments (View)
Oct 12 2011

Hitting the ground running: A Python programmer builds a 1-day Rails 3.1 app

About 6 months ago, I moved from Pythonland to the “magic” of Rails land. I use quotes because I think Rails is “magic” in both good and bad ways. The last 6 months have been a bit of a programotional rollercoaster. I was neutral in the beginning until I discovered 1.month.ago. It was beautiful. The elegance of the Rails way over the Pythonic way was all I talked about for weeks.

But then I got bit by the drastically dynamic nature of Rails. Coming from Pythonland (and C before that, and Java before that), I had learned that you could always walk up a line of function calls and imports to determine what was being called and what was going on — until I found out with a kick to the pants about :after_create filters, and all their heathen brethren. I still don’t like them; I appreciate their power, but I think I think dynamic programming quickly makes for hard to follow code.

Then I started appreciating Rails for what it is: a language that’s optimized for programmer performance and not program execution time. It absolutely produces slow code, at the virtual machine level and in how libraries like ActiveRecord were implemented (FWIW, I think ORM is very hard and I do appreciate what ActiveRecord has done to make simple things quick and reliable).

When I began Rails, I had jumped right into a Rails project at a new job. I didn’t give myself a chance to try to learn the full stack because we use a moderately old version of Rails. I just dove in, asking when I couldn’t get things to work and asking for code reviews when I thought I had things working. As a result, I had never began a Rails project from scratch — only contributed to an existing codebase. I had bought just10cards.com on a whim a few months earlier, an idea to make a microsite that made it really quick and easy to create business cards, and the 6 hours I needed to kill before my flight seemed like a good opportunity to try building it in Rails.

Installing Rails.This was frustrating on my Macbook and only a little better on my Linux server. Ruby iterates a lot and quickly — which is great, but makes it really hard to keep compatible versions straight. The Ruby community responded with bundler to keep Gem files (packages) in sync and RVM (Ruby Version Manager) to keep Ruby versions in order. These are great tools, but I still think it’s an added layer of complexity to worry about. I had problems installing both RVM and bundler on my laptop (Ruby compilation issues, issues with bundler forgetting settings), and those are problems I never had with Python. However, I realize that I’m also new to these tools, and if I had as deep a knowledge in them as I did in git, I’m sure I’d just figure out the power of them and use them right. In any case, it’s still a little annoying to get a basic setup finished and working.

Building the app.This was fantastically quick and easy to build — I spent 2 hour and 4 hour sessions building and polishing my app. I didn’t end up using ActiveRecord at all; the site was a default controller (/) that requested (/cards) and passed data over GET. The CSS is actually a SASS template that gets compiled into a static asset, but CSS is perfectly valid SASS. CoffeeScript was different. I accidentally put JavaScript in there and it promptly yelled at me. Overall, I thought the entire static asset system was a little overkill. I appreciate what it can do for bigger sites, but adding a build step so early into a project’s life is a little cumbersome. script/generate is fantastic though, and templating is really where Rails can produce some very clean looking code. It’s so customized for web programming that most common actions are very terse. I still prefer Python as a general purpose language, but Ruby on Rails is a better solution for web development.

Deploying the app.One of the reasons I wanted to build this project was to play with Heroku for deploying apps. All of my previous side projects have suffered from screen purgatory, where they run in the foreground in a screen session on my server, and when they go down, I completely forget to bring them back up. Setting up Heroku was pretty straightforward, but required some fiddling to get Postgres support running go for production (a requirement for Heroku, but not something I was doing in development — I didn’t see any easy way to disable it completely). After some other initial frustrations (completely user error, and fully documented on their web site), I got my deployment working. And that was it; it’s just worked ever since. I know that’s a boring story, but that’s exactly what you want in a deployment process to a dedicated web server.

Watching the app.After building it, I “launched” it — I posted it to Twitter, Hacker News, and used $100 worth of Google AdWords (thank you free mailer from Google!). I had Google Analytics set up, but it was also nice to tail the log from Heroku to just get a feel for how busy the site was at its peak popularity. This would have been nicer had the log files been on a server I had ssh access to though; getting the logs from Heroku meant the overhead of starting Rails to get them (there’s probably a better way to do this, but this was the first solution I found when I Googled it).

Overall, I think building Rails projects and deploying to Heroku is a lot easier than working with something like Bottle for Python and deploying to Google App Engine. Python is great for a lot of things, including both web development and heavy data crunching — but Rails is great for web development. At my last job at a Python shop, we spent a lot of time discussing the merits of Python, its syntax, and how to correctly use it. At my current job, Rails makes it easy enough that those conversations aren’t worth having, and instead it gives us an opportunity to focus on code quality and improving the engineering process — which is a fantastic opportunity to have.

Comments (View)