Daring Fireball on “The Life”

October 14th, 2005

An interesting commentary today from John Gruber on independent programmers and the alluring goal of achieving “The Life.

Gruber makes some great points about the not-so-simple criteria that define “ultimate success” for an indie programmer, observing that support responsibilities for one-person shows can be crippling. It’s almost enough to make a developer pray for obscurity. Who am I kidding, of course it isn’t!

In this excerpt, Gruber observes that Brent Simmons of NetNewsWire fame is closer to living “The Life” now as an employee than he was as an independent business owner:

Brent and Sheila get rewarded financially for their success and work over the past two years, and Brent gets to devote his time and energy to programming. By selling his company and working on NetNewsWire as a NewsGator employee, Brent has actually gotten closer to The Life than he was as an indie.

I find this especially striking because in many ways Brent has transitioned to steady employment without (it would seem) giving up the benefits of his independence. He continues to work from home (for better and for worse), is charged with mapping the future progress of NetNewsWire, and most likely received stock in the acquiring company, giving him a vested interest in the continuing growth of his product’s popularity.

Most importantly, he and Sheila don’t have to bear the brunt of *everything* anymore. In many cases an acquisition gives more power to the individuals in the smaller company than it does to any individuals in the larger one. Take Apple’s acquisition of NeXT. The individual employees of NeXT who stayed on at Apple suddenly became about a bazillion times more influential on the future of the Mac than the employees who had been working on the Mac for the past 15 years.

I agree with the gist of Gruber’s analysis – “The Life” is getting hired to keep doing what you’ve been doing, with fewer headaches, better pay, and more influence.

Stealing Seconds Back from Xcode

October 14th, 2005

A lot of people like to complain about how Xcode is, in some ways, too slow. Especially when it comes to compilation time, developers who were familiar with CodeWarrior’s relatively blazing speed are often disappointed at the non-stellar performance of gcc in Xcode.

While we wait patiently for Xcode’s performance to improve, it’s important to make sure that we don’t waste any more time or frustration in the program than we need to. To that end, I am always looking for ways to automate those “repeat them all the time” actions I am liable to take in Xcode.

One of the tedious tasks I often find myself can be summarize in three easy words: “Reveal Active Product.” Unfortunately, the process is slightly less straightforward in all but the simplest of projects. One must first navigate through the Files & Groups tree to find the “Products” group. This group may or may not need to be disclosed to reveal its contents. Then the brain must be asked to do extremely menial work for a few moments as it decides which of the multiple products generated by this project is actually the one you’re interested in now. When these brain cells finally die, you’re left with a mouse right-clicking the item of interest, to locate and select the “reveal in Finder” item.

That’s too much work for me! I do this all the time. I need a keyboard shortcut. So, compliments of FastScripts and the following AppleScript, I am from this day forward using “Ctrl-Cmd-R” as a shortcut in Xcode for “Reveal Active Product.”

-- Get the active target's product as a posix path
tell application "Xcode"
	set myTarget to active target of active project document
	set myFile to product reference of myTarget
	set myPath to full path of myFile
end tell

-- Convert to an alias and ask Finder to reveal
set myAlias to POSIX file myPath
tell application "Finder"
	if exists myAlias then
		activate
		reveal myAlias
	else
		beep
	end if
end tell

If the active target’s product exists, the Finder will reveal it. If there is no such file, you get a beep. Enjoy!

Font Panel Sucks the Life Out of Interface Builder

October 9th, 2005

Normally I find Interface Builder to be pretty snappy. From time to time over the past few months, however, I have encountered periods of time where Interface Builder’s responsiveness has slowed to a crawl. What the heck! Could my Nib files be getting too complicated for IB’s scrappy little frame to handle? I doubted it seriously, considering the complexity of other applications whose Nib files I have known and loved.

I finally traced it down to an insidious, parasitic relationship between the standard font panel and Interface Builder.

It seems that when the Font Panel is enabled, Interface Builder is liable to start choking on things like mouse clicks and drags. I have observed repeated delays of up to 2 or 3 seconds, just to click on a UI element in IB! And this is a on Dual 2.0Ghz G5! Pity the poor iMac user! When the Font panel goes away, responsiveness comes back 100%. If you’re just a little bit of a clutter-rat, as I am, then you’re liable to leave your Font Panel open as you forge ahead with your interface design. It never occurred to me that this might be robbing precious minutes from my work day!

This problem can be reproduced easily on Mac OS X 10.4.2 with Xcode 2.1 installed. Follow these steps to reproduce the problem yourself and gape in awe:

  1. Launch Interface Builder, creating a new “Cocoa Application” document.
  2. Observe the quickness with which you can click and change the selection between each of the 4 instance icons:

  3. Press Cmd-T to bring up the Font panel.
  4. Resize the Instances window such that the icons rearrange. For some reason this helps reveal the problem. I don’t know if this is a caching issue or what:

  5. Now try clicking between the icons again. It may take a few rounds through, but you will soon start to observe hideous delays between mouse click and selection change.
  6. Once you’ve observed the slowdown, close the Font panel by again pressing Cmd-T. This should return responsiveness to normal levels

