The New Openness

2010 March 4
by avdi

Herb Sutter wrote a post explaining the ISO meaning of the word “open”. I responded:

I understand that this was once a perfectly acceptable interpretation of the word “open”, but the software world has moved on. Groups like the IETF, W3C, and WHATWG - not to mention the Open Source movement as a whole – have set a new bar for what it means to be “open” in computing. And by and large the standards emanating from those groups have been the better for being transparently and publicly debated, and made available for free.

Not to mention the positive effect the new openness has on standards adoption. I can tell Github that I think they are using the wrong HTTP response code in a web service, and they can google “http response codes” and check it for themselves in a matter of seconds. They would be less likely to do that if they had to purchase some PDF and search through it.

The ISO version of “openness” is one of the reasons the English-speaking Ruby community has largely taken the view that the effort to create an ISO standard around Ruby is irrelevant and not worth their attention. I recently created a wiki just so interested people could have a place to openly pick apart and discuss the draft Ruby standard. I shouldn’t have had to do that.

I’m in the camp that thinks standards are useful and worthwhile efforts. C++ in particular has benefited from a robust standardization process. The world has changed, though; for the better in my opinion. “Open” means more than it ever has before, and that’s a good thing. Standards organizations would do well to embrace the new openness, or risk decreasing relevance.

Bookmark and Share

Removing files with varied capitalization

2010 March 3
tags: ,
by avdi

Nothing ground-breaking today, just a one-liner that I expected to be longer than a one-liner.

# Remove Rakefile, rakefile, RakeFile, etc...
File.delete(*Dir.glob('rakefile', File::FNM_CASEFOLD))
There are two notable things going on here:
  1. Dir.glob can take optional bitflags; in this case, FNM_CASEFOLD means to ignore case.
  2. File.delete can take N arguments.
Bookmark and Share

ruby-standard.org

2010 March 1
tags: , ,
by avdi

So there’s this draft ISO standard for the Ruby language. Is it a good standard? Is it useful to implementors? Do we even need a standard? I don’t know, I don’t know, and I don’t know.

What I do know is that it’s hard to have a meaningful conversation about a document which exists only in the form of a monolithic PDF, and for which the only public forum is an issue tracker.

So I give you ruby-standard.org. If you think that it’s helpful to the Ruby community to have a discussion about the standardization effort, I hope you’ll spend a few minutes helping to wikify the standard. If you think the standard is irrelevant, feel free to ignore this and move along. I don’t have an agenda with this; I just want to provide a place for the community to discuss the standard if it thinks the standard is worth discussing.

Bookmark and Share

Getting Pedantic About Ruby Semantics

2010 March 1
by avdi

I just can’t resist the tempation to be an asshole language lawyer.

Yehuda thinks that it’s important to keep a semantic model of Ruby behavior in mind, and not get hung up on implementation details. He’s right. While it’s important to understand the implementation, with a half a dozen or more different implementations of Ruby out there, it’s more and more important that we understand the semantics of Ruby as a language separately from Matz’ Ruby Interpreter (MRI).

The best resource we have for determining the semantics of Ruby-as-a-language is the draft ISO standard. The draft standard is not without it’s problems, not the least of which is that wider Ruby community hasn’t exactly been encouraged to participate in the standards process. But it’s the closest thing we have to a definition of Ruby’s semantics divorced from any specific implementation. I looked up the parts of the standard which pertain to blocks, in order to see if Yehuda’s mental model of Ruby agrees with that of the creator of Ruby.

Here’s the part defining blocks:

11.2.2 Blocks

[...]

Semantics
A block is a sequence of statements or expressions passed to a method invocation. A block can be called either by a yield-expression (see §11.2.4) or by invoking the method call on an instance of the class Proc which is created by an invocation of the method Proc.new to which the block is passed (see §15.2.17.3.3).

And here’s the part which specifies the semantics of &block arguments:

A block parameter: This parameter is represented by block-parameter-name. The parameter is bound to the block passed to the method invocation.

[...]

13.3.3 Method invocation

The way in which a list of arguments is created are described in §11.2.

Given the receiver R, the method name M, and the list of arguments A, take the following steps:

a) If the method is invoked with a block, let B be the block. Otherwise, let B be block-not-given.

[...]

Push B onto [[block]]. [This is a notational convention indicating an attribute of an execution context -Ed].

[...]
iv) If the block-parameter of L occurs, let D be the top of [[block]] .

I) If D is block-not-given, let V be nil.

II) Otherwise, invoke the method new on the class Proc with an empty list of arguments and D as the block. Let V be the resulting value of the method invocation.

III) Let n be the block-parameter-name of block-parameter.

IV) Create a variable binding with name n and value V in Sb .

As I read the standard, Yehuda is incorrect in his interpretation of Ruby block semantics. Blocks are non-object entities which form one of the attributes of an execution context. If the method provides a name for the block in the form of an &block parameter, then and only then is an object created, by explicitly calling Proc.new.

