Wednesday, May 19, 2010

Showing the Cancel button in UIActionSheets on iPad

In it's iPad Human Interface Guidelines Apple provides several guidelines about how user experience should differ between iPhones and iPads. One such element that should behave differently is the UIActionSheet.

Apple recommends that cancel buttons not be shown for action sheets on iPad:
Because taps outside the popover dismiss the action sheet without selecting an item, this results in a default way to cancel the sheet. Including a cancel button would therefore only cause confusion.
But the guidelines do allow exceptions to this rule:
However, if you have an existing popover and are displaying an action sheet on top of other content using an animation, a cancel button is still appropriate.
So you would think following this guideline is as simple as not specifying a cancel button in most cases, and only specifying a cancel button when you have carefully considered the exception case, right? Wrong. Even when you do specify a cancel button, it looks like the iPad runtime automatically always hides it.

So how do you provide a cancel button in the exception case? You could just provide another normal button that has cancel behavior, but that's not ideal because you really want the difference in appearance that UIActionSheets on iPhone provide by default. After some tinkering, the best solution I could find was to set the actionSheetStyle property of the UIActionSheet to UIActionSheetStyleBlackOpaque.

I can speculate why this works, but I don't know for certain so I'd rather not. If you know of a better/more correct way to do this, please do leave a comment.

I am surprised that Apple was mindful enough to list the exception case, and yet careless enough to not provide documentation on how to handle this case - they even seem to have forgotten to document that the iPad automatically overrides user-provided cancel buttons by default.

Saturday, May 8, 2010

Notes from a Week in Paris

I just got back from a lovely week in Paris with my wife - it was a rejuvenating and much required holiday for both of us. Work has been crazy, for her especially. Paris was wonderful and more than lived up to my expectations. We rented a tiny little studio in Le Marais (~120 sq ft, fully equipped including a washer - extremely efficient use of space!) Spending the entire week gave us enough time to explore sights, sounds and tastes of Paris without too much of a rush.

