Thought of the day: get rid of AppDelegate.h

We’ve all seen them (or written them).  App delegates that have their hands in everything, paired with hundreds of code snippets like [[AppDelegate sharedInstance].viewController pushViewController:[AppDelegate sharedInstance].loginViewController]. This kind of high coupling, low cohesion “design” is the enemy of stable, manageable code. Once its there, it is a real pain to get rid of.  So why not spare yourself the effort and make it hard for people to make the wrong choice?  Make the class anonymous!

Now of course, there is really no such thing as anonymous classes in Objective-C, unless you wanted to do something hardcore like modify the class definition at runtime, but there’s an easy thing you can do make it seem anonymous and give rookie developers pause.  Get rid of AppDelegate.h.

As you probably know, headers serve two purposes.  When the compiler sees the main implementation of a class, it uses it to validate that methods are implemented, compile a list of ivars, and trigger property auto-synthesis.  When it sees a method call in other files, it just uses the header to validate that the class exists, that the method exists, and in ARC inject appropriate retain and release messages.  If you move the contents of AppDelegate.h into AppDelegate.m, you satisfy the former while preventing the latter. The only place that is really impacted by this is main.m which has this line:

        return UIApplicationMain(argc, argv, nil,
            NSStringFromClass([AppDelegate class]));

This basically provides compiler level validation that AppDelegate exists and then extracts the string “AppDelegate” from it. This is a little silly since your app will crash instantly otherwise. You can just change it to be:

        return UIApplicationMain(argc, argv, nil, @"AppDelegate");

As a result, all my projects will start with a simple, clean AppDelegate.m file that looks like this:

#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder 
@property (strong, nonatomic) UIWindow *window;
@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Do stuff here.
    [self.window makeKeyAndVisible];
    return YES;
}

@end

Writing a future-proof app

I’m not the biggest fan of apps.  As I last posted, a reliance on apps (or even mobile web sites) to reach mobile users indicates that your core site is not robust enough to reach users in their desired medium.  No matter how great you market your app, your web site is infinitely more discoverable and will be your first entry point for most customers.  Remember, mobile users want to do things now more than they want to do things in an app, so much so that Facebook has more mobile web users than Android and iPhone app users combined.

What keeps an app from being future-proof?

While apps give you more control over the user experience and let you create richer user experiences, the web gives you more control over the content that users actually see.  If you roll out a new feature on your site and your app you’ll get 100% adoption on the site and trickling adoption on your app.  Maybe more of an exponential decay function but you will have plenty of users using the old version of your app again before they upgrade.  This is bad news if you’re trying out a new way to monetize your user base.

Another negative implication of this is seen when you’re releasing new versions of your app web services.  Unless you’re a large API provider like Facebook or Twitter, you’re probably dealing with one or two web service consumers, namely your apps.  And yet, because you have no control over when users update, you are forced to provide backwards compatibility with every service change.  You’re either releasing versioned API calls, versioned endpoints, or packaging old and new data together.  This introduces maintenance overhead.

A third case is for big companies with multiple departments producing their own APIs and web experiences.  Imagine a “reset password” flow.  You have zero ownership of the service but it is a critical feature of your app if you don’t want to drive users to the web.  Going native, though, has some critical risks.  That team could, for any number of reasons decommission their API or at least the API version you’re consuming.  Legal requirements could also change, forcing you to rush out a new app release to add a disclaimer to the screen.  As a result you make the experience a web view, but you can’t do this for every part of your app. Users hate that.

If you’re calling a large number of services, you could end up with scenarios where you’re releasing every week just to address these types of issues, and you still could run into issues with users not being able to perform their desired task without upgrading.  This may be a bit hyperbolic, but I am sure issues of these sorts are cropping up in your development flow, keeping you from focusing on what you should be: making kickass apps.

So how do we write a future-proof app?

To be clear, when I say “future-proof”, I am not meaning your app will last forever or that what I’m proposing won’t degrade the experience for affected users.  What I am offering is a proposal that will keep your site working through the issues mentioned above without requiring you to sacrifice user experience or spend your whole life putting out fires.

Removing Features

First, let’s deal with the scenario where you want to add or remove features from your app on a whim.  Let’s first focus on removal, since it is easy and common-sense.  Removing a feature is simply a matter of your app asking the server what features it can use.  Imagine a service “menu.json”:

menu.json?lang=en_US:
{
    "main-menu": [
        {
            "name": "Activity Feed",
            "controller": "ActivityFeedController"
        }
        {
            "name": "Friend Map",
            "controller": "FriendMapController"
        }
    ]
}

