The Future’s Not So Bright

March 2nd, 2006

I read Jason O’Grady’s comments (via Daring Fireball) on the keyboard backlight of the MacBook Pro with some surprise. I am the proud owner of one of these new machines, and his experience doesn’t exactly match mine.

Granted – I don’t have a PowerBook G4 to compare against – I haven’t owned another Mac laptop since my iBook G3, which certainly didn’t have any of these fancy backlighting features. But the staring into the sun metaphors alluded to by O’Grady seem really far-fetched. Unfortunately, he only shows us images of the two laptops at “half intensity,” while mentioning in passing that the MacBook Pro’s “keyboard backlight set to one bar is brighter than the keyboard backlight on the PowerBook set at 16 bars.” Where are the pictures for this – the interesting claim?

I’m also skeptical because the keyboard images are being shown out of context. We don’t normally stare down into our keyboards without the (usually more powerful) light of the laptop display to soften the relative intensity of those keyboard lights. I thought I’d contribute another set of photos which may at least offer hope to those of you who are starting to worry about SPF factors in relation to your future laptop:

The first is at maximum keyboard backlight, the second at minimum. Obviously, my photos might be deceptive, too. But all I can say is that dim version looks “pretty much” the same as it looks in my office. Maybe O’Grady got a defective keyboard? I would like to see a picture of this retina-burning “lowest setting.” If the dim version shown above is brighter than the maximum brightness of the G4 keyboard, I’d say it’s the G4 that was defective!

Five Things I May or May Not Know

March 2nd, 2006

To mark the occasion of my 100th (!) post, I’m recalling some of the major points of wisdom I’ve accumulated over the past ten or so years. Not to brag or anything, but in spite of my slacker attitude and a recurring assumption that I’ve “known everything” all along, I’ve actually learned a few important things along the way. Or at least, I think I have. I usually find myself jabbering on about these opinions to people who could care less: my helpless friends and family. Perhaps by writing them down here, somebody will actually get some use from them.

At first I thought it would be fun to scrape the barrel for 100 points of wisdom, but it turns out I don’t know as much as I thought. Plus, some people think my entries are long enough as they are! I’ve settled on five fairly general thoughts about the business and technology aspect of our lives. These opinions represent wisdom that has helped me achieve a fairly respectable level of success. If you’re looking at the glass half-empty and need a bit of inspiration, maybe some of these observations will excite a motivational bell for you.

Thing 1. Managers are soul-sucking zombies.

Managers are good people – well, most of them are. But they generally reached their position by giving up something they love. Somebody – usually another soul-sucking zombie, convinced them that they should stop doing whatever they were doing and become a manager instead.

Few children will state that they “want to be a manager” when they grow up. That’s because managers – in spite of getting things done, don’t “do” anything. Nothing you can explain to a kid, anyway. They don’t put out fires or bust bad guys or hit home runs. They get other people to do that for them. They’ve become the creative un-dead, and while performing valuable tasks like protecting you from other managers, raising your pay, and sending you on expensive business trips, they also try desperately to pull you into their miserable way of life.

Disagreements between managers and “individual contributors” usually boil down to a difference of opinion on the meaning of “compromise.” Individuals are relatively uncompromising, especially when it comes to doing what they love. Managers hate this, because it reminds them of how they used to be before they got promoted. One of the qualities of a great manager is an ability to compromise. But too often, this means letting life take a crap on you and smiling about it.

Thing 2. Your co-workers are dumber than you think.

Usually when you enter a new workplace, you can tell pretty instantly whether everybody is really smart or really dumb. It only takes a few brilliant quips or idiotic blatherings to pigeonhole a co-worker firmly into one camp or another. Or so you think. Most people are actually neither as smart or as dumb as they first appear.

A phenomenon occurs when people work together for a long time. They discover each other’s secret talents and secret flaws. This is good for the team, because it allows for more efficient delegation and group-attack when the toughest problems arise. But when a new employee comes on board, everything is thrown into disarray. If the new employee is senior, she receives a heightened presumption of brilliance by the existing team members. Because they haven’t had the benefit of observing her occasional failures over the past ten years, she is defined only by her impressive resume. On the other hand if the new employee is fresh out of college, regardless of whether he is the next Einstein of the field, he is presumed to be mostly ignorant by the team.

The junior employee enters the team with a particularly distorted view. He’s never been in a real job before. He’s not quite sure how it all fits together. Everybody on the team has well-practiced statements of grandeur that elevate their appearance of intelligence. They’ve been practicing the same industry jargon for years, so it rolls off the tongue with aplomb.

As a junior employee, you must appreciate that most people are just average – even if they appear to be geniuses. As you develop a stronger sense for your new co-workers talents, the presumed geniuses of day 1 will slowly fall by the wayside. If you’re lucky you’ll find some true geniuses to mentor you, but you should be encouraged by the reality that many people “at the top of their field” are downright stupid. That means you can really excel if you stick to your guns.

