Picture of Jim Nanney

Jim Nanney

Perpetual Student of Software Craftsmanship

TDD Your Rakefile

TLDR - Rake Tasks can be broken into objects, objects can be easily TDD’d.

Sometimes I forget that my best work occurs when I forego the cowboy coding, or unplanned unit of work because I already know how I want to implement something. That stupid lesson I keep having to learn over and over again is about testing first, driving design from need instead of gut feeling.

Rakefiles tend to give me a junk drawer of untested code I use consistantly but without tests. (Thanks to @sarahmei for the perfect wording here)

The thing is that no matter what I allow my gut to feel, or my instinct to drive, I have to abide by processes. Processes provide repeatability, both in results and in how I accomplish those results. TDD provides an awesome process to drive a design. This doesn’t mean I should never deviate, but as Sandi Metz stated, follow the rules until you understand why you should not.

Rakefiles consists of Tasks and Rules, in this post I’ll address tasks. In a later followup, I’ll go into detail on testing rules.

Creating a Gemfile

I wanted to add a quick note on how to create a gemfile. In the simplest terms, use bundler. It makes creating a Gem very easy!

1
2
3
4
5
6
7
8
9
10
11
12
bundle gem <gemname>

$ bundle gem sudokusolver
      create  sudokusolver/Gemfile
      create  sudokusolver/Rakefile
      create  sudokusolver/LICENSE.txt
      create  sudokusolver/README.md
      create  sudokusolver/.gitignore
      create  sudokusolver/sudokusolver.gemspec
      create  sudokusolver/lib/sudokusolver.rb
      create  sudokusolver/lib/sudokusolver/version.rb
Initializating git repo in /Users/jimnanney/code/ruby/sudokusolver

I create a separate gemset for each project.

1
rvm rvmrc create 2.0.0@sudokusolver --ruby-version

Adding RSpec is simple as well. Just add the following to the .gemspec and run bundle.

1
spec.add_development_dependency "rspec", "~>2.1"

Follow this with rpsec –init and your spec directory and .spec_helper and .rspec will be created for you.

You’ll also want to add the following to your Rakefile to create the RSpec tasks:

1
2
3
4
5
require 'rspec/core/rake_task'

RSpec::Core::RakeTask.new(:spec)

task :default => :spec

Ruby String.split Regex Gotcha

Using String.split and a regexp input might not behave how you think it should.

Yesterday I was a attempting to split an input string into an array of nine character wide strings. String.split seemed like a perfect tool for the job. However, I found a slight problem. Any regular expression sent to split is treated as the delimiter, not the capture. This results in the empty array as there is nothing in between the splits to collect into the array.

1
2
"1234567890111222333444555666".split /\d{9}/
=> []

We can verify this by adding a delimiter to the input string.

1
2
"123456789,111222333,444555666".split /\d{9}/
=> ["", ",", ","]

The “aha” moment is the regular expression is used to determine the delimiter, not the captured values. This is a bit different than I expected. So being clever, I thought, let’ use capture groups in the regexp.

1
2
"1234567890111222333444555666".split /(\d{9})/
=> ["", "123456789", "", "111222333", "", "444555666"]

Wait, what happened? Why the empty strings still? Remember, it is still using the regexp for the delimiter. The text that is not part of the delimiter is still returned. The captured text from the regexp is also returned.

It is stated in the ruby core docs, it just isn’t so clear what is going on until you test it like above.

If pattern is a Regexp, str is divided where the pattern matches. Whenever the pattern matches a zero-length string, str is split into individual characters. If pattern contains groups, the respective matches will be returned in the array as well.

So what is the correct way to accomplish our goal of splitting the text into 9 character length arrays when no delimiter is present?

String.scan

1
2
"123456789111222333444555666".scan /\d{9}/
=> ["123456789", "111222333", "444555666"]

So lesson learned, always check your assumptions. Thankfully, unit tests showed me what I was doing wrong before this got really ugly and hard to chase down.

Code Happy

What a wonderful day today turned out to be. I slept so little last night, fought poor variable naming at work, had a phone conversation with another company about possibly coming to work for them, decided it was a bad choice, couldn’t nap after work, and after all that, began to enjoy myself.

I pair programmed with a new friend thanks to the #pairwithme hashtag. From sending out that tweet, I met @Mattr. He introduced me to a project that needed some refactoring love. He drove, I learned lots and contributed a little. But in the end, I got to become entranced in a new project, and even better, gained a pet project to level up on using pull requests. I learn best by doing, but occasionally I require the mentoring of someone more versed in the project/language. Open source software and pairing really gives both of those to me.

Overall, it just caused me to get into a happy coding place, one that is collaborative an communicative.

I wish you all find that place.

Code Happy!

Fixing Pow Rails 4 Startup Problem

I just had an interesting problem trying to use pow for a Rails 4 project for the first time.

Pow was reporting an error parsing the following line in config/application.rb

1
2
config/application.rb:11: syntax error, unexpected ':', expecting ')'
Bundler.require(*Rails.groups(assets: %w(development test)))

That error message really looks like Ruby 1.8 trying to parse the new hash syntax. And in fact that is exactly what it is.

It turns out that I had RVM configured wrong. I use zsh and in my .zshrc I had the startup for rvm. If the rvm script doesn’t get called the default system ruby is used with pow. In the case of pow, it never loads the .zshrc because that is only called for interactive environments. The solution is to move the lines that call rvm from .zshrc to a new or exisiting .zshenv. Once you do this you will have to kill the exisiting pow process ps ax |grep pow

