Estimation: Planning for the Unknown

For any developer—regardless of seniority—estimating the time you think a development task or project will take can be a daunting task. I was reminded of this again recently after I read software engineer @jaimeohm's heavily re-tweeted tweet about what makes "us coders" special: "We are expected to know how to do things we've never done before and estimate how long they will take." Where seniority becomes a factor is having more experience and being able to more accurately guess how long a thing will take. Of course, this isn't an issue unique to software engineering, but the problem is that people without this experience (CEOs, Project Managers, n00bs, et al [I'm generalizing here]) often just think that a coding task is just opening up a text editor and putting some text in there. It's never quite that simple: It's thinking about scale, maintenance, communicating with teams and clients, installing software, setting up environments, research, discussion with designers, user experience—all that comes with creating a product. In short, you need to estimate for the entire project and not just the "writing code" part of it.

With this in mind, it's important to not only pad your time estimates a bit, but also communicate immediately with your team or managers when a task is proving more difficult than estimated, i.e. you estimated incorrectly. You cannot worry about this effect; it will happen. You should plan for it to happen and managers should not get upset when an estimate falls short. Once you're actually working on the task, the absolute worst thing you can do is to sit frustrated with a bug or issue and not enlist the help of fellow team members or keep your team aware that you are stagnating. We all know the experience of spending hours on a tricky problem, only to solve it in 5 minutes with a fresh pair of eyes after a good night's sleep. Having a buddy take a look at your problem can often solve that immediately. Ask questions; lots of them. Absorb everyone around you's knowledge. If someone knows about a library you've been asked to use, ask them for tips. Typically, most developers understand the pain and will happy to help you estimate (seriously, hit me up on AIM any time if you want to chat).

Now, padding time might sound like a negative thing (especially to your clients), but, in the end, you're setting a budget expectation, so when you do end up completing that feature more quickly than expected, your producer is happy, your client is happy and you've potentially made your company some profit. Don't forget than some features will take longer than expected so now you may have time to work on another feature that you underestimated or add that really kick-ass feature to surprise and delight your team and client.

I thought I'd share a recent example of how coding projects are often less about code and more about the things you don't estimate and the things most people don't see. Below you'll find a sample from a project log I wrote during the development of a Ruby on Rails application. I had done some Rails when it was version ~0.9, but had not touched it in it's modern incarnation (which was 3.0.9 when this was written), so I was basically starting from scratch. For the budget, I estimated based on the time that something like this would have taken me to produce in PHP (the language I use the most frequently) and added a bit of extra time for the unknown. You can see in this log that 90% of the work I'm doing has absolutely nothing to do with writing the code. I of course didn't expect to run into *any* of the issues in the log since I had never done it before, but now with this experience, I know to factor in some extra time to get my environments all ready to actually get to the "writing code" stage or I can estimate lower since I know how it works now.

Day 1

Going to be building an API using Ruby on Rails and deploying it on Heroku. First I’ve established that Heroku uses PostgreSQL, not MySQL, but shouldn’t be a big deal because of Rails’ database abstraction capabilities. Locally, I'm going to be lazy and use the MySQL installation provided by MAMP. Let’s get started.

First start updating Ruby gems.

gem update --system

Then I updated my system’s gems:

gem update

Rails was updated to version 3.0.9. Next created a rails app:

rails new app --database=mysql

Next installed the rails bundle:

bundle install

Hmm, failed hard. Needed to install mysql2 gem to make this work, but this didn’t work:

sudo gem install mysql2

Ok, so tried with explicitly setting the path to mysql_config:

gem install mysql2 -- --with-mysql-config=/Applications/MAMP/Library/bin/mysql_config

No dice. Forgot that the default MAMP install doesn’t have MySQL’s header files, so this won’t work. Decided to install a fresh copy of MySQL to do this instead. Used Homebrew to install it. Thankfully I’ve already got the Xcode developer tools (which Homebrew requires) so I don’t have to spend 4 hours downloading and installing those).

brew install mysql

OK, that took about 15 minutes. MySQL is installed in

/usr/local/Cellar/mysql/5.5.14

So let’s try this again:

gem install mysql2 -- --with-mysql-config=/usr/local/Cellar/mysql/5.5.14/bin/mysql_config
Building native extensions.  This could take a while...
Successfully installed mysql2-0.3.6
1 gem installed

Boom, hell yeah. Let’s try this install again inside the rails project:

bundle install

Everything’s installed. Fantastic. Edited my database configuration and tried

