Identify the Problem before the Solution

Posted by James Mead Tue, 15 Jul 2008 08:17:57 GMT

I was interested to read “Hold Off On Proposing Solutions”. It seems like humans have a natural propensity to immediately start thinking about solutions…

From pp. 55-56 of Robyn Dawes’s Rational Choice in an Uncertain World: Norman R. F. Maier noted that when a group faces a problem, the natural tendency of its members is to propose possible solutions as they begin to discuss the problem. Consequently, the group interaction focuses on the merits and problems of the proposed solutions, people become emotionally attached to the ones they have suggested, and superior solutions are not suggested.

Is this behaviour that you recognize in yourself or others? I know it’s something that I’m guilty of doing. How can we try to avoid this behaviour? At the risk of sounding like a small child, Sakichi Toyoda’s “The 5 Whys” is one idea…

The five whys is a question asking method used to explore the cause/effect relationships underlying a particular problem. Ultimately, the goal of applying the 5 Whys method is to determine a root cause of a defect or problem. The technique was originally developed by Sakichi Toyoda and was later used within Toyota Motor Corporation during the evolution of their manufacturing methodologies. The tool has seen widespread use beyond Toyota, and is now also used within Six Sigma.

Also see the “Ask yourself ‘Why?’ five times” section of “The Toyota Production System”.

In my experience some people react better than others to being challenged in this way. It’s all too easy for someone to take it personally. You need a high level of mutual trust and real open-mindedness for this to work effectively.

Hold Off On Proposing Solutions” suggests that another technique is to explicitly stop trying to think of an answer, but I suspect this is easier said than done…

Traditional Rationality emphasizes falsification – the ability to relinquish an initial opinion when confronted by clear evidence against it. But once an idea gets into your head, it will probably require way too much evidence to get it out again. Worse, we don’t always have the luxury of overwhelming evidence. I suspect that a more powerful (and more difficult) method is to hold off on thinking of an answer. To suspend, draw out, that tiny moment when we can’t yet guess what our answer will be; thus giving our intelligence a longer time in which to act.

Although it’s not very tolerant, I have some sympathy with the following extract from GeraldWeinberg’s C2 wiki page...

Becoming a Technical Leader” had more impact on me than just about any book I’ve seen. My favorite anecdote from it goes something like this: If a group of people ask you to help them, ask them what the problem is. If they tell you about a solution, ask them again what the problem is. If they again tell you a solution, walk out of the room. There is nothing you can do to help them.

Not something you’d really want to do, but it points out one thing that I suspect is universally true. If people spent even an eighth as much time examining a problem as they do trying to mend flawed solutions when they are stuck, they’d be much more productive. See HearProblemFormSolution. —MichaelFeathers

Not specifying an solution is often seen as a weakness by management types. I think the opposite is the case. The ability to keep an open mind and always seek out the best solution is tremendously powerful and worth fighting for.

Tags , , ,  | no comments

Rising Damp

Posted by James Mead Sun, 13 Jul 2008 22:26:37 GMT

Introduction

The Pragmatic Programmers and the Ruby on Rails community can take a lot of credit for introducing many developers to the DRY principle (Don’t Repeat Yourself). This principle is often interpreted very literally, i.e. many developers go to great lengths to avoid duplicate chunks of code in their application. Sometimes it’s applied too literally, but that’s another story. However, I’ve noticed over the years that there are other more insidious ways that dampness can creep up on you especially as your project and team grows.

Insidious Dampness

One such way can occur when a new library gets added to a project. If there is duplication between the new library and an existing library, you need to get your damp meter out. There are many good reasons to introduce a new library, e.g. it may allow a neater solution to the problem at hand, it may offer better performance, or it may be more actively maintained.

However, there are also bad reasons to introduce a new library, e.g. the existing library (with duplicate functionality) wasn’t noticed, the use of the existing library was not understood (but could have been used), the new library looked “shinier” (neophilia), or “religious wars” between team members. I plead guilty to having introduced libraries for such bad reasons in the past, but I hope that I’ve seen the error of my ways ;-)

Keeping the Damp at Bay

If you don’t have a good reason and can’t convince the rest of your team, don’t introduce the new library. If you do have a good reason, replace the existing library with the new library and update the code that was using the existing library – don’t just add the new library and use it only in your new code. The worst case scenario is when a new library is added, but the existing one is not removed.

The Value of Consistency

In my opinion, the value of consistency is often under-estimated, particularly in bigger projects where you are striving for collective code ownership. I think it’s better to have a consistently mediocre solution across the board rather than half a dozen different solutions varying from good to bad. This is because it’ll take much less effort for the team to understand and therefore maintain the code. What’s more, if you want the good solution, it’ll be much easier to apply it to all the consistently mediocre versions of the code at the same time.

