Good Products Gone Bad

April 17th, 2007

I love my Apple iPod Nano. This is a product that, even more than my first iPod, has changed my life. The combination of size, style, and ease of use make it so appealing that I’ve allowed it to become a major part of my daily routine. I rarely do a household chore without it, and I always take it with me when walking long distances or working out at the gym.

The product is so good, and I depend on it so much, that when my Nano recently went on the fritz, I wasted no time obtaining a replacement. The “lock” switch had stopped working, and being a geek I thought I might be able to crack it open and convince it to start working again. Pretty soon the whole thing was apart and I had irreparably broken it. OK, I’ll take most of the blame for that. The switch dying was annoying, but I haven’t exactly babied this thing over the past couple years.

I walked 30 minutes (painful, without the iPod!) to my local Apple store, avoided the bad genius, and plunked down muchos dólares for a replacement unit. Since the “black tax” didn’t exist when I bought my first Nano, I had to pay substantially more than before to match appearances, but I did so without hesitation. I learned at the register that I could have saved 10% by “recycling” my old iPod, but at this point the thought of another hour of walking was too much to bear. I’ll save the broken one for a future discount.

See what happened here? I bought a product, loved it, it broke, and then I bought another one. That’s good for Apple. My resilience with this product is high.

My love for the iPod is only possible because I’ve convinced myself to hold Apple mostly faultless for the fact that its standard headphones are utterly useless to me. I buy iPods without anger because I consider the little white plastic-coated electronics that come with the units to be disposable freebies, much like the poor excuse for a mouse that comes with today’s Macs. Little bits of disposable plastic are commonly bundled with products, but at least the little dolphin-threatening 6-pack loops do something useful before I discard them.

My perfect iPod experience is completed by perfect 3rd-party headphones. For the past two years, those headphones were the Sony MDR-A35G “Sport” headphones. See, I don’t like earbuds, because they inevitably fall out. I don’t like little hooks around my ear, because they are uncomfortable and look dumb. I don’t like big foam pads because they’re uncomfortable when running. I like the Sony MDR-A35G because they are light, water-resistant, block outside noise, can be folded up and stuffed in my pocket, and only cost $20.

(In a brilliant move, Sony puts a product code, “MDR-A35” on the product itself which, when searched for at Sony.com, yields no result. Only by looking on the package did I determine it’s actually the MDR-A35G.)

A couple weeks ago my beloved headphones followed the iPod into the great electronics graveyard. After two years of being battered, folded, stretched, worn through rain and snow, and keeping me entertained through countless miles of running, the sound in the right ear went dead. No big deal – I got my money’s worth! I walked out of my way to the local Radio Shack, which is the nearest place I know that carries them. I grabbed a pair from the rack and marched up to plunk down my $20. On the way out of the store I threw my faulty headphones in the trash on Massachusetts Avenue. I was back in business.

The next day, as I widened the headphones’ reach to place them on my head, the plastic on one side snapped, rendering the product useless. (My head’s not that big).

Just bad luck, I was sure. Though I felt a twinge of wonder: was the product being made more cheaply, now? All the same, because I’m a loyal, happy customer, I walked straight back to Radio Shack and paid another $20 for another pair. At this price, it’s not worth quibbling over warranties. In fact I often wonder what the point is of a warranty on a $20 product. When my $2500 MacBook Pro acted up, you’re damn right I’ll wait on hold and ship the product back for repairs. When my $20 headphones disappoint, there’s no chance I’m going to bother. (Which makes it even dumber that Sony requires the odd customer who does apply the warranty pay shipping if they want a replacement).

This time, I was determined to be gentle with the headphones. Perhaps they didn’t “make ’em like they used to,” but I still loved the product. It completes my iPod, after all. I wanted to be a happy customer again, even if it meant coddling the brittle plastic a bit. This was something I was willing to do.

Today, about a week into coddling them, I caught the wire on a doorknob as I was leaving the apartment. Snap! Another pair bites the dust. After two years of happily using a product, I go through two replacement units in little more than a week.

