Archive for the ‘Uncategorized’ Category

pair programming pros and cons

Wednesday, May 27th, 2009

I typed up the following in response to Bryan Liles’ recent Pair Programming Showdown.  There are better pair programming lists out there, but this is mine for today.

positive:

  • distractions are less common, it needs to be something that distracts both of you; get back into “the flow” faster (also a reason to do TDD); helps those among us with Attention Deficit be productive at *all* (this is an important one for me).
  • higher bus number, more team ownership of code, less personal jurisdiction
  • communication of design decisions is much easier/faster: “here, let me show you what I mean.”
  • creative tension, generally leads to better design decisions, better names for variables/classes/etc, better quality. Automatic “code review” on all pair produced code, at the time when it’s easiest to enact suggestions.
  • because you’ve cut the number of concurrent tasks your team can work on in half, you’ve made it easier to coordinate a larger team and juggle the team’s current tasks and priorities. In other words, pairing makes it easier to scale the team. Your team members are less likely to step on each other’s feet.
  • team culture grows more quickly, quick tips (did you know how to do X in vim? see how inject makes this simpler?) spread through the team more quickly. This could be mentoring of junior developers, or new fresh ideas for senior developers, or peers balancing and pulling each other out. A pairing team tends to gravitate towards the *highest* common denominator, versus individuals working together, tend to be bottlenecked by the weakest link.
  • pairing and TDD(BDD) go great together, even if you aren’t occasionally ping-pong pairing
  • morale boost: team camaraderie grows faster.

difficult or negative:

  • requires soft-skills, i.e. getting along with other devs, communicating, not being stubborn, etc.
    • good pair programming is a learned skill, but often is treated like something that should Just Work (and is obviously no good if it goes poorly on the first try).
    • the pairing experience can be spoiled by either person in the pair.
    • programmers are overwhelmingly introverts, and we would much rather just work (and be) alone, even if it isn’t the best thing for the team.
  • fewer tasks can be done concurrently. When you are being asked to finish 20 “highest priority” tasks by yesterday, even though it is probably faster to have four people pair on them, doing only two tasks at a time, our instincts are to divide and conquer (four tasks concurrently).
  • either there is no music (no headphones) or you need to agree/compromise on what to listen to.
  • it can be hard to replace the personal pride of “I did this” with the team pride of “we did this”, even if “We did this” really means “I did this and so-and-so helped out and it was better than if I did it alone.”
  • pairing (done right) can be more exhausting than working alone. this is mostly because you aren’t getting distracted as much, you are forced to defend your (often bad) ideas, and you have gotten more done. but still, it’s more *work* than working alone.
  • working with different editors is tricky. doable, but tricky. it slows you down and dampens some of the benefits.
  • remote pairing is tricky. doable, but tricky. it slows you down and dampens some of the benefits.
  • Awkward pairing:
    • mindless routine tasks feel like a waste of time, and sometimes they are.
    • research and spiking and experimentation are sometimes very appropriate for pairing, sometimes not at all, and it’s hard to tell when is which (very context sensitive).
    • pairing without the cadence of TDD(BDD) often feels awkward. (ahem… perhaps you should start to TATFT then!)
    • pairing done wrong (and sometimes even “done right”), might not *feel* very productive to one member of the pair. at that point, that person probably feels it is a waste of time, and the other person feels slightly guilty for wanting to pair. Note, this might be far more about emotions and perception than about logic and empirical reality.

In summary

Because of the above positives, pairing usually results in better code, done in less time, with more team members able to take ownership over it, than if the developers had worked on it individually.  Programming isn’t constrained by typing speed but by thinking, and two heads are better than one.

The above negatives mean that (in my experience), even when an entire team agrees that pairing is a good thing (in the abstract or based on experience) and the team has agreed to pair some or most of the time, the team often pairs less often or gets less out of it than expected.

Unfortunately, although I’ve experienced all of the positive reasons for pairing, I tend to get far too influenced and disheartened by the negative.  As a result, I usually pair far less often than I know I should, and both I and my team are less effective as a result.  Any suggestions?

See also these posts: Obie Fernandez, responding to criticism of his pair programming comments, Mike Hill: How TDD and Pairing Increase Production.

please don’t use before(:all)

Saturday, February 7th, 2009

Please do not use “before(:all)” (in rspec) unless it is imperative for performance reasons. Even then, it should only be used with the utmost care given towards any global or shared state, and with no expectations on order of the spec run. You will cause strange build failures if you do not heed this warning.