Thing 3. Simple is best.

There’s good wisdom behinds the famous KISS acronym (“Keep It Simple, Stupid”). It was obviously invented by somebody with a bit of experience behind them. It’s become such conventional wisdom now that many college grads probably think they “get it” from the start. They don’t get it. I don’t get it. No matter how hard you try, you won’t get it. It’s like yoga – you practice your whole life, always improving but never perfect. How does undue complexity manifest itself in the software industry? Two major pitfalls are premature design and overindulgence of customer whims.

Premature design is the variety of complexity that causes one of your “not as smart as they seem” co-workers to hole up in their office for weeks on end – emerging “victorious” with something that looks and acts exactly like the software did before. “But it’s totally redone! See, we could implement Pac-Man with this thing now!” But what if – and this is a long shot, I know – nobody wants to implement Pac-Man with the time-tracking web application?

Indulging the customer is even harder to reign in. They do, after all, pay the bills. The more bills a customer pays, the more complexity they get to inflict on your application. But you must resist this as much as possible! Joel Spolsky identifies software that evolves from over-obedience to customer whims consultingware. Basically, the app is as crappy as the customer wants it to be. I’ve seen projects where literally any request made by a customer (paying or otherwise) resulted in a change to the application’s source code. Every unwarranted change to please a single customer is done at the expense of every other customer, who doesn’t need or want the features.

A little bit of planning is a good thing, but design for its own sake is a mental illness that many developers suffer from. A little bit of tough “imposed managerial compromise” can go a long way towards treating this.

Thing 4. The customer is always interesting.

Although the customer’s whims should not be acted on willy-nilly, they must be considered. Carefully. Whatever your customer is telling you is a gift. It’s a peek into the mind of the world. A deeply religious person may find their spiritual path altered by a “message from God,” or some other divine intervention. For businesses, these unpredictable course-steering messages come in the form of customer support emails.

The biggest problem with customer communication is that whatever the language of your business is, your customer doesn’t speak it. If you’ve ever tried to get reimbursed for an out-of-pocket medical expense, you probably spoke with at least a half-dozen insurance industry wonks, each of whom studied your case carefully, verbally annotating their progress by rattling off the names of standardized medical forms and procedures. You sat there glazed-eyed, simply hoping to get your damn refund. Remember that feeling the next time you respond to a customer’s email. They are desperate for help, and they aren’t sure how to ask for it. If they sound like a Texan asking for directions in Chinese, it’s because they don’t speak your company’s language!

You have to sift through the coded communication for the real information. If you find yourself muttering, “idiot!” about a customer, consider applying the insult to your company, instead. How could my company drive a person to behave this way? Could we prevent future customers from behaving this way by fixing our product? Often a request for a “ridiculous feature” is code for some other problem. A customer asked me to add a feature to FastScripts allowing it to be launched multiple times. A devastating feature that would be! Digging a little deeper, I learned that the customer’s instinct was to work around a shortcoming of the application: that only one script can be running at a time. By struggling to understand the customer, I developed a ridiculous request into a meaningful TODO item.

Thing 5. Everything you may or may not know is temporary.

Everything you know, whether you’re fresh out of school or enjoying an active retirement, will one day be turned on its head. Nothing’s sadder than a know-it-all who refuses to admit when they’re wrong. It’s a real shame because often these stubborn individuals are real geniuses, not even the fake kind alluded to above, but they are geniuses who get sidetracked. Patting a genius on the back is dangerous because, despite their brilliance, they’re liable to make the fool’s move of assuming they’ve reached a permanent apex of wisdom. They figure if they’re so smart, then everybody else’s opinion must be wrong. Yikes!

This syndrome causes UNIX geniuses to continue using vi and nroff for all of their word-processing needs, in spite of the advent of the GUI. It causes procedural programming geniuses to shun objective-oriented languages, because they “know how to do it in plain C.” It causes marketing managers to insist on investing tons of money into marketing, because free, viral web marketing didn’t exist when they got their MBA.

Almost every thing we know to be wrong today was once right. And most of what we know today will one day be wrong. Knowing this separates the super geniuses from the mere geniuses (not that I would know, I’m just an observer). The advice included in this article is fairly timeless, but I don’t doubt that one day it too will be obsolete. If you’re lucky, and can grab hold of just a few seriously smart approaches to business and technology today, then you may or may not be on the fast-track to success.

NetNewsFlix

February 27th, 2006

First let me say, I love Netflix. When I’m not programming, sleeping, or running, I’m usually watching Netflix. What a life!

