Sacrificing Readability for Cleverness

I was looking at some code in the Three20 library when I came across this:

BOOL TTIsKeyboardVisible() {
  // Operates on the assumption that the keyboard is visible if and only if there is a first
  // responder; i.e. a control responding to key events
  UIWindow* window = [UIApplication sharedApplication].keyWindow;
  return !![window findFirstResponder];
}

The last line had me scratching my head as it has a double negation. While this looks like a mistake, it isn’t; this is a developer being clever. Let’s break down the line:

[window findFirstResponder]

This returns a nil value or a non-nil value. If we then negate it the result is YES if the firstResponder is nil and NO if the firstResponder is non-nil. If we negate it again, the rest is NO if the firstResponder is nil and YES if the firstResponder is non-nil. So, the bottom line is:

return [window findFirstResponder] != nil;

Why did the developer use the hard to read !![window findFirstResponder] when [window findFirstResponder] != nil is much more readable?

(We’ll ignore the fact that initial assumption is not always valid; I believe there are cases where the firstResponder isn’t a text field. Using keyboard notifications is the way to tell if a keyboard is visible.)

Writing clever code like this drives me insane as there is no reason to take shortcuts; a few extra characters isn’t the end of the world and the next person that reads the code has to closely examine the syntax to ensure that the !! isn’t an error.

The art of user interface

Years ago I thought I had the ability to design a decent user interface. Back then, the concepts were quite easy as the screen sizes were limited (Palm OS) and we were dealing with essentially black and white. As long as I followed the UI guidelines, the interface looked good. These days, I don’t think I could design a user interface to save myself. The flexibility of iOS, high resolution screens, full color displays and multi-touch add so much complexity to user interface design that it takes a professional, in my opinion, to design good user interfaces.

I’m quite lucky that I work with designers and artists do the design work which lets me concentrate on what I do best, writing code and solving problems. The lack of my own design ability makes it quite hard for me to come up with my own titles to publish. If I came up with a good idea, I’d need to find a good designer willing to take payment in the form of a split of revenues; good design isn’t cheap!

Developers need to keep this in mind when releasing applications; a good idea even well implemented is only half of what makes a good app. The other day I looked at an app that had the beginnings of a decent app, but the UI had a lot to be desired, so it quickly got removed from my device.

Does experience count in mobile development?

The other day, I was instant messaging with someone and jokingly questioned why anyone would listen to what I had to say about mobile development. Then I realized that I’ve been doing mobile application development for almost 17 years! Just writing that sounds unreal. I wrote my first mobile application my senior year in college for the Newton. On a tangent, how did a college student get a Newton and the quite expensive developer tools? The Apple Personal Interactive Electronics (PIE) group licensed my NotifyMail application and exchange, I received a Newton MessagePad 110 and the developer tools when developer tools cost way more than the $99 Apple charges to join the iOS developer program.

The application was quite basic; it counted down the number of seconds until I graduated from college. Yes, I was tired of school and ready to graduate! I guess I kind of got hooked on mobile development and that’s where I’ve spent a majority of my career; first Newton, then Palm OS, and now iOS. I’ve played with Windows CE/Mobile and WebOS, but never wrote anything for those devices.

I don’t think I could write Newton or Palm OS code these days, but some of the concepts are still the same, such as limited screen size and limited memory. However, iOS is so much more advanced, it’s unbelievable.

On the flip side, some may say that my experience is also a hinderance as I may be stuck in my ways. This may be true, but I’d like to think that it isn’t the case. Hopefully my long history of mobile development continues to serve me well.

Struggling with Distributed Version Control Systems, e.g. git

I’ve been using subversion for version control on just about all my projects for years, whether they were my own projects or for clients. It worked well and I got very used to it. Recently I’ve been put on projects that use distributed version control systems and have also been working on some open source projects that use it as well. Several of my projects use Mercurial, but most are using git.

As my work on the Mercurial projects has been quite limited, I’ve fumbled my way through using it without really learning about it. MacHg has been good enough for me to work on the projects. However, one of my projects relies heavily on git, so I’ve been trying to learn it. I’ve read a number of tutorials, watched videos, read through Pro Git twice, and still don’t feel comfortable with it. After talking with some other developers, I’m not alone in being lost with git.

