Monday, January 22, 2007

Author Interview: Brian Marick

Brian Marick, the author of the recently released Everyday Scripting with Ruby, was gracious enough to spend some time talking with my about books (including his), scripting, testing, and Ruby.


Would you please introduce yourself?

Brian: I'm a consultant. I work almost exclusively with companies using Agile methods (Scrum, XP, etc.). My emphasis is on testing in Agile projects, but one of the things about Agile projects is that roles don't work in isolation from each other. So, although I'm usually hired to work on testing, I end up sticking my nose into programming, planning, management, etc.

You've had a long history with Ruby, how did you first discover it?

Brian: In February 2001, I went to a workshop at a ski resort in Utah (the one that ended up writing the Manifesto for Agile Software Development). The shuttle ride to the airport was about an hour. Two of the other people in the shuttle — people I didn't know — were also going to the workshop, so we got to talking about programming. I mentioned that I'd been working with this language called Python and was liking it.

The two people were Andy Hunt and Dave Thomas. By the time we got to the resort, I'd promised to buy the Pickaxe book and try Ruby. As has happened with so many others, it just clicked. Things worked the way I guessed they would, so I learned fast.

What's kept you involved with Ruby?

Brian: Two things, really. One is that it's the best language I have for the kinds of projects I want to do. The other is that I used to be kind of a language geek in my Lisp programming days, and Ruby has that Lisp/Smalltalk air about it: the way there's something conceptually simple at the core that lets you do powerful things. In my Lisp days, I loved _The Little Lisper_, and Ruby inspired me to write a book in that style. I never finished, but the first few chapters are here

I loved that book when you first announced it, and have gone back to look at it a few times since. Any chance it will ever see the light of day?

Brian: There's always a chance... Dave Thomas said the PragPress might be interested in it, but that was long ago. They might be more pragmatic these days.

What warts do you wish the Ruby core developers would clean up?

Brian: I'm pretty happy with the core of the language. If I had one wish, it would be doc strings (originally from Lisp, now used in Python). Here's an example from my .emacs file:


(defun ruby-visit-source ()
  "If the current line contains text like '../src/program.rb:34', visit
that file in the other window and position point on that line."
  (interactive)
  (let* ((start-boundary (save-excursion (beginning-of-line) (point)))
  ...
That string is available at runtime. It allows a further step away from thinking of programming as editing text and then running it, toward programming as a more interactive dialogue with an interpreter — one that, oh yeah, produces a text file you can run again.

I suppose I'd also like something closer to what Lisp gives you: a method's parse tree as a first-class object. Editing and eval'ing strings feels clunky compared to what you can do with Lisp macros. (See Paul Graham's downloadable On Lisp.)

The standard library could use better documentation, despite www.ruby-doc.org. Javadoc-style documentation is weak at helping you get started with a library. (Same goes for RAA packages.)

To my mind, what we need most is an IDE for Ruby as powerful as IDEA is for Java. A few years ago, Ward Cunningham remarked to me that IDEA made using a statically typed language almost as pleasant as using the Smalltalk browser. Coming from an old-time Smalltalker, that's a stunning statement. But it's kinda true. I've been doing a lot of Java programming in the past month, and the refactoring support of IDEA is ever so wonderful. It's not impossible to have that in a dynamically-typed language: the very first refactoring browser was written for Smalltalk.

But that's pretty far afield from the core.

A lot of people bring up Ruby's slowness when this questions is asked. Is it not a big problem for you? Do you think there are other niches where Ruby is fast enough?

Brian: The premise of the book is that there are lots of tasks you do that could be done by a computer. Since the computer will always be faster than you at rote work, Ruby's speed is irrelevant. The thing that's relevant is how long it takes you to get the script working. There, it matters that you use a language that allows you to express your desires quickly, and that you program in a way that helps you from getting bogged down in complexity. Ruby works for the first, and I prefer test-driven design for the second. Even for smallish scripts, I think I'm faster when I use TDD.

Speed is a complicated emotional issue among programmers. When I came into the field, the great debate was between assembly language programmers and young whippersnappers like me who preferred C. Some assembly programmers said that C compilers could never produce good enough code to beat a competent assembly programmer, so people should program in assembly. Others said you should write in C, just put the parts that really need to be fast in assembly (though more people said that than did it). Others said you could program in C, but you should know assembly. That way, you'd know what the machine is really doing, and you could avoid faux pas like passing using records as function arguments instead of pointers to records.

That issue eventually went away because C compilers got better than even good assembly programmers.

But nowadays you can hear the same debate, just with the names changed. I recall reading a posting of Joel Spolsky's in which he decried all those young whippersnappers who graduate knowing only Java. They should learn C so they know what the machine is *really* doing...

A dispassionate person, I think, would see that discussions about speed and programming languages are often only masked discussions about who deserves to be "one of us" and who doesn't, about who's demonstrated enough dedication to be trusted making technical decisions, about what the right balance is between conversatism and technophilia. It's a proxy argument. An important conversation to have, really, but I prefer to ground it in other issues (like refactoring, design patterns, and attitudes toward duplication). That lets me err on the side of using Ruby and dealing with speed when I have to, not when I'm afraid I might have to.

(This does give me the opportunity to point to the story of Mel, which captures the aesthetic dimension of the speed issue.)

What do you like most about Ruby?

Brian: How blocks and modules work together. I *need* blocks for my personal happiness, so a favorite programming language has to have them. Modules and mixins are a nice compromise between single and multiple inheritance.

What made you want to write a book about Ruby? How does your book differ from the growing collection of books out there?

Brian: I didn't start out thinking of this book as being about Ruby. At the first RubyConf, there was talk about what would help Ruby break out into the mainstream. Did it need a killer app (like Zope was for Python)? Did it need a niche (like cgi scripts were for Perl)? The answer has turned out to be a killer app - Rails. But at the time, I suggested that one niche might be testers. Many of them could really save time (and, potentially, their jobs) if they could script their repetitive tasks. But the only languages with documentation or training that reached out to them were the languages embedded into GUI testing tools, which (1) don't have library or language support for non-GUI-testing tasks, and (2) are, by and large, pretty crummy programming languages.

That percolated for a while, until Bret Pettichord and I put together a tutorial called "Scripting for Testers", which walked testers through testing a web app via Watir. But we knew that only gave a taste of scripting. What testers really needed was a book, and I wanted Bret to write it, and Bret wanted me to write it, and eventually I did.

The book teaches scripting via a series of projects, each of which automates a particular manual task. I deliberately chose tasks that do not involve test execution. A lot of the time, testers only think about automating their manual testing, and they don't script other mundane tasks that would have more bang for the buck.

As a result, people started noticing that the book had a larger audience than the title suggested. There are lots of nonprogrammers on software projects who do rote tasks that ought to be automated.

People noticed another thing, too. Testers often write simple scripts that grow and grow and grow as new demands are put on them. At some point, the scripts get confusing enough that they can't grow any more. You hit the wall of complexity, and it's common for testers to hit that wall way too soon. Because of that, the book pushes important coping techniques like test-driven design, fear of IF statements, and a loathing for duplication. A couple of programmers who reviewed the draft thought that a lot of programmers would benefit from that material. So - *poof* - programmers were in the intended audience as well, and the book became "Everyday Scripting with Ruby." I'm really hoping that doesn't limit its appeal to testers.

So the short answer is: this isn't really a book about Ruby. Hope you publish this interview anyway.

What kinds of scripts do testers write as opposed to other kinds of programmers? Can you give us a short example?

Brian: I think you'll find proportionally more scripts that set up big piles of data. Some scripts drive programs, but in an interesting way: they move the program to a particular point where a manual tester takes over for some exploratory testing.

Chris McMahon does interesting things with Ruby support of testing. For example, suppose you have a system built in front of a database (perhaps replacing an old "green screen" application). The system ought to be able to handle all the existing records in the database. So Chris might write a script that semi-randomly finds "interesting" records in the database (via SQL queries), then feeds them into the new system (via SOAP) and checks what happens.

I'm guilty of several "simple scripts that grow and grow and grow". How did you approach refactoring? What place do you see for theory-laden topics like this in a book for 'Everyman'?

Brian: For refactoring, I lean heavily on three rules of thumb: get rid of duplication, fear IF statements, and change your names a lot. You get a lot of mileage out of just being prepared to do those things. (The word "refactoring" only appears twice: once in the glossary, and once in a parenthetical comment in the main text.)

My approach to teaching is to work through examples in print, talking about them as we go. The story told in the book (especially for the second part's example) is pretty close to what really happened, mistakes and all. I even include the bugs I made. When I noticed something ugly in the code in real life and changed it, the book describes what I noticed, why I thought it was ugly, and what I did about it.

The style I teach is very reactive, not proactive. In Part IV of the book, I tell the story of a class named Barker, an abstract superclass. It started out as just a part of the Watchdog class, but then I noticed that there were three methods there that had everything to do with each other and not much to do with any other methods. I pulled them out into a single place — a class — and called it Barker (because it was the part of the watchdog that barked). The Barker happened to bark via email. After that, I added code to bark to a Jabber server (renaming Barker to MailBarker and creating a JabberBarker). Their initialize() methods happened to be identical. Duplication is bad, so I pulled the initialize method into a superclass. As I went on, I found more bits to put up there.

In the 80's, this was called "inheritance of implementation, not specification", and it was considered a Bad Thing. But I think it's an OK thing - so long as you maintain standards of code cleanliness, are willing to change your mind, and have unit tests to help catch you when you mess up.

So: I avoid the problem of theory-laden topics by not talking about the theory much at all.

So it sounds like you're writing about scripting in general, aiming for testers, and using Ruby as the language. The first two are pretty clear, but why Ruby? What makes you think it's the right language for "nonprogrammers . . . who do rote tasks that ought to be automated."

Brian: I'm favoring convenience over speed. That immediately rules out languages without garbage collection.

I think having an interpreter like irb is an enormous help in learning a language, especially the first language. That rules out Java and C#. (What interpreters they have are not, I think, mainstream enough and are annoyingly not the same as the base language.) They also make you tell the language all kinds of things it could figure out itself (type declarations, for example). That's for speed and to eliminate a certain class of programmer mistake. Speed isn't an issue. Decent unit testing catches most of (but not all of) the same mistakes type checking catches, and it's not a hugely important class of mistake anyway.

I think Perl makes it easier than Ruby or Python to write hard-to-maintain programs. In Perl 5, the support for object-oriented programming is pasted on. I believe/hope that object-oriented programming is easy to learn if you don't cloak it in a lot of forbidding mysticism and theory. (Kids do learn Squeak all the time, after all.)

Visual Basic is out because it's not free and because it doesn't run on my Macintosh.

Lisp and Smalltalk aren't oriented toward processing text from files, which is a lot of what the target audience will be doing.

Other languages, like Groovy, don't have as much traction as Python or Ruby.

There's no overwhelming reason to pick Ruby over Python. I do think Ruby is an incrementally better language for lots of small reasons, but I could be wrong. It really comes down to: I've never been motivated to learn Python all that well (despite having maintained a Zope site), so if I were going to write a book, it would be in Ruby.

Since you've said this isn't a Ruby book, which Ruby books do you think people should be reading?

What non-Ruby books should Rubyists be reading?

Brian: I think the cohort of Rubyists who like thinking about programming as an end in itself (not *just* a means to an end) will like Abelson and Sussman's Structure and Interpretation of Computer Programs (long) and The Little Schemer by Friedman and Felleisen (short). (I prefer the earlier versions of _The Little Schemer_ called _The Little Lisper_, but they're out of print.)

When it comes to non-programming books, I don't care what you read: just read *some* book that makes you a more knowledgeable voter. That means something other than a "comfort book": one that will make you feel more virtuous about the opinions you already hold. Two books up on my queue are Barzun's, From Dawn to Decadence: 1500 to the Present: 500 Years of Cultural Life and Armstrong's Islam: a Short History.

3 comments:

murphee (Werner Schuster) said...

About LISP Macros and Ruby:
You can use ParseTree to get the AST of a piece of code as an s-expression; then do some list fiddling to turn the AST into the AST you want to have;
use Ruby2Ruby to turn the s-expression back into Ruby code that you can load (or eval).

ParseTree is available for C/Ruby (with RubyInline) and for JRuby . Having it available as part of Ruby 1.9 would be nice to have something like LISP Macros in Ruby;

Ċ½eljko Filipin said...

Link to http://www.visibleworkings.com/little-ruby/ is broken.

Tom Macklin said...

I am one of those "bad guys" who favors that nasty speed argument that Brian so eleganyly summarized. However, I prefer ruby as my scripting language anyway, as it has, in my opinion, the best C-linkage mechanism of any scripting language (and don't even talk to me about Java's JNI!!!) As a competant C programmer (with strong Prolog sympathies), I can use ruby to craft and profile a concept model, and then re-do the bottlenecks in C as appropriate. As Brian taught me to say, "make it work, make it good, then make it fast." I've been using this model for about 2 years, and it has been working great!