A friend who also loves Netflix came to me with a puzzling problem. He’s coming out of a long term relationship, and among the other shared possessions to be carefully divided was the couple’s Netflix queue. The account isn’t in his name, but he wants to keep his share of the hard-accumulated queue. He gazed at the long list of 308 titles and searched the web page carefully for an “Export” button. Nowhere to be found. It seems that Netflix, despite it’s totally awesome domination over all competitors, is a little teeny bit scared of what might happen if you could easily export your queue to a text file and then, say, re-import it to Blockbuster.

NetNewsWire, RSS, and AppleScript to the rescue! Since Netflix is hip enough to provide several RSS feeds for its savvy customers, I just grabbed my friend’s Netflix queue RSS feed, and subscribed with NetNewsWire. Then, after selecting the subscription, I typed the following into Script Editor:

tell application "TextEdit"
	make new document
end tell

tell application "NetNewsWire"
	set myHeadlines to (headlines of selectedSubscription) as list
	repeat with myItem in myHeadlines
		set thisTitle to (title of myItem)
		tell application "TextEdit"
			set text of document 1 to (text of document 1) & thisTitle & return
		end tell
	end repeat
end tell

It doesn’t matter if it’s efficient, it just has to work once. And voila! Switch to TextEdit and observe a 308 line file with the names of each film in order. If the numbered lines are a problem, a little bit of extra script could take care of that in a jiffy.

It’s exactly these kind of unforeseen circumstances where easy, predictable scripting interfaces save the day.

Update: It wouldn’t have been the worst thing in the world to simply save the HTML page listing the entire queue, but this solution makes it much easier to manage the data and process it however the owner sees fit.

String Theory

February 26th, 2006

Every good API (or language) should have a fundamental, powerful, impossible to ignore encapsulation of a primary building block in computer programming: the string. Wikipedia defines a string as a “sequence of various simple objects.” Wow! That’s an indulgent definition, but kind of nice in its flexibility. When such a robustness is properly implemented in a string object or type, it facilitates effortless and worry-free manipulation by developers.

Even back when it was generally presumed that only white, English-speaking dudes with lab coats would ever need to make sense of the bits of text that went into and came out of a computer program, there was an alarming lack of consensus on how that data should be represented. I’m sure some of you are old enough (or just unlucky enough) that you’ve had to stare down a chunk of data, scratch your head and ask, “Is this an ASCII or EBCDIC string? Mac programmers with a history of Carbon programming are no doubt familiar with the ever-tedious task of converting strings between Pascal and C-style formats. As the de facto standard programming language of the Mac slowly shifted, the format expected by Apple APIs followed suit at varying paces. For those of you lucky enough to have been born into a world where strings are magical objects that handle Chinese characters as easily as Roman type: you should count your good 时运!

Cocoa programmers are among the luckiest programmers in the world. NSString is a comprehensive, powerful encapsulation of Unicode strings. It’s because of this encapsulation that I was able to copy the Chinese characters in the above paragraph out of Safari and paste them into MarsEdit without thinking twice about whether it would work. OK, that was a lie. I was a little bit concerned, but I didn’t need to be! It was an old-man paranoia, based on years of living under the repressive restrictions of a world without Unicode. Now, it just works! And the developers of Safari and MarsEdit probably didn’t think twice about it, either.

But the biggest winners here are the users. José and Aslög, who have spent their lives tweaking the spelling of their names to suit fussy computer programs and DMV clerks, are more and more likely to see their names pleasantly represented in-full by our electronic friends. And their sacrifice has been slight compared to those whose names require a complete reworking to satisfy the technical ineptitude of Western technology. While the Windows and Linux platforms have also made great strides in recent years, it continues to be my experience that the Mac “just works” in far more circumstances than on other platforms.

It was enough of a gift for Apple to take care of all the encoding, multi-byte issues, allocation, etc. But they also snuck NSString into nooks and crannies of the system where only a developer could appreciate them. The flexibility of NSString is shown off in a few unexpected ways that not all developers are familiar with.

I Can See You

Most Cocoa developers are very familiar with the handy NSLog function. This little beauty is the modern replacement for traditional “printf debugging.” Some circumstances call for “step by step” debugging, while at other times its faster to spew information out to the console, hoping to get a clue as to why your program is misbehaving. Like printf, NSLog takes a template string and a variable number of value parameters which are then formatted and inserted into the template as requested by the developer. In addition to the standard printf codes for converting things like long integers to text, the Objective-C runtime gives us a super-powerful code, “%@”, for converting an arbitrary object to text. So if you’re confused as to why your array of fruits is not showing up as expected, you can simply add a line to your program at an opportune point:

NSLog(@”My fruits: %@”, fruitArray);

When you run your program, you get this output conveniently displayed in the console (or Xcode run log):

2006-02-26 11:56:35.939 MyApplication[25666] My fruits: (Apple, Banana, Pear)

