Disable assertions and logging in your Release build
[info]chanson
Typically, when you create a build of your software to release, you'll apply a whole bunch of additional optimizations to that version that you won't apply to the debugging builds. You'll strip debugging symbols — or, nowadays, build them to a separate DWARF with dSYM file — and crank up the compiler optimization and instruction scheduling settings that would normally make debugging hard.

One optimization that's often overlooked, though, is to turn off assertions. A lot of developers will use assertion macros as sort of a "continuous unit testing" technique within their code during development. They'll assert that methods' preconditions hold, that the postconditions of various operations continue to hold, that changes within methods produce expected results, and so on.

Standard C provides the assert(3) macro to perform a simple form of verification. By default, it just writes the failure information — including the failing file and line — and then calls abort(3); most environments also provide a way to extend its functionality by using assert as a wrapper for a sub-macro or other function.

Similarly, Cocoa's Foundation framework provides a number of NSAssert and NSParameterAssert macros that you can use in your code. (The primary difference is in the message of the exception they generate.) These normally throw an NSInternalInconsistencyException, but their behavior is extensible by subclassing NSAssertionHandler.

The thing is, you probably don't want the released versions of your applications terminating immediately or throwing exception in unexpected places — even though you probably do want them to do so during development. (After all, that's part of how you ensure they won't happen in production, right?) So you need to disable them in your release build.

Fortunately, Xcode makes this really easy. You just need to add two entries to the Preprocessor Macros build setting in your Xcode project, typically at the project level (since you'll want it to apply to all targets in your project). To turn off Standard C assertions, you just need to specify NDEBUG while for turning off Foundation assertions, just specify NS_BLOCK_ASSERTIONS. If you do this, you can put assertions literally everywhere in your code but be confident you'll only ever hit them during development.

Logging is in a similar boat. The release build of an application should, in general, never log in normal use. However, it can be extremely useful when things do go wrong to allow your users to enable logging by changing a hidden (or not-so-hidden) preference within your application. Ideally, you could even control the logging for different aspects of your application and different levels of severity, so enabling logging for one piece of functionality doesn't affect others, and so you can avoid spewing more log information than necessary.

Unfortunately, there's no built-in facility in Foundation for this sort of fine-grained logging. There's really just NSLog which, though useful during development, is both unconditional and doesn't have either aspects or levels. However, there's the Open Source (BSD licensed) Log4Cocoa project which aims to provide most of this functionality. It's currently based on the same design as Log4J, and it hasn't had a lot of work since its introduction, but it's a good starting point for working sophisticated logging into your own applications and it would be great to see developers pick it up again.

Bob Frank and Wolf Rentzsch presented on both of them for Uniforum a few years back, and made a PDF of their presentation available. Just be sure to tune the logging that actually gets compiled into your release builds by leveraging the Preprocessor Macros build setting...

Update (April 30, 2007): I've followed this up with another post on the importance of distinguishing between assertions and checks in your code. One of the main reasons I find that people don't want to turn off assertions before shipping is that they're using assertions as checks; if you distinguish between them, then this won't be a problem.

Mac OS X developer frameworks
[info]chanson
Anyone doing Mac OS X development should check out OCUnit from Sen:te and Log4Cocoa by Bob Frank.

OCUnit is a unit testing framework modeled on the Smalltalk unit testing framework written by Kent Beck, father of eXtreme Programming. I've raved about unit testing here before. OCUnit makes it extremely easy to integrate unit testing into the build cycle for your Cocoa applications.

Log4Cocoa is a straight port of Log4J to Objective-C and the Cocoa frameworks. Bob did a lot of good, hard work and now more developers need to pick up the ball and run with it. For the uninitiated, you use Log4Cocoa to add logging to all the various interesting parts of your code. And that logging can be controlled at run time. It can be useful for debugging hard-to-find bugs, like timing-dependent bugs and multithreading bugs.

(Oh, and if you haven't checked them out yet, be sure to look at BDControl and BDRuleEngine.)