Design Isn’t Just About Graphics
Back in June, a client approached me about writing an iPhone app that would let users report and be notified of speed traps while driving. I hadn’t been familiar with this app space and thought the idea was great! We spent the next two months working together designing, implementing, testing and ultimately releasing the app Fuzz Alert Pro which made it onto the App Store just a few days ago.
As a closeted UX Designer-wannabe (alright, I’m out of the closet now aren’t I?), I found this app fascinating in its challenge. We wanted to make an app with an interface perfect for driving. There’s a handful of other apps out there that do something similar, but it was clear that none of them had their UI right. In this industry, how your app speaks with the users is as much a part of its success as its technical achievements.
Speaking With the User
The first thing we did in our research was get an idea of how users would use this app. Now, the ideal way is to have an iPhone Car Mount. Not only does it accomodate a better viewing angle for the driver, but it makes plugging in to the car charger convenient since the slot on an iPhone is at the bottom of the phone where it would interfere with positioning. However, despite this, clearly most users would not have a mount and so we wanted to design for the most common case of the user driving with the iPhone sitting in a cup holder.
In addition, drivers would overwhelmingly not be looking at the app while driving. Many drivers might give a glance every so often, especially when stopped at an intersection, but audio would be important. From this, we came up with the idea of “Radar Mode.” Radar Mode can best be described as a replication of a classic radar detector, though obviously based on different technology. In fact, Fuzz Alert Pro plays similar audio “beeps” that you would hear from one, with beeps repeating faster and faster as you get closer to a known speed trap. This pure-audio interface means the user never has to look at the screen while driving. Ever.
Modal Interruption
In all of UI design, my biggest pet peeve is unnecessary dialog boxes, modals, and interruptions. The classic case has always been text search. There’s no doubt that, at some point, you’ve run a text editor or word processor and you ran a text search and this popped up:
Why are you interrupting my workflow? I can see that no words were found. Half the time, I’m kind of expecting it, anyway. Now, think about how this problem might effect a navigation app…
Clearly, with a user busy driving, both hands on the wheel (we hope), having the app pop up an alert would be silly. The users view of the map would be obscured and they’d be forced to hit the OK button. If this were a major error, it could be excused. However, what if it was just normal workflow?
Of the apps we’ve reviewed during the course of this project, no app personified this terrible design like Trapster. For a user to simply report a trap, it takes no less than 5 clicks:
- Click “Report Trap”.
- Move the map to line up the pointer under the location marker (which can be a little confusing to some users).
- Click “Done”.
- Click the type of trap that it is (e.g., red light camera, cop, etc.)
- Wait for the submission to process and then click “OK” when the alert pops up.
That last step is the most outrageous offender! Even if everything was perfectly successful, an alert pops up a good 1-2 seconds after submission to say “Success!” Why can’t we just assume success and have the app simply report the rare failure? The result is that the user has to either (A) hold the iPhone in their hand until the response comes back and they can hit “OK” and put the phone back down or (B) the alert pops up after they put the phone down and now they’ll need to wait until a good moment comes along to dismiss it.
In Fuzz Alert Pro, we made the process as quick and simple as possible. The user can report a trap in 2 clicks:
- Move the map to the location and double-tap where the speed trap is located.
- Click the type of trap that it is (e.g., red light camera, cop, etc.).
The user is notified on success or failure with a passive dropdown status header that displays for a few seconds and then goes away. The user never has to wait for an action to complete. They can keep their focus on the road.
Do One Thing Right
iPhone Apps, especially productivity or utility apps, tend to find themselves following the same paths many modern corporations do: they try to do too much. A friend of mine once criticized Apple because they aren’t focused anymore, “they make computers, MP3 players, phones, no wonder they screw up everything!” That last part was news to me, but the kicker was when he said, “Look at Coca-Cola. They make Coke. They do it well. And that’s all they do.”
I kindly informed my friend that Coca-Cola has several dozen lines of drinks, but what he says does have some truth. Focus is good. We felt that Fuzz Alert Pro needed that same focus. Here’s a list of the kinds of things it won’t do:
- It won’t navigate you to your destination.
- It won’t update you about where your friends are driving.
- It won’t tweet your friends when you arrive at your destination.
- It doesn’t estimate your time remaining until reaching a destination.
- It doesn’t use push notification to let you know when new speed traps are added.
All of these things appear in some of the competitors’ apps. They’re trying to do too much. In some cases, the user interface gets so overwhelmed with features the user no longer knows how to make the original functionality work! In one app, there are over a half-dozen pages of settings! We want to be the best at alerting drivers to speed traps and making it as simple (and fun) as possible to report them accurately.
iPhone apps are not desktop apps. Users expect to have dozens of apps on their iPhone at any given time, all with a specialty. They want the best-of-breed for everything they need. And we plan on providing that to them with our speed trap app.
How Did it Turn Out?
With the app now released, I can look at it and feel pretty good with what we did and on the budget we did it in. The app looks good to the eye, has some really sweet iconography, and does its job well. We’re now in a very important phase (post launch) where we need to build up the database. We hope that our game-oriented points system invites and motivates users to report all the speed traps they find and compete with other users on the Fuzz Alert website.
Care to give it a shot?
Apple Screwed Up (And Not Just With the iPhone 4)
Apple has gotten a lot of bad press lately over the iPhone 4. But, as “AntennaGate” (barf) closes up shop and we move on with life, it’s really important to point out that one other thing the whole controversy has done is cover up for a whole lot of bad decisions by Apple.
I’m miffed, and you should be, too. Let’s review, shall we?
The iPhoneOS 3.2 Release — Where’s iPhone?
iPhone developers saw the end of their honeymoon with Apple in April, 2010, with the release of the iPad. For the first time, developers had to deal with a substantially different piece of hardware: bigger screen, different user experience, no 3G or camera, and the real problem in a new iPhoneOS upgrade to 3.2. Well, the problem being that it ain’t for iPhone!
iPhoneOS 3.2 added a slew of new API features, but most notably user gestures. A nice little framework, it took all of the pain out of doing event management by hand. Gestures captured complex motions but sent simple notifications to the app. It’s great! However, it’s almost completely useless. The only time you can ever use gestures is for iPad-only apps.
The problem is that if you want your app to be 3.1.3-compatible (for the iPhone crowd), you can’t use gestures because they don’t exist in the 3.1.3 SDK. Your app would only support iOS 4. But supporting only iOS 4 is a non-starter right now, because…
The Big Middle Finger to 3G Users
When iPhone 4 was announced, iOS 4 was as well. We were all excited, there were lots of new SDK features and were eager to — wait, what? Original iPhone and iPod Touch users can’t upgrade????
Yes, for the first time, there was no longer an upgrade path for our “elderly” friends. We sorta let it slide because those devices were a few years old and too slow to handle our new applications well anyway. We also found out the heavily mainstream 3G wouldn’t support some of the newer features, most notably running apps in the background and home screen wallpaper. Oh, well.
What no one foresaw was the buggy upgrade Apple would make available for the 3G. Just about everybody I know with a 3G has seen their phone performance drop like a rock. Honestly, I don’t know how they deal with it. Huge hiccups and freezes, it would drive me crazy. From what I know, the problem isn’t the OS itself, but rather when you update it rather than restore. I believe it affects users more than developers because we were forced to restore during the betas. Users, however, generally do not. It’s risky, more complicated, and frankly I don’t blame a non-technical user for thinking it’s just a great sounding idea.
In fact, last month I was speaking with a particular industry icon (non-technical, you’ve seen her on TV) and we were discussing an iPhone issue she was having (not related to the 3G upgrade), and when I told her about restoring her phone her eyes went wide and she said, “You want me to erase all my data?”
Until now, Apple has not communicated well the problem. I work in a very tech-savvy office and there are literally dozens of people with useless 3G phones, walking around like zombies not knowing what to do. it was only in the last few days Steve Jobs hinted that the next update will fix the widespread problem.
This has been an unspoken disaster for Apple in terms of brand confidence. Surely, many of these people have decided to “upgrade” to a different phone completely — and they certainly weren’t choosing the iPhone 4 giving THAT publicity! (*cough* Android *cough*)
The iOS 4 Release — Where’s iPad?
Having sufficiently screwed over iPhone developers enough with the 3.2 mess, Apple has made amends by screwing over iPad developers even worse! Why on Earth can’t we run background apps on the iPad yet? My iPad feels so old and decrepit next to my iPhone 4. I can’t imagine why a company of such quality as Apple couldn’t possible release iOS universally on launch day?
Think about it. It’s not like there’s years of legacy here. At some point in the last few years at Apple, some exec (likely Jobs) said, “Hey, let’s make a bigger iPhone, we’ll call it an iPad!” and a wise developer responded, “OK, but we’d better keep the OS’s in sync because it would be a maintenance nightmare if we forked them!”
Well, apparently that developer DID NOT say that.
So, it seems the OS’s split, and they’re working towards unity within the next year. Kudos to them. But, WHY wasn’t there unity right away? Did they really want to start a new era of multi-versioned OS’s so soon, with just two pieces of hardware?? So now all of us iPad owners sit around wondering why we can’t use the GameCenter or get embedded fonts or background apps on our iPad. (And, heck, we got the home screen wallpaper before our iPhone friends — so now I’m really confused!)
We Expect More Form Apple
Our dream scenario of having all devices upgradable and supporting iOS 4 well doesn’t seem like it should be such a dream. We could all be building for and targeting iOS 4 right now if that was the case. Instead, most of our projects MUST still target 3.1.3 to support the bulk of 3G users who simply won’t upgrade. Plus, it doesn’t help that you can’t put out an iPhone-only app that targets 3.2 simply so iPad users can run it. (Apple forbids it when you try to distribute — the bastards.)
I expect Apple’s rough patch to stop. There’s no doubt there will be an iPhone 5 in July and they will address the antenna (and, yes, there really are problems with the iPhone 4’s reception) and put a TON of money into bringing confidence back to their brand. Hopefully, by then, the iOS is unified and the 3G issues are indeed snuffed.
We simply expect more, guys.
Going From $0.99 to FREE on the App Store
About a year ago, I released my first *real* app on the App Store, a To-Do List app I called Task List. I wrote it for myself, actually, as I didn’t like the variety of offerings at the time. I wanted something simple, quick-to-use, and with a UI that got to the point so I could update my tasks on the go.
I released Task List at the price point of $0.99 so that anyone else looking for the same thing could have it. Sales were OK, on good days I’d sell 15 copies. On slow days I’d sell a couple. As the year has wound down, however, sales were pretty slow at about 3 a day.
So, a couple days ago, I decided the profit wasn’t considerable to me anymore and that it’d be more fun to let anyone who wanted it have what I thought is a pretty keen app for FREE, and so I made it free! What has followed over the next couple days I think has been pretty enlightening and educational:
It’s hard for me to explain the explosion of numbers past the fact that the app was made free. I went from almost no new users a day to 500 and then to 1,000! On Reddit yesterday, some theorized that apps like PandoraBox have driven users to the app, but to me it’s still just a To-Do List app. It’s not Doom. :-)
My theory is that downloads have skyrocketed because the To-Do List market fills a huge demand — iPhone currently doesn’t bundle with a To-Do List app like BlackBerry does, which seems strange. So, many people come looking for one and are immediately drawn to the free apps. And now they find Task List which, being well-named and #1 on search for “task list”, is an attractive deal.
I’ll be very curious to see how downloads move over the next week.
Headed to 360 iDev
I’ve been told I should tell you this. :-)
I just bought my ticket for 360|iDev! The show will be going down November 7 to 10, 2010. You can find more details at the conference website: 360 iDev It’s being organized by the folks who put on the 360|Flex shows, which is a crowd favorite. Tickets are cheaper on a first come, first serve basis! So buy your tickets ASAP at 360 iDev to get the best possible price. I did!
See you there!
Abstraction()->_Abstraction()->__Abstraction()
For 4 years, I worked in the insurance software industry. I still can’t tell you how I ended up there. I had a nice string of fun jobs writing home-control software (sorry if I woke you) and email distribution systems (sorry if I spammed you), and one day I just couldn’t stand life anymore with a particular employer and I started looking for a new job where I ended up…I ended up writing Workers’ Compensation Insurance software.
(THE HORROR!)
During my first week, I spent my time absorbing code. My desk was covered in printouts of our software that I’d marked up in pen to high heaven. This class calls that class which creates a factory which returns a command which calls another class which makes a request that queues a call to an anonymous class which runs a threaded method that…wait, what were we trying to do again? I’ve lost track.
There’s something about writing so-called enterprise code that seems to make developers want to hide all the concrete functionality deep underneath an unimaginable number of abstracted layers. I HATE IT! I hate it and I want it to stop. Enterprise has nothing to do with abstraction so take your abstraction and EAT IT. Enterprise is about writing rock solid, correct code and hiding your functionality behind 3 interfaces, 4 abstract classes, 2 proxies, and 2 abstract factories is not conducive to reliable code.
Let’s walk through what leads to over-abstracted code and how it can be stopped.
Design Patterns
On every interview I give, I always ask the candidate about design patterns. Do they use them? How many do they know about? QUICK, WHAT’S THE VISITOR PATTERN AND WHEN HOW COULD IT BE APPLIED?? The way I see it, all good developers know some design patterns, but that doesn’t mean all developers that know some design patterns are good.
Factories, Template Methods, Bridges, Adapters, these are all well and good, and I’ve used most of them, but DO NOT IMPLEMENT THESE ON FIRST PASS! Write your code in iterations. The first time through, make your code works as simply as possible. Once it’s working correctly, identify the sections of your code that are candidates for future extension and refactor — only then should you be using these patterns if they are appropriate.
If you opt to implement th design pattern on first pass, you may find that the abstraction needs to change later due to:
- …changes to the inheritance hierarchy.
- …refactoring which allows you to narrow several code paths into just one.
- …functional changes.
- …requirements changes.
The problem is that when you run into one of these problems, you are most likely not going to rollback the abstraction you created in the first place. The extra time the abstraction took to write, plus the pride you take in having done it in the first place, handcuffs you to the implementation.
Your best bet is to write the code with basic logic and inheritance the first time and then, once everything is working, only then refactor the parts that need it. When starting from working code, you can make more informed decisions about what the right level of abstraction should be.
In fact, this is the soul of Agile design. We make our best decisions when we have the most information. You don’t buy a car based on a spec sheet. You get in the car first. You drive the car first. Then, you have more information to go on. You’ll make a better decision on if that car is the right fit for you. The difference is deciding to buy a var based on reading how much horsepower it has versus feeling how much horsepower it has. So, why would you create abstractions to support functionality that you don’t require yet? Why would you implement redirection when you haven’t written what it is you’re redirecting to?
Are you really in a position to make the best choice yet?
Code From the Bottom Up
Good Design™ generally dictates we code in a top-down approach, progressing our levels of abstraction generally lower as classes implement methods which call other methods. However, this leads to premature abstraction that can lead to the kind of unexpressive code that I’ve already described. One way to keep ourselves on the straight-and-narrow, ironically, is to intentionally code in the opposite direction.
Let me explain.
Say you need to write a key/value persistence system. You might conceptualize, and implement, the system with a top-down approach:
I want to be able to save key/value pairs. These can come from a user, or just be specified by the system. A flat file would work for now, but a database could be a better choice in the future. It’d also be nice to have an in-memory store. I got it! I’ll write an interface, IKeyValueStore, and then create a factory that will return one of many possible stores.
And this is perfectly reasonable. Good thought has been put in to this decision. You go about writing it. You go ahead and design the interface to be as implementation-agnostic as possible. The key/value pairs are easy, and save() is obvious. What about loading? You decide that should be kept private since you’ll need to think about database credentials and file a file path for the various implementations. Next, you set to work creating all three stub implementations. You create the factory that returns one of the three. You only fully implement the flat file implementation for now because that’s all you need.
But now, how will you pass the path to the flat file in? Is it specified in the factory? Or is it in settings? Wait! That’s what’s being written. And now you’re making a lot of decisions and you still don’t have a working key/value persistence system.
Contrast that with this line of approach:
I want to be able to save key/value pairs. This will initially be a flat file. I’ll write that. If we need other methods of persistence later, I’ll refactor.
Feel strange? It feels like we went to implementation too quickly, doesn’t it? We feel like writing a concrete class so soon is sorta dirty. Surely there will be some tight coupling as a result. And what happens if we later want to switch to a database? This can’t be right.
And if this was all we ever did, it would be wrong. In reality, we implement the file-based store and hardcode a file path in. But, as we do so, we realize that in order to unit test appropriately we’ll pull need to pull the file path into the constructor so we can better specify where it goes.
See how that decision was much easier to make? We based it on real needs, not theoretical desires. The decisions “bubble up.”
In a short time, we have a working key store and a clear mind. The application uses the file-based key store concretely; does this feel right. Why or why not? Perhaps we forsee changes later. So what? Why do we need to try to predict the future? When the time comes to add a new kind of key/value store, we can do it. So let’s fast-forward now…
New requirements have come and instead of a database store we want a networked REST store so that the settings can be shared via the Cloud. We go to our implementation and determine what needs to change: three of our methods assume a synchronous implementation and we obviously need a new constructor. Since we’ll have two key/store implementations now, we also need to pull out an interface. The new interface now supports asynchronous calls and we write the new REST implementation for it.
See what we did? We haven’t wasted any effort. As we’ve gone along, we’ve used our experience to anticipate future changes by writing flexible code, but we haven’t written any code for imaginary requirements. You see, anticipating change in the future is far different than prematurely building to it. Instead of trying to predict the future by writing high-level code before the low-level, we’re letting the real requirements of the application drive where the abstraction goes. Our decisions are made easier because we’re reacting to real stimuli.
Give It A Try!
The next time you find yourself having to write a complex system, start with the low-level classes and work your way up. You’ll find that the decisions are easily solvable when you have the benefit of existing, working code. Ideating on the theoretical leaves too many unknowns for you to make the best choices.
The end result will be concise, get-to-the-point code with no unnecessary abstraction because you only added the abstraction you needed, not what you anticipated.
Now come on, enterprise. Is that so hard?