Jan 17

Alex Payne has written a wonderful article about why cross-platform development environments ultimately fail to deliver what customers really want; a great experience. Alex says:

This post is about platforms and doing the right thing by your customers. It’s about the one big thing that I think HipChat and some other great companies are doing wrong.

He nails the reason that cross-platform development tools and environments like Adobe’s Flash and AIR products are attractive from a business perspective but end up failing from the customers perspective. Ultimately, that circle of life will come back to haunt the business.

Many businesses are attracted to the idea of writing software once and deploying it across multiple platforms. From their perspective they have one development team, one code base, and one release cycle. What’s not to love?

That’s where most businesses stop their investigation. They fail to even think about what their customers want. They’ll quickly jump up and say, “What they want is our product on their platform. We’re giving them that!”

Yeah, but you’re giving them a turd and that’s insulting. I hear the next bit of verbal diarrhea spilling out of their mouth … and this part kills me.

“Well, at least they’ll have our product on their platform.”

Ouch. I think I just threw up a little while typing that.

What you’re communicating with a poorly-done AIR app is that your business priorities – namely, saving time and money – are more important than what your customers want.

Ironically paradoxical in nature because without customers there is no business.

Alex points out a few very well known products such as TweetDeck, Pandora, and Remember the Milk, where their users are begging for a native application. Sadly, the folks screaming for a native application for Remember The Milk have been flat out ignored by that company since 2007. Actually, that’s not ignoring them. That’s giving them the finger.

My team experienced a number of the usual problems one has with AIR applications: lousy performance, odd interface bugs, key combinations and UI elements that didn’t conform to our operating system. AIR apps exist in an uncanny valley between a web application and a desktop application, and the result is unsettling and annoying. Pretty soon, we were itching to go back to Campfire (via the native Mac client Propane), even though HipChat has better features and the promise of improved reliability.

Why are these cross-platform products so bad? Do users even know if a product is using a cross-platform development environment? Yup, they sure do. Users, even if they’re not geeks or developers like me, can smell a cross-development turd. I love how Alex wrote this:

Humans are gifted with extremely sensitive bullshit detectors. The average computer user may not internalize the difference between an AIR app and a native app, but he knows when something doesn’t feel right or work correctly. Your tech-stunted uncle may not ever request a native application with that terminology, but he’ll sure complain about his computer acting funny when he experiences the oddities of an AIR app.

Just read the comments at this site and you’ll quickly see the common threads:

  • Slow
  • Sucks up CPU cycles better than a Dyson
  • Doesn’t conform/take advantage of native UI
  • Lack of support for native OS features. Instead, uses the least common denominator solution that works across all-platforms
  • Security issues

With comments like that, do you really think “investing” in that type of development environment is going to save you money/time in the long-run? Does this seem like the path to huge business profits and long-term customer loyalty?

Is it more expensive to create native applications across all of the different platforms? Yes and no. Yes, because it is an investment in the development of your product. No, because unless you’ve misjudged the market, this investment will more than pay for itself.

“We don’t have time” is the common excuse for delivering an AIR app instead of a good native app. Money, though, can buy someone else’s time. For a price, you can find a great contractor to build a native app for any platform under the sun. It’s an investment. Eventually, unless you’ve misjudged your market, the investment should pay off.

What should a company do when they don’t have the time, resources, or expertise to deliver a native application? You start by clicking on the link above.

Written by Terry Blanchard \\ tags: , , , , ,

Dec 23

Accessibility Zoom
Accessibility is one of those areas that most software engineers and product teams seem to have little or no knowledge of. When it is brought to the attention of the decision makers, I’ve heard all too often, “We’ll do that if we have time at the end of the project” or, “What is that? Why do I care about it?” What’s worse, is that in the eyes of many companies and project leads, they can easily rationalize to themselves why accessibility shouldn’t be included in the development cycle:

“Why would a blind person own a touch screen device?”

“I think you’re solving a problem that doesn’t exist.”

“That’s not our target demographic.”

“I can’t see how this would improve our App Store ratings.”

“QA doesn’t know how to test it.”

It’s really sad. Especially when Apple has made it so incredibly simple for us to implement. They’ve done all they heavy lifting for us and simply said, “Carry the baton across the finish line. Please.” And most of us drop the baton.

Honestly, it takes minutes to make your application accessible to a population that all too often gets the shaft. I am a fan of Matt Gemmell. Everything from his tweets to his blog. Even if you’re not a fan, I implore you to read just one article. It’ll make you a better software engineer, and you’ll make your software usable to an audience that seems to lack a voice.