A (very) old blog post of mine about “Big Refactoring” makes a similar point…

But this approach has the disadvantage of leaving the system in an inconsistent state with parts of it working one way and other parts working another way. This isn’t so bad in itself, but when it occurs multiple times without the inconsistency being removed, it can lead to a very confusing code-base.

As does “Sometimes it’s right to be wrong” by my former colleague Nat Pryce …

If you cannot refactor, be consistent. Consistency makes code easier to understand and maintain, even if the code is consistently awful.

Conclusion

A lack of consistency adds unnecessary complexity to your code. Libraries with duplicate functionality violate the DRY principle. Both of these result in an increase in Technical Debt.

Tags , , , , , ,  | no comments

Vim Learning Curve

Posted by James Mead Sat, 12 Jul 2008 22:52:35 GMT

Because I’ve been doing a lot of remote pair programming using vim and screen, I’ve been making a real effort to improve my vim skills in order to be more productive and feel like I’ve made some progress. Chris has rightly suggested that the only way to really improve is to make vim your editor of choice even when not remote pairing, so that’s what I’ve been trying to do. I’ve come across a few useful but random bits and pieces which I thought I’d record in case they were useful to anyone else…

Textile

I’m using a vim syntax file for Textile written by Kornelius Kalnbach to write this article.

svn blame

I’ve found Tammer Saleh’s key mapping for svn blame useful…

  vmap gl :<C-U>!svn blame <C-R>=expand("%:p") <CR> \| sed -n <C-R>=line("'<") <CR>,<C-R>=line("'>") <CR>p <CR>

I decided to invest a bit of time understanding how it worked and broke it down as follows…

  # key mapping for visual mode
  vmap gl
  # remove all characters between the cursor position and the beginning of the line
  :<C-U>
  # current file with full path
  <C-R>=expand("%:p") <CR>
  # pipe std out to sed which only outputs line N to line M
  \| sed -n N,M
  # line number of first line of selection
  <C-R>=line("'<") <CR>
  # line number of last line of selection
  <C-R>=line("'>") <CR>
  # print output
  p <CR>

Search & Replace

At the end of last week, Chris & I found out from Ibrahim Ahmed’s blog how to search and replace across multiple files...

  # select file on which to operate
  :args path/with/wildcards
  # find pattern, replace with replacement, and save file
  :argdo %s/pattern/replacement/ge | update

vimdiff

vimdiff seems like a nice tool, but unfortunately it doesn’t immediately play well with svn diff and its --diff-cmd option. There seem to be a couple of alternatives: (a) write a wrapper script for vimdiff which works with --diff-cmd; or (b) write a script which uses svn cat and then calls vimdiff.

Test::Unit

One of the things I really want to be able to do, is run Ruby Test::Unit tests and view the output, so I can jump to the line where an assertion failed. I haven’t managed to find anything suitable on the web, so here’s my first attempt…

  function! Ruby_run_tests()
    let results = tempname()
    set splitbelow
    silent execute ":! ruby % > " . results . " 2>&1 "
    silent execute ":10 sview " . results
  endfunction

  map <silent> <F7> :call Ruby_run_tests()<cr>
  imap <silent> <F7> <ESC><F7>

I’m sure this isn’t the best way of doing it, but when you put this in your vimrc file, pressing the F7 key runs the current file using Ruby and pipes the results to a temporary file. This temporary file is opened in a read-only window 10 lines high at the bottom of the screen. By moving the cursor onto the relevant line of any stack trace, you can then use “goto file” key sequence gf to goto the failing assertion. Although for some reason this only seems to work the first time round for me.

Ideally I’d like to be able to do the equivalent of “run focussed test” in TextMate, which should be quite straightforward, but that’ll have to wait for another day.

In the meantime, I’d love to hear from anyone else who has useful vim tricks for Ruby development. I’ll be bookmarking any useful links I find on del.icio.us.

Tags , , , , , , , , ,  | 4 comments

Optional Parameters in Mocha

Posted by James Mead Sat, 12 Jul 2008 11:30:03 GMT

One of the new features added in Mocha 0.9 is the ability to specify the values of optional parameters without requiring them to be present. Some examples should make this clearer…

Let’s assume we’re trying to set up an expectation for the invocation of a method which has some parameters with default values…

  def my_method(one, two, three = 3, four = 4)
    # implementation
  end

We can use the new Mocha::ParameterMatchers#optionally method within the call to Expectation#with as follows…

  object = mock('object')
  object.expects(:my_method).with(1, 2, optionally(3, 4))

This specifies that we are expecting an invocation of my_method. As usual, the first two required parameters (one & two) must have values 1 & 2 respectively. However, the last two optional parameters (three & four) only have to have the values 3 & 4 respectively if they are supplied.