Does it matter that this model differs from Yehuda’s? In at least one respect it does. Yehuda points out that in MRI, the object_id of a given block is always the same even. By my read of the standard, this is an optimization, and not something to rely on as a part of Ruby’s semantics.

But that’s not the end of the story. The stated intent of the Ruby ISO standard is to formally describe the the behavior of MRI 1.8.7. So does it, in this case? Let’s see:

class < < Proc
  alias old_new new
  def new(&block)
    puts "in Proc.new"
    old_new(&block)
  end
end

def foo(&block)
  puts "In foo"
  bar(&block)
end

def bar(&block)
  puts "In bar"
  block.call
end

foo do
  puts "In block"
end

# >> In foo
# >> In bar
# >> In block

It certainly doesn’t look like Proc.new is being called here. Now, whether this is because MRI is not flexible enough to enable an effective redefinition of Proc.new, or whether Proc.new is never called, is unclear without the assistance of a C-level debugger. If the latter, then Yehuda’s mental model is closer to the real behavior of MRI than the draft standard.

And when standards no more reflect reality than any given hacker’s imagination, the question becomes: what semantics do you think the language should have, moving forward? As a statement of what he thinks the semantics ought be, I personally think Yehuda’s mental model is pretty reasonable, and consistent with Ruby’s “everything is an object” philosophy. But stating that it is the canonical semantics of the language upon which Ruby hackers should base their assumptions – that seems a bit presumptuous to me.

Bookmark and Share

Calling Grandparents in Ruby

2010 February 25
by avdi

I’m not the first to post about this, but it’s worth re-posting since not everyone knows how to do it.

Ruby makes it easy to call an objects’ superclass methods:

class Parent
  def foo
    # ...
  end
end

class Child < Parent
  def foo
    super
  end
end

But what if we want to call the super-superclass method, skipping over the superclass definition? Or what if an included module has overridden the superclass method?

class Parent
  def foo
    # ...
  end
end

module Interloper
  def foo
    puts "Bwahaha all your foos are belong to us!"
  end
end

class Child < Parent
  include Interloper

  def foo
    # ???
  end
end

You can do it, of course (this is Ruby); but the means may not be immediately obvious:

class Child < Parent
  include Interloper

  def foo
    Parent.instance_method(:foo).bind(self).call
  end
end
If it's not clear what's going on here: we're creating an UnboundMethod object representing the Parent#foo method, binding that method to the child class instance, and immediately invoking it. It's a bit unwieldy, but when you want to be absolutely sure of which method implementation you are calling, this is the best way to go.
Bookmark and Share

Come see me in Harrisburg tonight!

2010 February 18
tags:
by avdi

If you’re in the central PA region and interested in learning some techniques for making your Ruby coding style cleaner and more confident, come see me speak tonight at the Harrisburg Ruby Group. I’ll be delivering an improved and reorganized version of the Confident Code talk I gave last month at B’More on Rails.

Bookmark and Share

Looking for a new NullDB maintainer

2010 February 16

NullDB network on Github

NullDB network on Github

I love Open Source. NullDB, a weekend hack that I barely touched after its first version, continues to attract periodic forks and patches. For a long time I’ve been meaning to sit down and roll in all the contributions that people have made over the last couple of years.

But I realized something yesterday. I haven’t used ActiveRecord for anything serious for around a year. And I can’t imagine choosing to use ActiveRecord for any projects in the future, because I literally can’t think of a single scenario in which AR is a better choice than DataMapper. (Just as an example of DataMapper’s awesomeness: it turns out NullDB isn’t even needed for DataMapper, because you get it for free).

There isn’t a foreseeable future in which I’ll be using NullDB regularly, and if I’m not using it it’s never going to be a priority for me. Which, realistically, means it’s never going to have my attention.

I think the time has come to turn NullDB over to a new maintainer, someone who has a more active interest in testing ActiveRecord-based codebases. The ideal candidate would:
  1. Be using NullDB on a daily basis.
  2. Have submitted at least one tested NullDB patch.
  3. Be committed to the NullDB philosophy of preferring public APIs to fragile monkeypatching.

If you think this describes you and you are interested in becoming the NullDB maintainer, please get in touch.

Bookmark and Share

RubyPulse

2010 February 10
tags: ,
by avdi

Rubyists: are you watching RubyPulse regularly? This show has rapidly become one of my must-see screencasts. Each episode is just a few minutes long, and demonstrates just enough of a useful Rubygem to give you an idea of what it is and what it’s good for. As someone who dislikes lengthy tutorial videos (I prefer textual documentation for in-depth learning), I find these to be the perfect length. Highly recommended.

(Disclaimer: my Hammertime gem has been a featured project.)

Bookmark and Share

Everything You Love about Java is Everything I Love About Good Design