There are lots of books and blogs about visiting Paris and things to do/see. We used a bunch of resources - advice from friends, Lonely Planet's excellent iPhone app, the very insightful Secrets of Paris website with lots of tips on what to see and do and Paris By Train for everything related to using Paris' excellent rail network. However, there were some things I hadn't read about or was surprised by:
  1. Cafés, brasseries and boulangeries/patisseries often have different prices for take away (emporter), eating inside (sallé) and terrace dining. Most cafés/brasseries offer set menus (Formulae) and chef's recommendations which change daily (menu and price). They are almost always much more cost effective than ordering a-la-carté.

  2. The French are very proper. You greet business owners when you enter their store/café and thank/greet them before you leave. Sprawling across lush, green lawns in the several Parisian parks (Jardins) or putting your feet up on empty train seats is frowned upon. You sit in chairs provided in the Jardins and sit up straight in trains.

  3. Freshly squeezed orange juice (jus d'orange pressé) is extremely popular. You'll find orange juice machines pretty much everywhere (including Starbucks), but it's best to find a green-grocer/fruit vendor and get a half-litre jar of fresh squeezed juice each morning. Fruit vendors are everywhere.

  4. By default, coffee means espresso. A cappuccino/café-au-lait at most Cafés is expensive (between 4-8 EUR) and isn't that great (for a Seattlelite, at least). A mocha at Starbucks is EUR 4.50. Little créperies or street cafés have better deals for coffee that tastes identical (1-2 EUR). Or, hit up a McCafé. A 'mocha' is called a 'chocochino' and isn't commonly available.

  5. Sit-down créperies are totally not worth the price/experience. Get a crépe from a street vendor/corner shop and sit in a park or a street bench. The more exotic crépes (savory & sweet) are only available in nicer establishments, obviously.

  6. Wine/liquor is available in grocery stores (supermachés). Supermachés open around 8:30am and shut around 8:30pm. You are expected to bag your own groceries. For late-night grocery runs, there's usually a little-store-that-sells-most-things every few blocks which stays open late (2am)

  7. Bars have later Happy Hours than in the US. Happy Hour generally runs from 6pm to 9-10pm. Folks eat dinner late (most restaurants stay open until 11pm).

  8. Time is specified using 24 hour notation. "What time do you shut?" is answered with "23 hours". Most people don't understand am/pm.

  9. Take binoculars to fully appreciate the amazing art/architecture details.

  10. Use the 'Vélib' shared bike service. Vélib stations are everywhere, the roads and drivers are biker-friendly and it is the cheapest and most convenient way to get between locations in the city. Buy a map-book that has streets sorted by districts (arrondissements) and also has metro/Vélib stations marked.

  11. It is not common for crémeries/gelaterias to offer tastes.

  12. On the metro, or just walking around, you'll see a significant number of people going home (presumably) with one or more fresh baguettes from the bakery. For some reason almost all of these people are men. Join the crowd - fresh baguettes are the only way to go. Bread is baked fresh twice a day (if not continuously).

  13. When you pay cash, check the change you get back. Parisians are either terrible at math or prone to short-changing customers. I routinely got back incorrect change, on average twice a day.

  14. Before you go to a specific place (café, boulangerie, museum, grocery store, monument) on a Saturday/Sunday/Monday check before you head out. Almost every establishment is closed on at least one or more of these days.

  15. Strange, English speaking 'beggar women' holding hand-written post cards will randomly approach you at monuments/museums and ask "Speak English?". I didn't quite figure out what the scam was (I never answered "Yes") but this is most certainly some sort of scam.

  16. Comté tastes awesome, and is the most popular cheese. Camembert is a close second. Get cheese fresh from your neighborhood fromagerie.

  17. If you decide to cook at home, chances are good that you'll find an Italian store nearby selling freshly prepared pastas and raviolis that you can cook at home, in addition to a large number of other Italian foods (including freshly prepared Tiramisu).

Monday, April 19, 2010

Why I use Google Voice for SMS

I have an iPhone with AT&T service, but I recently started using Google Voice for most of my SMS needs. SMSes sent to my Google Voice number are forwarded to my email. It works great for me:
  • I don't want to pay AT&T any more than I have to. I use AT&T out of necessity, not choice.

  • GMail has support for Exchange ActiveSync, and is the default Exchange account on my iPhone. So I get notified of the SMS in email on the phone as soon as it is received (assuming I have data coverage, which is pretty much all of the time) giving me the equivalent of the native SMS experience.

  • The Google Voice extension for Chrome. Chrome is my default browser, I'm in front of a computer for a large part of the day, and my browser is usually open. I can read, send and reply to SMSes using a full keyboard and without exiting the browser, instead of pulling out my iPhone and fiddling with the tiny keyboard to type out a message. So much more convenient!

  • All my SMSes are archived and made searchable not only by Google Voice, but also by GMail. Win.

Sunday, April 18, 2010

Living Every Developer's Wet Dream

Back in June I wrote about new technologies I had started working with and my experiences learning those technologies. Having continued working with most of those since then, I've become incredibly comfortable and proficient with them. It's pretty normal to have a week where I write a bunch of PHP, a few SQL queries, some fancy Javascript, learn new CSS tricks, hack up features in client software using Win32/Cocoa, debug some corner-case issue using logs and a mini-dump and also write some straight up C/C++ server side code with unit tests. Initially, jumping languages and client/server boundaries came with large context-switch penalties but it's become almost second nature now, which feels very empowering and has had a dramatic impact on productivity.

Then, there are the one-offs - new technologies that need to be learnt, integrated into the product/service (in a way that's easy to understand/change in the future) and then 'forgotten' before moving on to the next one. These tend to be client-side technologies usually - server side stuff is much more on-going and stable. Some of the 'bigger' things I've done in the last 6-9 months that would fall into this one-off category are:
  • Fiddling around with HTML5 <audio> and <video> before giving up
    For all the promise of new HTML5 multimedia standards, the sad reality is that we are far from any consensus. Different stakeholders have different motivations, which leaves the issue of a single standard codec up in the air. The proprietary nature of Flash, licensing issues surrounding H.264, Apple's opposition to including Ogg Theora in Quicktime and Microsoft's silence have resulted in the current stalemate. And this shows when you experiment with the different browsers. Development for web/mobile-web is poised to become radically easier once/if this is sorted out, but there is a lot of pain to be endured before then - pain that wasn't worth it to me presently.

  • Flash audio support
    Having decided to not want to build a flash media plugin myself, I first played around with this MP3 Player and later switched to the much more powerful SoundManager2. With a few tweaks, I was able to make it do exactly what I wanted.

  • Facebook Connect
    For single sign-on and any sort of social media integration, Facebook Connect is a must have. Having implemented Facebook Connect for my website and for iPhone, I must say that I am very pleased with the facilities offered by the platform and the consistency across client/server applications. XFBML and FQL are nice touches. My only gripe is that, for a mature and widely adopted platform, documentation seems disproportionately poor as compared to the richness of the Platform APIs.

  • Online Payments
    There's a lot you learn about how safe online transactions really are (they're not) when you dive into how payments really work. I developed a quick payment portal using Payflow Pro by PayPal. Can't really vouch for Payflow Pro yet, though. A few weeks after I finished working with Payflow Pro, PayPal X was announced. I'll eventually get around to migrating to it, I guess.

  • Identicons
    Simple, cute, pretty. I use the ones provided by Gravatar.

  • Javascript Craziness
    One of the crazier things I've done, among others, with Javascript is to try and emulate a desktop-software like user experience in a website. Dragging, dropping, keyboard navigation, sorting, multi-select with Ctrl/Shift/Meta... oh boy! It look a while, but with some help from jQuery UI (the different components work great individually, but try to also make a sortable a draggable and a selectable, and you're in a world of hurt) and a lot of long nights, I finally got a lot of this done. For Forefox. Then I spent some time making it work for Chrome. And then a whole bunch of more time making it work for IE8. It sorta works in IE7, and not at all in IE6, but honestly if you're still using those browsers you should be chastised. Someday, I want to wrap all this into my own little plugin that others can use. If you told me a year ago that I would be some kind of JS nut, I would have laughed. Ha!

  • iPhone web-app (before I ditched it for a full blown iPhone app)
    Not wanting to deal with Apple and their strange AppStore practices, I decided to try and be really creative with native Quicktime support built into Safari on the iPhone. I almost got all the way to hacking up really neat functionality, complete with callback from Quicktime into my website, background playback and an rich interactive experience. With Flash coming soon to other mobile platforms, this would have been ideal for providing mobile experiences without needing multiple platform-specific applications. However, the iPhone web app felt clumsy and not polished, so I ditched it and went the iPhone app route. I reserve comment on my experiences with development for the iPhone - my app hasn't been submitted/approved yet. ;)
    I also foresee myself playing with other mobile development platforms in the very near future. I think a blog post comparing my experiences with the different platforms might make for good reading.
