Monday, December 7, 2009

Why I Don't Like Pair Programming (and Why I Left Pivotal)

First, I want to say that I think pair programming is fine - for other people. Based on pairing fulltime for a month at Pivotal Labs, I've been exposed to both its good side and its bad side.

First, the good side. I think the production of good code with two people working together is greater than with two people working apart. It's not hugely greater. The pair has to generate twice as much code as one programmer just to break even. That's helped by the fact that pairing forces you to spend the day programming instead of goofing off.

But where pairing wins is the "good code" part. From my experience, stupid little bugs (which accounts for the great majority of bugs) are caught much more frequently at coding time. That's a big win.

I also think that there is way less "bad code" produced. "Bad code" can happen when someone makes the wrong design choice and spends time going down a rathole patching and fixing the code.

Those are the good parts of pair programming. I've no doubt left out others. Now for the bad parts.

When you pair program, you're effectively joined at the hip with your pair. You can't pair if only one of you is there. This means that you both come into work at the same time, you both take lunch at the same time, you both take breaks at the same time, and you both leave at the same time. The work is so concentrated that you work 8-hour days (which is good). But you can't take time off without affecting your pair. Working from home is possible, but it's obviously not as pairy as sitting beside one another. This is an aspect of pair programming I hadn't considered until I tried it.

You have to be able to think out loud - 8 hours a day. Then you have to type in code while someone is watching you. They'll catch your typos (hopefully after giving you a chance to spot them yourself) and they'll see when you're floundering for how to do something. This turned out to be my own personal biggest problem with pair programming. When I was at the keyboard, I got dumber. It could be simple nervousness, or it could be that gaps were being exposed in my knowledge - gaps I felt shouldn't exist. Either way, I was not comfortable, and I was definitely less productive than if I were on my own. This is a personal reaction. I don't consider it a failing of pair programming, but a failing of me.

I may have been able to work through this handicap. I certainly learned more in one day than in a whole week of solo programming. And there might have come a time when I was comfortable programming in front of other people. But there was an even bigger problem.

Pair programming doesn't encourage quiet reflection and exploration. You can't just sit back and read some code. You can't just sit and think. I mean, you can, but then your pair is just sitting there. If you both agree that such contemplation is necessary, that's fine, but what if your pair is perfectly happy with an existing way? You don't want to waste their time. You don't want to argue (unless the other person wants to as well). You give in more often than if you were working alone.

This can be a good thing. When each of you have veto power, that reduces the chance of bad design. However, I think it also reduces the chance of truly innovative design (unless you both agree to explore it).

An example might help. We needed to display a graph of the relationship between entities. The models contained the names of the entities and the names of their relationships. The graphing "little language" needed to be generated for each entity and relationship. My pair's idea was to give each model a method to generate the graphing code. I felt that graphing code was for viewing the models - not part of the models themselves. I proposed a Presenter to translate models into views. This certainly sounds more complicated than putting the code in the models, which is what what my pair wanted to do, and so that's what we did.

The design was perfectly workable, but it lead to its own complications as the work progressed. For example, when you click on a node, that node becomes selected. In order for the model to create the graphing code for it, it has to know which node is selected. This meant adding a 'selected_node' parameter to each call to the model graphing code. That wouldn't have been necessary using a Presenter who was in charge of graphing the model tree.

There were other small problems, and I believe more problems would be found as we worked with the code. The reason is because we were violating MVC.

I made this point to my pair (who was an extremely intelligent guy), but he disagreed, so we did without a Presenter. Big deal, right? But when you multiply that scenario by ten or twenty, you'll get some idea of my experience working with pair programming.

TDD? Well, we do it when it's easy. It's not worth testing views, after all. And what difference does it make whether you test before or after you write the code, anyway? Database normalization makes things too slow. MVC requires writing additional classes. Cucumber is only valuable when clients write features. Fixtures are faster than factories and mocking.