See Matt Legend Gemmell’s article:
http://mattgemmell.com/2010/12/19/accessibility-for-iphone-and-ipad-apps

John Gruber of Daring Fireball quoted this article as:

Must-read for developers. Both a good high-level overview of what accessibility really means and who it helps, and a technical overview of how iOS developers can take advantage of it. iOS is simply leaps and bounds ahead of the competition in accessibility.

Written by Terry Blanchard \\ tags: , , , , ,

Dec 22

Multithreading
Everyone has their own vision of how things should work. As you gain more experience in your craft, you become more grizzled. Well learned. After some time, you earn the privledge of passing this experinece on. Oscar Wilde said it best:

Experience is simply the name we give our mistakes.

Multi-threading in software engineering has been around for a long time. Many mistakes have been made, thankfully. From those mistakes, experience was born. Most of the engineering books talk about the essentials, and the dangers that must be respected and adhered to. But while they talk about the pitfalls of what could happen, none of them really give you great guidelines. I’ve been doing this a long time and I’ve worked with people who should not have made some of the mistakes I’ve witnessed.

Are they bad engineers?
No.

Was there a fundamental misunderstanding about multi-threading?
No.

But there are some fantastic guidelines that aren’t well-established. It seems like Brent Simmons and I agree on a lot of the same principles. He’s written a great blog post about Cocoa Threading that every Cocoa developer should read and understand. He refers to his post as his, “barely-organized thoughts on threading and Cocoa applications” but it covers the points in a concise manner.

Thread Communication Exclusively on the Main Thread

First up is his philosophy on all communication between threads taking place on the main thread. He extends this to notifications as well. I’ll add one more to that list which is KVO notifications. This is essential because UIKit and Core Data don’t like operating on secondary threads. I don’t know how many times I’ve seen

NSAssert( [NSThread isMainThread], @"This needs to run in the main thread" );

 go off because I received a notification or call from a secondary thread.

Communication between systems always happens on the main thread. (A system is one or more objects that work together.) In most cases, communication between objects in the same system happens on the main thread too.

If an object does something in the background, that is that object’s business and nobody else’s.

This extends to notifications: from background threads, I always make sure notifications get posted on the main thread. This way every notification observer can always assume that it’s getting called on the main thread.

Regarding KVO, Brent has this to say:

KVO is a trickier thing. Here’s how I handle that: anything happening in a background thread is not observable (by convention). Whatever is going on is private. When it’s time to set public stuff, stuff that could be observed, those things are set on the main thread.

Threading Methods

There’s almost as many different ways to spin off a thread as there are people in the United States. Brent and I also agree on which methods we use:

I’m very deliberate about my threading. I like Grand Central Dispatch, but for my purposes NSOperationQueue works best. The formal, easily-monitored approach of NSOperationQueue works best here. I definitely recommend against anything but GCD and NSOperationQueue — anything else (NSThread’s detach method, etc.) is too random. (Yes, we used it for years, but we have better stuff now.) (In fact, I almost never even use NSInvocationOperation — I much prefer the structure and defined stop/start of NSOperation.)

I use an NSOperation subclass that takes a target and selector in its init method. When it’s finished, it calls the target and selector on the main thread. This way the caller only ever sees the main thread — it creates the operation on the main thread, then gets called back on the main thread. The fact that the operation happens in the background is unknown to the caller: the caller just knows that it’s async, and doesn’t know anything else.

I almost exclusively use NSOperation subclasses with NSOperationQueue in my applications for the same reasons that Brent outlines. You can create multiple NSOperationQueue’s if you need different operating parameters (for example, one queue that is sequential, another queue that can operate concurrently). Making dependencies between various NSOperation’s is as simple as making an addDependency call. Plus, they can have dependencies across different NSOperationQueue’s.

Locking

NSCache seems to have suffered from poor marketing. It’s a little gem that very few people seem to know about. I’ll bet most of you have written your own class that performs much of the same functionality. I’ll take the very-well tested and used NSCache, which is also thread-safe, any day.

Locking sucks. If you have to do it, you have to do it. It doesn’t mean you’ve failed — failure would be not-locking when you really do need a lock.

There are a couple other things you can do which make sense.

  1. Use performSelectorOnMainThread to set some data that would otherwise require locking. (This is not a trick to use willy-nilly, though — typically it comes at the very end of an operation, not sprinkled throughout.)
  2. Use NSCache — it’s thread-safe.

I highly recommend you read Brent’s full article, “Some Notes on Threading” over at his site.

Written by Terry Blanchard \\ tags: , , , , , , , , , ,