So any of the following invocations would satisfy the expectation…

  object.my_method(1, 2)
  object.my_method(1, 2, 3)
  object.my_method(1, 2, 3, 4)

Whereas none of the following invocations would satisfy the expectation and an error would be raised…

  object.my_method(1)
  object.my_method(1, 3)
  object.my_method(1, 2, 4)
  object.my_method(1, 2, 4, 4)
  object.my_method(1, 2, 3, 5)

Tags , , , ,  | no comments

Mocha 0.9 Released

Posted by James Mead Tue, 24 Jun 2008 19:14:00 GMT

There’s been quite a bit of work going on in Mocha over recent months, but a release is long overdue. The API is now pretty stable and so this release jumps from version 0.5 to 0.9. Much of the work has been refactoring Mocha’s internals to support new features and make the code more maintainable.

Before attempting the refactoring, extensive acceptance tests were added. One of the benefits of this is that it should now be easier to write new acceptance tests if you want to suggest new features or illustrate a bug ;-)

Here’s a quick summary of the changes in the release. I’ll try to post some code examples here in the near future.

Ordering constraints

Based on the JMock constraints with the same names…

Configurable warnings or errors

  • When a method on a non-public method is stubbed
  • When a method on a non-existent method is stubbed
  • When a method on a non-mock object is stubbed (partial mocking)
  • When a method is stubbed unnecessarily (i.e. the stubbed method is not called during the test)

See Configuration for more details.

Improved error messages

  • A more readable and complete list of unsatisfied expectations, satisfied expectations and state machines.
  • Display more sensible failure message for any_instance expectations.

Parameter matchers

  • New to this release: optionally (allows matching of optional parameters if available), yaml_equivalent (allows matching of YAML that represents the specified object), responds_with (tests the quack not the duck).
  • Nesting of matchers is now supported.

Syntax shortcut

An optional block can be passed into the Standalone#mock method. The block is evaluated in the context of the new mock instance and can be used as a shortcut to set up expectations.

Ruby & Rails compatibility

Tested with Ruby 1.8.4, 1.8.5, 1.8.6 & 1.9. All related bugs and warnings believed to be fixed.

Tested with Rails 1.2.3 & Rails 2.1.0.

Deprecation

There is no longer any need to have a “require ‘stubba’” statement in your code. A deprecation warning has been added to this effect, because the file will be removed in a future release.

Bug fixes

Posted in  | Tags , , , , , ,  | no comments

Mocha Mailing List Move

Posted by James Mead Thu, 19 Jun 2008 20:32:38 GMT

The Mocha Mailing List has moved to Google Groups.

  • Group name: mocha-developer
  • Group home page: http://groups.google.com/group/mocha-developer
  • Group email address mocha-developer@googlegroups.com

Tags , , , , ,  | no comments

Nasty Ruby Bug Affecting Test::Unit

Posted by James Mead Sat, 05 Apr 2008 00:10:06 GMT

Introduction

Some time ago, while I was pair-programming with him, Chris alerted me to a Ruby bug he’d come across which was interfering with the diagnosis of a bug in our application. Since then I’ve tried to find out more about it, but couldn’t find much, so I’ve done a bit of investigation and thought I’d post it here in case it’s useful to anyone else. The bug has long since been fixed, but I’m sure there are still people our there with the affected versions of Ruby 1.8.6.

Ruby bug

As far as I understand it, the bug is in Ruby’s Kernel.at_exit hook. A call to Kernel.exit(false) should cause the process to exit with an exit status of 1 indicating the process did not complete successfully. The bug means that calling Kernel.exit(false) from within Kernel.at_exit incorrectly causes the process to exit with an exit status of 0.

The most relevant bug report is #9300 and the most relevant mailing list thread is made up of:- [ruby-core:10746], [ruby-core:10748], [ruby-core:10760].

The fix seems to be in changeset 12126…
r12126 | nobu | 2007-03-23 16:53:42 +0000 (Fri, 23 Mar 2007) | 9 lines

* eval.c (ruby_cleanup): exit by SystemExit and SignalException in END
  block.  [ruby-core:10609]

* test/ruby/test_beginendblock.rb (test_should_propagate_exit_code):
  test for exit in END block.  [ruby-core:10760]

* test/ruby/test_beginendblock.rb (test_should_propagate_signaled):
  test for signal in END block.

Implications for Test::Unit & Rake::TestTask

The bug has some important consequences. Test::Unit makes use of this mechanism to report test failures. Unfortunately, the bug means that a Test::Unit process will always return an exit status of 0 even when there have been test failures.

From test/unit.rb:
at_exit do
  unless $! || Test::Unit.run?
    exit Test::Unit::AutoRunner.run
  end
end