Aha! The strawberries are missing! This powerful “object inspection” facility is enabled by a simple message, “description,” which all Cocoa objects respond to by returning a human-readable representation of the object in NSString format. The quality of the description ranges from “not very useful” to “exceedingly informative,” depending on whether the particular object’s class has overridden the default implementation, which simply spits out the class and a hex-formatted representation of the object’s address in memory. The promise that something will be returned is powerful enough to make “printf debugging” of objects a lot easier than it otherwise would be.

String from What?

Once you become accustomed to NSLogging everything under the sun, it can come as quite a surprise that a few common Objective-C types don’t bend so easily as the rest. Examples of such types are NSRect, NSSize, and NSRange. These compromised “objects” are implemented as plain C-structs rather than as proper objects, presumably as a performance consideration. Since they’re not objects, there is no freebie “description” method enabling them to be effortlessly passed as arguments to NSLog. But these values are just as likely to run amok and cause bugs in your program, so what do you do when it’s time to spray their contents out to the log? Something I’ve witnessed developers doing on more than one occasion is to simply revert to printf-style inspection:

NSLog(@"My rectangle: origin = (%f, %f), size = (%f, %f)", 
	myRect.origin.x, myRect.origin.y, myRect.size.width, myRect.size.height);

Which yields:

My rectangle: origin = (0.000000, 0.000000), size = (300.000000, 500.000000)

Clearly, this works. And it’s a fine habit to get into if you’re training for the typing olympics, or you’re masochistic, or both. You might ask yourself why a group of engineers who designed such an elegant, introspective runtime environment would allow these essential building blocks to slip through the cracks. The answer? They didn’t. A number of handy utilities exist to not only convert these basic types to string format, but to then convert them back into their native struct format as you see fit. Using NSStringFromRect, we can replace the lengthy log statement above with this:

NSLog(@"My rectangle: %@", NSStringFromRect(myRect));

Which yields:

2006-02-26 12:19:45.578 MyApplication[29788] My rectangle: {{0, 0}, {300, 500}}

The developers at Apple acknowledge the universal usefulness of NSString, and therefore provide a number of these utilities, allowing you to “objectify” many fundamental types: NSStringFromRange, NSStringFromSize, NSStringFromClass, NSStringFromSelector, etc.

Not Just for Show

This objectification of basic types is very handy for logging purposes, and a great tool to keep in your belt for tackling everyday programming problems. Types like NSRect and NSSize can’t be tossed around willy-nilly in Cocoa’s collection classes, but NSString can! So when you find yourself needing to store a list of NSRanges in your Cocoa object, don’t revert to your old C ways of dynamically allocating an array of structs. Simply objectify the ranges and stick them in a mutable array:

[mRangesToWatch addObject:NSStringFromRange(newRange)];

When it comes time to examine a range, just convert it back to its native format:

NSRange oldRange = NSRangeFromString([mRangesToWatch objectAtIndex:0]);

This even works with nil values. NSRangeFromString(nil) produces an empty range.

Chris Liscio is a super, mega, ultra groovy Mac developer who points out that in some cases, this easy path to objectification is too inefficient for practical use. He recently authored a custom wrapper of NSRect, precisely so he could maintain an array of these objects. In his case, the array of rectangles needs to be constantly reviewed and compared with other rectangles, so the constant conversion to and from string format would have been ridiculous. But in many instances, taking advantage of the built in NSStringFromBlah functions will prove to be both an easier to implement and easier to maintain solution that writing your own custom wrapper.

Update: Michael Tsai comments below about the speed of such a wrapper vs. NSValue – essentially bringing to light my obliviousness to using NSValue … the way it’s documented! I’d always just associated NSValue with NSNumber. It makes my recommendations above to use NSStrings for such a purpose sound kind of stupid. C’est la vie! Thanks Michael for reminding us of yet another elegant feature of the API.

It’s on the House

Apple deserves a standing ovation for their clever use of NSString throughout the Cocoa API. Just about every method that calls for text as input or output does so in the form of NSString. So long as we’re in the cozy confines of Cocoa, we can sit back and bask in the glow of our convenient, precious little class. But Apple really went the extra mile by “toll-free bridging” it to CFString, its leaner, procedural cousin in the CoreFoundation framework. What this means is that the utility of NSString essentially reaches not only across the Cocoa API, but across the vast number of Apple APIs that rely on the CoreFoundation framework, and therefore use CFStringRef as their basic unit of text manipulation. This makes it easy for Cocoa developers to take advantage of lower-level libraries without jumping through hoops to do so. If you see a CFStringRef and wish it were an NSString so you could easily copy it or add it to an array, “just cast it.” Casting a CFStringRef to an NSString* (from Cocoa code) feels dangerous and dirty, but it’s actually the right thing to do, and is a heck of a convenience. Casting the opposite direction is also handy and equally valid. Just be sure to manage your retain counts. The best things in life are free. Thanks, Apple.