The “Friend Map” team decides to decommission it.  Rather than pushing a new release, we simply go to a friendly internal UI and uncheck “Friend Map”.  The change immediately goes into effect across your portfolio: desktop web, mobile web, apps.

Adding Features

Adding a feature could be the opposite, imagine we removed “Friend Map” and added “Top Posts”. Our menu.json looks like this:

menu.json?lang=en_US:
{
    "main-menu": [
        {
            "name": "Activity Feed",
            "controller": "ActivityFeedController"
        }
        {
            "name": "Top Posts",
            "controller": "TopPostsController"
        }
    ]
}

The problem with this, of course, is that not all apps support “Top Posts”.  The most basic case would be to ignore that menu items if you don’t have the controller but we would much rather let everyone access that feature right away.

You fill in the gap by sending the user to a webview of the page instead.  Users who have not upgraded get the mobile web experience, which may not be as great but is easily better than nothing.  You could tack in an upgrade link to give users the option of opening the app store right away:

menu.json?lang=en_US:
{
    "main-menu": [
        {
            "name": "Activity Feed",
            "controller": "ActivityFeedController",
            "fallbackUrl": "http://mycompany.domain/mobile/activity-feed"
        }
        {
            "name": "Top Posts",
            "controller": "TopPostsController",
            "fallbackUrl": "http://mycompany.domain/mobile/top-posts"
        }
    ]
}

This actually puts you in a really good position, because, depending on business demands, you can deploy an experimental new app feature cross platform without having ever written a line of native code.  The menu.json model can also be integrated with logic to, for example, only display an item to a certain set of users or device types during a staged roll out.  Once we know the feature is here to stay, we can then add a native experience.

Protecting against web service hell

Web service hell is a catchall for what I mentioned before, scenarios where either a service you consume goes offline or you want to make breaking changes to your web service API without maintaining the old version for outdated apps.  There are actually two mechanisms I would recommend using.

The first provides the best user experience by extending “menu.json” even further.  We can feed the current web service API versions into the JSON.  When the app encounters a menu item, it will first check if the controller is available.  It will then ask the controller which API version it supports.  If it does not match the version from the JSON, it will skip the native component and render the webview instead.  To do this, we would need our JSON to look something like the below:

menu.json?lang=en_US:
{
    "main-menu": [
        {
            "name": "Activity Feed",
            "controller": "ActivityFeedController",
            "apiVersionRequired": "4",
            "fallbackUrl": "http://mycompany.domain/mobile/activity-feed"
        }
        {
            "name": "Top Posts",
            "controller": "TopPostsController",
            "apiVersionRequired", "2.3.7",
            "fallbackUrl": "http://mycompany.domain/mobile/top-posts"
        }
    ]
}

A weakness of this approach is that you may not always know that a service is changing.  In this case, your service should be able to tell the app that the request is no good and your app should be able to take this hint.  If your service is down, the service should return 502,  or at least 500 or 404.  In this case, your app would fall back to the fallbackUrl.  If the service is up, the app should include the protocol version in the request and the server should respond with something like a 400 response.  In the headers, it could include X-SERVICE-VERSION-REQUIRED and possibly X-FALLBACK-URL.  The fallback URL could provide more-specific data for your logs, since in reality you should have avoided this request.

HTTP/1.1 400 Bad Request
X-SERVICE-VERSION-REQUIRED: 2.3.7
X-FALLBACK-URL: http://mycompany.domain/mobile/top-posts?error=bad-version

In both cases, if you’ve already rendered an unpopulated view, it is best to give a user a message letting them know why you’re leaving it in order to avoid confusion.

Conclusion

While apps may not inherently provide the same level of control over user experience that you find in web, a blending of experiences (being readily able to switch between native and hybrid for any given flow) will allow you to provide a more rapid delivery of features.  This flexibility will allow you to prioritize native app work effort, expand the areas you feel comfortable creating native views, and weather the tide of hundreds of projects you may have zero control over or knowledge of.  Bottom line: a more stable resilient app and more time to focus on creating cool features.

Why you should develop vanilla HTML first and CSS, JavaScript, Flash, et al last

Imagine you own an concert hall.  The year is 2005 and you’re finally getting into the online ticketing game.  You want to let users pick their seats off a map of the concert hall so you use Flash.  You create a slick seat picker that does asynchronous calls to get the available seats and prices, lets users pick their seats, and then populates the values to a hidden input field.  I’m sure you know by now that there are many problems with this approach, but let’s go over them.