Each individual example (”it” blocks) should be able to run by itself or in any order and the example group (”describe” blocks) may run in any order, even in random order.

Corollaries:  If you change any global or shared state inside an example, please ensure that you reset it to a baseline before the next example.  If you depend on any global shared state, please set it to a baseline before this example.  Both of these are achieved easily with a before(:each) block (or after(:each) in some cases).

Nine times out of ten, when I see a weird sporadic build failure and there is a before(:all) nearby, I can fix it merely by changing it to a before(:each).  The original author of the spec assumed that it would always run front to back and then proceed to change global or shared state in some of examples (sometimes inadvertantly).

Although I’ve phrased this advice for rspec, it applies equally to test/unit in ruby, or xUnit on any platform.

mock abuse – asserting the implementation

Tuesday, February 3rd, 2009

I use mocks (and stubs and other test doubles) for checking expectations: I’m a “mockist“.  Likewise, a guideline for specs or unit tests is to focus on testing your code (separately from integration tests which might exercise the full stack), and assume that the framework has tested its own code.  However, I think that this guideline is sometimes taken too far, leading to mock abuse.

Here are some guidelines that help me follow another important principle: test the interface, not the implementation.

  • If the test looks like a copy and paste or trivial transformation of the production code, something is probably wrong.
  • “Complex” code should be avoided in specs, especially if it is a reproduction of the production code (e.g. SQL, ActiveRecord::Base#find conditions, and non-trivial regular expressions).
  • I prefer business language examples over technical language modeling (e.g. “belongs_to” or “verifies_format_of“).

Some (bad) examples

As an example of what I’m talking about: Testing Named Scope with shoulda’s should_have_named_scope (also should_belong_to, should_have_one, and should_have_many from shoulda’s ActiveRecord Macros).  The rails documentation for named_scope also suggests that you can test it by looking at the proxy_options method.

What’s wrong with the following?

# from rails rdoc:
expected_options = { :conditions => { :colored => 'red' } }
assert_equal expected_options, Shirt.colored('red').proxy_options
# from shoulda
should_have_named_scope :eighteen,  :conditions => { :age => 18 }
# example of the sort of thing I've seen in codebases I work with
Model.should_receive(:find)
     .with(:all,
           :conditions => ["foo => ? and (bar like ? or blatz in ?)",
                           foo, bar, blatz]).and_return([...])
# I've also seen bastardizations of the above for SQL building
# code which gets piped into a mocked Model.find_by_sql

Should your specs care if those conditions are created as hashes or arrays, or even at all?  From the outside, it is completely unimportant whether it uses named_scope or a conditions hash behind the scenes.   What you should care about is whether or not they return the correct objects, don’t return the wrong objects, and (maybe) stack appropriately with other named scopes or finder methods.

More practically, those conditions hashes qualify as production code that represents the very core of the business logic you are supposed to be testing.  If you expect that {:colored => 'red'}, but the column name is “color” or the value is actually stored in hex RGB, you won’t have a hint that the code is broken.  If you expect that {:age => 18}, your specs won’t remind you that you were actually supposed to be matching 18 and older.  If you expect the wrong SQL, then your specs have lost their power to help you find the right SQL.  You are wide open for letting sloppy bugs through the very specs that should have caught them.

So, these mocks verify expectations that don’t matter much, but they copy and paste the bits that do matter, the parts you really should be testing.   You are gaining “code coverage”, and thus false confidence.  It’s like a weird form of regulatory capture.  However, a few examples of what you should and should not match would clarify many mistakes immediately.  When working with examples, the boundaries that you need to poke often become obvious.

Good examples: Named scope or finder methods

# the following lines would generally be done using factories
good_examples = [FooBar.create!(...),
                 FooBar.create!(...), ...]
bad_examples  = [FooBar.create!(...)
                 FooBar.create!(...), ...]
# now exercise the code under test
results = FooBar.my_spectacular_finder_or_named_scope(...)
# expectations
good_examples.each {|e| results.should     include(e) }
bad_examples. each {|e| results.should_not include(e) }
# or perhaps
results.should == good_examples

This wins in almost every regard over mocking SQL or checking the conditions hash or proxy_options.  It is clear what is being tested and how. We are oriented towards results, not implementation. The examples should make it clear if we are missing anything.

However, it is not as concise, but it doesn’t matter how concise bad specs are.  We could make macros to make the above code more concise, while still retaining the clarity.  It would also be nice to follow the “one assertion per example” rule, so that developers get fine grained failure notifications.

And it may be slower if it hits the DB, but it doesn’t matter how fast bad specs run.  This is a trade-off  of the ActiveRecord ORM style: to test that you wrote the right queries, you need run the queries and verify the results.

Alternatively, this style is well suited to cucumber or fit tables, enabling the subject matter experts to easily contribute their own examples (and detect mistakes that the developer wouldn’t know about).

Good examples: Validations

Sorry to pick on shoulda above… but it was the easiest example to google for.  To balance the scales there, I do like two of the macros shoulda uses for validations: should_allow_values_for and should_not_allow_values_for.  I also wrote up a short little rspec matcher that does about the same thing.

# shoulda's macros
should_not_allow_values_for :phone_number, "abcd", "1234"
should_allow_values_for     :phone_number, "(123) 456-7890"
# my rspec validation matchers
it { should.reject(:phone_number).of "abcd" }
it { should.reject(:phone_number).of "1234" }
it { should.accept(:phone_number).of "(123) 456-7890" }
it { should.accept(:phone_number).of "(123)456-7890" }
it { should.accept(:phone_number).of "123-456-7890" }

Specs that verify that the “appropriate” regular expression was sent to validates_format_of scare me.  Regular expressions aren’t just opaque blobs, they are a DSL, a programming language in their own right.  Regexes are code, and we test code.  You shouldn’t care that a particular regular expression is sent to a particular rails validation macro; you care that your model validations work appropriately, i.e. accept some values and reject others.

When I’ll ignore my own advice

Here are some contraindications:

I just don’t know what to do:  I might be exploring new realms, and feel a bit lost.  Writing some specs, any specs, is a good way to learn, a good way to keep focused while working, and a good way to just get the job done (TATFT).  Even if the specs are no good and tightly coupled to implementation, at least they can act as “change notifiers”.  The next time someone edits the code, they’ll trigger a build failure that will force them to re-evaluate the specs.  Maybe they’ll come at it with more knowledge and improve the situation.

Pair programming significantly reduces the likelihood of this occurring.

too much yak shaving, time to punt:  I know what to do, but it’s too much work.  For example, if you have some models that are so truly heinous that you cannot simply or clearly create them right there in your spec, my first instinct would be to invest some time in my factories.  It’ll pay off.  But that is yak-shaving, and it may be too much for now.  “Emergency mocking” is excusable.  Document your compromise in the spec, and hopefully that technical debt will be repaid in the future.

But excessive mocking can feel like yak-shaving too.  Weigh your options before going the “quick and dirty” route; it might actually be slow and dirty.

debugging and sanity checks:  If I’m trying to figure out why the results aren’t what I expect them to be, I’ll probably throw in some extra assertions about the implementation, as a sanity check.  I might delete them when I’m done or keep them in but document them as special.

There may be other contraindications, but these are what come to my mind.

What do you think?

Ubuntu is “too easy”?!

Monday, January 19th, 2009

I’d like to respond to a meme that has spread around the linux neighborhoods of the Internet for a while now:

“I’ve been using Ubuntu for quite some time now and, honestly, I’m getting a little tired of having everything handed to me. I want to switch to a less noob friendly distro.”

“Is anyone else worried, that because Ubuntu is so stable, and because you rarely have to fix issues, that your Linux knowledge is fading?”

“I want to use a distro that will challenge me to learn how things work.”

And so on…

My response

You might enjoy giving Debian a try.  You also have the option to go with Arch Linux or Slackware or Gentoo or Linux from Scratch, etc.  You could also install Ubuntu JeOS or Ubuntu Server (or another distro’s simpler versions) and then only apt-get or compile software as you want it.

If you are the type of person making the same sort of remarks as above, you obviously have a lot of time.  I’m jealous of you.  ;-)   But lots of time is not limitless time.  So if you want a challenge that will pay off, I suggest that your time might be better invested by sticking with Ubuntu (or Debian), and simply diving under the hood a bit more.