And just like the “snap!” of cheap plastic, so went my customer loyalty. A product that served an integral role in my daily lifestyle, as far as I’m concerned, is now no longer on the market. $20 is affordable, but not if I’m paying weekly! I’m convinced that the Sony MDR-A35G is now a cheap product. It’s possible that I just got lucky with my first pair. Perhaps the cheap breakable version is the standard, and mine just happened to be durable? Or maybe it’s just a huge crap shoot. Maybe some pairs are still durable today, and you need to get lucky.

In any case, I bought a $7 pair of stupid foam-covered headphones from Walgreens. They’re uncomfortable, they don’t block sound, and they look ridiculous. I find listening to my iPod to be joyless, now. Meanwhile, the Radio Shack is a 20 minute walk, and I could have my old lifestyle back for only $20. But I can’t afford to put my faith in a product gone bad.

Earlier today I whined about this on Twitter, and learned that at least two others, EcoChick and Dan Moren, have had similar disappointment with Sony’s headphones. Surely there must be a company that can make decent, comfortable, stylish headphones that don’t break within the first week of use. Any suggestions? I’m a headhones free-agent, now. (And desperately need my old lifestyle back).

Update 5/2/2007: I searched and searched for a “better choice,” but to my great disappointment I found nothing as suitable as the original Sony design. I decided I would try them once more, but take the advice from the comments and at least pick some up from a different shop. Maybe the ones at Radio Shack were part of a bad batch. I ended up buying a similar but slightly different pair from Newbury Comics in Boston. This pair is the Sony MDR-A34, and is in almost every way the same as my beloved A35, except $7 cheaper and in a stylish flat black. Best of all? The band is noticeably more flexible (this might equate with “cheaper,” but it’s working for me). I noticed immediately that they could be comfortably stretched over my head without the slightest fear of breaking. The “Sport” version I had been using before is supposedly good at deflecting liquid away from the earphones, but to me they look identical to these. I think this could be an instance of identical parts being used to build a cheaper and more expensive product.

The real test? I just pulled a majorly clumsy move with my headphones attached. I was kneeling down and stood up quickly, snagging the cord underneath my knee. I gasped as one side of the headphones snapped off. I was sure they had broken, like others before them. But to my great relief and surprise, the portion of the headphones had simply detached from the rest. I snapped it right back on and voila, good as new.

The Sony MDR-A34 are easily my new favorites. So Sony kept me as a happy customer after all, even if I had to waste $60 or so getting here.

Cheap Yet Laudable Extravagance

April 14th, 2007

Today I would like to call out Google, and applaud them for continuing to support a wide variety of projects through their innovative Summer of Code micro-funding program.

This will be the third summer Google has offered a $4500 stipend to students willing to work “for free” over a summer on one of more than a hundred qualified projects. They also provide a nominal $500 “mentoring stipend” to the sponsoring project, for each student.

It would be easy to dismiss this is a cheap way for Google to promote development in open source projects from which they take value, while enhancing their reputation among the developer public, and also indoctrinating the loyalty of a bunch of students who will soon be entering the work force.

It is all of those things, but it’s also something wonderful. The list of projects this year number over 130, and the list of students over 900. If you do the math, you realize that Google will spend as much as $4.5 Million on the stipends over those few summer months (the full stipend amount is only paid if the student’s work is deemed “passing” by the mentoring organization). One only needs to look at the breadth of projects being sponsored to realize that while Google may benefit from the net rewards of the program, there are many other organizations and people who benefit as well.

$4.5 Million is a lot of coin, but in the context of the billions in revenue that both come into Google and go out of Google in the form of acquisitions, the money is chump-change. For chump-change, Google realizes it can dramatically affect the development momentum of 130 projects, give 900 students a sense of pride and experience in a team-working environment, and endear the development world to their good deeds. That kind of equation makes this investment a no-brainer for the corporate behemoth.

On a philosophical note, what kinds of cheap yet laudable extravagances can you afford to share with the world? It might be only answering a question on a mailing list, or sharing a bit of tricky source code. Google reminds me that we don’t always have to sacrifice much to benefit much. And our peers will applaud us, too.

Leopard Isn’t The Problem

April 12th, 2007

Apple announced yesterday that Mac OS X 10.5, code/marketing-named “Leopard,” will not ship in Spring as promised, but will instead ship in October. (Confoundingly, the “Hot News” item at Apple doesn’t even have its own link, naked among the other public relations tidbits. Perhaps a sign that they’re not proud of the statement).

