Vincent Gable’s Blog

January 26, 2009

Adobe UI Gripes

Filed under: Design | , , ,
― Vincent Gable on January 26, 2009

Adobe UI Gripes is a blog with screenshots of Adobe’s weird, non-standard interfaces. (Too much of) Adobe’s current Mac software is like Microsoft’s during the Word 6 period.

(Via Michael Tsai, Jonathan Rentzsch.)

If Adobe didn’t make, you know Photoshop etc. al., I would cut them more slack when it comes to their software’s face. It’s like a dermatologist with terrible acne. Graphic designers seem like exactly the types who would be bothered the most by a tool’s interface not being pixel perfect.

But I am impressed by what I’ve seen of Adobe Lightroom. They deserve UI props for that.

December 28, 2008

Open Radar

Filed under: Announcement,MacOSX,Programming | ,
― Vincent Gable on December 28, 2008

Open Radar is a place for developers to share bug reports they have filed with Apple. Please post bugs there after you have filed them with Apple.

Understandably, third-party developers don’t have access to Apple’s bug database.

But that means they can’t see bugs someone else has filed, hence Open Radar. (Update 2009-01-04: to give you an idea of how difficult this can be, recently Apple closed some of bugs I filed as “Duplicate”, but I can’t read the original bug report they are tied back to. So I have no way of knowing what the status of the fix is, if they have a work around, or even if it’s already been fixed.)

Amazingly “(it was) less than 24 hours from idea proposition to (Open Radar) being built, deployed, and used.” That should give you an idea of how useful this can be.

Open Radar is still nascent. There’s no RSS feed for example. But with community involvement, it can only get better.

I’ve filled my bugs, have you?

Bug: @encode(long double)

Filed under: Bug Bite,MacOSX,Objective-C,Programming | , , , ,
― Vincent Gable on December 28, 2008

UPDATE 2010-08-16: I ran a test today, on Mac OS X 10.6.4 (i386), and the issue has been resolved, @encode(long double) evaluates to "D". I’m not sure when this change happened, or what platforms it effects.

@encode(long double) returns the same string, "d", as @encode(double), at least on i386, Mac OS X 10.5.6 / 9G55. But a long double and a double are not identical:


double aDouble = M_PI;
long double aLongDouble = M_PI;
NSLog(@"sizeof(aDouble) = %d, sizeof(aLongDouble) = %d",

   sizeof(aDouble), sizeof(aLongDouble));
NSLog(@"aDouble = %f", aDouble);
NSLog(@"aLongDouble printed as a double (%%f) = %f", aLongDouble);
NSLog(@"aLongDouble printed as a long double (%%Lf) = %Lf", aLongDouble);

sizeof(aDouble) = 8, sizeof(aLongDouble) = 16
aDouble = 3.141593
aLongDouble printed as a double (%f) =
   -88796093704928900002674917893032219152220160.000000
aLongDouble printed as a long double (%Lf) = 3.141593

I haven’t tested another configuration. TYPE_LONGDOUBLE_IS_DOUBLE in ConditionalMacros.h is 1 under __ppc__, so this might not be a problem on PowerPC.

Submitted as radar://6468314.

December 18, 2008

Automator Bugs

I’ve started using Automator in IMLocation to let people build a set of actions that are executed when they arrive somewhere (for example, muting their laptop’s speakers in a classroom).

Unfortunately, my impression of Automator.framework so far is: buggy.

Here are some issues I’ve run into so far.

-[AMWorkflowController stop:] does not stop the workflow! I do not yet have a workaround.

AMWorkflowController sends its delegate a -document message whenever an action is removed from the workflowView, by clicking the (x) button. If the delegate does not implement it, the action will not be removed!

The (x) button is enabled , but does nothing, in workflows that are not editable.

-[AMWorkflow initWithContentsOfURL:error:] throws an exception when the URL is nil.

This project demonstrates the first two issues.