rake db:create

No dice. Better add the path to the UNIX Socket to the config to both development and test configurations:

socket: /Applications/MAMP/tmp/mysql/mysql.sock

Now db:create works and I’ve got two databases.

Starts writing code...

Day 2

After some time doing research on MongoDB and document-based databases in general, I've decided to offload some of the writing tasks for this project to a database on MongoHQ. So I'm going to install Mongo locally first.

brew install mongodb

Well, that was easy.

Added mongoid to my gemfile:

gem 'bson_ext', '~> 1.3'
gem 'mongoid', '~> 2.1'

bundle install to get up to date

then rails task to generate a config file:

rails generate mongoid:config

Writing code...

Day 3

I wanted to use bigints for some of my records, so after researching how Rails defines the default field types in databases. I added this to config/environment.rb as a new database type:

require 'active_record/connection_adapters/mysql2_adapter'
require 'active_record/connection_adapters/postgresql_adapter'

ActiveRecord::ConnectionAdapters::Mysql2Adapter::NATIVE_DATABASE_TYPES[:big_primary_key] = "BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY".freeze
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::NATIVE_DATABASE_TYPES[:big_primary_key] = "bigserial primary key".freeze

Added a few config items to config/application.rb to get ORM rake tasks working after installing Mongoid:

# In order to properly set up single collection inheritance,
# Mongoid needs to preload all models before every request in development mode.
config.mongoid.preload_models = true if Rails.env.development?

# mongoid has overridden activerecord as the default orm so any attempts
# to generate migrations or ActiveRecord models will fail. Therefore we
# must configure our default generators so we can still use activerecord.
config.generators do |g|
  g.orm :active_record
end

Today I installed haml gem and set up the front end of the site. Super easy and HAML is pretty amazing! Only took about an hour. Researched how to create custom rake tasks and made this frivolous task in lib/tasks/database.rake:

namespace :db do

  desc 'Drop and recreate the database and reseed it.'
  task :reboot => [:drop, :create, :migrate, :seed] do
    puts 'Database rebooted.'
  end

  desc 'Recreate the database with a blank slate.'
  task :clean => [:drop, :create, :migrate] do
    puts 'Database cleaned.'
  end

end


How do you estimate? Let's talk about it on Twitter @typeoneerror.

November 6th, 2011 | Permalink

Easy Translation of Wordpress Admin Texts

Taking a break from iOS development to work on some front-end development on a Wordpress site. Now that Wordpress 3.2 has a pretty badass custom post-type system, it's much easier to create custom admin elements and it makes it a logical CMS choice for many projects. To contribute to making a more customized user experience for a client, I wanted to change some existing texts in the admin tool, but not make a whole language file with .mo and .pot files and all that (no thanks). Here's how this is accomplished.

First in your template's functions.php, make sure we're in the admin context with is_admin. We then load an .ini file that'll contain all our custom translations:

if (is_admin())
{
    $translations = parse_ini_file(dirname(__FILE__) . '/translations.ini');
    function my_gettext($translation, $text, $domain)
    {
        global $translations;
        if (isset($translations[$text]))
        {
            return $translations[$text];
        }
        return $translation;
    }
    add_filter('gettext', 'my_gettext', null, 3);
}

my_gettext will be called whenever Wordpress asked for translated text with the __() helper. If the original text is set in the .ini file as a key, it'll instead return our defined text. And here's how that file looks:

; translations.ini
; Old text=New text
Featured Image=Thumbnail
Remove featured image=Remove thumbnail

In this case, when Wordpress requests the string 'Featured Image', 'Thumbnail' will be displayed instead. That's it. 

Special thanks to Soulseekah on the Wordpress Stackexchange for the assist on simple translations.

October 18th, 2011 | Permalink

Liquid Hacynth Vol 26