In addition to these one-offs, there are the perpetual how-will-it-scale and how-will-it-perform issues that need to be considered for every little feature. One of the harder lessons for me was to change my default mindset about how I approached design. While I wouldn't say I optimized prematurely, my design was heavily influenced by potential for optimization. (segue: This, I now realize, is a result of my years at Microsoft. At companies like Microsoft, you do things once and you do them right - rapid iteration is often not possible or not practical. So, while this approach has its merits it's not ideal for agility in startup environments). The new approach that's imbued into me now is to build it quick and make it simple first. Simplicity is the bedrock of agility. Simpler code is easier to revisit and to scale. Complexity is technical debt that you don't really need or want.

What's the biggest thing I've learnt in the last year? I learnt how to learn efficiently.
You can spend hours studying/learning about something and barely scratch the surface. Or you can study to retain information for very short periods of time. Exceptional developers are able to identify when they need to deep-dive vs when they need to simply skim the surface. They can instinctively answer the "How do you learn enough to make well informed decisions and yet don't spend a disproportionate amount of time learning without producing?" question. Transient learning is only good when you never need to revisit a decision - such cases are rare. Otherwise, learning to execute quickly and leaving a trail behind you is a crucial skill. I believe I'm well on my way down this path.

So yes, in many ways I am living a developer's wet-dream. And fortunately, I am able to do a little more than just development stuff. But I know this probably won't last forever. This series of blog posts is my attempt to capture my memories for when I'm not doing this everyday anymore.

