Red Squirrel Reflections
Dave Hoover explores the psychology of software development

Dave Hoover
dave.hoover@gmail.com

Categories
All [Atom]
Craftsmanship [Atom]
Dynamic [Atom]
Intersection [Atom]
Learning [Atom]
Links [Atom]
Polyglot [Atom]
Projects [Atom]
XP [Atom]
Old Blog

Obtivian Blogs

Andy Maleh
Colin Harris
Fred Polgardy
Jim Breen
Kevin Taylor
Todd Webb
Turner King
Tyler Jennings

Archives

March 2009 (1)
January 2009 (1)
December 2008 (1)
October 2008 (3)
September 2008 (1)
June 2008 (4)
April 2008 (3)
March 2008 (1)
February 2008 (1)
August 2007 (1)
July 2007 (1)
June 2007 (1)
May 2007 (4)
April 2007 (3)
March 2007 (5)
February 2007 (6)
January 2007 (6)
December 2006 (10)
November 2006 (5)
October 2006 (8)
September 2006 (8)
August 2006 (5)
July 2006 (12)
June 2006 (7)
May 2006 (5)
April 2006 (5)
March 2006 (4)
February 2006 (2)
January 2006 (5)
December 2005 (5)
November 2005 (3)
October 2005 (3)
September 2005 (6)
August 2005 (4)
July 2005 (7)
June 2005 (14)
May 2005 (6)
April 2005 (8)
March 2005 (9)
February 2005 (11)
January 2005 (16)
Old Archives

 

Wed, 30 May 2007

Rails moves my Bottleneck in Web Development

Geoffrey Grosenbach's latest post reminded me of something I've grown to appreciate over the last couple years: web development with Rails pushes me out of the confines of my codebase and into the other aspects of web development much more quickly than any other web development environment I've used before. Rather than slogging through the painful verbosity of a J2EE codebase, on a Rails project I am (like Geoffrey) hopping around on various servers' command lines, configuring Apache, defining CSS, and crafting Prototype-inspired JavaScript features. For whatever reason, these are all aspects of web development that I had grown to belittle in a previous life when I was more interested in intellectual pursuits.

What I'm realizing lately is that while I cherish what I've learned about objects, agile, and patterns, I'm feeling a bit lop-sided (which isn't surprising if you look at my reading lists over the years). Rails has internalized some the ideals that came out of some of the most important software development revolutions of the last few decades. Martin notes:

...the [R]uby community has formed around the best ideas of the OO and Extreme Programming communities. Listening to the keynote of Jamis Buck and Michael Koziarski I was delighted to reflect on the thought that they were right there in the values of Ward, Kent, and all the other people who've been advocating clean code, well-factored object-oriented design, and testability. These ideas have made a great impact on many other technological communities, but in Ruby-land they are the orthodoxy.
Ruby and Rails' intrinsic values mean that my bottleneck has moved away from application code and (as always) I've got some learning to do in the ecosystem that surrounds and supports a successful Rails project. Thankfully I work on a team of people that have a great diversity of backgrounds and talents. On teams like this, we often have both partners in our pairing sessions switching frequently between student and teacher. It is a priceless dynamic and one of the great advantages of working with apprentices.

[/dynamic] permanent link

Fri, 20 Apr 2007

Ruby has variable scoping

Gareth joined me in the d'oh! club today when I revealed to him the revelation that Ryan provided me back in January. Ruby has variable scoping, meaning that this code works just fine:
if false
  a = 1
end

puts a # nil
Up until Ryan revealed this to me, I had been merrily (and needlessly) declaring my variables outside the control structures that defined them. Maybe Gareth and I are the only ones who weren't aware of this aspect of Ruby (and many other dynamic languages), but just in case, I thought I'd share it with you.

[/dynamic] permanent link

Thu, 15 Mar 2007

TextMate is my friend