Lots of great music from Marky and S.P.Y. (who've been tearing it up lately) on this month's mix.

Liquid Hacynth Vol 26

  1. Feeling Inside - Big Bud
  2. Without You - Marky, Makoto
  3. Mystic Sunset - Marky, SPY
  4. Run! - Syncopix
  5. Who Can Say? - Tali, Lynx, Drs, Malibu Rhodes
  6. Solar 9 - Redeyes Sinistarr
  7. Bossa Nouveau - Hybris
  8. Movin Fast - Enei
  9. Hidden Smile - Paul SG
  10. Days Go Slow feat. Miri [Makoto remix] - Marky, SPY
  11. Lincoln Place - Kjell
  12. Heaven Sent - Syncopix
  13. Brainstorm - Marky, SPY
  14. When I Remember - Cutworks
  15. Lover's Groove (feat. Adisa) - Mr.abstract
  16. Hasat - Ali Sural


As always, enjoy the ride and make sure to follow on Twitter if you want more music.

→ Download Liquid Hacynth Vol 26 from Dropbox

August 15th, 2011 | Permalink

Tutorial: Rails with Rspec, Spork and Guard From Scratch

Getting set up to test a Rails app with Rspec is relatively straightforward. One of the troubles is the length of time it takes for the tests to run when issuing either the rspec spec or rake spec commands from the command line. My current tests for example take about ¡16 seconds! to complete. Also, who wants to switch back to the command line to run the tests. What if we could automating the tests and speed them up at the same time? Enter Guard and Spork.

Guard is a command line tool that, when running, responds to events when files are modified. We can start Guard and have it observe certain files for changes, then run the Rspec commands in response. Using Spork, we can in effect pre-load the Rails environment into the Spork test server. Spork manages a pool of test processes for you so each test is clean (but fast because of the pre-load).

You can add these items to your existing rails app, but I’m going to take us through doing this from scratch (mainly so I can have documentation for this myself for future apps!).

Get Started

I’ve created a demo app to go along with this article. You can grab it on github at https://github.com/typeoneerror/Guard-Spork-Demo or create your own.

Start by creating a Rails project and moving into it:

$ rails new guard-spork
$ cd guard-spork

We only need a handful of gems and a config file or two to get this going. Let’s start by editing our Gemfile to add Rspec for Rails and Spork (this file shown with the initial comments removed):

source 'http://rubygems.org'

gem 'rails', '3.0.9'

gem 'sqlite3'

group :development, :test do
  # Rspec
  gem 'rspec-rails', '~> 2.6'

  # Spork
  gem 'spork'
end

Add the gems to your Gemfile and then run

bundle install

The ~> syntax is an interesting one. Essentially, this is equivalent to >= 2.6 AND < 2.7. So it’ll install the latest version of the 2.6 (so 2.6.5 would install if that was the latest, but it would not update to 2.7).

Anyway, now that the gems are installed, we need to bootstrap Rspec. Command line again:

$ rails generate rspec:install
      create  .rspec
      create  spec
      create  spec/spec_helper.rb

I then add the following snippet to config/application.rb to tell the Rails app to use Rspec as my test generator:

config.generators do |g|
  g.test_framework :rspec
end

Running rake -T spec at this point should display a series of rake task for rspec. You can skip the rake way of doing it and use Rspec directly though. Let’s create a sample model to test.

$ rails g model Article title:string
      invoke  active_record
      create    db/migrate/20110814231432_create_articles.rb
      create    app/models/article.rb
      invoke    rspec
      create      spec/models/article_spec.rb

Note that it generated (g is an alias for generate) the model, a database migration and automatically added a spec for testing that model. Neat!

Let’s create our database (sqlite3 since we’re just doing a demo which is the default Rails database):

$ rake db:migrate
==  CreateArticles: migrating ================
-- create_table(:articles)
   -> 0.0011s
==  CreateArticles: migrated (0.0012s) =======

Great, we’ve got our initial database. Let’s add a simple validation for that model:

# app/models/article.rb
class Article < ActiveRecord::Base
  validates :title, :presence => true
end

Just for example’s sake, let’s add two simple (and largely pointless) tests to our spec in spec/models/article_spec.rb:

require 'spec_helper'

describe Article do

  it 'should test some silly thing that will pass' do
    @article = Article.new(:title => 'The Title')
    @article.should be_valid
  end

  it 'should test some silly thing that will fail' do
    @article = Article.new
    @article.should be_valid
  end

end

Now you can run

$ rpsec spec

to test your app (this will run all your specs). Even with just these ridiculously simple tests, we can run

$ time rpsec spec
real    0m3.017s

and this thing is taking 3 seconds already! Imagine what happens when you’ve got hundreds of tests.

Spork

So let’s see what Spork can do for us. Start by bootstrapping Spork from the command line:

$ spork --bootstrap
...
Using RSpec
Bootstrapping spec/spec_helper.rb.
Done. Edit spec/spec_helper.rb now with your favorite text editor and follow the instructions.

Looks like we should edit spec/spec_helper.rb with our favorite text editor. Spork added a few blocks. In summary, anything in the Spork.prefork block gets pre-loaded and anything in the Spork.each_run block will be done on each test run.

I’m basically going to grab everything that was previously in this file (the Rspec stuff that should not be towards the bottom of this file) and drop it into the prefork block:

require 'rubygems'
require 'spork'

Spork.prefork do

  # This file is copied to spec/ when you run 'rails generate rspec:install'
  ENV["RAILS_ENV"] ||= 'test'
  require File.expand_path("../../config/environment", __FILE__)
  require 'rspec/rails'

  # Requires supporting ruby files with custom matchers and macros, etc,
  # in spec/support/ and its subdirectories.
  Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}

  RSpec.configure do |config|
    # Mock Framework
    config.mock_with :rspec

    # If you're not using ActiveRecord, or you'd prefer not to run each of your
    # examples within a transaction, remove the following line or assign false
    # instead of true.
    config.use_transactional_fixtures = true
  end