Friday, March 5, 2010

SecureCRT and Windows 7 - The Case of the Magically Disappearing Window

Ever since I upgraded my copy of SecureCRT to 6.5.1 on Windows 7 x64, I started noticing really strange behavior. Occasionally, my SecureCRT window would just 'disappear'. What do I mean by 'disappear'? The SecureCRT icon on the Windows 7 taskbar, which appears like this when a window is open:

would suddenly change to this, which is what an icon looks like when the process has no windows open:


I could still see SecureCRT.exe running, but didn't find any windows for it, even in the Alt+Tab menu. Nothing appeared in my system tray either except for the network connection, volume and system time information.

Once this happened even after a system restart (isn't that the usual fix for everything?! ;)) I got curious. Eventually, I realized that this happened each time I minimized the window. Somehow, minimizing the window is muscle memory for me now and I don't really notice I'm doing it until I consciously try.

Minimizing a windows shouldn't ever cause the window to just 'disappear' so I started looking at the different SecureCRT settings and noticed a curious "Minimize to Activator" setting that was checked, and seemed suspicious. Unchecking it was all it took to restore sanity.

What is this 'Activator'? It's an icon that sits in your system tray. But Windows 7, by default, hides away all my system tray icons so I had no idea this even existed until I started investigation this issue. This is the 'Activator':


SecureCRT removes the window and sticks it into this Activator. Without any sort of visual cue or notification bubble. By default. Ugh! To restore it, you need right click the icon and select the "Restore" option. Umm... isn't that the whole point of Windows' built-in minimize implementation?

This seems like a poorly designed feature, especially given how Windows 7 treats tray icons (and I know SecureCRT v6.5.1 has some Windows 7 specific features so this isn't accidental). Making the process 'appear' like it's not running and sticking into into the 'Activator' (why isn't it called 'system tray icon'?) instead seems like bad design. If anything, this should definitely not be on by default.

Ed: Title inspired by Mark Russinovich's blog posts

Update: Just got an email response back from SecureCRT's support staff to a query about I this I had sent last night. She clarified "... the global option is **not** enabled by default. The session option by default is a "tri-state" option, meaning it uses the setting found in the global option."

Wednesday, March 3, 2010

Discouraging Tardiness in Social Circles

What's the best way, if any, to incentivize punctuality in a social setting i.e. among friends and family? Alternately, is there any way to dis-incentivize/discourage impunctuality?

In professional environments this isn't usually a problem. There is generally one party which has some form of authority (the boss running a meeting, the doctor who is so booked up that you got an appointment only after months, the VP who can only meet for 20 minutes before he has to run to another meeting, the senior engineer whose time really is more precious than yours) who sets an example that is expected to be followed, and can dangle a carrot or wield a stick to manage tardiness. There is also a personal incentive to be on time - you want to make a good first impression, not appear to be the one holding the team behind, or not miss out on something important if you're late.

The social dynamics that exist among friends and family are vastly different though. Often times, no one person holds a position of authority over another, the 'meetings' aren't usually that important and outcasting the offenders as a group isn't really an option either. Hence the repercussions of tardiness are pretty mild, if any. In many ways, the punctual folk have more to lose.

The ideal solution wouldn't make any individual or sub-group appear to be 'jerks' and yet make each member of the group want to be punctual. Poking fun at the offenders or just generally being prudish isn't going to help, I think.

So, any ideas? I'm drawing blanks...

Friday, February 19, 2010

Coupon etiquette?

What's the 'correct' social etiquette about using restaurant coupons purchased online (such as those from restaurant.com or groupon.com) when you go out in a group and split the check?

For coupons you get in the mail, or basically free stuff, I assume common etiquette is to offer the coupon to the group to use and split the remainder. Does it work the same way when you've bought, say, a $50 coupon for $25 (i.e. you use the coupon to cover $25 off your tab and offer the discount value to the group)? Do you use the entire $50 to cover just your tab? Or maybe simply not using the coupon when dining as a group is the right way to go?