December 11, 2008

There are Worse Things Than Crashing

Filed under: Design,Programming | , ,
― Vincent Gable on December 11, 2008

Crashing is not the worst thing a program can do. Data-loss and corruption are worse bugs than crashing. I think this is generally accepted in theory, but I often hear developers say things like,

If there’s one behavior of your application that you should focus on eliminating, it’s the behavior of crashing. Above all other “nuisances,” this is the one that is absolutely unacceptable.1


And I certainly agree that crashing is unacceptable, and a high-priority bug. But it’s not the highest priority kind of bug.

For example, say your bank’s website crashes all the time. That sure sucks for everyone! People will be upset, some of them enough to take their business elsewhere. But if the website even occasionally moved the decimal point around when you sent money, the bank would be out of business faster than you could say suedfornegligence.

Even for software that isn’t used by banks, hospitals, nuclear reactors, etc., the basic principle is the same, it’s better to crash than vandalize people’s data.

As with any general rule, there are exceptions. It’s probably worse if an email program crashes than if it “corrupts” data by adding an extra space to the end of of a message. In fact, Mail could be doing this right now, and I wouldn’t know or care. (Outside of movie plot scenarios where evil CS 101 students are holding the city hostage, and I have 10 seconds to defuse the bomb by sending an email with a body containing the de-activation code and not a single extra character. Although to be fair, there’s probably a clause in Mail’s EULA saying it’s a violation of the terms of sale to use it to defuse thermonuclear weapons.)

But the threshold of “acceptable” corruption is vanishingly small. If about 1% of the time Mail made the subject-line of an email all lowercase, that is plausibly worse than a 1% chance of crashing. It’s not OK for the subject of a job-application email to be changed to “vincent gable, professional and detail-oreinted programmer“[sic] (and you know what they say about first impressions).

The Unthinkable

I think a lot of why crashes are thought the worst thing a program can do is, fortunately, crashes are the worst thing most programs will ever do. So they end up taking the #1 spot on the bug severity triage sheet.

Data-vandalization is orders of magnitude less common then crashing in shipping programs. And if you count crashes during development, that proportion shrinks dramatically. Every non-trival program has crashed at some point during the development process.

And a leading cause of data loss is programs crashing without saving something. Do you classify that as a data-loss bug or a crash? Well, the crash is the thing that needs to be fixed to solve the problem, so probably a crash.

Small wonder then that crashes are considered by some to be the worst kind of bug, even though erasing or corrupting someone’s data is worse. Most recently, I have been going by Wil Shipley’s bug triage priorities, which give highest priority to “Data-loss bugs”.


1 I don’t mean to call out Daniel Jalkut; his was just the first quote that jumped to mind. And for all I know he agrees with me, and classifies mauling a user’s data as something worse than a “nuisance”.

December 2, 2008

Bug In The Machine

Filed under: Announcement,Programming,Reverse Engineering | , , ,
― Vincent Gable on December 2, 2008