The obvious one is that Flash is not a 100%-reliable technology.  Before the iPhone came out we considered it ubiquitous but it has had many historical issues.  It isn’t a default feature of the operating system, when people get a new browser it may not be installed, and there was a period where IE blocked plugins by default.  Your more cautious users may even block Flash to prevent security risks.  At the very least, imagining a world where everyone can have and wants to have Flash, you’re still dealing with the scenario where they don’t have it right now.  You’re going to have to put up a “Download Flash” link and have your users go through that process before they can access the site.  Your site’s main goal is to have users buy tickets and have a positive experience doing it.  Your goal is not to increase the number of Flash-enabled browsers.

There’s also a risk of vendor lock-in.  What happens when you open a second theatre or demolish a few seats to add wheelchair seating?  Did you design that ticketing UI in a way it is easily configured?  You may need a second engagement to get the interface to reflect your on-the-ground changes.  You could pay through the nose to keep your dates from slipping.

There’s the disruptive scenario we skipped over above, where users are on an iPhone and cannot use your site.  What do you do?  This is a big market.  You can’t retool your site easily.  Make an app!  Now you have two UI’s to maintain along with a handful of frontend services to recreate the ticket buying process.  Maybe instead you go with an HTML5 mobile UI.  Now you’re stuck supporting multiple mobile browsers.  You go ahead and do it anyway to provide quick support for Android, Blackberry, and Windows Phone 7.  Now you have three interfaces: Flash, iPhone, mobile web.  But you’re still not prepared for everything.

Another disruptive scenario where your theatre becomes popular with a audience.  They love your venue but hate your UIs.  Nothing is accessible so they have to call in their ticket orders.  To keep this customer base you must retrofit all your UIs at a high cost due to your multiple vendor partners.  You do it now but who knows what the future may hold.

How could this mess have been avoided?

I would argue that you need to go back to your roots.  While not sexy, an HTML3.2-compatible form coupled with basic PHP/JSP/ASP is the answer.  Get rid of all the frills and thrills and make a dumb-old web page.  While it may not impress anyone, it can accomplish your two goals getting people through the ordering process and keeping them happy.  While it is harder to use an <select multiple> than a flash seat picker, users will probably be impressed with the wicked speed of its one HTTP request.  Ordering happens in the blink of an eye, possibly faster than an XHR request.

It also meets all your past and possibly future use cases.  Smart phone users have no problem. Neither do blind users.  Given HTML’s track record, I would guess that your eyeball tattoo web browser will be able to use it 10 years from now.

No, no, no.  I’m not advocating ugly web pages.

Ugly webpages are your baseline.  Everything from here is to enhance the experience for users that can benefit from it and not hinder the experience for users that can’t.

The first thing you do is make your site beautiful.  You create CSS to style your page and possibly add a few <div> elements and class names to make it all work.  Of course, you do all this in an object-oriented, semantic manner.

The second thing you do is add JavaScript where it makes sense.  You’ll probably want to show the order total.  This will involve attaching dollar-values to the seat <option> elements.  Following rules you would end up with something like <option value=”A1″ data-price=”100.00″>A1 ($100.00)</option>.  You will also end up with more elements with ID’s.  Your first impulse may be to write:

<tr>
    <th>Total Cost:</th>
    <td id="totalCost"></td>
</tr>

This works, but gives the user a confusing experience if JavaScript is disabled.  You have three options for the page to make sense for that use case, hide the element with CSS by default and show it with JavaScript if enabled, inject it via JavaScript and DOM manipulation when the page loads, or put a meaningful default message that will be seen if JavaScript is disabled.

The first option is fine but you have to be careful.  You’ll want to have a script like Modernizr configure the page in the head so the user experience isn’t jarring with the element appearing later and moving content.  You also have to worry about the scenario where JavaScript is enabled but your particular script fails due to a defect.  The second solution all but guarantees you’ll make a user visible change to the page.  It does however eliminate the risk of showing the element if the script fails.  The third option is my favorite because it has low risk and introduces no extra integration points.  Think of the following:

<tr>
    <th>Total Cost:</th>
    <td id="totalCost">Visible in cart.</td>
</tr>

This gives JavaScript-less users useful information and requires zero extra work.  You don’t have to worry about CSS or user-visible painting or any of the other complexity that goes along with it.

