Misaccounting for Programmer Productivity

When it comes to programmer productivity one metric, widely used in times past, is lines of code produced.  Since code is one of the more visible outputs of a programmer it seems reasonable, at least on the surface, to use this as a gauge of how much work these people you’re paying lots of money to are doing.

The problem with this is that it puts the metric on the wrong side of the accounting ledger.  One of the surest ways to improve the quality of software is to write less of it.  This seems counterintuitive but it’s a natural corollary of the concept of reuse. 

It’s a familiar principle in pretty much every other area of modern life.  We don’t expect construction workers to produce their own vegetables, raise their own cattle, sew their own clothes, make their own mattresses, etc…  because it’s much more efficient for them to focus on construction work and purchase those necessities from people that specialize in producing them.  That is, the construction worker does a better job focusing on construction and gets a better mattress from the mattress maker than if he tried to do both.  The mattress maker needs a place to make mattresses and gets a better quality building if he lets the construction worker build it.

The analogue in software is the use of libraries.  Of course not all libraries are created equal but if you’ve got a choice between using something that’s been specifically built for a purpose that is largely ancillary to your own purpose then you can reap major efficiency gains by taking advantage of it. 

The sorting library that has every kind of sort from merge sort to quick sort to postman’s sort has probably done a much better job at implementing the sorts than you have time to replicate.  Especially if sorting is only a small part of the total piece of functionality someone is paying you to produce.

When considered in that light, the phrase “lines of code produced” seems incongruous.  It should be, to borrow a phrase from Dijkstra, “Lines of code spent” and accounted for as a cost.

A Shortcut a Day Keeps Efficiency Away

What follows is a totally fictional dialog.  It’s the kind of conversation that might happen several times a week on a software team as a release nears.

Hacker, speaking to co-worker, announces: “There’s no way to make these buttons invisible.  They’re initialized by an array that gets set before the screen is displayed. … So I’m just going to disable them instead.”

Co-worker: “But isn’t there a way to remove the buttons?”

Hacker: “There’s a way to add buttons.  … I think it’ll just be easier to disable them.”

In walks Subject Matter Expert (SME) who, after overhearing this conversation, points out: “There’s another screen that does that, it’s probably a good example to use.”

We have reached an inflection point: Does the Hacker go with the technique he figured out after spending quite some time tracking down the issue?  Or does he take the SME’s advice and use the approach used by other screens?

There are many things to be gleaned from the Hacker’s decision that directly bear on how well the software he builds will stand the test of time.

Abandoning an approach that you’ve invested in does not come naturally.  In fact, in other areas of life it’s what you’re not supposed to do.  It’s hard for us even to detect how attached we are to an approach and how that attachment influences our judgment or willingness to abandon it.  But when it comes to software design, like any other exploratory activity, being able to recognize a dead end quickly is crucial to delivering quality on time.

Even though it doesn’t come naturally I’ve found that it does become easier with practice.  Once you’ve done it a few times and, more importantly, reaped the rewards of a system that either functions better or is more easily maintained (or both), those benefits make it easier to swallow the next time.

Sharing a struct definition between managed and native code

By defining a struct in IDL the struct definition can be used in managed and native code.

When the IDL file is compiled the C++ bindings are automatically generated in a header file.  This allows you to use the struct definition from C++.

When the resulting type library is imported by the type library importer the struct gets created along with any other visible IDL type definitions (e.g., interfaces, coclasses, enums, etc…).  This creation involves translating the IDL into IL metadata (you can see the metadata with ildasm).

Troubleshooting:

  1. Make sure the native code builds a type library and that the type library is registered.
  2. Use OleView to see the types included in the type library.  The struct should show up in this list of types.
  3. Don’t typedef the struct in the IDL; although this will compile the type library importer will ignore the resulting alias.  If you want the typedef for use in native code create it manually.
  4. Use the Object Browser or ILDASM to verify that the type library imported the struct.