This in turn means that a Rake::TestTask process will also always return an exit status of 0 even when there have been test failures. This is significant, because many continuous integration systems rely on Rake::TestTask processes returning an exit status of 1 to indicate that there have been test failures. Thus you will get false positive passing builds – not good.

Affected versions of Ruby

I’ve built and installed a number of versions of Ruby and run tests on them to try to establish which ones are affected. Although they aren’t comprehensive, here are the results…

affected? version
N ruby 1.8.4 (2005-12-24) [i686-darwin8.10.3]
N ruby 1.8.5 (2006-08-25) [i686-darwin8.10.3]
N ruby 1.8.5 (2007-03-16 patchlevel 37) [i686-darwin8.10.3]
N ruby 1.8.5 (2008-03-03 patchlevel 115) [i686-darwin8.10.3]
Y ruby 1.8.6 (2007-02-17 patchlevel 0) [i686-darwin8.10.3]
Y ruby 1.8.6 (2007-03-13 patchlevel 0) [i686-darwin8.10.3]
Y ruby 1.8.6 (2007-03-16 patchlevel 2) [i686-darwin8.10.3]
Y ruby 1.8.6 (2007-03-19 patchlevel 4) [i686-darwin8.10.3]
Y ruby 1.8.6 (2007-05-22 patchlevel 5) [i686-darwin8.10.3]
Y ruby 1.8.6 (2007-05-22 patchlevel 6) [i686-darwin8.10.3]
Y ruby 1.8.6 (2007-05-22 patchlevel 7) [i686-darwin8.10.3]
N ruby 1.8.6 (2007-05-22 patchlevel 8) [i686-darwin8.10.3]
N ruby 1.8.6 (2007-05-23 patchlevel 9) [i686-darwin8.10.3]
N ruby 1.8.6 (2007-05-23 patchlevel 10) [i686-darwin8.10.3]
N ruby 1.8.6 (2007-08-22 patchlevel 50) [i686-darwin8.10.3]
N ruby 1.9.0 (2007-11-28 patchlevel 0) [i686-darwin8.10.3]

Tags , , , , , , , , ,  | no comments

Prefer Commit Notes over Comments

Posted by James Mead Sat, 29 Mar 2008 19:05:00 GMT

My colleague, Chris, recently posted about what makes a good commit note. His main point is that a good commit note should explain why the changeset exists rather than what it contains (which should be more self-evident). I agree with this and (as Chris mentions) it’s of particular benefit when you have to do some software archeology. I’d go a step further and say that, for me, the best commit notes express the business reason for the changeset. If as a developer you are struggling to explain the business case for a particular change, (imho) you should try to find out before committing – otherwise how do you know the changeset is delivering value to the business?

In a previous post about preferring tests over comments, I expressed similar sentiments about using comments and tests to explain why rather than what. Chris’ post prompted me to re-read that old post and I noticed that it didn’t explain why I prefer tests over comments. The reason is that comments have a nasty habit of becoming out-of-date and getting left lying around to confuse the unwary, whereas you are forced to keep tests up-to-date (assuming they are part of a continuous integration build). For similar reasons I also think that commit notes are better than code comments, because they are forever associated with a snapshot of the code at the time they were written – leaving less scope for confusion.

Tags , , , , , , , , ,  | 2 comments

Java Rehabilitation Clinic

Posted by James Mead Mon, 17 Mar 2008 09:23:26 GMT

Not long after Ben persuaded me to join the fledgling Reevoo, we got our first big ReevooMark partners (Dixons & Currys) live. To celebrate this event and my having left Java behind at Thoughtworks, Ben bought me a Java Rehabilitation Clinic mug. The mug has recently developed a crack. I wonder if it’s trying to tell me it’s time to learn another language…

java-rehab-clinic-mug

Java Rehabilitation Clinic mug

Tags , , , ,  | 1 comment

Remote Pair Programming

Posted by James Mead Thu, 13 Mar 2008 09:48:22 GMT

A while ago, Chris mentioned that we’ve been trying out a few ideas for making remote pair-programming easier. We’ve been doing quite a bit more remote pairing recently. Most of the time we just use a combination of VNC (I’ve been using Vine Server) and voice over Skype (using a headset really helps).

But something else we’ve used successfully is multi-user GNU screen sessions. The advantage of this technique is that much less bandwidth is required and the terminal is much more responsive. I thought I’d post the magic incantation we’ve been using (on OSX), in case anyone else finds it useful…

  # on the server
  sudo chmod u+s /usr/bin/screen

  # first user connects to server over ssh and runs the following
  screen -S <session_name>
  ctrl-A :multiuser on
  ctrl-A :acladd <client_username>

  # second user connects to server over ssh and runs the following
  screen -x <server_username>/<session_name>

Tags , , , , , , , , ,  | 2 comments

Older posts: 1 2 3 ... 9