Adam Tuttle

From the Department of Poorly Chosen Defaults

I've got approaching a dozen PhoneGap powered apps in the Apple App Store and the Google Play Store. I'm pretty familiar with the various reasons your app can get rejected and usually do a fine job of staying within the established boundaries.

I recently ran into an issue with an app that was rejected because it "violates the iOS storage Guidelines." In particular, they said that my app downloaded an unreasonable amount of data and stored it in such a way that it added 6mb+ to the device's iCloud backup. Just in case this ever happens to you, or future me, I thought I would document what I did to resolve this.

As it turns out, more recent versions of PhoneGap include a default value for the BackupWebStorage preference that would appear to be, at least as far as I can tell, poorly chosen. As far as I can tell, this setting tells iCloud to backup the majority of the content (code and other assets!) of the application. That has to be the case, because my app was only downloading a few kilobytes of data -- no way it was getting anywhere near 6mb -- and not even saving that much of it in localStorage: 0.7kb!

To fix this, I added the following preference to my config.xml:

<preference name="BackupWebStorage" value="none"/>

Whether you're building locally or using PhoneGap:Build, adding that line as-is to your config.xml is sufficient.

According to the PhoneGap documentation, the default value is cloud, which of course tells iOS to back stuff (ALL THE THINGS!) up into iCloud... hence my problem. I don't know all of the other use-cases for this setting, but it would seem that this setting could potentially get a lot of people in trouble with Apple.

Hat tip to Max Lynch of the Ionic Framework project for clueing me in to this preference. Thanks for being available in IRC, Max!

Published 2014-05-12 @ 01:02 in Apple PhoneGap

My cf.Objective() 2014 Schedule

As some others have done, I thought I would post my intentions for which cf.Objective() sessions I'd like to attend, and my reasons for doing so.


After a brief layover in Atlanta, I should land in Minneapolis around 5:00pm, just in time to make my way to the hotel and settle in before the Welcome Reception, which is always a good time. The hotel bar is a great venue for this as well, with some billiard tables and lots of standing and sitting room to hang out with the friends you haven't seen for months or possibly since last year's conference.


9:00 am - The opening keynote this year looks like it's going to be really good again. Jen Myers comes from outside of our community and brings a lot of experience and wisdom that I hope we'll all take to heart.

10:15 am - There are a bunch of really great things to kick the conference off, but I think the one I'm most interested in is Dan Wilson's The Top 5 Things You are Doing Today to Hinder Scalability. With our plans for this year, architecture, scalability, and performance is on my mind a lot lately.

11:30 am - I think I'll get the most from Leveling-Up at Javascript: DOM Traversal by Brian Rinaldi. JavaScript is easily the majority of what I write these days, so squeezing every bit of performance possible from it sounds like a good use of my time.

3:00 pm - I asked the community to find someone to present on Running CF on Linux and Pete Frietag stepped up. I'm really eager to see what sort of things I haven't thought about, and hopeful that he's got a simple solution to what I perceive as a black box of torture: Appropriate system/file permissions for a server.

4:15 pm - While I probably won't pick up much new information, I'm planning to attend Sharon DiOrio's Node.js: Why Would Anyone Want to Write Their Own Web Server? In part as moral support, because it's a polarizing topic and I'm on her side (Node is awesome!) but also because I know Sharon is f*%$#ing smart and I'm hoping she can elevate my game in some subtle, and maybe not so subtle ways.


9:00 am - This might be the first time slot where I feel conflicted. It helps that I had a hand in the schedule's organization, but you can never get completely away from this feeling with so much good content to find a spot for. While I would love to attend Kev McCabe's Software Craftsmanship session (his blog series on the same topic was really good), but as a rule of thumb I only allow myself to miss an Elliott Sprehn presentation is when I am speaking at the same time... so I'll be at Web Components are Awesome (and Polymer too).

10:15 am - This is another time slot with conflict for me. I really want to learn more about Angular.js so I would go to Sharon DiOrio's AngularJS: Getting the UI Sugar without the jQuery Pain, but I expect that to be on the simpler end, whereas I think I'll really get a lot out of Ryan Anklam's Stop Making Excuses And Start Testing Your JavaScript! -- so that's where I'll be. I admit it: I believe whole-heartedly in testing, but I don't do enough of it. Because I'm lazy.