The third thing you do is add the flash object.  Because you are now constrained by the <select> object you’re manipulating, you will need your Flash UI to pull from and write to that data source.   You will hopefully realize that you need a truly configurable interface that doesn’t just work for one theatre layout but it’s okay if you don’t.  You’re already saving money by avoiding that async interface for getting seat configurations.  To make it truly compatible with all use cases, use JavaScript to show the Flash and hide the <select> if Flash is supported.  If you’re truly invested in a resilient design, don’t even hide the <select>.  Place it to the side and let the user use either input.

Cool, I’m back where I started, how does this solve my problems?

Let’s step through the scenarios.

Flash doesn’t work?  No problem.  Users get a <select multiple>.  Same for JavaScript, CSS, et al.  The page is resistant to failures of all non-essential components.

New theatre or seating change you didn’t design for?  No problem.  You can disable Flash for those use cases until you get your new resources from the vendor.

iPhone comes out?  No sweat.  Your script detects that Flash isn’t supported and degrades to the drop-down giving you time to work on an iOS app or HTML5 canvas interface.  Your page isn’t mobile friendly but if you removed all the CSS and added a <meta name=”viewport”> it would be.  You create mobile-friendly CSS and use media queries and you’ve pretty much invented responsive web design.  Your site is so simple and fast that you may even bypass the app in general.

Windows Phone 7 becomes popular (with your demographic)?  If your CSS breaks on that device, no biggie.  A custom stylesheet gets you back on track.

Popularity among blind users?  Quick usability testing shows your semantic site is 90% there.  You do some tweaking to make the <select> always accessible even if not visible and make screen readers ignore the Flash UI.

The one scenario where it seems like it would be worse is if you go with a native smartphone app since you skipped the async seat loading in the Flash UI which could be an asset for the phone.  I would argue that it isn’t worth it since the increased complexity increases the workload for analyzing and reimplementing the total process.  Now because all the technical work is being done by a single web page, even if you have a terrible design with database calls and business logic in the frontend layer (e.g., PHP), you only have one frontend layer to deal with.  You could abstract that out into two files the logic and the form.  You then use the logic the web service.  You’re not hunting through multiple source codes in multiple languages to capture all use cases.

Wait, isn’t this just called progressive enhancement?

You caught me.  This is nothing new.  Progressive enhancement is often sold as a way of improving performance, reducing last-minute issues, et al.  I want to sell it as something more basic.  It is a way to cut through the complexity of your designs and future-proof your site.  When you start with nothing and build on top of that, you have to thing of things as logical layers.  When things aren’t working with an enhancement, you can always peel it back.  Your core message isn’t lost in a sea of “Please install flash” or “Please download our app”.

Thanks

If you got to the end, I hope you enjoyed reading it as much as I did writing it and forgive my lack of editing.  I’ve been trying to get this blog restarted for a while but keep getting caught up on the little things.  Hopefully this marks the first of many more posts.

Reversi Revisited (HTML5 canvas on Chome, FireFox, IE9, iOS Safari)

Back in September I posted a HTML5 Reversi game taking advantage of the element.  At the time, I only targeted Chrome so I thought I would follow back up and add Firefox 4 and Internet Explorer 9 support.  In just a couple of hours work, I have a fully functioning Firefox version of the game and a mostly complete version for IE9.  Click here to play the game or here to view a screenshot of the three browsers in action.  Below is a description of the problems I encountered and how they were resolved.

Firefox Support

Problem: The Firefox mouse event object does not support the clientX or clientY properties.  ClientX and clientY are fantastic because they give you the position relative to the element.
Solution: Most sites recommend using (event.pageX – elem.offsetLeft) but this gives inaccurate values when the HTML element has auto-margins.  The solution to this problem was to relatively position the canvas element.  Relative positioning doesn’t affect the rendering of the element at all, preserving its position in the document and its flow, but it does reset the coordinate system for event.layerX and event.layerY.  Simply adding this simple CSS allows the code to work for both Firefox and Chrome.

Problem: Firefox failed to render the game pieces.  The gameboard itself was rendered correctly.
Solution: After a bit of debugging, I found that FireFox was rendering correctly until it received a command equivalent to ctx.scale(1,0) when the pieces flip.  This command, while not raising a JavaScript error, effectively crashed the canvas, causing it to not accept any future commands.  Simply wrapping that block of code with an -if- statement got things rendering. The issue was filed with a testcase as bug 661452.

Problem:  Rendered text wasn’t updating.
Solution: FireFox doesn’t support innerText, switched to innerHTML as no markup was included.

Problem: Some gradient backgrounds weren’t rendered.
Solution: Added Mozilla gradient CSS.