I don’t mean to say that any of the other distros or paths you might choose aren’t valid… one of them may well be a better fit for you and your ambitions than Ubuntu.  But, unlike proprietary OSes, Ubuntu’s hood is not welded shut.  Much of the “magical” hand-holding is done in shell, perl, or python scripts.  So you may not even need to look further than your own box for the source.   And just because Ubuntu is intended to be user-friendly with no-assembly-required doesn’t make it any less configurable or less geek friendly, nor does it get in the way of your deconstructing and reconstructing it (and wondering about those leftover pieces at the end).  The wires and pipes are all showing, there’s no magic going on, and you are in control of your box.

for example

Are you interested in mucking around with webservers?  Then go ahead and compile apache/nginx/lighttpd/etc from source yourself.  Muck about with the config files.   Spend days with man pages and google and upstream’s bugtrackers. Use the distro’s packages as a “cheat sheet” to see what patches, config, scripts, etc the distro maintainers used, and then selectively pick and choose your own way from there.  Rig up benchmarks or compare them on features, ease of configuration, etc.

Post your troubles/successes/thoughts/etc to mailing lists and blog about what you’ve done.  Post the results to launchpad or github or some other publicly accessible DVCS repo.  Respond to the comments of the people who tell you you’re doing it all wrong (many of them are right).  Adjust your approach and iterate until something else more interesting catches your interest.