I consider myself a fairly intelligent person that can learn new technologies. I’m not sure why it has been so hard for me to learn git, but I’m starting to see some of the benefits of it. Another developer I work with has cursed git because he just wanted to look through a snapshot of a source tree, but with a distributed version control system, he had to download the entire repository in order to browse the code (he didn’t have access to export the source without the rest of the repository). When he first told me about this, I completely agreed with him on how ridiculous this aspect was, but the more I read (read the same material, that is), the more I’m starting to get how powerful git is.

While git is quite powerful, it is going to require me to change my workflow as git seems to encourage creating branches for every little thing. Branching code, to me, has always been avoided as it was a royal pain and merging was unpleasant. Merging can still be unpleasant with git, but everything I’ve read seems to indicate it is painless. We shall see.

I wasn’t until I found the Git Reference website that the pieces started to make sense. I’m not sure why every other tutorial doesn’t make things this clear. Maybe this should be everyone’s starting point in learning git.

I’m comfortable with command line tools, but prefer a GUI if at all possible. With subversion, I used to use Versions, but switched to Cornerstone after I tried it and found that it showed diffs right in the app without requiring an external application. Now that I’m using git, there are a number of GUI tools for it, but I’ve found that Tower is the only git app out there for the Mac that currently has diffs right in the app, so that’s my app of choice. There are some things I don’t like about it, for instance I like a list of repositories on the left side. However, it’s helping me become more comfortable with git.

Maybe I need to write an idiot’s guide to git. If a reasonably good developer like me is struggling with git, how can it become widely adopted? Is it that other developers aren’t as entrenched in subversion as I? I kind of feel like I’m missing something in how much time I’ve spent in trying to learn git.

Storing User Data in Application Support

I recently switched to a new MacBook Pro and decided to piecemeal move my data over so that I wouldn’t bring over old crusty preferences and files like that. This has worked quite well, but in two cases today, I found that some user data was stored in the Application Support folder. Since I hadn’t copied this directory over, when I ran the apps, I had no data and had to dig through an old Time Machine backup to find the data. To make matters worse, I’m storing my personal data on an encrypted disc image and in order to get the apps to run, I had to create a symbolic link to my disc image’s directory that contains the data.

Apple explicitly states in the developer documentation that the Application Support directory:

Contains application-specific data and support files such as third-party plug-ins, helper applications, templates, and extra resources that are used by the application but not required for it to operate. This directory should never contain any kind of user data. By convention, all of these items should be put in a subdirectory named after the application. For example, third-party resources for the application MyApp would go in Application Support/MyApp/. Note that required resources should go inside the application bundle itself.

In ReceiptWallet 1.0, I made this mistake for ease of use and stored user data in this directory, but when I moved to a document based app, I rectified this issue.

Developers, please read Apple docs and store user data in a user defined location or in Documents; Application Support is the wrong location for this data.

Broken Xcode 4 project templates

The other day I received a crash report from one of my projects that included a symbolicated crash log. This was very strange as I’ve never received a symbolicated crash log for an iOS project; I’ve always had to match it up with the dSYM file that I’ve stored away. After a little research, I found that some settings in the project didn’t strip out the debug symbols. I found an older article on Apple’s developer site that seemed to address this. I flipped on the switches and the project size dropped by 500K which would make sense.

The next step was to see how I missed these switches. The default Xcode 4 template for an iOS navigation based app has the following:

STRIP_INSTALLED_PRODUCT = YES

for the release build. However, the article above indicates that the following flag must also be on for the above one to have any effect.

Xcode provides several built-in options for stripping executables of their debugging symbols. One of these is the Strip Linked Product build setting. While typically set, it has no effect unless the Deployment Postprocessing setting is also set. Deployment Postprocessing is a master switch that enables the action of a host of other build settings. It’s approximately analogous to running the xcodebuild tool with the install command.

DEPLOYMENT_POSTPROCESSING = YES

Unfortunately it’s a bit hard to test with a basic project as the file size is too small. However, I opened the CTPageViewer sample app and tested with DEPLOYMENT_POSTPROCESSING on and off and with it off, the file size was definitely larger indicating that the flag must be set to YES.

So, did Apple mess up the default project? If you have your own template (which I might cover in another most), you can change the settings. If Apple didn’t mess up, what am I missing?