I got a little thrill just now when I wanted to have a look at some changes I've made in one of our Rails projects and it occurred to me that I love TextMate's diff view. I hadn't tried this before so I typed it in and crossed my fingers...
svn diff config/* | mate
Which (and I shouldn't be surprised by this) instantly popped up exactly what I wanted:

[/dynamic] permanent link

Wed, 28 Feb 2007

3.weekdays.from_now

sudo gem install facets
require 'rubygems'
require 'facets/more/times'

puts 0.weekdays.from_now # Wednesday (today)
puts 2.weekdays.from_now # This Friday
puts 3.weekdays.from_now # Next Monday
puts 4.weekdays.ago      # Last Thursday
See http://facets.rubyforge.org/src/lib/facets/more/times.rb for details.

[/dynamic] permanent link

Fri, 23 Feb 2007

Ruby's Protected Access

Jamis posted yet another nugget of wisdom. This one was about Ruby's method visibility, which can be tricky for people coming to Ruby from Java or C#. Jamis left one aspect of the protected access level as an exercise for the rest of us, so I figured I'd write up an example that helps illustrate when you would use protected vs. private.
class Sibling
  def ask(sib)
    sib.tell
  end
  
  def spy_on(sib)
    sib.secret # will always complain
  end

  protected

  def tell
    secret
  end
  
  private
  
  def secret
    "Charlie tooted"
  end
end

rose  = Sibling.new
ricky = Sibling.new

begin
  puts ricky.tell
rescue
  puts "Ricky will only tell another sibling"
end

begin
  puts rose.spy_on(ricky)
rescue
  puts "Ricky complains when Rose tries to find the secret"
end

puts rose.ask(ricky) # Ricky will tell if Rose asks nicely
One of the main differences for Java developers is that objects of the same class can't see each other's private methods.

[/dynamic] permanent link

Sat, 17 Feb 2007

Relentless Simplicity with ActiveRecord

The Active Record pattern is a wonderfully simple and sufficient approach to ORM on many projects. I first used it in Java and it worked well on a small project. But in a staticly typed language like Java, using Active Record is limiting and/or awkward. It wasn't until I starting using ActiveRecord in Rails that I saw just how powerful this pattern could be when applied within a more flexible, readable language. Where nasty getter/setter hell and XML configurations are the standard in Java, we get clean, readable classes and objects in Ruby.

One of the things we do at Obtiva is provide coaching and development for Rails projects that are in trouble. I call them rescue missions. We've found that the downside to Rails' power and simplicity is that people can crank out functionality with minimal understanding of how to write maintainable, scalable software. It's only a matter of time until they hit a wall, and that's where we step in. We find people usually get into trouble with ActiveRecord when they allow themselves to write ugly code. I'm sure that there are some cases where ActiveRecord doesn't do what you need and an ugly solution is required, but I think those cases are exceptionally rare for most Rails apps.

During one of our rescue missions, I discovered a fat controller with lots of calls to find_by_sql. Again, I'm sure there are cases where this nasty method is needed, perhaps for optimization, or for some odd cases that I can't imagine (since I've never used it), but this was just plain ActiveRecord abuse. Most of us aren't aren't writing abusive ActiveRecord code, but many of us need to be more relentless in our pursuit of clean, readable, ActiveRecord usage.

We're kicking off a Rails e-commerce project so I downloaded a copy of the Rails e-commerce book to brush up on ActiveMerchant. By the way, I recommend the book to anyone coming to Rails with an immediate need to write an e-commerce site. It's also a good book for anyone wanting to see an example of TDD in Rails. But on page 175, I found a snippet of code that spurred me to write this post ... it wasn't ugly ActiveRecord code, but I would go so far as to say that it is just plain bad.

class Post < ActiveRecord::Base
  belongs_to :category  

  def self.find_all_in_category(category)
    category = Category.find_by_name(category)
    self.find :all, :conditions => "category_id = #{category.id}"
  end
  ...
end
I can read this code and understand what the author was trying to do. The method is returning all of the Posts for a given Category name. But what happens if the call to Category.find_by_name returns nil? And why would a simple thing like this require 2 separate calls to the database?
SELECT * FROM categories WHERE (categories.`name` = 'foo') LIMIT 1
SELECT * FROM posts WHERE (category_id = 1)
This is an example of not pushing hard enough to keep your code clean and simple. The first solution you can think of isn't necessarily the simplest. Don't be satisfied with anything less than elegance when you're using ActiveRecord and you'll be much better off. Here's how I would rewrite that little method:
class Post < ActiveRecord::Base
  belongs_to :category  

  def self.find_all_in_category(category_name)
    category = Category.find_by_name(category_name, :include => :posts)
    category ? category.posts : []    
  end
  ...
end
Which, thanks to the eager loading of :posts, would result in just 1 call to the database, and (to me) reads better.

[/dynamic] permanent link

Sat, 09 Dec 2006

You know the Bears are having a good season when...

...even the programmers are scheduling their user group meetings around Monday Night Football. I love Chicago.

[/dynamic] permanent link

Fri, 29 Sep 2006

Rails Across 3 Oracle Databases

Over the last couple weeks at my main client, a small revolution has begun. This medium-sized Java shop is slowly, but surely adopting Ruby and Rails. It has been exciting to be a witness to the productivity gains and the willingness of people to learn something new. (Thanks in no small part to the simplicity and power of Watir.) I'll have more stories to share about this little revolution, but first I need to tell the story of a 30-minute development episode that Tyler and I just paired on.

Short version: Rails can integrate wonderfully across multiple legacy Oracle databases.

Longer version:

Over the course of my Rails development experience, I've (wrongly) assumed that trying to get Rails to do enterprise'y things is difficult. I'm not going to go into why I assumed this, but I would bet that there are others out there who have been scared into believing that they shouldn't try to swim against the Rails' convention of a single database with specific table-naming conventions.

My assumption was blown out of the water this morning when my pair and I needed to grab data from 2 other databases for a little Rails app that we created yesterday. The app was the brain-child of our client manager who needed a way to track the status of features and bug-fixes as they progressed through QA. We use XPlanner for iteration planning and iTracker for bug tracking, so she wanted to be able to refer to an XPlanner story id and/or an iTracker issue id for each QA task. We were able to deliver this to production in about an hour (thank you Capistrano) yesterday afternoon (yes, T is approaching zero).

This morning, our client said that she didn't want to see the issue and story ids, she wanted to see the name of the issue and story. For that, we needed to grab them from the XPlanner and iTracker databases. With much wringing of hands, and prepared to see our Rails productivity plummet, we Google'd around to see how to connect to multiple databases in Rails. First, we needed to configure our databases:

config/database.yml
production:
  adapter: oci
  username: foo
  password: 
  host: FOO:5353/BAR

planner:
  adapter: oci
  username: xplanner
  password: 
  host: (DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=...

tracker:
  adapter: oci
  username: itracker
  password: 
  host: (DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=...
Then we needed models to represent the issue and story.
app/models/story.rb
class Story < ActiveRecord::Base
end

app/models/issue.rb
class Issue < ActiveRecord::Base
end
Then we needed to create the associations between a QA task and the Issue and Story.
app/models/task.rb
class Task < ActiveRecord::Base
  belongs_to :issue
  belongs_to :story
  ...
end
Then we needed to configure Rails to use the appropriate connection and table names for Issue and Story.
config/environment.rb
Story.establish_connection "planner"
Story.set_table_name "story"

Issue.establish_connection "tracker"
Issue.set_table_name "issuebean"
And this just works:
task = Task.find(1) # from prod Oracle database
puts task.story.name # from XPlanner Oracle database
puts task.issue.description # from iTracker Oracle database

[/dynamic] permanent link

Thu, 21 Sep 2006

If you've ever wanted to_bool in Ruby

class Object
  def to_bool
    !!self
  end
end

[/dynamic] permanent link

Tue, 22 Aug 2006

Rails Integration Testing redirect_to :back

ActionController provies some ultra-convenient functionality via redirect_to :back. To get it to work in your Controller and Integration tests, you'll need to make sure that the HTTP_REFERER is set on the request. This is fairly straightforward for Controller tests:
  @request.env["HTTP_REFERER"] = "/babies/new"
  get :create, :baby => { ... }
  assert_redirected_to "babies/new"
For Integration tests, it's a little different:
  get "babies/create", { :baby => { ... } }, { "HTTP_REFERER" => "/babies/new" }
  assert_redirected_to "babies/new"
Unfortunately, this Integration test will fail. There is a bug in ActionController::Integration::Session (patched here) which can be worked around if you change the header to 'REFERER' => "/babies/new" or :referer => "/babies/new".

[/dynamic] permanent link

Sun, 16 Jul 2006

def_init'ly DRYer Ruby

I'm leading a study group at my current client. Nine of us are reading Ruby for Rails and get together every week with a projector to answer questions and hack away at some examples. I read a few chapters ahead so that I can provide exercises for the group to prepare for our meetings. I was reading chapter 5 today, it's fairly basic Ruby stuff, introducing the convenient and self-documenting attr_* methods. The following class is the example from the book, your typical brainless data holder...
class Ticket
  def initialize(venue, date)
    @venue = venue
    @date = date
  end

  def price=(price)
    @price = price
  end

  def venue
    @venue
  end

  def date
    @date
  end

  def price
    @price
  end
end
Using the attr_* methods, the mind-numbingly boring getters and setters can be collapsed into this more readable version...
class Ticket
  attr_reader :venue, :date, :price
  attr_writer :price

  def initialize(venue, date)
    @venue = venue
    @date = date
  end
end
Now, I've written constructors like that one more times than I care to remember in all sorts of languages. And everytime I do it, I feel a twinge of pain, it just feels silly to have to do that mapping of parameters to instance variables manually. When I'm writing Java, IDEA reduces this pain by generating most of it after a few ALT-ENTERs. But when I'm writing Ruby, repetitive constructs like these hurt even more, since that sort of repetition goes against one of the Ruby culture's most fundamental values: DRYness.

And thus the cousin to the attr_* siblings was born: def_init. By using def_init, the constuctor in the example could be reduced to...

class Ticket
  attr_reader :venue, :date, :price
  attr_writer :price
  def_init :venue, :date
end
I'm guessing that this functionality is already out there somewhere, so let me know if I've missed it. Here's the code that makes it happen...
class Class
  def def_init(*attrs)
    constructor = "def initialize("
    constructor << attrs.map{|a| a.to_s}.join(",")
    constructor << ")\n"
    attrs.each do |attribute|
      constructor << "@#{attribute} = #{attribute}\n"
    end
    constructor << "end"
    class_eval(constructor)
  end
end
It's interesting to note how Ruby and Java solve these sort of repetition problems differently. Java tends to solve repetition with excellent tools that generate code at development time, while Ruby tends to solve it through giving developers the power to generate code at runtime.

[/dynamic] permanent link

Sat, 08 Jul 2006

Adding a month to a Ruby Date object

It must be the Perl Hacker in me that enjoys this sort of syntax...
    @event.date >>= 1
Any idea what that does? Well, Date has a method called >> which returns the Date plus the specified months. But I wanted to reassign the Date immediately, so I tried >>= and it worked. If anyone has a cleaner way of doing this, email me.

[/dynamic] permanent link

Fri, 07 Jul 2006

Ruby on Rails TDD Bootcamp

Just thought I'd plug Obtiva's initial venture into the world of Ruby on Rails. If you're interested in learning Rails with a strong emphasis on TDD, take a look. Ruby Primer and Ajax on Rails add-ons are available.

[/dynamic] permanent link

Sun, 25 Jun 2006

RailsConf: Acceptance Testing

Well, my talk is over and whoa, am I sleep-deprived! Why do I procrastinate like that? Well, mostly because I hate public speaking and I nearly always find ways of putting off preparing for stuff that I hate to do. The upside of my procrastination was that I had the flexibility to incorporate last-minute stuff into my talk. Which meant I got to demonstrate FireWatir on the Mac, along with plain old Watir on Windows via Parallels, and most importantly, Alex Chaffee was able to give a 15 minute experience report on his company's use of Selenium RC on Rails, which in a lot of ways stole the show. The audience I spoke to was very responsive and clearly wants to see progress in the acceptance testing space. I believe that with the rise of Ajax, browser-based-testing is an area that is ripe for a lot of movement in the next few years.

It was an awesome, humbling experience to be a part of the stellar community of people that RailsConf drew together. Before I left early to get to my daughter's softball game, I got to hang with Obie and Aslak a bit, and listen to Gareth and Martin make some of the strangest sounds I've ever heard as they watched their football team beat Ecuador.

[/dynamic] permanent link

RailsConf: Homesteading

All of the RailsConf keynotes were in the evening, which meant I missed most of them due to obligations on the homefront. It hurt to not be able to listen to Paul Graham, someone who continualy inspires me with his work. Thankfully, I did get to listen to Nathaniel Talbott talk about Homesteading, an excellent metaphor for the entrepreneurial programmer (which at this conference is a bit redundant). And I loved Nathaniel's use of scripture to supplement his talk.

[/dynamic] permanent link

Fri, 23 Jun 2006

RailsConf: Herds of Macs

I've never seen so many Macs in one place. I'm sitting in Mike's Captistrano talk and here's the table behind me (one of these kids is doing his own thing).

[/dynamic] permanent link

RailsConf Guidebook

I spent the day in Rails Nirvana ... which strangely enough is right near O'Hare ... and has really bad wireless access. But nonetheless, it was awesome. The Guidebook was just what I needed. The begining was ultra-basic Ruby ... but since Obtiva will soon be offering Rails on TDD training and coaching, it was an excellent opportunity to watch the leading Rails instructors in action to see how they introduced people to Ruby (so I could learn how to teach these ideas). And then it got good ... metaprogramming. I had poked around a bit in the guts of ActiveRecord and played with some DSLs, but it wasn't until I listened to Dave's walkthrough of metaprogramming that I could say I really grok'd the stuff. And wow, I'm a different programmer tonight than I was this morning.

The afternoon was spent on Rails. Lots of review, but again, I was looking at it from a trainer's perspective, stealing ideas from Mike and Dave. And I also picked up some new stuff that I hadn't looked into yet: I especially liked Named Routes because they are a more elegant solution than they way I had solved link_to duplication with helpers.

My talk will be on Sunday morning, hopefully a few people will be awake enough to stop by to get a few tips on acceptance testing Rails+Ajax apps.

[/dynamic] permanent link

Tue, 25 Apr 2006

Just capture requirements as fake Ruby code

One of Kent Spillner's reflections on Rich Kilmer's talk at the Silicon Valley Ruby Conference...

He spent the first day on the project pairing with the domain expert, writing everything they said in Ruby assuming the DSL already existed, and then spent the remainder of the project back-filling what was needed to make the DSL work and building the UI. via Obie
Mostly posting this to remind myself that now is the time to adopt this approach.

[/dynamic] permanent link

Thu, 22 Dec 2005

My take on Dynamic vs. Strongly Typed

Update: Dave Astels has alerted me that I am mixing some orthogonal concepts in this post. I'll leave the post as-is, but it looks like I'll need to hunker down and educate myself a bit more before I spout off about this stuff again.

I've followed a recent thread of blog posts that will probably spawn several more threads over the next few days and on into eternity as the conversations and debates over dynamic vs. strongly typed languages perpetuate themselves. This particular thread has not provided a compelling argument either way, but it does bring up some critical issues: 1) the safety provided by strong typing, and 2) the safety provided by strong testing.

I've been programming for 5 years. The first half of those 5 years was spent writing all sorts of Perl code. I remember people shaking their heads (in pity, I think) when they heard I was learning to program with Perl, and I always wondered why. I understand now. Dynamic languages like Perl are insanely powerful. It's like giving a Harley Davidson to a 16-year-old. They're going to do some damage: it's just a matter of time. And with Perl, I did some damage, but I also got it under control and began to use it responsibly.

And then I switched to Java. I was excited to learn Java because it had such a huge mindshare advantage over Perl (not per capita, but just by sheer numbers). I remember the strange constraining feeling of declaring types for the first time. It felt different, but I liked how explicit the code looked when I read it. It was comforting to use a compiler, and the IDE's were incredible!

At the same time I was teaching myself Java, I was beginning to practice test-driven development. Over the second half of these 5 years, I have come to value TDD as the most fundamental practice in my toolbox. It is an enabling practice that allows me to refactor mercilessly and evolve designs incrementally.

Over the last year I have had the opportunity to get back to my dynamic language roots. I've spent about a quarter of my time in Perl and Ruby. Coming back to dynamic languages I have observed two important phenomena: 1) I am suddenly interested in contributing to Open Source again, and 2) (Dynamic languages + TDD) == (power + safety) == confidence.

The comment that spurred me to write this post was from Simon:
Strong testing is fabulous, no doubt about it: the problem is that most developers don't have the discipline to write and update their test suites. The consequence is that, in the real world, there actually are benefits to static typing in complex projects. One way of thinking about static typing is as "just another test suite", except that it's a test suite developers are less likely be lazy about or subvert.
I couldn't disagree more, on so many levels. And comments like these speak volumes about the different perspectives we take as an industry. I currently live in the real world of a complex project written in a static langauge, and I observe daily what little difference that compiler makes in the face of a mountain of untested code. If you don't have the discipline to write tests for your software, then please stop writing software, and by all means, don't use dynamic languages. If people choose strongly typed languages because most of their developers are undisciplined, they've already lost. Paul Graham has more to say about this.

I'll sign off with this thought from Justin and Stuart...
The "safe language" argument appeals to fear, while the "flexible language" argument appeals to a sense of opportunity and adventure. Both are powerful motivations, so for a long time this argument has been a stalemate. Happily, that period is coming to an end. Two new factors have come into play: automated testing and transparency. Over the next five years they will turn the balance totally in the favor of more flexible languages.

[/dynamic] permanent link


powered by blosxom