end

Spork.each_run do
  # This code will be run each time you run your specs.
end

We’re also going to set up Rspec to use Spork DRB server. Open up .rspec and add the following:

--colour
--drb
--format documentation

Next start Spork in a new Terminal window (in your project directory):

$ spork
...
Using RSpec
Loading Spork.prefork block...
Spork is ready and listening on 8989!

Basically, now we’ve got Spork DRB running and now when we run Rspec, it’s configured to use the running DRB server. With Spork running, switch back to your project and run Rspec again:

$ time rspec spec
real    0m0.499s

Wow. We’ve basically decreased our test runtime by ~85%. You can just leave Spork running until you’re finished working then send it a ^C command to quit.

Should we take a break? Nah, let’s get this testing thing automated so we can take more breaks. A lazy developer is a good developer, right?

Guard

Next, let’s add Guard and some of its really cool “extensions” that allow us to “guard” (or watch and respond to changes in) resources. Edit your Gemfile (this is where our Gemfile starts to get kinda wordy):

source 'http://rubygems.org'

gem 'rails', '3.0.9'

gem 'sqlite3'

group :development, :test do
  # Rspec
  gem 'rspec-rails', '~> 2.6'

  # Spork
  gem 'spork'

  # Guard
  gem 'growl'
  gem 'rb-fsevent', :require => false if RUBY_PLATFORM =~ /darwin/i
  gem 'guard-bundler'
  gem 'guard-rspec'
  gem 'guard-spork'
end

Taking a look at our Guard includes now, you can see I’ve added guard-rspec. This gem bundles guard as a dependency, so there’s no need to include the guard gem itself. I’ve also included the “guards” for bundler and spork. rb-fsevent is required to respond to changes in a directory tree. Keep in mind, this is how to do this on Mac OSX, so if you need a different platform, the install instructions for Windows and Linux on Github are quite straightforward.

Growl can be added as well if you want to show Growl messages when your tests finish running. I find this pretty useful, but a lot of people can’t stand Growl. Keep in mind you have to install the growlnotify extra from the Growl .dmg for this gem to work. Note that it took me awhile to get growl going. guard-rpsec notes using the growl gem and guard recently changed this to growl_notify, so it seems pretty volatile. Growl seems to work great if you’re just running the Rspec guard, but I haven’t been able to get it to notify me when running Rspec through Spork. Please message me on Twitter if you have a way of doing this.

Back to command line; let’s install the next set of gems:

$ bundle install

Next generate a Guardfile via the command:

$ guard init
Writing new Guardfile to guard-spork/Guardfile

Staring guard is easy, but first we have to create some guards in our Guardfile. Here’s a starter file for you that I am using:

guard 'spork', :cucumber => false, :test_unit => false do

  watch('config/application.rb')
  watch('config/environment.rb')
  watch(%r{^config/environments/.+.rb$})
  watch(%r{^config/initializers/.+.rb$})
  watch('spec/spec_helper.rb')

end


guard 'bundler' do

  watch('Gemfile')
  # Uncomment next line if Gemfile contain `gemspec' command
  # watch(/^.+.gemspec/)

end


guard 'rspec' do

  watch(%r{^spec/.+_spec.rb$})
  watch(%r{^app/(.+).rb$})                           { |m| "spec/#{m[1]}_spec.rb" }
  watch(%r{^lib/(.+).rb$})                           { |m| "spec/lib/#{m[1]}_spec.rb" }
  watch(%r{^spec/factories/(.+).rb$})                { "spec" }
  watch(%r{^spec/models/.+.rb$})                     { "spec/models" }
  watch(%r{^spec/routing/.+.rb$})                    { "spec/routing" }

  watch('spec/spec_helper.rb')                        { "spec" }
  watch('config/routes.rb')                           { "spec/routing" }
  watch('app/controllers/application_controller.rb')  { "spec/controllers" }

