Obstacles to getting real feedback are now mainly cultural, not technological; any business that isn’t learning from their users doesn’t want to learn from their users.
February 15, 2010
Usability Problems are Cultural
June 11, 2009
Early Adopters Wanted!
I am wrapping up work on Prometheus, an iPhone app that edits the Simple English Wikipedia.
Unfortunately, I am having trouble finding people to take the pre-release version for a spin, and tell me what they think. I want to be sure I’ve fixed any glaring issues before I push my work out to the App Store.
If you are interested in helping, please visit the Prometheus webpage.
Thank you!
March 4, 2009
Professionals Check What They Broke
Mark Chu-Carroll, on how to tell if someone defining division-by-zero is a competent mathematician,
One good way of recognizing a crank is by looking at what they do with their new division-by-zero defining system. A serious mathematician starts working out what affect their definition has on the basic axioms, and what still works. A crank defines division by zero, and then proceeds to continue working as if they haven’t broken anything.
There are parallels in most every profession.
December 4, 2008
NSAssert Considered Harmful
The NSAssert()
function is unreliable, and therefore dangerous. Plain-old assert()
is a better choice.
Note that #define NDEBUG
disables assert()
; and #define NS_BLOCK_ASSERTIONS
disables NSAssert()
. One kind of assert being disabled does not mean the other kind is. Nether kind of assertion is disabled by default when building in “Release” mode — you must be sure to disable them yourself. Be careful, a user will not appreciate the difference between a bug and a failed assertion — both are a crash.
assert()
immediately stops your program with a SIGABORT
signal. You can’t miss a failed assert()
, its behavior is predictable, and it fails fast (link is a PDF).
But a failed NSAssert()
behaves unpredictably. Sometimes it stops program execution, sometimes it does not and leaves the program in a strange inconsistent state. I have entirely missed NSAssert()
s failing, because I did not look at the console. if(!expr) NSLog();
would have been a better choice in the those cases, because at least I would have known how it behaved.
Assertion macros, such as NSAssert and NSCAssert … pass a string to an
NSAssertionHandler
object describing the failure. Each thread has its ownNSAssertionHandler
object. When invoked, an assertion handler prints an error message that includes the method and class (or function) containing the assertion and raises anNSInternalInconsistencyException
.
Complicated! The complexity means it is possible to customize what happens when an NSAssert()
fails. That sounds cool, but I’ve never heard of someone needing to actually do that.
If a framework catches NSInternalInconsistencyException
s, then your program will keep right on running after a failed NSAssert()
. I have had this happen to me several times. I apologize for not having taken the time to investigate what frameworks were catching what.
Apple could change what catches what with any software update.
Variability and complexity are the last things you want while debugging. There’s no reason to invite it them by using NSAssert()
over assert()
. Since NSAssert()
is not guaranteed to stop your program, it can not be relied on to guard against data corruption, or anything worse then a predictable crash.
UPDATE 2009-06-01: You can annotate assert()
, so it prints an explanation like NSAssert()
, by &&
ing in a string after the condition. For example assert(i < j)
is a lot more useful with an explanation: assert(i < j && "unexpected cycle in graph")
— on failure it prints
Assertion failed: (i < j && “unexpected cycle in graph”), function WillHalt(), file /path/to/code.m, line 30.