This is a small demonstration of what it’s like to have this kind of delay plague your entire design session. The delay applies to anything clickable, selectable, draggable, etc., in IB. This includes all UI elements in your windows, views, etc.

So if you’ve been plagued by mysterious, dramatic reductions in IB responsiveness. Make sure your Font panel is closed. It may be sucking the life out of IB!

I’d be interested to hear if any readers can or cannot reproduce this on their own machines. For now I’m assuming it’s widespread, and I’ve reported it as Radar 4293149.

Man in the Middle System Espionage

October 7th, 2005

Many system services on the Mac rely on command-line tools either stored in public paths or stashed away in hard-to-find places. When I’m curiously poking around on my system (as I’m a bit too often likely to be doing), I often discover one of these master-slave relationships and wonder exactly what’s going on behind the scenes. Usually there are some magic command-line incantations that may or may not be documented for the tool itself. By examining what parts of the system do to take advantage of these command-line entry points, we can potentially come up with ways of facilitating improved behaviors for our own purposes.

As an example, let’s take the screencapture tool. Located at /usr/sbin/screencapture, this is what provides the core functionality for the Cmd-Shift-3 and Cmd-Shift-4 screenshot shortcuts. The process responsible for invoking screencapture is the SystemUIServer. Now, if we are curious about what exactly gets passed to the screencapture tool, we have two obvious choices: intercept the invoker, or intercept the invoked.

Intercepting the invoker can be difficult. Not only do you have to identify which process it is, but you then have to attach to the calling process and attempt to break at the relevant code that executes the target tool. Much easier at times when you just want to take a quick peek is to swap the called tool with a bogus stand in. You don’t even need developer tools! The stand-in is named identically to the real deal, but instead of performing the expected function, it simply echoes the provided arguments to a specified temporary file:

#!/usr/bin/perl
`echo "@ARGV\n" >> /tmp/testDCJ`;

I like to send the arguments to a temporary file instead of printing to the standard output, because some callers will manipulate the forked task such that its standard output is disabled. The nice thing about the simple script above is that it’s completely independent of the tool being replaced. You can keep it around and simply copy it in when you want to peek on something. Don’t forget to move the original aside!

Of course, you could also add another line below the echo to go ahead and call through to the original application, if you want to keep the functionality going while your snooping is in place. For instance, this lets me see exactly what screencapture is being asked to do, without diminishing its ability to do it:

#!/usr/bin/perl
`echo "@ARGV\n" >> /tmp/testDCJ`;
exec("/usr/sbin/screencapture-original", @ARGV);

Once you’ve got this mechanism in place, the possibility of mucking with the passed in parameters is irresistible. Say I don’t like the screenshot sounds, and I tend to take more screenshots of windows than of selected ranges. I just sneak the required parameters in before passing the ones that came from SystemUIServer. I’m done with my snooping so I’ll comment-out the argument printing line until the next time I need to pay attention. This is a simple example, but with a little parsing you can remove unwanted options from the passed-in ARGV array, fine-tune provided filenames, etc:

#!/usr/bin/perl
#`echo "@ARGV\n" >> /tmp/testDCJ`;
exec("/usr/sbin/screencapture-original", '-W', '-x', @ARGV);

The major drawback to leaving your custom file in place of the original is that it’s bound to get clobbered when you update your system and Apple releases a new version of the patched tool. One way to avoid this problem is to keep your man in the middle stashed somewhere outside of the target directory, and point at it with a symbolic link. For instance, if you put your perl script in /Users/Shared, you can perform the patch as follows:

% cd /usr/sbin/
% sudo mv screencapture screencapture-original
% sudo chmod 755 /Users/Shared/ScreenCaptureHack.pl
% sudo ln -s /Users/Shared/ScreenCaptureHack screencapture

Now when Apple comes along with a new screencapture, you can just pop in and repeat those steps to get your custom functionality back (or write a script to do it!).

While we’re talking about screencapture, let me point out some useful, under-published user defaults that control the way SystemUIServer invokes screencapture. I was turned on to the presence of these by a post in MacOSX-Talk, which prompted me to search for and find more detailed explanations on MacOSXHints.com. I found hints for the "type" and "location" keys there, which encouraged me to do my own further snooping (set a breakpoint on CFPreferencesCopyAppValue while re-launching SystemUIServer) and discover the "name" key. Using these keys, you can customize your screen captures to be other than the default PNG "Picture N" on the Desktop (as of Tiger):

% defaults write com.apple.screencapture name "Booyah\!"
% defaults write com.apple.screencapture type "jpg"
% defaults write com.apple.screencapture location "/Users/daniel/Documents/Screen\ Captures"
% killall SystemUIServer

The killall at the end is not necessary for some of the keys, but appears to be necessary for the location.

Now all of my screen captures get stowed away in a tidy subfolder of my Documents folder, they are jpg format for maximum portability, and they have a very silly name.

Many behaviors of Mac OS X are unchangeable, or require heavy hex-editing to alter. But thanks to the frequent use of command-line helpers and defaults-driven behavior, much can be altered with a little snooping and careful patching.