I really love using pow during development as it allows me to completely ignore the localhost:3000 and 5000 and other ports and can load the app in my browser by name instead.

You can find pow and the documentation from Pow.cx.

More Remote Pairing Tips

In my latest session of what I am learning I have begun setting up an EC2 instance to handle remote pair programming. The biggest reason to do this is because it eliminates the need to setup so many little pieces at home. It seems every remote pair session I start, begins with me explaining the ssh command to login to my laptop only to find that my dynamic dns is changed and ssh doesn’t work. Inevitably I also miss that my router has port forwarded ssh to the wrong machine. Then there is the need to make sure a common user is setup, or that the permissions are setup on the socket that tmux uses.

In the classic scream of the 80s: STOP THE MADNESS!!!!!!

If something is painful, stop, evaluate what makes it painful, and find a way to relieve at least some of it. In this case, that means stop reconfiguring everything each time and do it once on Amazon’s EC2 instances.

So now that the mini rant is done, let me point out some great tips on remote pairing.

Pick a sensible project

If this is the first session you and someone else has ever done. Don’t do serious work. Do a code kata, or pick a code retreat style project. This enables you to focus your attention on how you work together, not the problem you are trying to solve. Pairing is about communicating, and if you don’t give yourself time to learn how each other communicates, you won’t solve problems together well. If you don’t have one, let me suggest one from my friend Bill Gathen. He put together the 7 Degrees of Fizzbuzz for the groups he teaches.

Start your tools with vanilla config files

If you both have wildly differing vim configurations and key remappings, only one person will be comfortable driving. Also, the same goes for tmux configs. A remapped leader key kills productivity for the driver.

Setup your login motd to explain how to get the session started

I can’t tell you how well this works to ease the nerves of the begining pair and sets the tone for the rest of the session.

Here’s mine as an example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  _       _         _                                   
 ( )  _  ( )       (_ )                                 
 | | ( ) | |   __   | |    ___    _     ___ ___     __  
 | | | | | | /'__`\ | |  /'___) /'_`\ /' _ ` _ `\ /'__`\
 | (_/ \_) |(  ___/ | | ( (___ ( (_) )| ( ) ( ) |(  ___/
 `\___x___/'`\____)(___)`\____)`\___/'(_) (_) (_)`\____)
                                                        
                                                                                                              
I'm glad you could join me in my journey of learning Ruby, 
Rails, vim, and tmux. I am still new in so many regards, and 
I welcome your inputs, criticisms, and patience with my knowledge. 
I am sure we will both work well together.

Now that you have logged in, you can join my pairing session 
by typing the following at your prompt:

~~~
tmux -S /usr/local/tmux/learning attach
~~~

Then increase the size of your terminal as far as it can go.
If your screen resolution is larger than 1920x1200 your terminal 
will be filled with dots outside of my screen's resolution.

I tend to tab complete alot.  In Mac terminals this causes a *lot* 
of audible bell sounds. If you want to turn them off, go to preferences, 
Settings, and under the advanced tab, uncheck audible bell.

Happy Pairing!

VIM Automatic Registers

Vim adventures has taught me an incredible new (to me) trick. The ability to paste a previously deleted line is easy. Use p or P to paste it. But what if it was the third time you hit dd and you wanted to paste in the first thing you deleted. I cannot begin to count the number of times I needed to do that. Further down, I’ll reveal this secret, but first the backstory:

Recently I saw a link to Vim-Adventures.com and followed. It was appealing, but seemed basic in the first three levels. So I decided not to purchase the subscription.

And then, at Rails Conf 2013 in Portland, I met up with a friend who was working through one of the levels. I immediately asked if she was playing vim adventures and she said yes and that she was stuck. Of course I offered to assist. This proved several points to me right away.

First, I am not as good with VIM as I had thought.

Second, I am a horrible teacher of things I have little grasp on.

Third, Vim Adventures advances terribly quick after level 3 and is well worth the subscription.

It was inevitable afterwards that I subscribed. I have learned a ton, and the most profound ended up being the automatic buffers.

Here’s how they work:

Given these lines:

1
2
3
Delete me last.
Delete me third.
Delete me first.

If you delete line three by using dd, followed by line one with another dd and then line two with again a dd, several deletion registers would be created.

You can see these by typing :reg

First, notice they are numbered from “1 to “9 and that they are in order from first in to last in. They also rotate out as more are added.

So to paste the first deletion from above, you would use “3p

This simple thing has bothered me many times, but not enough to look it up. After playing vim adventures to level 10, I’ve learned this new trick.

Remote Pairing - Lessons Learned

When I first encountered and heard the term pair programming, I was amazed at the possibilities. It takes programming to a communication exercise rather than logic puzzle, and gets two seperate minds working on the same problem. Living in the location that I am in, pair programming was not an option unless it was remote. Remote pairing seems like an exciting and productive way to work.

I have come close to what you might call pair programming while helping my wife learn Ruby. She has worked on some small programs with me in the background giving advice and steering her in the right direction. And she has once sat in the non-drivers seat and asked questions as I worked a problem. However, this did not prepare me for remote pairing.

My Tmux Config Explained

Before I get too far into my posts on pairing I wanted to start adding my configuration files and why I have chosen to use the pieces in them.

I must admit that prior to this week I had never used tmux. I heard the ruby rogues talk about it on their podacst. However, being a previous Linux admin, I have used and taught others to use screen for any task that was important, or long running. Largely due to the simple fact that a session could be detached and reattached.

Tmux is like screen on steroids. I have never used panes within screen and tmux makes this easy to do. With a few customizations it is incredibly useful, and your fingers rarely leave the home row on a keyboard!