Erudition and Inanity

brian guthrie blogs

Somebody Else's Code

Posted by Brian Guthrie Fri, 11 Jul 2008 14:40:00 GMT

G. K. Chesterton:

[T]he truth is that nobody has any business to destroy a social institution until he has really seen it as an historical institution. If he knows how it arose, and what purposes it was supposed to serve, he may really be able to say that they were bad purposes, that they have since become bad purposes, or that they are purposes which are no longer served. But if he simply stares at the thing as a senseless monstrosity that has somehow sprung up in his path, it is he and not the traditionalist who is suffering from an illusion.

It’s easy to slag somebody else’s code. Sometimes it’s almost impossible not to. Nobody likes a big hairy mess, and if you’re the software development world’s equivalent of a neat freak, as I am, the reaction can be immediate and visceral.

Certainly not all code is great. I find good writing an apt comparison: styles differ, and reasonable people differ in their preferences, but there exist some pretty clearly-defined differences between good writing and bad. Books and articles are written to be read by humans, and good code should be too, but because code has a second, overarching goal of executability and functional completeness, the kinds of structure, syntax, and flow that are so important to a good book tend to fall by the wayside. In code, expressing intent to humans is nice; in writing, it’s everything. Not every line of code receives that kind of care and attention, and when you find yourself staring the kind of tangled mess that promises whole weeks of fun to tease apart it’s hard not to lay a finger of blame on its human stewards. I myself prefer a kind of good-natured mockery when I stumble across something particularly egregious and a have a good guess about the person1 (or, more likely when pairing, persons) responsible.

Even at ThoughtWorks, where we all like to think that we’re pretty decent coders2, I haven’t been thrilled with every line of code code I’ve stumbled across. I find the above quote helpful because, substituting ‘social institution’ for ‘line of code’, it points the way to humility: people generally do things for a reason, and they may be drawing from painful experience that you yourself haven’t had the benefit of, not to mention the kinds of tight deadlines that we’ve all been under before. Resist the urge to rip it all apart until you understand it well enough to approach it with respect and humility.

1 Sarnacke. Kidding! Or am I? Hmm.

2 On our writing I plead the fifth.

Posted in | 1 comment |

Speeding up ActiveResource

Posted by Brian Guthrie Fri, 30 May 2008 02:09:00 GMT

I’ve been knocking around ways to speed up ActiveResource recently. My colleague Tim Cochran discovered that you take a big performance hit from Hash.from_xml (which uses XmlSimple to transform the parsed XML into a hash with a particular structure) and I’ve knocked up a couple of alternatives, one for libxml-ruby and one for Hpricot. I haven’t packaged them up into a plugin yet, but I’ll attach the raw source, and hopefully that’ll help someone.

There’s already at least one other attempt to adapt libxml to ActiveResource floating around, but as far as I can tell it doesn’t work: it doesn’t place the resulting XML in a form that allows ActiveSupport to successfully undasherize the keys, deserialize primitives by their type attribute, and place the result in an ActiveResource object (though it is of course possible that I configured the library incorrectly). I’ve tested the parsers below against the corresponding XmlSimple call and I know that they succesfully deserialize into the desired end result.

  • libxml (extends XML::Document with a to_hash method, roughly 5-10x faster than XmlSimple)
  • hpricot (extends Hpricot::Doc with a to_hash method, roughly 3-5x faster than XmlSimple)

Use them like this:

module ActiveSupport
  module CoreExtensions
    module Hash
      module Conversions
        module ClassMethods
          # libxml
          def from_xml(xml)
            xml.gsub!(/\s*\n\s*/, '')
            typecast_xml_value(undasherize_keys(XML::Parser.string(xml).parse.to_hash))
          end

          # hpricot
          def from_xml(xml)
            typecast_xml_value(undasherize_keys(Hpricot.XML(xml).to_hash))
          end
        end
      end
    end
  end
end

Posted in | no comments |

Six Months with NetBeans on Rails: A Retrospective

Posted by Brian Guthrie Thu, 29 May 2008 16:09:00 GMT

I’m at RailsConf this weekend, capping a six-months engagement delivering a couple of Rails apps written using NetBeans as our team’s primary Ruby editor. We ended up with it because the client requested that we do our all development work in Ubuntu 6.06, and because we couldn’t build a consensus around a more lightweight editor like Vim or jEdit. I thought I’d share some of my thoughts on it for anyone’s who’s interested in switching.

Executive Summary

There’s a lot to love and a fair amount to hate, but it’s a solid alternative to TextMate if you’re not on a Mac.