Nov 01

When Xcode 3.0 was released Apple introduced a new file format for the source code-unfriendly NIB format to the XIB format. XIB files are text-based and far easier to work with when you need to diff you changes before submitting them to version control. XIB files are only used during development and turn into the more efficient and smaller compressed NIB format when you build the product.

In a recent project I used iLocalize 3.8.4 to manage the localization process. The problem with iLocalize is that it only exports in NIB format so my English resource files were in XIB format, but all of the localized resources were in NIB. Fortunately, there’s a quick and easy way to do this with a single Terminal window session. Just type:

ls | grep nib | xargs -L1 ibtool --upgrade

and all of the NIB files in your folder will now have a corresponding XIB file.

iLocalize should do this for you automatically. Sadly, it seems like future development on this product has ceased.

Written by Terry Blanchard \\ tags:

Sep 21

As I write this, I’ve been working on an iPhone application that is very reliant on Internet connectivity. One of the challenges I encountered early in the development of this application was debugging the HTTP requests I was making and the responses I was getting back from the server. One of the requirements is that all communication was performed over HTTPS which clouded my debugging even further.

Meet Chuck, or Charles as the more formal and official name goes. Chuck is my new best friend. Yup, we’re so close that I can call him Chuck. We’re tight.

Charles is a web proxy, HTTP Proxy, and HTTP Monitor that runs on your Mac. Your web browser (or any other Internet application) is then configured to access the Internet through Charles, and Charles is then able to record and display all of the data that is sent and received.

In Web and Internet development you are unable to see what is being sent and received between your web browser / client and the server. Without this visibility it is difficult and time-consuming to determine exactly where the fault is. Charles makes it easy to see what is happening, so you can quickly diagnose and fix problems.

This is great for running your application on the iPhone simulator on your Mac. You can download a free-trial, but trust me on this, you’ll be buying the full version for $50 and thanking me later.

I was curious to know how some of the competing applications worked. While I can build and run my application in the iPhone simulator and use Charles to debug it, I couldn’t help but long for that same insight into other competing applications that I had on my actual iPhone.

Was there some way to have Charles work with my physical iPhone instead of the simulator so I could monitor it’s HTTP traffic?

Oh, hells yes!

It’s actually very easy to configure. Here’s all that you need to make this happen:

  • Your Mac with Charles installed and running
  • Your iPhone with the applications you’d like to monitor
  • Both your iPhone and Mac with Charles must both be on the same WiFi network

That’s it! Got that? Good, let’s configure it. First, we’ll configure Charles:

  1. From the Help menu, choose Install Charles CA SSL Certificate… This will allow you to debug and monitor HTTPS traffic.
  2. If you are debugging or monitoring an SSL connection (or HTTPS request), you will need to configure this in Charles. From the Proxy menu, choose Client SSL Certificates…
  3. Charles SSL Certificates Configuration

  4. Ensure that Enable SSL Proxying is selected. One of the great things about Charles is that you can use wildcards when choosing what SSL sites you would like to monitor. In the above screenshot, I am monitoring all HTTPS traffic on any .com domain.
  5. Run the Network Utility application and make note of your AirPort wireless IP address:

Network Utility IP Address

Now that your Mac is setup with Charles and the HTTP proxy, we need to configure your iPhone to use that Mac as it’s Web Proxy. But first, we need to install the Charles CA certificate on your iPhone.

  1. Open up Safari and navigate to (iOS 4) http://charlesproxy.com/charles.crt or (iOS 3) http://charlesproxy/iphoneconf. When you are prompted to install the Charles certificate, tap on the Install button.
  2. iPhone Install CharlesCA Certificate

  3. Open up your iPhone Settings application and tap on Wi-Fi settings. Tap on the blue disclosure indicator of your local Wi-Fi network
  4. iPhone Disclosure Indicator Network Settings

  5. Scroll down to the bottom of your Wi-Fi settings and tap on the Manual segment control in the HTTP Proxy settings.
  6. Enter in the IP address you wrote down from your Mac running Charles. In my case, when I ran Network Utility I had the AirPort IP address of 10.0.1.33. I put that IP address in my proxy settings as well as the default port Charles runs on, 8888:
  7. iPhone Charles Proxy Setup

  8. To verify your settings, open up Safari on your iPhone. As soon as you make an Internet request, Charles will prompt you on your Mac with a mesage box like the following. You want to click on the Allow button.
  9. Charles Proxy Allow

That’s it! Now fire up that application you’ve always wondered about.

Written by Terry Blanchard \\ tags: , , , , , , ,