Short Feedback Cycles
07 Jun 2015Forty-two days into my year of commits initiative has come and gone. With it, I have found some great processes for making my contributions efficient and effective. Feedback is extremely important when writing software. After all, the code you write is probably designed to work, right? Right. A good way to verify correctness in your software is through automated tests. These can either be unit tests for specific methods and functions or integration tests; those that make sure a complete code path behaves as expected. Regardless, we write these tests to ensure our code works now and in the future. “In the future” is where I have started to contribute to projects.
Good projects have test files that the original author(s) provide. Great projects have fast test files that the original author(s) provide. Fast tests provide short feedback cycles. Short feedback cycles prevent bugs and help make new feature development and refactoring much more painless. Feedback governs our behaviors in and outside the development world. Without it, we would not be as efficient or effective at the tasks that are important to us. From writing software to training for a half marathon, feedback matters a great deal.
In a recent contribution of mine, I relied heavily on automated testing and short feedback cycles. It was important to me that I was able to identify how the specs were changing as I upgraded them to RSpec 3. I used Guard to help run my tests automatically when any of the code changed. Guard is a tool to automatically run your automated test files as you are making changes to the code.
Guard has been around for a long time. I chose to use it due to how simple it is to set up. All you need to do is include the guard-rspec
gem in your repository create a Guardfile
.
An example Guardfile
(which exists in the root of your repository) would look something like this:
guard :rspec, cmd: 'rspec', notification: false do
watch(%r{^spec/.+_spec\.rb$})
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
watch(%r{^models/(.+)\.rb$}) { |m| "spec/models/#{m[1]}_spec.rb" }
watch('spec/spec_helper.rb') { "spec" }
end
Let’s break this file down and see exactly what is going on.
watch(%r{^spec/.+_spec\.rb$})
This line tells Guard to watch each spec file and run the contained tests if the file has been saved. The file does not need to be changed, only saved for guard to run the specs.
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
watch(%r{^models/(.+)\.rb$}) { |m| "spec/models/#{m[1]}_spec.rb" }
These two lines do the same thing in different directories. The first looks in the lib
directory for anything ending in .rb
and runs the associated spec files in spec/lib/
. For example, if we have changed a file, lib/foo.rb
, then the spec, spec/lib/foo_spec.rb
, is run. The second line does the exact same thing for the models
directory.
watch('spec/spec_helper.rb') { "spec" }
This last line tells guard to run a specific directory (in this case, spec
) whenever our spec/spec_helper.rb
file is saved.
With our Guardfile
set up, seeing the successes and failures of our test suite while we do development is as easy as running guard
in the root of our directory structure. Personally, I use guard --clear
to make the terminal clean up after itself between runs. This creates a nice blank slate to run each spec on and requires no additional scrolling.
Guard has been a very valuable asset to me during my Year of Commits and it, or technologies in the same space, would be worth looking into for anyone searching for short feedback development. Go out there, keep your Guard up and make some great contributions to other people’s code!