11:30 am - I have a pretty strong focus on JavaScript this year, so I think I'll probably go to Leveling-Up at Javascript: Understanding the Confusing Bits by Jason Dean, but the BDD session by Luis also looks interesting.

1:45 pm - I'll be presenting Building Communities: Lessons Learned From 4 Years Running a Successful Open Source CFML Project (and you should be there!)

3:00 pm - I'll be at the CFClient session by Simon Free. Just kidding! Dollars to donuts I'll bet Adam Cameron just did a spit take. I may need a quick breather and a nap before I get back on stage at 4:15, but if I don't, I'll be at Say Goodbye to “It works on my machine” with Chef and Vagrant by Curt Gratz. Vagrant is a really awesome development tool that I don't think enough people are using. I'm not using it enough myself. But I know its power, and I know it tends to evolve pretty quickly, so I'm interested to see what's new.

4:15 pm - I'll be presenting Open Yourself to Closures, an updated version of my CFSummit 2013 presentation. It's introductory / core principles, so if you have never used closures before or if you have but you want to get a better understanding of how and why they work, you should be there!

8:00 pm - Ryan Anklam and I will be hosting a BoF workshop for you to come and take your first baby steps with Node.js. Even if you've dabbled with it before, there's plenty you can learn. This will be a hands-on workshop so bring your laptop and be ready to install Node and get your hands dirty! We'll be introducing you to, and the wealth of knowledge it contains.


9:00 am - I will be up, bright-eyed and bushy tailed, not hung over, and in the front row for Ryan Anklam's Ember.js - A Framework For Building Ambitious Web Applications. As I mentioned in my interview on the CFHour Podcast, I am keen to use Ryan's Ember knowledge to contrast with my own Angular knowledge and make sure I'm leading my company down the right technological path for our future.

10:15 am - Again thinking toward the future of my company, Enterprise Service Bus' are on my mind. How fortuitous, then, that Luis Majano will be presenting Decouple and Scale with Enterprise Messaging

11:30 am - I don't always see eye to eye with Ray Camden, but I do respect him, and sometimes the healthy skepticism that comes from personal conflict helps you see the best in what they're offering. So I'll be at his session, Leveling-Up at Javascript: Organization, Performance & Testing hoping to further hone my JS skills. Note that I'm attending all of the "Level Up your JavaScript" talks -- a very important thread for me this year.

1:45 pm - There are 3 sessions in the final time slot that I would love to attend, but I think a great way to end a long conference is with an eye to the future, so I'll be at FutureJS: An Introduction to ECMAScript 6 “Harmony” by Marcin Szczepanski, learning about what's coming in the future of JavaScript. I'm particularly excited about Generators, but I know there's much more to it than that.

And there you have it. Your complete guide to stalking me for the next week or so. See you there!

Published 2014-05-12 @ 09:30 in cf.Objective()

On cf.Objective() 2014 Scheduling

The schedule for cf.Objective() (just 14 days away!) is almost final. Pending some last minute shuffling to accommodate sessions with higher demand, it's pretty well solidified. How will they know what demand is going to be? That's where you come in.

Head to your friendly neighborhood (App|Play) Store and download ConBop (AppleAndroid). Once installed, enter event code cfo2014. Then indicate your interest in sessions by tapping the star icon next to them in the sessions list.

Important: When you click the star, the app will offer to add the session to your device's calendar. Unless you're already in the U.S. Central time zone, do not say yes; it will use your current local time, resulting in incorrect times when you arrive at the conference! (You can re-apply the star after you arrive to add it to your device calendar, if you like.)

See you there!

Published 2014-04-29 @ 11:44 in cf.Objective()

Learning Lessons

If you stopped me on the street and asked me if I had good enough backup coverage for all of the important computers and files in my home, my answer would be an instant and unqualified, "Yes." And to a certain extent, that's true.

Pretty much the only things not continuously backed up to my BackBlaze account are my downloads folder, as things in there are transient and never stick around for long, and my Virtual Machines folder, because the virtual harddisk files are enormous and some of them change on a daily basis (the idea of having to upload two 30gb files on a daily basis gives me heartbleedburn)... and because given enough motivation and time they could all be rebuilt. My virtual machines are all either test environments -- like a ColdFusion 8 server -- or MSSQL (and therefore Windows) backups of production databases with which to do development and debugging.