IE9 Support

Problem: Values for event.layerX and event.layerY were way off.
Solution: Since Chrome and IE support event.clientX and event.clientY, I ended up using the following code for all three browsers:

 var x = event.offsetX == undefined ? event.layerX : event.offsetX;
 var y = event.offsetY == undefined ? event.layerY : event.offsetY;

Problem: Internet Explorer does not support gradient backgrounds.
Solution: While Internet Explorer doesn’t support gradients, it does support SVG backgrounds.  Creating a SVG file with a gradient and a width and height set to 100% has it fill the box.  Best of all, this solution works with Chrome, IE9 and FF4, meaning we don’t need to use browser specific CSS.

Unsolved Problem: IE9 does not yet support text shadows.  While there are some hacks out there for basic shadows, the iOS style elements use inlaid shadows and there’s no obvious solution.  Fortunately this is a small cosmetic issue.

Unsolved Problem:  IE9 does not yet support web workers.  I could move the AI logic into the main thread for IE, but this would make the browser unresponsive.  In the mean time, a JavaScript exception will raise (not user visible) when you select an AI level but clicking back 0n Human will let you resume single player mode.

iOS Safari Support

Interested in how it would do, I opened the original version in the my wife’s iPad.  The game worked flawlessly, even with the AI.  Of course, the iPad has the same browser engine as Chrome.  There are a couple things I noticed that could stand some improvement:

  • Since your fingers don’t really simulate a mousemove event, there is no move previewing.  For this kind of device a two click approach would simulate nicely, with the first click simulating the mouse entering a square and the second confirming the move.
  • Clicking on the canvas highlights it briefly.  I haven’t really looked into why but it would be nice to eliminate that graphical problem.
  • Testing on a friend’s phone, I noticed that the AI didn’t work, which suggests that the iPhone 4 doesn’t support web workers.  It’s interesting to see two different iDevices released so close together have different feature support.  One correction would be to check for the Worker object before showing the AI selector.
  • Testing on the iPhone, I also saw that the game existed in a one inch square on account of the retina display.  The game would benefit from mobile device and resolution detection.

Conclusion

If you didn’t notice, not a single change above was related to the canvas’s rendering.  There was just one related to the context crashing.  The canvas did phenomenally in all three browsers, behaving identically and rendering the exact same results.  Admittedly this isn’t the most complex example, but it does include mouse event driven animation that can respond pretty rapidly.  Given how well the canvas is supported across the different browsers, I would consider using it for more complex applications.

As far as the other aspects of HTML5 go, I was a little sad to see text shadows and web workers not supported in IE9 but was delighted to see the SVG background in action.  Since SVG backgrounds have cross-browser support, I would recommend using them in place of browser specific background gradient CSS.

HTML5 Experiment – Reversi

Having read about HTML5 for so long, I decided to finally take the plunge and do a little experimenting.  The result, a canvas-based Reversi game.

Features

  • Canvas based Reversi board with animated moves.
  • Worker based AI that can be interrupted to change the difficulty or disable. (Warning: Anything above easy was incredibly time and CPU intensive on my 4 year old computer.  It may be better with new computers.)
  • Goofy iPhone style interface, since the next step would be to turn this into an iPhone app.
  • Warning: Only tested with Chrome.  No clue how it will react to other HTML5 compatible browsers.

Thoughts

The canvas interface is pretty easy to work with and reminded me a lot of working with the Cairo graphics library.  It took less than a day to get the actual game up and running, a couple days to get the worker AI running, a few more days rewriting the JavaScript using proper class structures and inheritance, and a few days just messing around with the CSS.  The development tools available in Chrome were invaluable, making it a cinch to debug code, track down performance problems, and quickly identify what CSS was being used by other sites.

Recognition

Current State of TagLib#

As many of you have observed,  TagLib-Sharp.com no longer exists and the TagLib# NovellForge site hasn’t been updated in over a year.  The fact of the matter is, I haven’t been involved with TagLib# in about two years and the blog and forum are lost to the ages.

That said, TagLib# is still alive and kicking under the umbrella of the Banshee Project.  It’s just not well publicised.  If you would like to use TagLib# in your next closed or open source project, below are some links that can help.

Many thanks to Gabriel Burt for his continued maintenance of the library.

Best regards,
Brian Nickel

Israel and Monologue

For a group that suffers a lot of unfounded and hateful criticism, there’s a lot anti-Israel propaganda linked to on Monologue. Like with Mono, I wish people would do their own research rather than relying on the words of pundits and bloggers.