Showing posts with label ruby. Show all posts
Showing posts with label ruby. Show all posts

Sunday, 16 December 2012

Dickens on Ruby on Rails

There is much good in it; there are many good and true people in it; it has its appointed place. But the evil of it is that it is a world wrapped up in too much jeweller's cotton and fine wool, and cannot hear the rushing of the larger worlds, and cannot see them as they circle round the sun. It is a deadened world, and its growth is sometimes unhealthy for want of air.

- Charles Dickens, Bleak House

Saturday, 18 June 2011

gets gets my goat

I'm participating in a virtual study group on the book Seven languages in seven weeks. The first week has been on Ruby, which has been a liberating and and frictionless experience - except for one glitch.

One of the exercises in the book involves writing a primitive grep in Ruby. This program reads text line-by-line from stdin and echos the lines that contain a fragment specified as a command-line argument.

My first attempt looked something like this:
#!/usr/bin/ruby 
while line = gets
    puts line if line.match ARGV[0]
end 
But when I tried to run it...
> ./grep.rb foo
./grep.rb:3:in `gets': No such file or directory - foo (Errno::ENOENT)
 from ./grep.rb:3
After a lot of head-scratching, I finally figured out that gets behaves differently if there are command-line arguments. From the Ruby documentation on gets:
Returns (and assigns to $_) the next line from the list of files in ARGV (or $*), or from standard input if no files are present on the command line.
So, I actually needed to do this:
#!/usr/bin/ruby 
while line = STDIN.gets
    puts line if line.match ARGV[0]
end 
After becoming a little frustrated at this seemingly inexplicable overloading of gets, I took a moment to think about why it bothered me so much.

One benefit that Ruby advocates often cite about the language is its adherence to the Principle of Least Surprise. So in the case of this particular unpleasant surprise, I felt cheated.

But then I realised that the strength of my reaction was a backhanded compliment to Ruby. The gets incident stuck in my mind only because it contrasts so strongly with the rest of my experience of Ruby as a consistent and well-designed programming language.

Sunday, 11 October 2009

Vision is a feature

A few weeks ago Mark Whiting and I had a brief Twitter conversation about his suggestion that as design quality increases the designer disappears. He went on to suggest that the formalism we when recognising a designer's work is as much an imperfection of the design as a feature.

I was not so sure. There are definitely instances where the designer's mark seems to contribute to the design. Programming languages are a good example. Ruby would not be what it is without the strength of Matz's personal vision.

On the other hand, I do get annoyed when a designer's vanity tempts them to graffiti their signature onto a design that would have been better left alone. I'm thinking here of 'clever' designs like teapots with two spouts.

The difference between these two scenarios is, in my opinion, is whether or not the design space is convergent. I mean the term in the same sense as convergent evolution. In a convergent design space, the differences between designs will gradually disappear over time as individual designers are gradually more successful at approximating the best solution to the problem at hand.

In such a domain, it follows that any deviation from the one true design is noise. The designer's personal touch therefore detracts from their attempt to produce good design. A double-spouted teapot might help the designer express their individuality, but the result is just slightly less convenient tea.

However, it's rare to find a design space where a Platonic 'best' design exists. When have the various stakeholders in the construction of a new building ever agreed what is best? And to revisit my earlier example, which language is 'best' is one of the most common topics of programming flame wars.

Designers usually have to balance competing interests. How much should the finished product cost? What kind of user/customer should it be optimised for? What about older users/customers, or ones with disabilities? And not least, when is the deadline for the completed design? How designers balance these interests will inevitably affect the design. There is rarely any objective way to balance these subjective interests, so there is rarely an objective best design.

In such open design spaces, the designer's vision serves an important purpose - coherence. There are so many elements in a complicated design that it can be hard to take them in all at once. A strong authorial vision helps users/customers by giving them a guide to predict and/or remember the designer's choices.

Many Ruby admirers speak of the Principle of Least Surprise. Ruby is comparatively easy to learn and understand because its design choices aim to produce the least astonishment in the programmer. But since every programmer comes from a different background, they will each have different expectations and standards of astonishment.

So more precisely, Ruby was designed according to the Principle of Matz's Least Surprise. Once the programmer gets a handle on Matz's programming aesthetic, they can make educated guesses about parts of the language that they have not yet encountered.

So in conclusion, the formalism we when recognising a designer's work is a feature because it makes understanding complicated design simpler.