These were the sorts of issues that came up during my one month of pairing. And I lost on every point. That, to me, is the greatest drawback to pair programming (at least when I'm doing it). You just want to get the story done. Innovation can be stifled. Programming according to generally recognized principles is cast aside, as long as one of the pairs (especially the dominant one) "doesn't see the need" for it.

And that's the kind of stuff I'm good at. I reckon that 95% of my code over the last 10 years has been written in response to a failing test. I keep view code out of models (and vice versa). I program from the UI in, because I think what happens on the screen and the keyboard is the only truly important part of an application (everything else is implementation details). My database tables are in third normal form. I believe I write well-factored code that is simple because it puts responsibility in the right place. Of course, I know there are exceptions to every one of the preceding principles. But you start by doing it "right."

So that's why I don't like pair programming. My weaknesses are exaggerated and my strengths are vetoed. For me, pairing doesn't work. For plenty of others, it very clearly does work. But not me. And that's why I quit the best company I've ever worked for: Pivotal Labs.

Friday, July 3, 2009

Jane Eyre and feminism

I read Jane Eyre recently. This was necessary because I'm reading Simon Callow's excellent biography of Orson Welles, and I'd got to the part where Welles appears in that movie. I had to see the movie before reading that section of the biography, and I had to read the book before seeing the movie. So it fit in well with my desire to enjoy some of these famous works as I get on in years. Call it a literary bucket list.

For most of the book, I found myself laughing at Jane and the rest of the characters. It's hard for me to imagine real people speaking and thinking in this way. I'd love to hear how they talk after the collective stick had been removed from their asses.

But at some point, I simply accepted the style, and I enjoyed the book far more. The plot was just as ridiculous, however. Mr Rochester goes from talking about marrying Blanche and sending Jane away to clasping her in his arms in the space of a paragraph or two. I never did understand the reason for or in fact any evidence of a transition in his intent. One sentence Blanche - next sentence Jane. We were all expecting it, of course, but it certainly made no sense.

Then there's the amazing coincidence of the house Jane stumbles upon, which just so happens to contain her nearest relatives. She's apparently half-dead by this time from exposure and hunger, but as near as I can tell, she was only away from a soft bed and a hot meal for about three days. Not very stern stuff, one feels.

But the reason I wanted to make this blog post was to react to the statement in the (modern) introduction that Jane Eyre is "one of the most intensely erotic books in the English language." First, it's good of the writer to concede that there are eroticer books in other languages (too bad she doesn't mention what they are, or I would by all means start a course of study in those languages). Second, what the fuck? It is impossible to imagine Jane even possessing a clitoris, much less any kind of erotic feeling.

The writer of the introduction is from feminist school of the 1980's. I am all for feminist schools. I consider myself a feminist and have done since the age of 12. I am so feminist, in fact, that I know that I'm sexist. But besides being erotic, this novel is, according to the writer of the introduction, a triumph of feminism and female power. How can it be, when all Jane does is serve and obey? True, she twice obeys her God over her male masters, but this is hardly empowerment. Throughout the book, Jane is either a slave or trying to become a slave.

I still enjoyed the book. The character was foreign enough to make her interesting. And I did read on, wondering what would happen next. As for the movie, it was fun to see Orson Welles play Mr Rochester. He certainly played the part in my imagination as I was reading the book.

And now I've moved on past that part in Callow's biography of Welles. Tonight I watch The Lady from Shanghai.

Saturday, June 27, 2009

It's hard to make a game easy

I'm just getting to the end of Prince of Persia. It's considered by gamers to be an easy game - too easy, some say. For me, it's just hard enough to make it rewarding but not so hard as to be frustrating.

The first computer game I ever played was Zork. Now there was a frustrating game. I spent literally hours getting nowhere, simply because I didn't use the right combination of words to get something to happen. That, of course, was the challenge of the game. It was a difficult puzzle to solve. It wasn't particularly fair, either. Logic took a back seat to obscurity sometimes. On the other hand, finding one of those obscure combinations of words was tremendously satisfying.

Another way games like this can be hard is to not permit escape from prior bad choices. You didn't pick up that item in the room you were in three weeks ago (in real time)? Too bad - now you're stuck. You have to go back to that point (if you even have a saved game from then) and do it all over. This is not fun by anyone's definition.

But both kinds of game design are easy for the designer. It's actually quite easy to make a game hard. What's hard is to make it easy.

Which is where Prince of Persia comes in. I don't have a lot of time for gaming. I spend perhaps an hour a day, and a few more on weekends. If I choose to stick out a game to the end, it's because it consistently gives me more fun than doing something else. Prince of Persia does that by having puzzles that are just hard enough to make me think (a little bit, at least), but allowing me the freedom to swing across vines without worrying about painting myself in a corner.

Of course, the game is famous for "not being able to die." If you fall off a ledge or get beaten in combat, your companion Elika saves you and you start again from a checkpoint that's usually not too far before the point when you died. Some would say that this isn't challenging enough - that there's not enough "penalty" for doing something wrong. Good! I don't play games to inflict pain on myself, and I don't like having to repeat a sequence of events over and over until I get it right. (This does happen in Prince of Persia, but it's nothing like one situation I was in in Halo 3, where I would spend at least a minute gathering weapons, spend another couple of minutes killing Brutes, die, lather, rinse, and repeat.)