Stuff I liked

  • The basic refactoring support is surprisingly handy. Until I got back the ability to rename classes and methods I hadn’t realized I’d missed it. I’m told that Aptana can perform similar tricks, but it’s been a while since I’ve tried it out.
  • Likewise, the ability to jump directly to a class definition is handy, although it isn’t perfect. (If you have more than one class of the same name defined but located in different files or scoped to different modules it can’t figure out which one, exactly, you’re referencing, which I suppose is understandable.)
  • RSpec support! A must-have. And the ability to jump back and forth between test and class… most of the time.
  • If you’re a Vi user, the jVi plugin is almost worth the price of switching purely on its own. It’s a truly excellent piece of software, with an enormous amount of tweakability and really support for Vi constructs, and one of my complaints with Vim itself has always been that it lacks good project/directory browsing support, and yes, I’ve tried the Project plugin… again and again and again.
  • It knows to insert an “end” when I hit enter after a block or method definition. Just a stupid small thing, but I miss it now when I don’t have it.

Stuff I didn’t like

  • It opens up a new output window each time you hit Shift-F6 to run a test, leading to a million open output windows after you’ve been using it for a while. This is an enormous pain in the ass, and it’s compounded by the problem of really poor tab management support in the section of the IDE that displays your previous test runs. This is my single biggest complaint.
  • The “jump to file” functionality doesn’t insert automatic wildcards the way TextMate does. This drives me absolutely nuts and it’s something I miss desperately.
  • Method autocomplete doesn’t work well and is far more trouble than it’s worth. I turn it off almost immediately.
  • It does not, and here I am being charitable, have the most attractive design on the face of the planet. I realize that by stating this I am probably slagging the work of some diligent UI designer somewhere, and I realize that you have to work within the constraints of Swing themes across multiple platforms. But it doesn’t stack up well next to the clean design of TextMate, or the brand new, achingly sexy (YMMV) MacVim.

Lessons Learned

  • Use a nightly build, and keep it fresh. It’s the only way to get support for stuff like RSpec. The nightly builds have been stable and make for happy funtimes.
  • Spin up your dev server on the command line rather than using the builtin server runner. Maybe it’s just me, but using an IDE for this just doesn’t seem worth the trouble.

If you’ve spent any time working with Ruby in NetBeans I’d be curious to hear about it.

Posted in | no comments |

Out of Hibernation

Posted by Brian Guthrie Fri, 09 May 2008 05:06:00 GMT

Many people can drink and write; there is, in fact, a grand tradition of engaging in both simultaneously. I am not one of those people1, and have spent much of the last year in this new city, job, and social circle engaged in much of the former and not enough of the latter. Even that cannot suffice to explain my extended absence from blogging; indeed, I must ultimately confess to having surrendered to the shallow charms of sloth. No more! Everything is now deployed, configured, and arranged in more or less the fashion that I desire. I have met the enemy, and he is me, and he is vanquished. Allow me to take a moment and put in an associate cheer for mod_rails.

I’ve also taken the opportunity to finally design my own custom theme. Many good and widely admired technical bloggers use stock or mostly-stock layouts. But it’s my little corner of the internet, and I can stumble blindly around Photoshop as well or better than the next poor sap when the need arises. Folly follows futility, however, with the knowledge that a large proportion of readers will simply consume this content through syndication and never stop to admire the elegant curve of my header, or its tacky nod to Web circa-2.0 fashion. In fact I haven’t even bothered testing it in IE6, and almost certainly never will; I am profoundly, almost fanatically indifferent to legacy browsers, even though their users are, being somewhat behind the technical curve, proportionately far less likely to consume this content through a feed reader and must thus endure my less-than-finely-tuned CSS.

I nonetheless submit that I am part of the solution, not the problem.

Frankly I haven’t tested it in IE7 either. I tried Firefox 3 and Safari 3 and then I got bored and went out for coffee. Either way, expect future blog entries to be more technical and perhaps less baldly narcissistic.

1 I’m young yet, though, and everybody needs a dream.

Posted in | 1 comment |

Give Camino another look

Posted by Brian Guthrie Tue, 12 Jun 2007 14:02:00 GMT

If you ever find yourself frustrated with the choice of Mac web browsers, check out Camino. I’d written it off, but the latest release remembers your tab session (finally) and is both snappy and stable. It’s the best of both worlds, between feature-rich but memory-bloated (and ugly) Firefox and underpowered and frequently unstable Safari. It also features superior tab handling, including single browser mode, which is among my must-haves. Get it at http://www.caminobrowser.org.

Posted in | no comments |

Slides and video from last month's Handshake presentation

Posted by Brian Guthrie Mon, 11 Jun 2007 22:40:00 GMT

I should have posted these a long time ago, but better late than never: the slides from the presentation I gave at last month’s Boston RubyGroup on Handshake are available here in PDF format, and I’ve embedded the video below. I hate seeing myself on camera, so I haven’t watched it yet. Stay put for the big finish, where my laptop’s battery runs out of juice.