end

The above configures each guard (remember we installed the -rspec, -spork and -bundler guard gems?) to watch certain files (by path or regular expression matching) and perform actions when those files change. For example, in our Rspec guard, we’re watching spec/spec_helper.rb and when it changes “spec” is going to be called. So basically, save a spec and your tests will be run automatically.

The bundler guard file watches your Gemfile for changes and bundle install’s when it is saved. And now the Spork server is restarted any time we make configuration file changes. Guard even starts Spork for us so we no longer have to issue the spork command at the command line, just:

$ guard
...
Using RSpec
Loading Spork.prefork block...
Spork is ready and listening on 8989!
Spork server for RSpec successfully started
...
Refresh bundle
Your bundle is complete!
...
Guard::RSpec is running, with RSpec 2!
Running all specs
...
Finished in 0.10119 seconds
2 examples, 1 failure

So there you have it; guard is running, listening for changes and Spork has started and has our Rspec/Rails stuff pre-loaded. If you go an edit spec/models/article_spec.rb now…

require 'spec_helper'

describe Article do

  it 'should test some silly thing that will pass' do
    @article = Article.new(:title => 'The Title')
    @article.should be_valid
  end

  it 'should test some silly thing that will now pass' do
    @article = Article.new
    @article.should_not be_valid
  end

end

…guard will note the changes and run spec to run your tests. Everything should now pass.

So there you have it. Your tests should now run pretty damn fast. Full disclosure, this is my first time working with Rails and gems so I may have done some things somewhat ass-backwards. I’d appreciate any comments you might have to that effect on my Twitter account. Please don’t hesitate to send me feedback there.

August 14th, 2011 | Permalink

Relative Image Links in Wordpress Uploader

Wordpress has a very sophisticated image uploader that allows you to insert images directly into your post. It inserts images with an absolute path, including the full path to your image as an absolute link. My guess is this is for SEO and theming purposes, but if you're just building a one-off site using Wordpress as your platform, you might want to have a relative URL in there instead, i.e.:

/wp-content/uploads/2011/07/image.jpg

instead of:

http://yoursite.com/wp-content/uploads/2011/07/image.jpg

Relative attachment URLs would be useful if you were working locally at a dev domain or localhost or if you moved the website to a different server. Forcing Wordpress to insert a relative link into the database is pretty simple; you can do this by hooking a filter on the wp_handle_upload method:

function yoursite_get_relative_attachment_path($path)
{
    $paths = (object)parse_url($path);
    return $paths->path;
}

function yoursite_wp_handle_upload($info)
{
    $info['url'] = yoursite_get_relative_attachment_path($info['url']);
    return $info;
}
add_filter('wp_handle_upload', 'yoursite_wp_handle_upload');

This filter method receives the info about the upload which will be saved in the database after the upload completes. You parse the URL of the image and grab just the relative path and send it back. Your image's path in the database will now be relative to the root of your site.

That's great, but Wordpress still inserts the full site path on the front end and when you use the "Insert Image" button when writing your post. Easy fix:

function yoursite_wp_get_attachment_url($url)
{
    return yoursite_get_relative_attachment_path($url);
}
add_filter('wp_get_attachment_url', 'yoursite_wp_get_attachment_url');

By attaching another relative URL filter to the wp_get_attachment_url filter, anywhere where Wordpress requests an attachment URL will return the path relative to the root.

I haven't tested this too much with the rest of the platform, but it seems to work well so far for me. I typically create custom one-off sites with Wordpress, so I'm not super concerned with creating reusable themes.

Here's the final snippet that you'd add to functions.php. You'd just replace yoursite with your site's namespace.

function yoursite_get_relative_attachment_path($path)
{
    $paths = (object)parse_url($path);
    return $paths->path;
}

function yoursite_wp_handle_upload($info)
{
    $info['url'] = yoursite_get_relative_attachment_path($info['url']);
    return $info;
}
add_filter('wp_handle_upload', 'yoursite_wp_handle_upload');

function yoursite_wp_get_attachment_url($url)
{
    return yoursite_get_relative_attachment_path($url);
}
add_filter('wp_get_attachment_url', 'yoursite_wp_get_attachment_url');
July 6th, 2011 | Permalink
prev 1 2 3 4 5 6 7 8 9 10 next