2010 February 9
by avdi

I just read Why I love everything you hate about Java. You should too. There are some very good points about modularity in there.

Unfortunately they are all mixed up with some unnecessarily combative us-vs-them rhetoric. Apparently in Nick Kallen’s view, as a Rubyist I slap my hands over my ears and start rocking back and forth when I hear the words “Dependency Injection” or “Factory”.

Let us be clear. If you are a Rubyist and your hackles do rise at the phrase “Dependency Injection”, you need to check yourself. Using a dynamic language shouldn’t mean throwing the Gang of Four out the window. And anyway, you probably use software daily – such as Rails – which is just lousy with enterprise design patterns.

The patterns Nick cites – Dependency Injection, Factory, and Decorator – are patterns I use daily. They are some of my favorites, to the point that they are practically second nature. For instance, here’s a paraphrased and simplified example from some production code I wrote:

def execute_shell_command(command_line, options={})
  shell_command_maker = options.fetch(:shell_command_maker) {
    ShellCommand.method(:new)
  }

  command = shell_command_maker.call(command_line, options)
  command.execute!
end

This example combines Factory and Dependency Injection and tops them with some Convention Over Configuration sauce. The dependency on a command line object is injectable, and we inject it by passing in an optional factory named :shell_command_maker. This factory, rather than having to be a Factory class, can be any callable object – such as a lambda. If no option is specified, the code uses ShellCommand.new() to instantiate the object. We can inject a different command line class:

execute_shell_command("ls", :shell_command_maker => RemoteCommand.method(:new))

But we can just as easily inject something fancier. Lets inject a ShellCommand wrapped in a logging Decorator:

require 'delegator'
class CommandLogger < SimpleDelegator
  def initialize(shell_command, logger=Logger.new($stderr))
    @command = command_line
    @logger = logger
    super(shell_command)
  end

  def execute!
    @logger.info "Executing '#{@command}'"
    super
  end
end

logger = Logger.new($stdout)
make_logged_shell_command = lambda do |command_line, options|
  CommandLogger.new(ShellCommand.new(command_line, options), logger)
end
options = {
  :shell_command_maker => make_logged_shell_command
}
execute_shell_command("ls", options)
execute_shell_command("ps aux", options)
# ...

What I find repugnant about Java development is not the use of industrial strength patterns, but the fact that using those patterns in Java is so awkward, high-ceremony and obtrusive that people wind up writing entire books on simple concepts such as dependency injection. A fact which Nick seems to have grasped as well, since he’s writing his examples in Scala, a language with a level of expressiveness similar to that of Ruby.

The Java ecosystem warps your brain into a mode of thinking where modularity patterns like DI and decoration are like ancient gods which can only be invoked with a great deal of pomp and ceremony. And I think that perspective tends to make it hard to see that other programmers use the same patterns, just with less fanfare. For an even better take on this topic than mine, read Jamis Buck’s classic account of writing and discarding two Ruby DI frameworks.

Bookmark and Share

Cargo Cults and Dharma Transmission

2010 February 8
by avdi

Here’s a pattern I see a lot in discussions of development practices:


Skeptic:
I’ve tried practice X, and it doesn’t work

Believer:
What do you mean it doesn’t work? It works for me and everyone I know. You must be doing it wrong.

Skeptic:
Nonsense. I did it exactly the way the book says to do it. You’re just a blinded by the kool-aid.

Believer:
Unprofessional lout.

Skeptic:
Deluded imbecile.

Believer:
I know you are, but what am I?

You get the idea.

I highlighted what I think is the key point n this conversation: the fact that the Skeptic learned about Practice X from a book. It could just as well have been a Wikipedia article or a series of blog posts. The point is that our Skeptic tried to put into practice something which he had never witnessed first-hand, and was disappointed at the results.

It strikes me that there is a form of cargo-culting going on here. Only in this case, when the cargo planes fail to arrive, the cultists experience an understandable crisis of faith. Sometimes followed by a period of angry backlash against the”faithful”.

In some Buddhist traditions the concept of “Dharma transmission” is held to be central. A Dharma transmission is the direct person-to-person teaching from master to student. A teaching is regarded as true and authentic if a lineage of direct transmissions can be traced, teacher to teacher, all the way back to Sakyamuni Buddha himself.

Dharma transmission cannot occur through reading holy books. It must occur in person. I think this may sometimes be true of software development practices as well. We have a wealth of books and articles on best practices. You can learn everything there is to know about Test-Driven Development or Separation of Concerns without ever leaving your desk. But without sitting down with a master and working through a real-world problem, you risk missing that moment of enlightenment when everything clicks into place.

I’m usually quick to say “you’re doing it wrong; read more and try again” when I see people complaining about practices that I find profoundly beneficial. But maybe that isn’t helpful. Maybe some understandings can only be effectively passed by direct transmission.

Bookmark and Share