I haven’t had much chance to work on Handshake recently, no excuse really, but with any luck I’ll get a chance to push out another release of that and RubySearch before Sunday. Then I’m on to Chicago for a two-day initiation at ThoughtWorks, my new employer, followed by a six-week training session in India. I can’t wait.

Posted in | 1 comment |

On IBM and patents

Posted by Brian Guthrie Thu, 17 May 2007 07:21:00 GMT

The latest Microsoft/Linux patent controversy has stirred up some interesting commentary from former IBMers about IBM’s voracious hunger for new patents. Mark Pilgrim discusses being coerced into filing, whereas Brian Levine, who I’m proud to call a former colleague and mentor during my two co-op stints at Lotus, agrees but takes offense at Mark’s histrionics:

What I take issue with is Mark’s need to point out that he was coerced into filing a patent application and to justify it by pointing out that he has a mortgage. Lots of people have mortgages. Many more people with more significant financial responsibilities than that are asked to do much more heinous things than file a patent in order to keep those jobs.

Software patents may suck, but Brian is right: they should not rank that high on any reasonable scale of heinosity.

IBM has been the patent king for many years now, and I suppose it makes good business sense: if you employ more engineers than virtually anyone else in the world it behooves you to exploit them in any way you can. But even if you believe IBM’s claim that its software patents are purely defensive, a shift in management could change everything in a heartbeat. It’s not all that long ago that they were suing Amazon for patent infringement. Although I don’t mean to cause any offense, it seems to me that forcing software engineers to patent anything even remotely novel is a reasonable disincentive for those of us who are concerned with the future of software IP to work there.

Posted in | no comments |

You can take the software company out of the jungle

Posted by Brian Guthrie Mon, 14 May 2007 16:22:00 GMT

But etc. In my job search this past semester I declined to apply there, even though I have contacts, and now I remember why.

Microsoft takes on the free world

Posted in | 2 comments |

Benchmarking Handshake

Posted by Brian Guthrie Sat, 12 May 2007 20:49:00 GMT

I gave a presentation on Handshake at this past Tuesday’s Boston RubyGroup and had a great time. There was a large crowd (although I suspect most were there to see Hackety Hack in action) and I got a number of excellent questions at the end. In particular people were curious about performance characteristics and whether disabling a contract system in production mode is a wise idea. I’ll address the question of mechanisms for selectively disabling and enabling Handshake in particular classes in a future post.

I tend to think that it’s fine as long as you’re aware of the situation and plan for it. A contract system will always impose a performance overhead, even with languages that support it natively, and you can anticipate its absence by using conventional exception mechanisms at sensitive spots, like the places where your code interacts with data from the outside world. But I can’t admit to much experience in that regard.

Nonetheless it’s probably worth knowing the answer to the question of exactly how much of a performance overhead Handshake imposes. I’ve run some tests and the results aren’t pretty.

Methodology

To perform the tests, I created two classes modeled on the BankAccount example I presented on Tuesday. The first checks the class and methods by enforcing contracts on it, much like the example, while the second checks it by raising conventional exceptions. Seeing them side-by-side gives a good feeling for the added expressiveness you get with contracts. I’ve included them both below. For this test I made a large number of deposits and withdrawals on three different objects: one checked with Handshake, the underlying object wrapped by Handshake’s proxy, and one checked conventionally,

Finally, I created a simple one-line class that does nothing except include Handshake so I could get a feeling for the performance penalty it imposes on object creation (class Foo; include Handshake; end). For this test I created a large number of convention Ruby objects, objects that include Handshake and define contracts on the constructor, and objects that merely include Handshake without adding any contracts.

Infinity = 1.0/0

class BankAccountHandshake
  include Handshake

  invariant("balance must always be positive") { @balance >= 0 }

  positive_n = 0..Infinity

  contract positive_n => self
  def initialize(balance)
    @balance = balance
  end

  contract positive_n => anything
  before do |amount|
    assert( (@balance - amount) >= 0, "Amount: #{amount} must be less than balance: #{@balance}")
  end
  def withdraw(amount)
    @balance -= amount
  end

  contract positive_n => anything
  def deposit(amount)
    @balance += amount
  end

end

class BankAccountChecked

  def initialize(balance)
    raise Handshake::ContractViolation, 
      "Given balance #{balance} must be greater than or equal to 0" unless balance >= 0
    @balance = balance
    raise Handshake::ContractViolation,
      "balance must always be positive" unless @balance >= 0
  end

  def withdraw(amount)
    raise Handshake::ContractViolation,
      "Given amount #{amount} must be greater than or equal to 0" unless amount >= 0
    raise Handshake::ContractViolation,
      "Amount: #{amount} must be less than balance: #{@balance}" unless ((@balance - amount) >= 0)
    @balance -= amount
    raise Handshake::ContractViolation,
      "balance must always be positive" unless @balance >= 0
  end

  def deposit(amount)
    raise Handshake::ContractViolation,
      "Given amount #{amount} must be greater than or equal to 0" unless amount >= 0
    @balance += amount
    raise Handshake::ContractViolation,
      "balance must always be positive" unless @balance >= 0
  end