other examples

Or do the same thing with…

  • mail servers (postfix/sendmail/exim/etc)
  • filesystems:
  • X Windows
  • GNOME or KDE
  • Dig into HAL and D-BUS and all of those magical goings-on beneath the covers, and learn how to make them do your bidding.
  • Learn about LSB and freedesktop.org.
  • Figure out what Ubuntu did wrong with pulseaudio, and then fix it or swap it out with another audio stack.
  • Learn how dpkg/apt does its magic,
    • understand the Debian packaging guidelines (and why they are wonderful or horrible or just don’t meet your needs or desires),
    • and start your own Launchpad PPA for software packaged the way you like it.
  • Run “ps faux” and make it your mission to discover the purpose behind every running process and how it got there… and then remove or replace the ones you don’t want.
    • Run “dpkg -l” and do the same thing with every package on your system.
  • Install bootchart and figure out how to shave several more seconds off of your boot-time.
  • Restore the geeky log messages to the Ubuntu boot screen.
  • Spend a week figuring out out to use wmii,
    • another week with xmonad,
    • and another with awesome;
    • Ubuntu doesn’t force you to use metacity or compiz (or GNOME).
  • Install the 64-bit version,
    • discover all the myriad places it breaks horribly,
    • and file bug reports with all of those packages.
  • Obsessively install the latest beta version of some software you like a lot,
    • and report the new bugs on every release.

When you’ve picked out an interesting challenge and jumped into it: Post, respond, adjust, iterate.

personally

I personally use my own compiled version of ruby and related libraries, because the ruby upstream maintainers released a new “minor” version with myriad backwards incompatibilities (and a few segfaults), and the Debian/Ubuntu maintainers followed their advice and upgraded. But the software at my day job still needs that older version. Ubuntu doesn’t make it hard to do this for the packages that I know and care about, and I get to continue relying on Ubuntu for everything else I don’t care about and don’t want to spend time on (right now).

Several years ago, I compiled compiz/beryl myself. Then I switched to someone else’s apt repository. Now I just use the compiz provided by Ubuntu (and I can spend those regained several hours a week geeking out on something else).

Years ago, I used debian unstable for everything.  Now I really appreciate the stability and twice a year upgrades of Ubuntu.  Generally, my “ls /etc/apt/sources.list.d/ | wc -w” stays between 2 and 6 (currently 3).  Occasionally this less stable software is an unwelcome source of bugs and a time-sink.  But I try to always file bugs.

So then…

The opportunities for non-hand-holding non-newbie stuff in Ubuntu is limitless. You could transform yourself into one of the gurus that holds other people’s hands. You could even make it your goal to become a Debian package maintainer or an Ubuntu MOTU or a GNOME contributor or a KDE contributor or a $FOO contributor (which will look mighty nice on a résumé).

but practice safe geeking

But above all, consider doing your experimentation on a spare computer or in a VirtualBox VM, so that when your friends ask you to play a movie or browse the web or do something simple (that their “welded-shut” Mac or Windows box can handle just fine), you don’t need to say “oh my computer’s currently hosed… {sound,X Windows,TV Tuner,booting,etc} doesn’t work. It’ll be back up in a week.” In my experience, that excuse can get kinda embarrassing. :-)

xkcd.com web comic

From xkcd.com, Cautionary, CC licenced By-NC.