articles
I’ve finally gotten around to putting my recent talk on Triaging Rails Issues on my speakerdeck page. The slides are extremely terse, though, and it will probably be easier to follow by watching the video of my talk, embedded here. (Thanks to Dave Laird for the video!)
CoffeeScript Wishlist
I’ve been working a bit with CoffeeScript lately, and I’ve pretty much fallen in love. But as a Rubyist, I find that I miss a few things. Allow me to explain.
Over the Christmas holiday, I found a GitHub project called Github Fantasy League, which cleverly quantifies a GitHub user’s open source “score” by assigning point values to certain activities, such as creating a pull request or filing an issue. The project is written in CoffeeScript, and I decided I would find something to fix so I could work in the CoffeeScript file and file a pull request. My change was modest; I decided that the form needed validation. So I spent some time looking over the CoffeeScript syntax, and I rewrote one particular function thusly:
Original
$('#username').bind('keypress', (e) =>
if (e.keyCode == 13 )
$('.score-trigger').click()
)
My Edit
$('#username').bind('keypress', (e) =>
$('.score-trigger').click() if e.keyCode == 13)
This was a few months ago, and I now realize I could’ve made it still more simple:
$('#username').bind('keypress', (e) =>
$('.score-trigger').click() if e.keyCode is 13)
The elegance of that line asounded me, and it reads like natural English: “The score-trigger element [should receive a] click if the keyCode is 13.” That, to me, is the hallmark of a great language: readable syntax.
Wish List
But while I love so much about CoffeeScript, a few things don’t quite make sense to me. For example, it uses Ruby’s unless
keyword, but still prefer’s JavaScript’s native else if
conditional for control flow to Ruby’s elsif
. Now, I suppose this is a matter of personal preference. That is, elsif
isn’t a word, where as else if
is proper English. But I feel like if CoffeeScript is going to adopt certain Ruby idioms, it should be done uniformly. Thus, I’d prefer to use elsif
.
The second thing I’d like is a ternary operator. I try not to overuse this expression, but if a bit of logic can be placed on one line with the use of a ternary operator, I often prefer it. Consider a simple function to check whether a number is even or odd:
isEven = (number) ->
if number % 2 is 0
true
else
false
This is the pefect case for a ternary operator:
isEven = (number) ->
number % 2 == 0 ? true : false
#=> not correct CoffeeScript
I suppose you could argue that writing the function that way is too terse. But stylistically speaking, having a single word on a line bothers me. It’s inefficient and could be cleaned up. But I suppose that’s a matter of personal preference.
Conclusion
I’ve very much enjoyed the little CoffeeScript I’ve done, and I look forward to more complex projects in the near future. However, I do wish that it had the elsif
construction (or even supported either else if
or elsif
just like it supports ==
or is
) and supported the ternary operator. I imagine I’ll find more as I continue to dive into the language.
What features do you wish CoffeeScript had?
Special Characters in Vim
It took me two or three false starts to really get working in Vim. I loved Sublime Text so much that it was hard to switch. But when I would watch my coworker type at dizzyingly fast speeds, I knew that I would have to make the switch to Vim in order to maximize my efficiency at work.
It has mostly been a great ride, but once in a while, Vim gets weird or wonky. Today, I had a problem that a good deal of Google searching didn’t seem to want to fix, so I stumbled on a solution I thought I’d share in case anyone else is pulling their hair out.
I was working in Sublime (don’t ask) reworking some HTML markup on a particular page, and I had decided to convert it to HAML for inclusion in our app at work. I used the html2haml gem to convert it, and when I opened it up in Vim, I saw a number of special characters that looked like this: <200b>
. They were all over, littering the document. I didn’t want to try to remove them by hand, but trying to find and replace them with an empty string didn’t work, because Vim wouldn’t let me search for <200b>
.
I did some searching, and found out that this character is the zero-width space. This oxymoronically named unicode character is, I gather, the equivalent of the
HTML entity in that, to quote Wikipedia, “In HTML pages, this space can be used as a potential line-break in long words.”
Well, whatever it is, I had to switch Vim to utf-8 mode (:set encoding=utf8
). That enabled me to search for <200b>
. After that, it was simply a matter of finding and replacing: :%s/<200b>///g
. You’re probably familiar with that syntax, but let’s break it down. :%s/old_string/new_string/options
. That is, :
puts Vim into execute mode, %s/
tells it you’re going to search, <200b>
is the search string, and we’re replacing it with nothing, hence the next two slashes: //
, and the g
flag stands for global, in other words, do this throughout the file.
Note that, in order to include <200b>
in the string search, I had to physically highlight it with my mouse and copy paste it into the search; yanking or using visual mode did not work.
I hope that was able to save someone a headache.
Method Aliases In Ruby
I often find myself wondering why so many of the Ruby native string and array methods have aliases. For example, with string methods, we have next
and succ
, which are equivalent; they both return the next alphanumeric character. Like so:
1.9.3p194 :024 > string = "a"
=> "a"
1.9.3p194 :025 > string.next
=> "b"
1.9.3p194 :026 > string
=> "a"
1.9.3p194 :027 > string.succ
=> "b"
So why do we need both? Here is another example. length
and size
are also synonymous. Both return the character length of a string.
1.9.3p194 :028 > a = "supercalifragilisticexpealidocious"
=> "supercalifragilisticexpealidocious"
1.9.3p194 :029 > a.size
=> 34
1.9.3p194 :030 > a.length
=> 34
This is perplexing to me. As much as I love Ruby, I often think that my mind philosophically prefers Python’s approach. The following is a direct quote from ‘The Zen of Python’:
There should be one—and preferably only one—obvious way to do anything.
I don’t necessarily have an answer (other than the likelihood that one or the other will be more familiar to programmers coming from other languages), but here’s a thought. We’re not working in Python, so let’s embrace the fact that Ruby has two ways of doing things sometimes.
If we think intuitively, it seems to me that we would want to find the ‘size’ of an alphanumeric string like, for instance, a base 64 token. That, to me, makes more intuitive sense than to get the ‘length’ of it. length
, to me, seems to be the method we would want to use to find the length of a word, where the word ‘size’ (and method of the same name) don’t make as much lexical sense.
For example:
1.9.3p194 :018 > token = SecureRandom.urlsafe_base64
=> "OFiTxLeCuosWXiLe9nVLeQ"
1.9.3p194 :019 > token.size
=> 22
Compare that to this:
1.9.3p194 :022 > sentence = "An incredibly long sentence about whosits and whatsits"
=> "An incredibly long sentence about whosits and whatsits"
1.9.3p194 :023 > sentence.length
=> 54
Doesn’t that just make more sense? To me, it seems more expressive.
Just to reiterate, whereas a developer coming from Python might be tempted to use one or the other method uniformly throughout a project, I like to think that Ruby’s features lend themselves well to expressiveness, and I would prefer using one method or the other in the context it makes sense. After all, we work in a language with this syntax:
3.times do 'Hello World!'
This is as close to spoken English as I’ve ever seen programming syntax. So let’s write Ruby like we would speak, and use methods where they make sense contextually, even if they do the same thing. As a result, our code will be eaiser to read, and therefore maintain. That’s why we have the canonical saying:
‘Programs must be written for people to read, and only incidentally for machines to execute.’ - H. Abelson and G. Sussman “The Structure and Interpretation of Computer Programs)
That sounds good, but let’s make this a little bit more complex. Look what happens when we make our string an array. size
and length
still apply, but to count the number of items in an array we also have, you guessed it, count
. Check this out:
1.9.3p194 :017 > sentence = "An incredibly long sentence about whosits and whatsits"
=> "An incredibly long sentence about whosits and whatsits"
1.9.3p194 :018 > a = sentence.split(' ')
=> ["An", "incredibly", "long", "sentence", "about", "whosits", "and", "whatsits"]
1.9.3p194 :019 > a.size
=> 8
1.9.3p194 :020 > a.length
=> 8
1.9.3p194 :021 > a.count
=> 8
So when should we use which? According to the Ruby docs, size
and length
are truly the same, but count
can take a block, and will return the number array items that give a true value. So let’s look at our previous example with this in mind:
1.9.3p194 :027 > a
=> ["An", "incredibly", "long", "sentence", "about", "whosits", "and", "whatsits"]
1.9.3p194 :028 > a.count
=> 8
1.9.3p194 :029 > a.count('long')
=> 1
1.9.3p194 :030 > a.count('hello')
=> 0
So while count
can return the number of array elements, it also has this added feature of count
ing the number of passed in items the array elements match.
Thus, the only rule I can think of when working with arrays is to choose size
or length
and work with it throughout a project to return the number of array items, but only use count
when you need to pass in a block so that there is no confusion about why you used differerent methods in different places to do the same job. This will lend to more cohesion and more expressiveness.
Gotchas
There are, of course, some gotchas to this idea. When I first started writing Ruby, I was so in love with the English-like syntax that, for a time, I decided I wanted to use words instead of symbols for conditional operators. Thus, I might’ve at one point been prone to write:
def greeting
if user.logged_in? and not(user.nil?)
"Welcome back, #{user.name}"
end
end
That was a contrived example, for sure, and an exaggeration, but I wanted to get to this point: While researching the logical operators, I found a case where and
and &&
returned different values:
1.9.3p194 :013 > result = true and false; result
=> true
1.9.3p194 :014 > result = true && false; result
=> false
That scared me enough to make me want to use symbolic logical operators all the time and sometimes parenthesis just to communicate intent. I now do this even when not strictly necessary:
def viewable_by?(current_user)
current_user.system_admin? || ( current_user.logged_in? && current_user.owner? )
end
In this case, the parenthesis weren’t absolutely necessary, as can be seen when we boil this example down:
1.9.3p194 :024 > false || true && true
=> true
But I use parenthesis anyway. I don’t sacrifice the aesthetics of the code (in my opinion, anyway), and that way, my code intentions become immediately more clear. And isn’t that the goal?
Refactoring Cucumber
At work, we’ve been moving away from Cucumber tests for the past number of months, in favor of the more robust Capybara and rspec paring. Given that I’m a relative novice in Rails test-driven development, the supposed brittleness of Cucumber tests wasn’t immediately clear to me, so I did some digging, and came up with a few posts that talk about the pitfalls of the “imperative” style of step writing for user stories. A solid example of this is Ben Mabey’s ancient, but still applicable post, “Imperative vs. Declarative Scenarios in User Stories”. Mabey’s assertion is that it is too easy to rely too heavily on the built-in Cucumber web steps. For example:
When I fill in Name with 'Alligator'
And select Phylum as 'Chordata'
And fill in Animal Class with 'Sauropsida'
And fill in Order with 'Crocodilia'
And fill in Family with 'Alligatoridae'
And fill in Genus with 'Alligator'
And check Lay Eggs
And click the Create button
Here, Maybe suggests, the “story” part of the user story tends to get lost and mired in the technical details. I was heavily influenced by this post, and decided to do a little Cucumber refactoring at work to try out Mabey’s declarative style, which he demonstrates thusly:
Story: Animal Submission
As a Zoologist
I want to add a new animal to the site
So that I can share my animal knowledge with the community
Scenario: successful submission
Given I'm on the animal creation page
When I add a new animal
Then I should see the page for my newly created animal
And the notice 'Thank you for your animal submission!'
As Mabey notes, it has more of the token for conversation feel to it, and it’s immediately clear that it is more likely to meet the user’s need, since, in this case, the user cares more about completing their goals than how those goals are handled on the back end.
My Attempt
I took Mabey’s advice to our own codebase, and I extracted a Cucumber test that I had written a few months back. Now, I won’t start to bad mouth my code and talk endlessly about how terrible a person I am for having written it this way, but I’ll give you a taste of how poorly this test spoke to the user’s need. I present to you this feature test for our site’s feedback form:
#features/feedback.feature
Feature: Feedback
Scenario: Submitting feedback
Given I go to the feedback page
And I fill out the feedback form and submit it
Then I should see a success message
Then I should see "Email can't be blank"
When I fill in "Your email" with "nick@navigatingcancer.com"
And I fill in "Summary" with "This site rules"
And I fill in "What you observed" with "This site rules"
And I press "Send"
Then the flash notice should be "Thank you for your feedback! |
We try to respond to questions and requests within one business day."
And ruby FeedbackForm.last.email.should == 'nick@navigatingcancer.com'
And ruby FeedbackForm.last.content.should match "This site rules"
Yep, you read that right. That’s a Ruby function inside of a Cucumber test. I wonder what user will be thinking of their form submission in terms of a Ruby method chain? Now here’s my improved version, written with Turnip and Capybara.
#spec/acceptance/forms/feedback.feature'
Feature: Feedback form
As a user of the site
I want to be able to submit feedback about the site
So that I can report if something breaks
@feedback
Scenario: Submitting feedback (successful)
Given I go to the feedback page
And I fill out the feedback form and submit it
Then I should see a success message
#spec/acceptance/forms/feedback_steps.rb
require ‘spec_helper’
steps_for :feedback do
step 'I go to the feedback page' do
page.visit '/feedback'
end
step 'I fill out the feedback form and submit it' do
page.click_button 'Send'
page.should have_content "Email can't be blank"
page.fill_in 'Your email', with: 'joe@navigatingcancer.com'
page.fill_in 'Summary', with: 'Just saying' page.fill_in 'What you observed', with: 'I am awesome'
page.click_button 'Send'
end
step 'I should see a success message' do
page.should have_content "Thank you for your feedback! We try to respond to questions and requests within one business day."
FeedbackForm.last.email.should == 'joe@navigatingcancer.com'
FeedbackForm.last.content.should match 'I am awesome'
end
end
See how much more nicely that reads? Now the user story is really coherent. They go to the form and submit it, and they should get a success message. That’s truly how simple the step should be. Notice that I still handled the validation in Capybara. But the it’s not the user’s job to think about what should happen if they don’t submit the form correctly, it’s mine. Thus, I should handle that in the test logic that doesn’t involve the user story. ##Onward## As a front-end developer coming to the TDD Rails world, Cucumber was helpful to me because it helped me to think about things from the browser’s perspective. The gherkin syntax, when used well, really does allow for expressive steps and user stories that invite collaboration with non-developers. But that syntax paired with Capybara’s more robust step handling make for a much clearer and well-executed test. Notably, the reason I went back to this test was that we had changed the UI for the form. Our previous form submitted an unfuddle ticket, but we have recently switched our ticketing system to Assembla. Also, we added a few fields and renamed others. In this case, the Cucumber test (previous to the one I have posted) would have failed because it wouldn’t have been able to find the form labels it was looking for. But the user story remained the same. All the user wants to do is submit a feedback form. So rather than changing several tests to reflect this, why not only change the ones that are concerned on the back end? They’re easier to maintain, and as great as Cucumber was, I find that I prefer the Capybara-rspec approach when it comes to looking for content on the page. I’m looking forward to exploring this technique across our codebase during refactoring, and in the future.
Recently
- 21 Feb 2013 » CoffeeScript Wishlist
- 30 Jan 2013 » Special Characters in Vim
- 18 Dec 2012 » Method Aliases In Ruby