22 Apr 2014

OSG for iPhone

In 2009 I was struggling to manage my lists of todos and goals that had built up over the years. During a long drive home one night my wife and I discussed ways that I could overcome my goal-accomplishing paralysis. Out of that conversation came the idea for One Simple Goal. Excited over the idea, during the next few evenings I quickly built a small and simple app for helping me "manage" the mountains of todo lists I had created for myself.

While the app was helpful at the time to myself and a handful of others, I never really built it into the app with the full set of features I wanted. I often forgot to set a goal for the day, and soon my goals lagged days and months apart, until finally I stopped using the app entirely.

The idea of OSG hadn't grown stale, but the medium wasn't right. The app didn't remind me how to think about the upcoming day and set an appropriate single goal (if one was present). At the time the iPhone was only a few years old and I was daunted by the prospect of learning a new language (Objective-C) and set of libraries (Cocoa Touch, now iOS) to build OSG into a mobile app. So, I let things be, and OSG kind of faded out of my life for a few years.

Since that time I have gained a lot of knowledge and understanding of how to build mobile applications in iOS and Android. Last year the idea popped up that OSG would be a great first time personal app to build. I started building the app last November, and am finally able to announce its release today. You should go download it. :)

If you're new to the OSG way, let me take the time to teach you the fundamentals. It won't take long, I promise.


What OSG is not

  1. OSG is not a new way to prioritize A over B. Should I drop the kids off from school or get the dog's hair cut? As a culture, we tend to wear our busyness as a badge of honor. Turn it inside out and wear your simple life as a badge of honor.
  2. OSG is NOT a tool for helping you build and curate a large list of goals or todo items.
  3. OSG is NOT a tool to tell you what you should not be doing. You should shy away from creating goals that are the opposite of doing, such as "Don't smoke a cigarette today". Focus instead on what you will do.
  4. OSG is NOT an app that you will use every day. I certainly don't. Use it when you are not living as simply as you wish.
  5. OSG is NOT actually a todo-list app, or even a mini todo-list app.

If the above list of missing features annoys you, go download Clear or Wunderlist instead. I've used them, and they really are fantastic apps for what they are built for. But simplicity is NOT their game.


What OSG is

So if OSG doesn't help you organize your todo list, what is it good for? OSG is almost an embarrasingly simple concept. But I believe in simple things, and here's a simple definition of the OSG philosophy:

OSG is a tool designed to help you think clearly about the upcoming day.

When you create a new goal for the day, you're prompted with the fill-in-the-blank statement: "If I accomplish nothing else today, I will...". What is the most important thing you need to accomplish today? If the world falls apart and the dishes stay in the sink and the dog doesn't get his hair cut, what is the one thing you must get done?

In my few years doing OSG on and off, I've found that usually the answer to those questions is the thing I have continued to avoid for days or even weeks. OSG is a tool, a priority scalpel, to get you to be brutally honest about what you should be doing. Forget the complex time schedules, forget the prioritization of 20 items, forget the prioritization of 20 lists.

One item, one goal, one priority. And once you've set your goal for the day, DO IT.