In a pinch, I could recreate those test environments; re-download those databases.

You can probably guess where this story is going: My laptop died. Sort of. The tl;dr version of the story is that it appears that the graphics board is shot and I have to mail it into an Apple repair depot, and may not get it back for 5-ish business days. And that's where it gets interesting, and why I thought it would be worth writing about here, as a cautionary tale of sorts. It could happen to you.

Late on Wednesday evening, I was listening to Spotify and occasionally watching some YouTube videos while building a new desktop computer for my wife. As I was finishing up and cleaning off my desk for work the next morning, my laptop crashed -- but not in a manner I've seen before on OSX. Instead of the "gray screen of death" I got what looked like black and white pinstripes. I didn't think much of it, just powered down and went to bed.

In the morning I made my kids breakfast and packed their lunches as usual, took a shower, made myself breakfast and sat down at my desk. When I turned on my laptop, it didn't progress past the gray boot screen with the Apple logo. With only my phone to search the web for debugging tips, I managed to try booting into safe mode (blue pinstripes!) and reset the nvram/pram, but was still unable to get the machine to boot.

I made an appointment at a semi-local Genius Bar (the closest one with early availability) and headed off for an hour drive with my laptop tucked under my arm. After some praise from the Genius for the physical condition of my now-long-out-of-warranty laptop (I saw in his notes there was a spot for this detail, and he wrote, "excellent.") and a few diagnostics, we determined that the most likely cause was a bad graphics board. Known good RAM and HDD replacements and it still wouldn't boot, and his other diagnostics gave a clean bill of health to every bit of hardware they checked.

The bad news was that they didn't have the part I would need in stock, and if they were to order it, it probably wouldn't arrive for 5-ish business days... so either way I'm without my laptop for a week.

The worse news was that Apple requires that the SSD be installed when shipping it in for repair, and says that it might choose to reformat the drive. Obviously less than ideal.

And of course, I've got some important deadlines looming and can't afford to waste additional days rebuilding VM's.

I left, laptop and now-removed and anti-static-bagged SSD in hand, with a plan to drive to a local TigerDirect store, buy a sled or enclosure for the SSD, drive an hour home, back up the SSD, drive an hour back to the Apple store to drop it off for repair, and then drive an hour home again. 3 (more) hours on the road and a lot of gas money wasted seemed pretty bleak. Fortunately as I was giving Steve a sitrep he prodded me and we agreed that a store full of computers and "Geniuses" should be able to make a backup of the drive without me spending 3 hours on the road. After confirming that they could (coaxing them into it, really -- and they still charged me $99 for the pleasure), they agreed that if I supplied a backup drive they would image the installed SSD onto the backup drive that I could take home with me.

That was all well and good, but my god it took forever. I left my house at 9:45 for a 10:45 appointment at the Geinus Bar. I left the Apple Store bound for TigerDirect on a mission to get the backup drive and get back to the Apple store for my new 1:00 appointment to have the drive imaged. By 1:30 I was picking up a horrible lunch in the food court.

To their credit, Taco Bell replied quickly offering to rectify the situation somehow, but I forgot to call them when I was killing time in the parking lot. I will be calling them soon and hope to have good things to say about the situation in a day or two.

After lunch, instead of wandering around the mall aimlessly I decided to sit in my truck and listen to podcasts -- at least that would be semi-productive. At 4:00 lunch was coming back to haunt me so I headed into the mall. While I was there I decided to check on the status of my drive, and it was just wrapping up. By 4:30 I had signed the paperwork and was on my way home with my backup. At 5:30 I walked in the door and did what I could to help get dinner finished and on the table for the kids.

So that was my workday yesterday. I hope yours was a bit more productive.

The moral of the story is that I should have been doing local backups of my VMs. Even just having them live permanently on the external drive is equally dangerous, because that drive could die, too. If I had been using Time Machine for just these files, or even just regular manual backups to my external hard drive, I would have been fine, and home before 1:00, almost $200 richer.

And you can bet that as soon as I get my laptop back, I will be doing exactly that.

Published 2014-04-25 @ 08:15 in Meta