Dev Series #1

Beginning Rake Tips

Welcome to Dev Series #1.

Related resources: https://github.com/shawnbaden/dev-series-1

Recently in my first month as a professional software engineer (after more than a decade in quality assurance) I needed to setup several Rake tasks in a couple of different projects. One project I started from scratch and the other was an existing project. Beyond a few toy projects over the years, this is my first real Ruby experience and my first time using Rake. During the process I found some best practices for using Rake I plan to use going forward.

Set The Default Task To List All Available Tasks

I found it useful to have Rake’s default task list all available tasks for the project. For a small project I could see setting the default task to the most common task. But for most projects what exactly is the default? Rather than guessing what the default task is or typing out “rake --tasks” just set :default to list all tasks.

task :default do
  system "rake --tasks"
end

Keep Rakefile Small And Group Similar Tasks Into Their Own .rake Files

A project’s Rakefile can quickly become difficult to navigate if everyone treats it like a dumping ground. Similar tasks may even end up not grouped together. Rather than trying to group similar tasks together in Rakefile I found it made the most sense to keep Rakefile relatively small and lightweight and then logically group like tasks into separate files.

lib/
    tasks/
          doughnut.rake # tasks to make doughnuts
          cake.rake     # tasks to make cakes
Rakefile

Use Namespaces

Closely related to separating similar tasks into individual .rake files, use the same process to create namespaces for similar tasks. I like to match the file name to the namespace.

# doughnuts.rake
namespace :doughnuts do
  namespace :raised do
    task :doughnut1 do end
    task :doughnut2 do end
    task :doughnut3 do end
  end

  namespace :cake do
    task :doughnut1 do end
    task :doughnut2 do end
    task :doughnut3 do end
  end
end

# cakes.rake
namespace :cakes do
  namespace :raised do
    task :cake1 do end
    task :cake2 do end
    task :cake3 do end
  end
end

A Task And A Namespace Can Have The Same Path

I didn’t expect this to work but it turns out a task can share the same path as a namespace. For me this solves the case to “run all” tasks under a namespace. An example illustrates this best.

task :doughnuts do
  # run all doughtnuts:* tasks
end

namespace :doughnuts do
  task :raised do
    # run all doughtnuts:raised:* tasks
  end

  namespace :raised do
    task :doughnut1 do end
    task :doughnut2 do end
    task :doughnut3 do end
  end

  task :cake do
    # run all doughtnuts:cake:* tasks
  end

  namespace :cake do
    task :doughnut1 do end
    task :doughnut2 do end
    task :doughnut3 do end
  end
end

For Passing Parameters To Tasks, Prefer Environmental Variables

This seems to be the prevailing wisdom and after using environmental varaibles myself I agree.

I like environmetal variables for passing parameters to Rake tasks because it looks cleaner and it provides flexibility in several ways. Sticking with my running example:

> rake doughnuts:raised:doughnut1 NUMBER_TO_MAKE=1 # make 1 raised doughnut1
> rake doughnuts:raised:doughnut2 NUMBER_TO_MAKE=2 # make 2 raised doughnut2
> rake doughnuts:raised:doughnut1 NUMBER_TO_MAKE=3 # make 3 raised doughnut3
> rake doughnuts:raised           NUMBER_TO_MAKE=5 # make 5 of each raised doughnut
> rake doughnuts:cake             NUMBER_TO_MAKE=4 # make 4 of each cake doughnut
> rake doughnuts:cake:doughnut3   NUMBER_TO_MAKE=2 # make 2 cake doughnut3
> export NUMBER_TO_MAKE=10
> rake doughnuts:raised:doughnut3                  # make 10 raised doughnut3
> rake doughnuts:cake                              # make 10 of each cake doughnut
> rake doughnuts:raised:doughnut2 NUMBER_TO_MAKE=2 # make 2 raised doughnut2

What’s Up Next?

In the next edition of Dev Series I’m eyeing JSON Feed.

Originally published May 20, 2017