The announcement caps off a season of speculation alleging fluctuations in Leopard’s ship date. While early 2007 brought us lunatics predicting a March release, more recent speculation has hinted that a substantial delay was inevitable. This theory was soundly rejected by Apple less than three weeks ago, in a response to what turned out to be quite an accurate preview of the brutal truth.

The news has inspired reactions by respected Mac OS X developers (Gus Mueller, Brent Simmons, David Weiss, among others) and users (David Chartier, John Gruber, the Macalope, and many, many others). But while these people offer intelligent views on the relative pros and cons of the delay and its consequences to ordinary people, I don’t see much reaction to the core problems in Apple’s confession. I envision a bunch of PR folks sitting in an office toiling with the fact that they’ll have to break this unfortunate news. What to do, what to do. One of them has the brilliant idea that they can simply “blame” the iPhone. By blaming a problem on what’s widely perceived by the public to as a success, it will somehow make the company appear mature and well-reasoned in its decisions. Something more excusable than a company that occasionally fails to work a miracle. And somehow this idea made its way through some review process and all the way to public release. In stark contrast to Steve Jobs’s brilliantly candid Thoughts On Music, this statement sounds made-up and poorly thought-out. Bluntly crafted, sleazy marketing bullshit.

The best we can hope for is that it is only sleazy marketing bullshit. Because if what Apple’s telling us is true, then they’ve confessed something tragic: they’re incapable of building more than one amazing product at a time. The iPhone looks like it will be an amazing product, but if Apple can’t keep an OS team focused and operational at the same time as they keep a cell phone team hacking away, then the company is destined for extremely rough waters as it attempts to expand the scope of its product line.

What happens when the phone takes off, and Apple’s stuck following through on their Mac OS X commitments? “Sorry, no iPhone 2.0 until 2009 – we’ve had to move everybody back to OS X!” Needless to say, even with the apparent comingling of iPhone and iPod technologies, this situation leaves me unable to speculate as to when a dramatically new iPod might find time to be developed in this environment.

If Apple is truly so strapped for talent that they can’t focus on more than one product at once, then it’s a symptom of a sickness within the company. Perhaps they’ve regained success too quickly. If a company with a market capitalization of $80 Billion, and a cash account of at least $6 Billion, cannot hire enough people to build three of the hottest, most demanded products in consumer electronics (the iPod, the Mac, and the iPhone, if it’s not obvious), then maybe it’s time to reevaluate their modus operandi for attracting and retaining talent.

The first thing Apple should do is go global. Their products are universally renowned, yet the company requires the vast majority of its engineering teams to live and work in California – in a suburban, high-cost area of California, at that. Sure, Apple has a few small teams scattered around the world, but mostly as side-effects of specific acquisitions. The message to all Mac developers I know is being heard loud and clear: if you want to be part of this revolution, you’ll have to move to Cupertino. By limiting the company’s ranks primarily to those people willing to live in this one particular geographical location, they shut down their ability to attract a huge number of talented individuals.

If Apple’s having trouble growing its ranks of geniuses, the solution may require something that no amount of cash or stock can buy: a change of attitude.

Abusing Objective C With Class

April 12th, 2007

Dynamic messaging is one of the nifty features of Cocoa and Objective-C programming on the Mac. You don’t have to know which class, or even which method your code will call until runtime. The feature is utilized a great deal by the delegation pattern employed by most standard classes in AppKit. For instance, when a window is threatening to close, Apple yields the final decision making to a delegate method, if present:


- (BOOL) windowShouldClose:(id)sender;

If you implement this delegate method and return NO for a particular window, then the user’s attempts to close it are thwarted (hopefully because you just did something friendly like ask them if they were sure or not).

If we’re agreed that delegation and dynamic messaging are a good idea, we should be prepared to use them in our own code as well. Let’s say we’re writing a custom class where delegation of this kind would be useful. We’d like to be as much like Apple as possible, to further solidify the patterns that we all use on a regular basis.

My example application is a coffee maker, and it makes coffee at regular intervals unless the delegate method believes it should not:


- (BOOL) coffeeMaker:(RSCoffeeMaker*)theMaker
	shouldBrewForScheduledDate:(NSDate*)scheduledDate;

What must the code in the coffee maker do in order to satisfy this contract? The “scheduledBrewTimerFired:” method might look something like this:


- (void) scheduledBrewTimerFired:(NSTimer*)brewTimer
{
	BOOL shouldBrew = YES;
	
	// Give the delegate a chance to reject
	SEL delSelector = 
		@selector(coffeeMaker:shouldBrewForScheduledDate:);

	if ((mDelegate != nil) &&
		([mDelegate respondsToSelector:delSelector] == YES))
	{
		shouldBrew = [mDelegate performSelector:delSelector
			withObject:self
			withObject:[brewTimer fireDate]];
	}
	
	if (shouldBrew == YES)
	{
		//...
	}
}

Nifty, right? Yes, nifty. But wrong. What’s the problem? It’s that line where performSelector is called. If you have as many warnings turned on as you should, you’ll see something along the lines of “warning: assignment makes integer from pointer without a cast.” The reason? The performSelector method returns an “id”, not a “BOOL”. We’re expecting magic to happen here, and those of us who grew comfortable with the nuances of PowerPC-based calling conventions have seen magic happen here more often than is healthy.

By violating the function prototype for performSelector, we’re robbing the compiler of its ability to accurately produce assembly code that retrieves the BOOL return type correctly. That means we’ll get the wrong answer some percentage of the time, where that percentage is determined by the degree to which BOOL and id return types are handled differently on the platform.

My first instinct in addressing this problem was to go down a layer. Surely if performSelector is using an unsatisfactory prototype, I could just drop down to objc_msgSend and handle the messaging myself. But alas! The lower-level function also returns an id. At this level, there are some special functions such as objc_msgSend_stret, which messages an object and returns a structure, but there isn’t a handy objc_msgSend_boolret for our convenience.

So what’s a conscientous developer to do? I was lucky to discover a mailing-list thread, in which the answer to this question was beautifully outlined by Greg Parker of Apple. Credit also goes to Rosyna of Unsanity, for asking the question that led to Greg’s answer. Rosyna later expressed appreciation in a follow-up post.

So what’s the trick? In order to get the freedom of dynamic messaging combined with the complete cooperation of the compiler, we need to define a custom function pointer. This points to the same address in memory as the objc_msgSend function, but is defined with a differing prototype. This way we get the message delivery functionality of the Objective-C runtime, while letting the compiler in on the fact that the method being messaged will in fact return a BOOL typed response.


#import <objc/objc-runtime.h>

- (void) scheduledBrewTimerFired:(NSTimer*)brewTimer
{
	bool shouldBrew = YES;
	
	// Give the delegate a chance to reject
	SEL delSelector = 
		@selector(coffeeMaker:shouldBrewForScheduledDate:);
	if ((mDelegate != nil) &&
		([mDelegate respondsToSelector:delSelector] == YES))
	{
		// Give the compiler a clue - courtesy of Greg Parker
		BOOL (*MyMagicSender)(id, SEL, id, id) = 
			(BOOL (*)(id, SEL, id, id)) objc_msgSend;

		shouldBrew = MyMagicSender(mDelegate, delSelector,
			self, [brewTimer fireDate]);
	}
	
	if (shouldBrew == YES)
	{
		//...
	}
}

Nifty, right? And correct, too. Enjoy!

Update: Paul Kim via chat, and Jan Van Boghout in the comments below each noticed a flaw in my contrived example. Since I already know the selector I’m planning to call, I could just define it explicitly with a regular Objective-C method prototype. Then the compiler would know exactly how to generate the code if I called the delegate directly:


shouldBrew = [mDelegate coffeeMaker:self
	shouldBrewForScheduledDate:[brewTimer fireDate]];

That’s true, and it’s a fault in my overly-contrived example. But imagine a more dynamic scenario, where the prototype of the method is known, but not the selector. For instance, if the class offers clients the ability to specify a selector:


- (void) scheduleBrewingAtDate:(NSDate*)brewDate
	withBrewDelegate:(id)brewDelegate
	withDelegateSelector:(SEL)delSel;