I was going through some old (OS 9 old at youngest!) backups, and found this dump from a MacsBug session. You can actually see a bug sitting in memory! To me it looks like the bug is inside an old television, with distortion sweeping across the screen, so some of the bug’s left side is wrapped around to the right.

 Displaying memory from 1D9F8CB0
  1D9F8CB0  •???•???•???•???•???•???•???•???•???•???•???•???•???•???•???•???
  1D9F8CF0  •???•???•???•???•???•???•???•???•???•???•???•???•???•???•???•???
  1D9F8D30  •???•???•???•???•???•???•???•???•???•???•???•???•???•???•???•???
  1D9F8D70  •???•???•???•???•üÖ`´••••••P•••Ñ•y•pÄ@•••••Ä•@•••••••••H•••H••••
  1D9F8DB0  •••••••••••É9ÿ•••••••••••••••••••üçÄ´••••• •••‚ 0000000000000000
  1D9F8DF0  0000000000000000000000000000000000000000000000000000000000000000
  1D9F8E30  0000000000000000000000000000000000000000000000000000000000000000
  1D9F8E70  0000000000000000000000000000000000000000000000000000000000000000
  1D9F8EB0  0000000000000000000000000000000000000000000000000000000000000000
  1D9F8EF0  0000000000000000000000000000000000000000000000000000000000000000
  1D9F8F30  0000000000000000000000000000000000000000000000000000000000000000
  1D9F8F70  0000000000000000000000000000000000000000000000000000000%***$*#**
  1D9F8FB0  #*$$*$*#*#**$$*00*$*$*$$**#*#*#*#*#*#**#%00000000000000*•!#•!!!!
  1D9F8FF0  !!!•!!!!!!!!!!!0%!!!!#!!!!!!!!!!!!!!!!!!*00000000000000*!"!•!!!!
  1D9F9030  !!••!!!!!!!!!!!0.!!••!!!!!!!!!!•!•!!•!!!#00000000000000*!!!(•!!!
  1D9F9070  !!!(•!!!!!!!!!!0%!!((!!!!!!!!•!!!!!!!!!!*00000000000000#!!! ••! 
  1D9F90B0  •••••••••••••••0*••!•••••••••••••••••••••00000000000000*!!!•••00
  1D9F90F0  •••••••••••••••0#••!•••••••••••!00•••••••00000000000000#!!!••#0/
  1D9F9130  0&••••••••••••••!••! •••••••••+0$0.••••••00000000000000#!!!•!0••
  1D9F9170  !00#••••••••!000000$!•••••••!00!••,••••• 00000000000000*!!!•0%••
  1D9F91B0  ••%0%••••••%00000000/••••••,0.••••%0•••••00000000000000$!••00•••
  1D9F91F0  ••!*00••••000000000000••••00!••••••00#•••00000000000000*!!/0••••
  1D9F9230  ••!••/0$•00000000000000••0$••••••••*0%!•!00000000000000#•#0$••••
  1D9F9270  •!•••!$•*00000000000000%•!•••••••!(•*0*• 00000000000000*•00••••!
  1D9F92B0  (•••••••0000000000000000•••••••!* •••%0•!00000000000000*00••••!0
  1D9F92F0  &!•••••/00000000000000000!•••'$00!••••00*00000000000000*•*!•••00
  1D9F9330  000••••000000000000000000•!•*00/%0••••••*00000000000000$!•!••$0•
  1D9F9370  ••%00•!000000000000000000*$00%!••0#••••••00000000000000$!••••0.•
  1D9F93B0  ••••$•%0000000000000000000•%!•••••0!••••!00000000000000*!•(•00••
  1D9F93F0  •••(••00000000000000000000!! •••••/0"••••00000000000000#!!!$0•••
  1D9F9430  ••!!••00000000000000000000•!!••••!#0%!•••00000000000000*!!*0*•••
  1D9F9470  ••!•••00000000000000000000*!•••("!••0#•••00000000000000*!!0,••••
  1D9F94B0  •! •••00000000000000000000#!•!•!••••/0•• 00000000000000#!%0!••••
  1D9F94F0  ••••••00000000000000000000#•*••••••••0%!!00000000000000*!•$•••%0
  1D9F9530  0000#•00000000000000000000#%00000%•••!•!•00000000000000*!!!••!0%
  1D9F9570  *•! ••00000000000000000000*#*$!!•0!•••••*00000000000000*!(!••00!
  1D9F95B0  ••••••00000000000000000000••!!•••/0•••••#00000000000000#!!!•$0••
  1D9F95F0  ••••••%0000000000000000000!(!!••••0%•••••00000000000000*!!!(0*••
  1D9F9630  ••!!!!.000000000000000000.!!!••!!!%0-!••!00000000000000*!(•0,•••
  1D9F9670  ••!•!•!000000000000000000•#*•••••••,0••••00000000000000$!!$0••••
  1D9F96B0  •!•$00•/00000000000000000•00/*••••••0.!•!00000000000000*!!!!••••
  1D9F96F0  #000•••!0000000000000000$(•.00%••••• •!!•00000000000000*!!••••••
  1D9F9730  00!•••••/000000000000000!!(!!*00•••••• !•00000000000000$!!(••••$
  1D9F9770  0•••••••!00000000000000*!!!!!•!0!••••••!$00000000000000#(!!••••0
  1D9F97B0  ,••••••!!$000000000000$!!!!!!•!00•••••••$00000000000000*!!!••••0
  1D9F97F0   ••••!••••!0000000000$(!!!!!••••0*••••••!00000000000000#!!!•••,/
  1D9F9830  ••••!!!•••••00000000*!!!!"!!••••/0••••••!00000000000000*!!!•••0!
  1D9F9870  ••••••••••••••$%%%•!!!!!!!!••••• 0)••••••00000000000000#!!!••/0•
  1D9F98B0  •••!!•••••••••.,/•(•!!!!!!•••••••0,!!••••00000000000000*!!!••0!•
  1D9F98F0  •••••••••••••00000•!!!!!!••••••••!0!!••••00000000000000#!!!•••••
  1D9F9930  ••!!••••••••.000000!!!!!••••••••••••!!••!00000000000000$••!•••••
  1D9F9970  ••!•••••••••0000000!• •••••••••••••••!•••00000000000000*!•!•••••
  1D9F99B0  •!!•••••••••0000000$!••••••••••••••••!!•!00000000000000#!!!•••••
  1D9F99F0  •!•••••••••!0000000*!"••••••••••••••••!• 00000000000000#!!••••••
  1D9F9A30  ••••••••••••0000000#!!••••••••••••••••••!00000000000000#!!!•••••
  1D9F9A70  ••••••••••••0000000•!!!••••••••••••••••••00000000000000$!"••••••
  1D9F9AB0  •••••••••••••000000!!!••••••••••••••••••!00000000000000*!!!•••••
  1D9F9AF0  •••••••••••••/0000•(!!!••••••••••••••••• 00000000000000#!•!•••••
  1D9F9B30  ••••••••••••••!*$•!!!!!••••••••••••••••••00000000000000#!!••••••
  1D9F9B70  ••••••••••••••••!!!"!!!••••••••••••••••••00000000000000*!!!•••••
  1D9F9BB0  •••••••••••••••••!!!!!•••••••••••••••••••00000000000000%$#*!!•! 
  1D9F9BF0  •!!!•• ! •! • • !#*$*#!!!•! !! !•• ! • !*00000000000000000000000
  1D9F9C30  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9C70  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9CB0  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9CF0  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9D30  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9D70  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9DB0  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9DF0  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9E30  0000000000000000000000000000000000000000000000000000000000000000
  1D9F9E70  0000000000000000000000000000000000000000000000000000000000000000
 Unrecognized symbol 'prinf'
 Closing log

I swear this is a real memory dump of a sold-for-money application that I didn’t have any part in writing. Unfortunately I don’t remember some specifics, like which application it was.

July 7, 2008

Bug Triage Priorities

Filed under: Programming,Quotes | ,
― Vincent Gable on July 7, 2008

Roughly, my triage order is:
* Data-loss bugs
* Unavoidable crashers
* Functionality-blocking bugs
* Avoidable crashers
* Avoidable bugs
* Misfeatures
* Performance issues
* Feature suggestions
* UI feedback
This is, of course, a rough ordering

Wil Shipley

I totally agree that data-loss / corruption is a higher priority then crashes. You can upgrade|downgrade a crashy program. But once data is gone, it is gone. Protecting users data should be your prime directive. I have always strongly disagreed with any bug triage that put crashes at spot #1.

Powered by WordPress