But easy resurrection is just a part of it. Much harder, it seems to me, is the ability Prince of Persia gives you to follow paths wherever and whenever you want, without fear of being unable to get back to where you are. Although the game is essential a platformer, with narrowly-defined places you can go, there are usually at least two ways to get to every important place.

And doing this without making it obvious takes design skill. I suppose one could win the game merely by trying every path in every combination. But it doesn't seem that way. I really feel like I'm exploring, not just following a script.

Monday, June 22, 2009

Assertion as argument

I saw a thread today in which someone asked whether they should add NilClass#to_s to return an empty string instead of raising an exception.

A well-respected member of the Rails community answered by talking about concatenating strings with +. He said

First off, don't do that. String#+ is generally the worst thing you can choose. Second [...]

I had to wonder whether that member would accept a statement like that himself. Don't we programmers tend to examine assumptions and reject arguments from authority?

What he could have said is "String#+ creates a new string by concatenating its argument, so if you're doing it thousands of times a second, it can create problems because of memory consumption. In ordinary practice, it makes no difference."

Sunday, June 21, 2009

Discovering OOP

Before I'd ever really heard of OOP, I was simulating polymorphism by using dispatch tables in structs. I'd define a struct for a listbox, e.g. This would have members for the size of the list, the width, the position on the screen, etc. There would also be a linked list of the items to display. I'd pass these structs around to functions that operated on them. I believe this was called module-based programming. The data was encapsulated in that only certain functions in a certain source file (or module) were allowed to operate on it. So far, so basic.

But sometimes, I'd want to have different functionality on a single listbox (or on a group of similar listboxes). For example, when the user selected an item, maybe I'd want to display information about that item somewhere else. So I'd define a function that was called by the main listbox code when an item was selected. But this function didn't belong with in the main listbox module, since it might be particular to only one application or even only to one screen. So I added a function pointer to the struct. The main listbox code would call that function if the pointer was nonnull. Different listbox clients could define their own functions to get the behavior they needed, without cluttering up the main listbox module.

This is essentially polymorphism - using indirection to select a function to execute at runtime, based on the inherent "nature" of the struct, rather than its incidental contents. Of course, there could be many such function pointers in the listbox struct. Today, we'd recognize this as a dispatch table, implemented in C++ to support virtual functions. But this was 1985, and I'd never heard of C++ or polymorphism. I just knew that I wanted to paramaterize this data structure not only with data, but with behavior. And it worked really well. (This is all obvious to anyone's who's programmed in the last 20 years).

However, the solution wasn't perfect. I eventually came to want to be able to further refine the behavior. I wanted one listbox to act just like another listbox, but also do something additional when an item was selected. This is where inheritance comes in. I ended up adding another function pointer for these cases, that pointed to the original function, and that I could call from the new function. The new function could call the old function before, during or after the new code, or could even completely ignore the old function altogether.

However, this solution never seemed as clean as the first solution of using dispatch tables for polymorphism. It was too obviously hacky having to maintain these chains of function pointers, and too easy to screw up and create bugs.

So imagine my delight when, soon after, I got a job with Sierra On-Line, then (1989) the most prominent adventure game company. They had actually created their own language, SCI, that was a very pure implementation of OOP. I'll never forget that first night reading the documentation on my bed and just being consumed with this language that did things I wanted to do and even things I didn't know I wanted it to do.

Ever since then, I've run into lots of people who talked about the difficulties of making the paradigm shift to OOP. But not me. It was love at first sight.

Monday, May 4, 2009

Listing the contents of your git stash

I had a feeling there was something in my git stash that I'd forgotten to apply. But I couldn't figure out a simple way to list the contents of each of the stashes.

git stash list -p should work, I think, but it just lists one line for each stash, not the diff with the parent.

git stash show stash@{0} shows the contents of one stash, but I don't want to have to do that for each one in the list.

My coworker at Rupture, Rick Fletcher, came up with this, which works a treat:
git show $(git stash list | cut -d":" -f 1)

Wednesday, April 22, 2009

Rails MySQL adapter and tinytext

Ruby on Rails's MySQL adapter doesn't grok the tinytext datatype. The following code will use that type when a text field with limit 255 is defined in schema.rb (which is what the adapter generates when it sees a tinytext in the database).
class ActiveRecord::ConnectionAdapters::MysqlAdapter
original_type_to_sql = self.instance_method(:type_to_sql)
define_method(:type_to_sql) do |*args|
return 'tinytext' if args.first == :text && args.second == 255
original_type_to_sql.bind(self).call(*args)
end
end
Put this code in config/initializers/mysql_extensions.rb.