end

Deposit and withdrawal

Benchmark.bmbm do |bm|
  [ :handshake_enforced, :handshake_ignored, :nohandshake_checks ].each do |name|
    account = tests[name].call
    bm.report(name.to_s + "_iteration_50_000") do
      50_000.times { account.deposit 100; account.withdraw 100 }
    end
  end
end

Updated: After running this test, I altered the Proxy class to lazily create named methods each time method_missing is called. The performance increase is considerable-around 33%-and I haven’t released the fix yet but I’m adding a line to the tests below to reflect the improved performance.

test user system total real
handshake_enforced 6.560000 0.030000 6.590000 6.694150
handshake_enforced_cached 4.390000 0.020000 4.410000 4.452219
handshake_ignored 0.060000 0.000000 0.060000 0.058443
nohandshake_checks 0.120000 0.000000 0.120000 0.116770

Object creation

Benchmark.bmbm do |bm|
  [ :handshake_enforced, :handshake_nochecks, :nohandshake_checks ].each do |sym|
    bm.report(sym.to_s) { 100_000.times( &tests[sym] ) }
  end
end
test user system total real
handshake_enforced 4.270000 0.020000 4.290000 4.305064
handshake_nochecks 2.250000 0.010000 2.260000 2.271066
nohandshake_checks 0.190000 0.000000 0.190000 0.193954

Analysis

It’s much slower than I feared, so slow that I wonder whether my benchmarking methodology is flawed. A walk through the relevant architecture might be in order in order to determine why exactly performance takes a hit, but feel free to skip.

Handshake uses the included module callback to alias the relevant class’s new method. It replaces the existing method with one that checks constructor contracts and class invariants, actually instantiating the object as necessary. Rather than returning the instantiated object, it returns a new proxy object that wraps the original object. The Handshake::Proxy class, through a combination of method_missing and forwarding, intercepts all method calls, performs a lookup on the relevant method, and executes any defined contracts as necessary.

Although the problem doesn’t seem purely algorithmic, the large disparity in object-creation performance between the Handshake class that performs contract checks and the Handshake class that doesn’t (the checked constructor is twice as slow) suggests that there are ways to optimize the checking mechanism.

The other problem is that the system removes virtually every Ruby runtime optimization and redefines several language-level mechanisms. Method arity isn’t preserved (because it can’t be). Methods defined on Object are redefined in Proxy. Method_missing imposes its own performance penalty.

As I see it, then, this leaves two opportunities for further performance improvements: caching method calls and rewriting some portion of the library in C. I’ve played with the Ruby/C bridge but I’m expert in neither C nor the Ruby runtime. I’m also leery of these types of low-level solutions because providing Windows support is difficult, and because they wouldn’t be compatible with JRuby. I’m much more adept with Java than with C, so perhaps I’ll perform similar tests with the JRuby runtime and use that as a starting point. I’ll report back here if I get that far.

Posted in | no comments |

Career announcement: I'm joining ThoughtWorks

Posted by Brian Guthrie Mon, 07 May 2007 03:51:00 GMT

Update: I’m not sure if I made this clear below, so just for the record: ThoughtWorks is a cool company with a great reputation and I’m thrilled to be joining them. All of my comments below should be taken in the spirit of that statement.

I’m tickled pink to announce that I’ve accepted a job with ThoughtWorks as some kind of Ruby guy and so I’m moving from Boston to Chicago to live the dream of 80-100% travel to places that are not Chicago. I thought it might be worth explaining briefly why I chose them.

In short: I get to work in Ruby (apparently), on a diverse range of projects, in diverse settings, at considerably greater job security than I might find at a startup; I expect to learn a tremendous amount about developing good software; it’s a change of scenery and a chance to travel; everyone at the interview impressed me, and were kind enough to let me geek out over Handshake, yea, even unto the whiteboard; and significantly, I couldn’t find anything credibly negative about the company, either from former employees or outside observers. If they suffer from a little hubris, well, there are far worse sins to have.

I’d also like to note that everyone I met at the interview event, in particular their founder Roy, was remarkably and even alarmingly candid. It was a breath of fresh air.

The job starts on June 18th, and shortly thereafter I’ll be attending ThoughtWorks University for six weeks. I’ve always wanted to see India. I also have to relocate to Chicago between now and then; I don’t know anything about the city, and if anyone has any advice about living and working there I’d love to hear it.

Posted in | 2 comments |

Older posts: 1 2 3 4 ... 6