Failure to check return Location Manager values

Last night I downloaded the Bing for iPad app and it looks quite interesting. However, I ran into a problem that shows a failure for the developers to properly handle an error condition. I told it to use my current location and it said I was over 500 miles away from my home. The location was where I was a few weeks ago. I switched to the Maps app and that app said it was unable to determine the location. A quick device reset fixed everything including Bing, but the fact that Bing didn’t know where I was got me thinking about what caused it. (My WiFi router is registered with Skyhook, so my iPad will always return my house’s location when it asks for the location if I’m home.)

I’ve worked a lot with CLLocationManager and have found some quirks with it. First, sometimes it never returns a value, so developers must set a timer and alert the user. This, however, was not the problem in the Bing app. When the app requests the location, it does something like:

    self.manager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;

which means it only needs to be accurate within 3 km. As the CLLocationManager updates its location using:

- (void)locationManager:(CLLocationManager *)inManager
 didUpdateToLocation:(CLLocation *)newLocation
 fromLocation:(CLLocation *)oldLocation
{
 	if (newLocation.horizontalAccuracy >= 0.0 &&
          newLocation.horizontalAccuracy <= 10000.0)
	{
	}
}

it needs to check the horizontalAccuracy to make sure it is positive and within the desired range. I believe that the Bing app isn’t properly checking this and just taking the value that is immediately returned. Since CLLocationManager caches the last location for efficiency, it is instantly returned. This is the wrong thing to do without checking the result.

Choosing a software contractor

When companies look to hire a developer to write software, in particular iOS (iPhone and iPad), they expect to hire an expert. However these days everyone and his dog claims to be able write iPhone and iPad software. While this may be true, it is nearly impossible to know if you’re getting a good product. Apps may have great visual design, but in some cases it is just a pretty face. So how do you pick a developer that is going to produce a quality product that is stable, maintainable, and works well. Many projects get passed from developer to developer, so having good quality code to begin with, the app will have a higher change that it can continue without being completely rewritten.

I’ve written software as a contractor for many years and like to think that I know what I’m doing, so here are some tips and questions to ask that may help companies hire a quality developer.

  • Does the developer rely heavily on open source? Open source itself isn’t inherently a problem, but should be used sparingly for specific purposes and should be easily removed at a later time if need be. Building an entire application on an open source framework makes things needlessly complicated and fragile.
  • How long has the developer been writing Objective-C software (Mac or iOS)? Experience says a lot about how easily the code can be maintained in the future.
  • What do the applications that the developer has developed look like? Take a look at the App Store and see how complicated the apps are and how well they work?
  • Ask for references. Ask why the developer is no longer doing work for the references. There are a number of ways to say “we got fired”, so be on the lookout for those. If the app is no longer being developed, the company ran out of money, or the developer no longer has time are probably the best reasons; anything else might be suspect.
  • Does the developer use source control? This is a pretty basic requirement. If a developer doesn’t use source control for his/her own projects, that would worry me. There are many sites that offer free or cheap source control, so there is no excuse for avoiding it.
  • Does the developer use code analysis tools such as CLANG? It’s built into Xcode and there is no excuse for avoiding it.
  • Does the developer allow warnings when building the project? Compiler warnings should be avoided at all costs.
  • Can the developer provide code samples for review? In particular, an app that can be built using the Apple Developer Tools. This is important as some developers have a huge list of tasks to get a project built. A project should be delivered such that you can unzip the archive and build the project. I’ve seen projects delivered that have a list of steps to build including checking out code from open source repositories. This is extremely problematic and error prone as the repositories could change by the time the app is delivered.
  • Ask the developer what is the right way to determine if a feature is available on a particular device. Today I saw code that checked the OS version to determine if Retina display graphics should be used. This is completely wrong because for example, iOS 4 runs on devices that don’t have Retina displays. (Also the code that checked the OS version didn’t properly check the version.) Apple has identified ways to determine if a particular function should be used or a feature is available.

These questions are probably hard for non-developers to ask and know if the answers are legit, so it might be worth spending a few bucks to find an expert, such as me, that can spare a few hours to evaluate a developer, but doesn’t have time to actually do the project.

When do you give up and start over?

