Using Capistrano 1.4 with 2.x
March 31st, 2008
At Elevator Up we typically use Capistrano for deploying our applications. Though I do have a bookmark to investigate Vlad when I get some time.
We've been a bit slow to upgrade to Capistrano 2.x, and have a lot of existing applications that depend upon Capistrano 1.4 for deployment.
One tactic we've taken is to write a custom script to explicitly use 1.4 in conjunction with 2.x. A minor hack from the original, and we have:
#!/usr/bin/env ruby
begin
require 'rubygems'
gem 'capistrano', '<= 1.4.1'
rescue LoadError
# no rubygems to load, so we fail silently
end
require 'capistrano/cli'
Capistrano::CLI.execute!
I threw this into a script called cap1.4 in /usr/local and can now do:
illian:~ zach$ cap1.4 -V
Capistrano v1.4.1
illian:~ zach$ cap -V
Capistrano v2.1.0
Obviously, a better approach would be to freeze in the capistrano gems per project, and access them via RAILS_ROOT/script/cap, but that too has been time sensitive. Notice a trend here?
Commonly overlooked usage of named routes
March 30th, 2008
Given a route :
ActionController::Routing::Routes.draw do |map|
map.foo "foo/:first/:second", :controller => "foo", :action => "something"
end
Obviously you can pass in :first and :second via:
foo_path(:first => "the first param", :second => "the second param")
However, for a more concise call, you can accomplish the same via:
foo_path("the first param", "the second param")
It's not explicitly documented, but you end up doing the same thing with nested resource paths
Watch Star Wars via Telnet
March 30th, 2008
One of the best HTML / CSS theme songs
March 29th, 2008
Testing content_for
March 29th, 2008
After we started writing view specs we came across views similar to this:
<p>Stuff in the main content area</p>
<% content_for "secondary_content" do %>
<p>Stuff that will go in an side panel in the view </p>
<% end %>
Obviously when rendering the view inside the spec, only the blurb about main content area will be in the response.body. For instance the second spec written will fail:
describe "/path/to/view" do
def do_render
render "/path/to/view"
end
it "should have blurb about main content" do
do_render
response.should have_text(/main content/i)
end
##
# This won't pass.
##
it "should have blub about side panel" do
do_render
response.should have_text(/side panel/i)
end
end
However, you can shove something in your spec_helpers.rb to test items inside the content_for blocks.
def content_for(section)
template.send(:instance_variable_get, "@content_for_#{section}") || ""
end
And rewrite your spec like this:
describe "/path/to/view" do
def do_render
render "/path/to/view"
end
it "should have blurb about main content" do
do_render
response.should have_text(/main content/i)
end
##
# This will now pass
##
it "should have blub about side panel" do
do_render
content_for("secondary_content").should match(/side panel/i)
end
end
The have_text() matcher won't work, but you can use the have_tag().
If you haven't toyed with content_for, I suggest looking into it. It will help clean and organize your views and layout(s).
Education vs Justification
March 23rd, 2008
Aaron, Janson and I were at Applebees a month ago discussing an estimate for a client. We started talking about a particular part of the estimate that would require us to take more time than usual. We worked on their project previously, and used a few testing practices that we've stopped since. I wanted the estimate to include the refactoring of the code, but not publicize the fact. Aaron wanted to communicate with the client our exact intent.
Now keep in mind, I have no qualms about transparency with clients. And I don't go to great lengths to keep clients in the dark, as some of my previous work environments have. My point was that refactoring the code and the tests was a necessary step of development. I didn't want to publicize those specific intentions because I didn't want to come across that they were optional. In other words, I didn't want our client to think that the one of our values, quality software in this case, was negotiable.
Now, I know I may be coming across rather harshly. And I may appear as the developer with blinders, who tells everyone "Just trust me, you won't get screwed." This was exactly how I portrayed my perspective to Aaron and Janson, who more or less disagreed with me for those exact reasons. We debated for a bit longer, while eating our lunch, and I finally had the Eureka moment.
Our job is a technical one. Not only does it involve many hours of learning, but it takes the obsessive-like passion to stay current. It is rather rare for clients to possess the technical knowledge, or the experience involved in constructing quality software. However they know their domain intimately, and for a developer to play the "trust me" card in a bit arrogant. As a developer, I often forget that.
Help educate them
I was feeling as if I had to justify our development practices to the client. It made me upset that I needed to have them approve my reasoning in deciding to refactor older code. Yet as I was getting worked up, it dawned on me, the client hadn't even seen the estimate. I was already prepping counter arguments, as well as previous experiences to sell my decisions which required more work.
Listening to Aaron and Janson, I realized the client didn't need justification. They weren't bringing my decisions into the light in order to criticize my knowledge as a developer. They merely wanted to match the impact of my decisions with what they knew. They sought to understand the reasoning behind my decisions.
As I've thought more about that conversation I've come to an important resolution in my career. I should never justify myself to a client, however I should always try to educate our clients. I should spend the effort to tell them the impact of taking alternate routes. I should find better ways to articulate myself and speak their language rather than swamp them with intimidating geek-speak.
Justification isn't evil
While my client's aren't developers, I am, and so is the rest of my team. This brought up the second big question and resolution "How do I know my decision is right?", which led me to: Always justify my decisions to myself, and to my team. I believe a key ingredient in improving ourselves is constant introspection. If I make a decision, and I can't debate myself or a team member on the end result, then it's probably heavily influenced by preference, or even fear.
I should always justify to myself why we test, and the rigorousness of our tests. I should always justify why we should use agile approaches to planning. I should evaluate the reasoning behind using git over svn and whether programming in ruby makes more sense than developing in java.
I've found that it's very easy to surround yourself with a community who evangelizes tools or practices, while not sincerely asking the honest questions. I've also seen a similar pitfalls in ignoring new technologies and trends, because a lack of self-justification.