If you fail to accomplish your goal that day, set it tomorrow (assuming it's still the most important thing you need to get done), and take another swing. There is no harm (or shame) in taking a few days to get something done.


So, with happy heart I give you One Simple Goal for iPhone. If it does well enough on the store I'll port it to Android and Windows Phone in a few months. I've already had some great suggestions from friends on ways to improve the app while maintaining its simplistic goals. I'll post more about those things as they take shape.

If you do download the app and find it useful in some small way I would appreciate a kind word on facebook or twitter (@osgapp) to help me spread the word. I am not very interested in pumping this thing up and posting about it on 50 indifferent review sites. I believe products and services flourish due to word of mouth if the user finds them beneficial.

Good luck, and keep it simple.

01 Jul 2011

Binary Search in Ruby, or, "Picking the Right Number, as Quickly as Possible"

So you're writing a parser in C that parses the lines of a file. The line you're parsing is made up of a 40 character key and any number of ip addresses after, space-separated. You need to know a max line length to read (because C is mean like that), but you're not sure how many ip's you can fit on a line for a given key.

Such was my case yesterday and decided to write a mini script in ruby to figure it out. My first stab was to iterate from 1 to 100 and checking the line lengths by literally building a line with x number of ip elements on the line. While the code was correct and produced the necessary information for the given inputs, it was horribly inefficient and so I decided to rewrite it to be smarter. Enter the Binary search algorithm.

Using the binary search algorithm, we take a lower and an upper bound of possible elements and try to quickly guess which number is the highest possible without exceeding the line limit. So here's the concrete data we know. The line format (as described above) will look something like this:

86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 174.18.0.1 174.18.0.2 174.18.0.3 174.18.0.4 174.18.0.5 174.18.0.6

... with theoretically unlimited ips per line. The first value is a key we'll use to store the ips against in a lookup table, but don't worry about that right now. The key is generated using sha1 digesting, so we know it will always be 40 characters. The max length for any given ip address is 15 assuming all 4 blocks are at least valued at 100 (e.g. 100.100.100.100). Space-separating the key and x number of ips and your line length calculation is f(x) = kl + (el*x) + x where x is line length, kl is key length, and el is element length (ip address length). In other words, if we're testing 50 elements on the line, the line length would be 40 + (15*50) + 50 which equals 840 .

Now that we can arbitrarily calculate the length of a line based on the number of ip elements we want to test, we can start "guessing". This isn't guessing at all, we just split our possible range in half and use the middle ground to test the possible length. In other words, if my initial range is 1..100 (read as "anywhere from 1 ip element to 100 ip elements"), then our first test value for x above would be 50, which if you remember produces a line length of 840. I assumed that I'd be okay with a max line length of 1000 characters, and so we assert that if len is less than the max, then we can use the upper half of the range boundary, or 50..100 . If len was more than our max of 1000, we'd take the bottom half, or 1..50 .

Using this technique recursively we can whittle down to the exact number of ip elements that can be inserted on a line before we go over the limit of 1000 characters on the line, which happens to be 60. You know you're done checking when your range is only one element apart, in this case 60..61. With my first solution to iterate up from 1 to 100, this meant we had to check 61 times before we knew we were over the limit. With this new range, we actually only needed 8 iterations! Very cool how "guessing" can solve the problem quite nicely.

require 'digest/sha1'

  @k_len = Digest::SHA1.hexdigest('a').size # 40
  @ip_len = "255.255.255.255".size # 15
  @range = 1..100 # starting range
  @max_line_len = 1000 # length to check against
  @count = 0 # iteration counter

  # Given a upper and lower boundary, determine if its
  # middle value is over or under the given line length
  # If over, use the lower boundary (lower..mid) for a recursive check,
  # otherwise use upper boundary (mid..upper)
  def check_boundary(lower, upper)
    # determine middle value
    mid = lower + ((upper-lower)/2)

    # Exit recursion if we've found the value
    throw(:found_value, mid) if (upper-lower) == 1

    # only increment iter count if we're checking the length
    @count += 1

    # Get the line length for the variable number of elements
    len = @k_len + (@ip_len*mid) + mid

    # Perform the test
    if len > @max_line_len
      puts_stats lower, mid, upper, len, :over
      # use the lower boundary
      check_boundary(lower, mid)
    else
      puts_stats lower, mid, upper, len, :under
      # use the upper boundary
      check_boundary(mid, upper)
    end
  end

  # Log method for values in a given test
  def puts_stats lower, mid, upper, len, over_under
    puts '%10d | %10d | %10d | %10d | %10s' % [lower, mid, upper, len, over_under]
  end

  # Specify some information for readability
  puts 'Determining how many ip elements can sit on a line with a max length of %d' % @max_line_len
  puts

  legend = '%10s | %10s | %10s | %10s | %10s' % %w(lower mid/test upper len over/under)
  puts legend
  puts '-'*legend.size

  # Run the recursive boundary checking
  golden_ticket = catch(:found_value) do
    check_boundary(@range.first, @range.last)
  end

  # Output results

  puts
  puts 'Golden Ticket (under) = %s' % golden_ticket.to_s
  possible_iterations = @range.last-@range.first
  efficiency = @count.to_f / possible_iterations.to_f
  puts '%d iterations for %d possible iterations (%f efficiency)' % [@count, possible_iterations, efficiency]

Running the above script will produce the following output:

Determining how many ip elements can sit on a line with a max length of 1000

  lower | mid/test | upper | len | over/under
  --------------------------------------------------------------
  1 | 50 | 100 | 840 | under
  50 | 75 | 100 | 1240 | over
  50 | 62 | 75 | 1032 | over
  50 | 56 | 62 | 936 | under
  56 | 59 | 62 | 984 | under
  59 | 60 | 62 | 1000 | under
  60 | 61 | 62 | 1016 | over

  Golden Ticket (under) = 60
  8 iterations for 99 possible iterations (0.080808 efficiency)

I'm not really sure if the efficiency part makes sense, but you get a sense that it's a LOT faster, not only because we're calculating the line length per test, but also because we're recursing a fraction of calls that the brute force method performs. It's also fun to inflate/deflate the max line len or the starting range values to see how it affects the number of recursions needed to find the number. For instance, set the max line len to 100000 and see how many extra calls have to be made. Also, what happens if your range isn't big enough? What if the range is off (e.g. 75..100)?

Algorithms are nifty.

01 Jul 2011

Git Pre-receive Hook for Rejecting a Bad Gemfile

Bundler has a cool facility with Gemfile s that allow you to specify some fine-grained options for a given gem beyond specifying a version. Things like :path , :branch , :git , and :tag . All of those things are neat for development, but horrible for production. I wanted a way to reject pushes to a repo if the Gemfile was changed to include any one of those options, and a git pre-receive hook was just the tonic.

#!/usr/bin/env ruby

  BRANCHES = %w( master stable )
  REJECT_OPTIONS = %w( git tag branch path )

  old_sha, new_sha, ref = STDIN.read.split(' ')
  exit 0 unless BRANCHES.include?(ref.split('/').last)
  diff = %x{ git diff-index --cached --name-only #{old_sha} 2> /dev/null }
  diff = diff.split("\n") if diff.is_a?(String)

  if diff.detect{|file| file =~ /^Gemfile$/}
    tree = %x{ git ls-tree --full-name #{new_sha} Gemfile 2> /dev/null }.split(" ")
    contents = %x{ git cat-file blob #{tree[2]} 2> /dev/null }
    invalid_lines = contents.each_line.select do |line|
      line =~ /\b(#{REJECT_OPTIONS.join('|')})\b/
    end

    unless invalid_lines.empty?
      puts
      puts '> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
      puts '> ---- PUSH REJECTED by origin ----'
      puts '>'
      puts "> You've specified an invalid option for #{invalid_lines.size} gem definitions in the Gemfile"
      puts "> Invalid options are: #{REJECT_OPTIONS.join(', ')}"
      puts '>'
      puts "> The offending gems:"
      puts ">\t" + invalid_lines.join(">\t")
      puts '>'
      puts '> To fix:'
      puts ">\t* Remove the offending options"
      puts ">\t* bundle install"
      puts ">\t* Run tests"
      puts ">\t* Ammend previous commit (git add . && git commit --amend)"
      puts ">\t* git push origin #{ref.split('/').last}"
      puts '>'
      puts '> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
      puts
      exit 1
    end
  end

The script above monitors pushes to the "master" and "stable" branches (our development and production lines, respectively). It checks to see if the Gemfile was listed in the new commit file list, then parses the blob of the Gemfile for any of the offending options. Each offending line is then output back to the pushing developer with instructions on how to fix his/her Gemfile and how to amend the commit. Here's what the output looks like:

$ git push origin master
  Counting objects: 5, done.
  Delta compression using up to 8 threads.
  Compressing objects: 100% (3/3), done.
  Writing objects: 100% (3/3), 362 bytes, done.
  Total 3 (delta 0), reused 0 (delta 0)
  Unpacking objects: 100% (3/3), done.
  remote:
  remote: > !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  remote: > ---- PUSH REJECTED by origin ----
  remote: >
  remote: > You\'ve specified an invalid option for 2 gem definitions in the Gemfile
  remote: > Invalid options are: git, tag, branch, path
  remote: >
  remote: > The offending gems:
  remote: > gem 'utilio', :git => 'git@github.com:localshred/utilio.git'
  remote: > gem 'rails', :git => 'git@github.com:rails/rails.git'
  remote: >
  remote: > To fix:
  remote: > * Remove the offending options
  remote: > * bundle install
  remote: > * Run tests
  remote: > * Ammend previous commit (git add . && git commit --amend)
  remote: > * git push origin master
  remote: >
  remote: > !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  remote:

  To git@git.mycompany.com:repo1.git
  ! [remote rejected] master -> master (pre-receive hook declined)
  error: failed to push some refs to 'git@git.mycompany.com:repo1.git'

It's also worth noting that since this is a pre-receive hook, when returning an exit status of anything but 0, git will reject merging the commits. This is good because we don't want "bad code" in our repo. You could also use this to do other checking measures, such as running a CI build or syntax checks.

To use the above hook, simply copy the script above into the ./hooks/pre-receive file in your origin repo. Be sure to chmod +x ./hooks/pre-receive otherwise git won't be able to invoke the script when a new push occurs. We have ~15 repos that I manage at work that I want to use the hook on, so I just kept the file out on the git user's home directory and symlinked it back to each repos hooks directory. Same results, just easier to manage if I need to make a quick change to the hook.

Happy coding.

25 Jan 2011

Thor Script for Managing a Unicorn-driven App

Today I deployed a mini sinatra app on one of our test servers to manage some internal QA. I've put out quite a few apps backed by Unicorn in QA recently and finally wrote a little script to handle stopping, starting, and reloading of the unicorn processes. Nothing super special here, just thought I'd share a useful script. Drop the following code into your application's tasks directory, or place it on the app root and call it Thorfile .

tasks/unicorn.thor (or Thorfile)

# put me in /path/to/app/tasks/unicorn.thor
  require 'thor'

  class UnicornRunner < Thor
    include Thor::Group
    namespace :unicorn

    UNICORN_CONFIG = "/path/to/app/config/unicorn.rb"
    RACKUP_FILE = "/path/to/app/config.ru"
    PID_FILE = "/path/to/app/tmp/application.pid"

    desc 'start', 'Start the application'
    def start
      say 'Starting the application...', :yellow
      `bundle exec unicorn -c #{UNICORN_CONFIG} -E production -D #{RACKUP_FILE}`
      say 'Done', :green
    end

    desc 'stop', 'Stop the application'
    def stop
      say 'Stopping the application...', :yellow
      `kill -QUIT $(cat #{PID_FILE})`
      say 'Done', :green
    end

    desc 'reload', 'Reload the application'
    def reload
      say 'Reloading the application...', :yellow
      `kill -USR2 $(cat #{PID_FILE})`
      say 'done', :green
    end
  end

Usage

From your application root directory, run any of the three commands. Keep in mind you'll need a unicorn config file that actually dictates how Unicorn should behave (like number of workers, where your logs go, etc). You'll also need a Rackup file ( config.ru ) which tells unicorn how to run your app.

$ thor -T
  $ thor unicorn:start Start the application
  $ thor unicorn:stop Stop the application
  $ thor unicorn:reload Reload the application
  $ thor unicorn:start # starts the unicorn master
  $ thor unicorn:stop # sends the QUIT signal to master (graceful shutdown)
  $ thor unicorn:reload # sends the USR2 signal to master (graceful reload of child workers)

Plop this puppy behind nginx and you're golden. Thor has a lot more things you could do with this (like overriding which config file to use) by providing method-level options, but this is a great starting point for most people. Leave a comment if you have any improvements or other ways you handle this.

07 Jan 2011

Mapping Object Values With Ruby's Ampersand-symbol Technique

Discovered another little Ruby nugget the other day. The nugget gives a shorter syntax when you want to map the return value of a message sent to a list of objects, say, the name of the class of the object. In the past I would use Array#map to produce the list with something like:

objects = [1, :number_1, "1"]
  classes = objects.map { |o| o.class }
  classes.inspect
  # => [Fixnum, Symbol, String]

Turns out that Ruby has a shortcut that shortens your keystrokes a bit:

objects = [1, :number_1, "1"]
  classes = objects.map(&:class)
  classes.inspect
  # => [Fixnum, Symbol, String]

The two snippets are functionally identical. By passing a symbol to map preceded by an ampersand, Ruby will call Symbol#to_proc on the passed symbol (e.g. :class.to_proc ), which returns a proc object like {|o| o.class } . Where would you use this you ask? The day I learned this little ditty I was writing some tests that were verifying some active record associations. Whenever I needed to update values on a has_many collection for a particular model, I actually needed to assert that the associated collection of objects were rebuilt with the new values, deleting the old rows and recreating new ones. The ampersand-symbol technique above was nice for this.

describe Father do
    it 'should create new children when I attempt to update the children' do
      father = Factory(:father)
      orig_children = father.children.map(&:id)
      # perform the update method
      father.reload
      father.children.map(&:id).should\_not == orig\_children
    end
  end

So I thought I'd pass the word on. Cool stuff in Ruby. Who knew?