I’ve worked on many, many projects in my career. Some of the projects I’ve started, some I’ve inherited. There comes a time in every project, not just software, but also home projects and car repairs, where I have to decide to scrap what I have and start over. This decision is never taken lightly as I’d be throwing away something that works in exchange for a clean start.

I’ve done this with my NotifyMail program a few times as the application was quite small, but in the process I had to drop features and probably ticked off a number of users. In all my time working on ReceiptWallet, I asked myself a number of times if it was time to scrap the code and start over. While I never completely scrapped the code, I did rewrite chunks of it as I learned more and better ways to write code.

With many of the projects I’ve inherited, the decision to start over has pretty much been a non-starter as the programs had existing users and I was under time pressure to get things done. Unfortunately this sometimes lead to fixing lots and lots of bugs that I didn’t create and probably wouldn’t have been in there if I started over.

The same type of decision has to be made with respect to cars and even a lesser extent, houses. If you keep pouring money into a car for repairs, at what point do you decide to buy a new car? Granted the cost is much higher for a new car, but over time the repairs could add up to the price of a new car, not to mention the hassle of taking a car to the mechanic.

Synchronous vs asynchronous networking programming

When I first started learning how to write code, everything I wrote was done sequentially with some goto loops; it waited for input, did something and then waited for more input. When I started writing network code on Mac OS, I had to fumble through Universal Procedure Pointers (UPP) in order to wait for connections and not block the user interface. Now that we’re into the golden age of Mac OS X and iOS, those days are behind us. Most network programming is done with NSURLConnection either the synchronous or asynchronous calls.

The synchronous call

+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request
	returningResponse:(NSURLResponse **)response
	error:(NSError **)error

is quite easy to use as it simply returns an NSData object. Anyone that has done iOS programming knows, you absolutely cannot use this call on the main thread as it blocks and won’t return until it times out, errors out, or returns data. The iOS watchdog timer will kill an unresponsive application as outlined in an Apple technote.

So what many developers do is either wrap this call in an NSOperation or simply perform it on a separate thread. This allows the user interface to be responsive and won’t get the application killed by the watchdog timer.

However, this is probably not the best way to handle network calls and I’m kind of disappointed that Apple has even provided the method. There are a number of things that the synchronous call can’t do (even in a background thread):

  • Requests can’t be cancelled. Once you issue the call, it only returns when it times out, when it gets an error, or gets the data back. There are many cases where you want to cancel a request; for instance, if you’re loading a bunch of images and a use exits a screen, you should cancel the outstanding requests.
  • Authentication can only be specified at the start of the call. Using NSURLProtectionSpace, the authentication can be specified as part of the request. If you want a user to enter a username/password based on an HTTP 401 error, you can’t do this with a synchronous call.
  • Responses can only be handled at the end. For instance, redirect (page moved requests) can’t be acted upon until all the data is downloaded whereas with an asynchronous call, you get the response once the header is downloaded. A former Apple engineer, Jens Alfke, wrote that basically the synchronous call treats many response as errors instead of recoverable conditions.

The first point is my biggest problem with the synchronous call and people might say that if you never want to cancel the call, who cares? That seems a bit short sighted to me.

Using the code that Dave Dribin wrote on concurrent NSOperations you can easily construct a nice asynchronous networking class and queuing mechanism. I’ve done this twice and there is no reason that I can think of to still use synchronous networking calls on iOS.

I’m sure that some people will argue with my logic and that’s fine. I’ve been writing networking code for my entire career and while I’m not going to claim to be an expert on it, I’ve seen good and ugly (mostly written by me). The synchronous calls look quick and dirty while the asynchronous calls look like a lot of work. I agree with a friend of mine when he said in a StackOverflow discussion that asynchronous calls were the “The Right Way”.

In fact, asynchronous networking calls really aren’t a lot of work. I was scared of asynchronous networking calls until I started writing Objective-C code; you just have to structure your code with delegates and handle the callbacks. I believe you should do this wrapped in an NSOperation to make sure that you only have a few networking calls outstanding at a time (you really only have so much bandwidth so trying to flood the channel with calls isn’t going to be all that effective). In addition, this will help properly display the network activity indicator on iOS.

Can anyone think of a reason besides “it’s easier” to use the synchronous version of NSURLConnection vs the asynchronous call?