Category: programming

“Technical debt” concept can be harmful

I think classifying certain types of programming as “paying down technical debt” via “rewrite” can be harmful. In my experience, when people say “pay down technical debt” they often mean stop moving forward on the product and spend some time “rewriting” or “investing in infrastructure”. They do the work in a vacuum, without the context of actually solving problems / adding features. They end up either a) achieving subjective code beautification (“making the code less hacky”), or b) adding premature optimizations (“We need to add support for ___ so that we can scale later”).

Rewriting is almost never a good idea, as Joel Spolsky explained in a memorable essay. And premature optimization is “the root of all evil” about 97% of the time, according to Donald Knuth. Bug fixes removed in the name of clarity will have to be re-discovered and re-added; wrong-headed optimizations will have to be removed.

And who decides which code issues should be classified as “technical debt”? It seems very subjective.

Programming isn’t a code-production activity, it’s a knowledge-acquisition activity. Good programmers don’t focus on cranking out code and then fixing it later. They continually rewrite code as necessary to solve problems / add features / improve performance as their understanding of the problem increases.

If you’re managing programmers and they say something about accumulating technical debt, ask them about it. Ask why they consider it technical debt. Have a discussion about what it really means and whether it’s a valid concept or an excuse.

Mac app version utility

As part of my process for releasing a new version of Arq, I needed a way for my script to get the version of an app bundle.

So, I wrote a simple utility called appversion which prints the value for the CFBundleVersion key in an app’s Info.plist.

For example:

	appversion /Applications/iPhoto.app

yields:

	8.1

Download the 32/64-bit Universal binary (in a zip file) here:

appversion.zip

Using Breakpad on Mac OS X 10.6

Unlike web apps, desktop apps crash without the app’s developer knowing about it, unless the user sends a crash report to the developer. Whenever an app crashes, OS X puts up a dialog for the user to submit a crash report to Apple. Unfortunately for non-Apple apps that crash report never gets to the developer!

So, Arq needs its own “crash reporter”. After reading Daniel Jalkut’s nice roundup of crash reporters, I chose Breakpad because it seems the most similar to Apple’s built-in crash reporter.

Adding Breakpad to your Mac OS X app is easy since the Breakpad team created a Framework around it.

Building Breakpad

Just download the source, open the XCode project under src/client/mac and compile the target “All”.

If you’re on 10.6 though, you’ll need to set the compiler for all the targets and sub-projects to “GCC 4.0″, or else you’ll get an error “GCC 4.2 is not compatible with the Mac OS X 10.4 SDK”.

The default settings for the project (at least as of svn revision 394) create a “32-bit Universal” build. 64-bit isn’t supported yet. See the Breakpad issues list for more details.

Adding Breakpad to Your App

Once you’ve built Breakpad, drag Breakpad.framework into the Linked Frameworks folder of your XCode project. Be sure to check the “copy items into the destination group’s folder” box in the sheet that appears. Also check the target you want to add Breakpad to.

Next, create a “Copy Files” build phase in your target with a destination of “Frameworks”, and drag Breakpad.framework into that.

Next, add a bunch of variables to your app’s Info.plist, including:

	BreakpadProduct
	BreakpadProductDisplay
	BreakpadVersion
	BreakpadVendor
	BreakpadURL
	BreakpadRequestComments

See the comments in Breakpad.h for how to set those variables. One tricky bit: BreakpadRequestComments should be a <string> with a value of "TRUE" in your Info.plist, not a <true>.

As an example, here’s how I set my plist variables for Arq:

    <key>BreakpadProduct</key>
    <string>Arq</string>
    <key>BreakpadProductDisplay</key>
    <string>Arq</string>
    <key>BreakpadVersion</key>
    <string>1.1</string>
    <key>BreakpadVendor</key>
    <string>Haystack Software</string>
    <key>BreakpadURL</key>
    <string>http://crashreport.<yourserverhere>.com/arq/new</string>
    <key>BreakpadReportInterval</key>
    <string>0</string>
    <key>BreakpadLogFiles</key>
    <array>
        <string>/var/log/system.log</string>
    </array>
    <key>BreakpadLogFileTailSize</key>
    <string>40000</string>

Finally, create a Breakpad object in your app:

    BreakpadRef bp = BreakpadCreate([[NSBundle mainBundle] infoDictionary]);
    if (bp == NULL) {
        NSLog(@"failed to create Breakpad");
    }

That’s it! Now crash your app to try it out :)

On the server side, you’ll need something to process the report. I’ll post my server-side code soon. Tweet me @reitshamer if you need it right now.

UPDATE: I put the server-side code at http://github.com/sreitshamer/breakpadserver.