Web Developer’s Life in Beta Making broken software somewhat less broken

18Aug/100

Continuous Deployment to CPAN

Recently I was working on a refactor of one of my CPAN modules which, among other things, involved changing its name from Test::A8N to the specific Test::Story.  Doing so made me think about the process I usually go through when I consider releasing a CPAN module.

First, let me explain something about myself: I don't like tedious or repetitive tasks.  I hate having to do the same thing over and over again, partly because I don't want to waste my time, but mostly because inevitably one of the following will happen:

  1. I'll forget a crucial step, and will screw something up;
  2. I'll forget how to do it, and in my efforts to re-learn it I'll screw something up;
  3. I won't care enough to go through the effort, so something will get screwed up.

I expect you're noticing a trend here.  Really the only reason programmers come into this profession in the first place I suspect is because we're just so bad at doing things the normal way, we have to automate everything we'll either do poorly, lazily, or forget to do all together.

For those of us who are programmers, many times we're so lazy that we won't want to do the same thing within our programs more than once, so we abstract functionality into reusable modules.  By that token the Perl community must be some of the most inventively lazy group of people, because CPAN is full of useful tidbits like that.  Getting modules to CPAN requires a contributor to actually, you know, submit their project.  And this is, in itself, a somewhat manual process.

I do all of my development in a version control repository, and I write a decent amount of unit tests to prove my functionality works.  So once I come to the decision that a set of new features is worthy of a new release, this is the process I go through:

  1. Run "perl Makefile.PL && make && make test" to verify everything runs okay;
  2. Run "make dist" to create the distribution tarball;
  3. Noticing the version number is wrong, I go in and change it in the main Perl module;
  4. After running "make dist" again, I realize I forgot to change the README;
  5. Potentially after another "make dist", I'll remember I'm supposed to update the Changes file to indicate what I've added;
  6. It's at this point I realize that I forgot to add new documentation to cover this new feature;
  7. I run "make test" again, this time with TEST_POD=1 set to ensure my documentation checks are run;
  8. I'll then try to remember what the command is for uploading a new CPAN module, which involves searching on CPAN for something related to "Upload";
  9. Finding "cpan-upload", I'll have to look at its documentation to figure out how to use it;
  10. I run "cpan-upload", only to realize I forgot to set my PAUSE credentials in ~/.pause.

At this point, if I'm lucky, the upload will succeed.  This process isn't meant to be a negative reflection on CPAN, but rather on my own forgetfulness and need to automate.

Read on to find out how I managed to automate this part of my life as well.

  • Share/Bookmark
18Jun/10Off

Building iPhone apps with Hudson, Part 2

I've already posted before on how to set up Hudson to compile and build iPhone applications, but I just had a "OMG I <3 Hudson!" moment just now, and felt I had to share it.

I do most of my mobile development literally while I'm mobile; on the train during my morning commute, from coffee shops on the weekend, or in front of the TV in the evenings when I'm winding down for the night. Because of this, I don't have any consistent time when I'm making checkins, nor do I have the time to create builds for my beta users.

One of the iPhone apps I'm building is for a client, and because my time is limited, I want to streamline communication as much as possible, especially since I have a day job that I really like and uses 8 of my precious 24 hours per day. I don't want to have to tell them every time new features are ready to be tested. Additionally, if I have to manually compile and send a beta build to them whenever I complete a new feature, I'll never have enough time to actually get any work done. Add to that the fact that many mail servers will block iPhone applications for one reason or another (file size limits, misfiring antivirus filters, or any number of reasons).

So the solution I've come up with is an extension of my iPhone application build scripts combined with some nice plugins for Hudson. All of the above steps are completely automated away and handled for me just by checking my code into git.

  1. The first thing I did was updated my build scripts to generate an ".ipa" archive for Distribution builds containing an iTunesArtwork file, and a ".zip" archive for Release builds.
  2. My build script sets the version number of my application to the $BUILD_NUMBER of my Hudson job, so that the version is guaranteed to be unique.
  3. I added the SCP plugin to Hudson and configured a location on my web server where Hudson could upload completed builds to the website. This enables my clients to access the page to download new releases.
  4. In order to inform my clients that a new build is available, I've used the customizable email support in Hudson to send an email to a custom list of email addresses when a successful build is completed. In this email I include a link to the uploaded IPA so they can easily download the beta archive.
  5. So that I don't have to go through the trouble of describing what changes I made, I use the $CHANGES_SINCE_LAST_SUCCESS variable in my custom email template that lists all the commit messages I'd submitted to git that were included in this build.
  6. For good measure, I SCP to the website a copy of the ".mobileprovision" certificate file that was used to build the application, so the beta tester can add it to iTunes if the contents have changed.

The result of all this work is that I can work wherever I am, continually committing changes into git. When I'm ready to cut a new build, I submit my changes to github where a webhook script will notify Hudson that changes have been made. Hudson checks out my changes, builds them on my Mac Mini at home, SCP's the resulting archive up to my web server, and notifies my beta testers that a new archive is available and what changes they should keep an eye out for.

For a copy of the build scripts and configuration I use inside my projects, take a look here:

This assumes there's a file in the build user's home directory called ".build_password" that contains the password used to unlock your keychain. Run "chmod 600" on that file in order to make it hidden to anyone else on your system.  And make sure you check in the ".mobileprovision" files your XCode project file references.  If you change your certificates, you'll need to copy the updated mobileprovision files from your "Library/MobileDevice/Provisioning Profiles" directory.

So you can see why I'm excited about this.  I hope you are too.

  • Share/Bookmark
3May/10Off

Silent no more…

Wow the past few months have been quite a wild ride, and a ton of things have happened!  So much has gone on and I've been writing so much software that I haven't had the time to blog about it.  In the time I'm not writing software, I'd rather spend it with my wife than spend it writing about the software I'd written.

Over the past few months, while the PhoneGap team started a major refactor of their codebase, I spent some time learning more about Objective-C and UIKit, and discovered that writing native software on the iPhone is a heck of a lot easier than I'd previously expected. It shouldn't have surprised me, because I've heard rave reviews from developers I have a great deal of respect for, and it also shouldn't come as a great shock that Apple treats their developer SDKs with the same degree of polish and attention-to-detail that they do to their hardware. So while I was working with PhoneGap I'd contributed a number of plugins exposing the iPhone's native UI elements to JavaScript-based apps, I'll no longer be updating or adding any new plugins.

While my blog was collecting dust, I also finished a PhoneGap-based app, Parking Mobility, and while it was nice to start the project in familiar languages like HTML and JavaScript, a ton of time ended up getting eaten up chasing random bugs, memory leaks, and strange UI behaviours that required odd work-arounds to eliminate.  In the end I discovered I'd spent more time getting the application to market than if I had built it in native code.  Starting this past weekend I've begun doing just that, writing the application in UIKit and Objective-C in order to get more performance and a better user-experience out of the app than we have currently.

One of the other big reasons why I haven't been as chatty on my site as usual is, of course, the launch of the iPad and the iPhone 3.2 SDK.  I decided to hit the ground running with this platform, and used this new SDK as my playground for learning more native development skills.  I developed two applications for the initial launch of the iPad, Boomle and myDrum Pad.

Boomle is an easy-to-play game featuring peaceful sounds, low-touch interaction, and an addictive gameplay.  It was a lot of fun to build, and got me started working with OpenAL, manually drawing displays, and dealing with real-time games.

myDrum Pad in contrast is an interactive drum pad that aims to allow people to tap beats out with a variety of sound packs along to music, or create their own riffs.  It's still in active development, but this has been a blast.  I'm developing it with CoreData, OpenAL sound playback, multi-touch displays, In-App purchase and asynchronous downloads from Amazon S3.  It's a highly dynamic UI with a smooth user experience.  It's also the first iPhone project that I'm directly involving a graphic designer with the whole process, and once we get a beta ready, I'm sure you'll like the screenshots and demo images we'll be putting up.

Last, and certainly not least, I've changed roles in my day job at Sophos, and am working once again in the Email Security team developing our Email Security Appliance.  I get to play with all sorts of complex problems, web-based administration interfaces, and pretty much every technology under the sun.

Now that these projects have all stabilized, I'll hopefully be blogging more about Objective-C, Javascript web applications, and technology in general. Plus Summer's quickly approaching, so hopefully I'll have some pictures of my motorcycle and any trips my wife and I take this summer up here soon.

  • Share/Bookmark
12Nov/09Off

Last minute talk on automated Perl builds using Hudson tonight

My friend Scott McWhirter, who heads up the Vancouver Perl Monger's group, asked me yesterday to give a last-minute talk on anything in particular at tonight's Vancouver.pm meeting. He wasn't exactly begging, but I know he's short on speakers this month, and he wanted something interesting to show.

So I decided I'd talk about building and testing Perl-based projects using Hudson. I've been planning on writing a blog post on the subject for the past month, but haven't found the time to finish off the post properly. So if you're interested in the topic, and you don't want to wait for me to get around to writing about it online, please feel free to drop by tonight!


Update: The talk went well! Until I have time to put a more comprehensive post up on the topic, you can always read the slides from tonight's talk.

  • Share/Bookmark
4Nov/09Off

I’m in Movember this November

Just like most of the men at my office, I'm participating in Movember this year, largely due to the razzing I got last year when I didn't participate. Yes, I've succumbed to peer pressure...what would my mom say? At least it's for a good cause. Of course, the first question I asked is "What's Movember?" It's a fundraising event for prostate cancer where men grow mustaches during the month of November.

While I can grow a mustache fairly well, I really don't look good with one. So hopefully I won't have too many pictures taken of me this month. And if you want me to feel better about it all so I don't feel like it was a total waste, please head on over to my Movember profile page and donate a few bucks, or more.

As you can see, it's a few days and it's at a respectable and not-yet-annoying length. If you contribute, you get a vote on what style my mustache should be. I figure of I'm going to have nasty facial hair, I might as well go for it wholeheartedly. So donate to a good cause, frustrate my wife, and get a few good laughs in.

  • Share/Bookmark
Tagged as: 2 Comments
26Oct/09Off

Telling your user that a PhoneGap application is busy

Plenty of times in applications, especially on mobile devices, you just need to tell your users to hold their horses and wait while your application processes something in the background.  Maybe you need to query some data from a remote server, save a file to disk, or maybe you just need to do some number crunching.  Whatever the reason, you don't want your user to think the program has crashed if you don't give them some sort of visual feedback that you're busy and they just have to wait a few seconds.

PhoneGap provides a few methods to handle just this task. There's four methods within the Notification class that are of interest.

  1. navigator.notification.loadingStart()
  2. navigator.notification.loadingStop()
  3. navigator.notification.activityStart()
  4. navigator.notification.activityStop()

Modal loading messages

Modal loading indicator

Modal loading indicator

The easiest approach to take when making your users wait is to show a modal loading dialog, one that doesn't let the user interact with the application until you're done.  There's a lot less for you, as a developer, to manage when the user isn't allowed to poke around on buttons when you're updating the display.  Asynchronous operations are a lot simpler when you're in control.

The loadingStart() and loadingStop() methods do just this.  They put up a modal semi-transparent layer over top of your application, with a "Loading.." spinner message. You simply call the first method when your application is about to do something, and when it finishes you call the second.

Here's an example of how to use it.  This will load a remote HTML document and place its contents into a node in your PhoneGap application.

Not only does this make it easier to integrate external content into your PhoneGap application, but it guarantees your user is informed that it's actively working. As a final bonus, if your external web site doesn't respond, or if the user doesn't have an Internet connection, the modal loading screen will close after a timeout.

Asynchronous loading messages

Asyncronous activity loading indicator

Asyncronous activity loading indicator

Sometimes you want to tell your user that the application is busy, but you still want to continue using the app anyway.  If your app doesn't turn off the top statusbar (where the time, reception, and battery status is displayed), you can control the busy indicator from within PhoneGap.  Just like the above example, you just have to call the appropriate PhoneGap JavaScript methods.  In this case, just update the above example with these messages:

navigator.notification.activityStart();
// Do something that might take a while...
navigator.notification.activityStop();
  • Share/Bookmark
19Oct/09Off

How to use the native Alert dialog in PhoneGap

PhoneGap's custom alert notification is nicely customizable

PhoneGap's custom alert notification is nicely customizable

An important part to any application is issuing a simple alert to your user. Whether it's to tell them about an error that just occurred, or if you need to ask them a simple question, giving a message to your user is about the most basic part of any app.

Sadly, when you try to rely on the ever faithful "alert()" function in JavaScript inside a PhoneGap application, you'll notice the alert box it shows is titled with a very unprofessional "index.html" across the top. Not only does it make it obvious that the app they're interacting with is actually HTML-based, but you can't convey the importance of one message or another with a title. Most people only ever read the title anyway, so in order to provide this capability to your application, PhoneGap has an answer for this problem.

Inside PhoneGap there's a class called "Notification" which is used for, well, sending notifications to your user. And, by calling:

navigator.notification.alert(
  message,
  title,
  buttons...,
  options);

Everything, except for the message, is optional. The more arguments you provide, the more you can customize the alert box. For instance, if you don't supply a button label, one single "OK" button will be created. Want to ask a Yes/No question? Simply pass two labels for their respective button names.

Like other functions in PhoneGap, the alert notification can be passed an "options" object that allows you to give it more information, such as an onClick callback.

That example shows how to ask your user what to do in the event of an Internet connection problem.  You'll notice that I've decided to pass two button labels.  In the onClick callback function I supplied in my options argument, I'm checking the "buttonIndex" variable it passes.  This tells your function which button was pressed.  If you want more than 2 buttons, just list multiple labels and it will show as many as can fit on the screen.

A very simple function, but invaluable as a developer resource.  And, more importantly, a very easy and professional way to get feedback from your user.

  • Share/Bookmark
18Oct/09Off

Device.saveScreenshot added to PhoneGap

One of the integral features of the next application I'm releasing (I'll write a post about it soon, honest) is the capability of saving a copy of the user's work in my app to their Photo Library. For a while now I've been wanting to be able to save screenshots from within PhoneGap for two main reasons:

  1. Be able to export the user's work and allow them to email it, import it into other applications, etc.
  2. Save a screenshot to their splash-screen image, that way when the application restarts it shows their previous state while they wait (for example, the Notes application on the iPhone).

I've implemented #1 right now, meaning with a simple non-blocking call you can save the current view to the photo library. In the future I'll add another three options: Save to the default splash-screen image, save to a file, and save and upload to a remote location.

Check out the check-in I've made and if you have any comments, please let me know!

  • Share/Bookmark
16Oct/09Off

How to use the ActionSheet in PhoneGap

The ActionSheet is a handy control on the iPhone, and is a very intuitive way of getting a multiple-choice answer from a user in a modal but unobtrusive way.

Using it in PhoneGap makes interacting with your user easy, while keeping the display responsive. And as an added bonus, you don't need to update any HTML or CSS to get the buttons to look right. The native iPhone codebase handles it for you.

So the question is, how do you use it effectively? As most Web2.0-style developers are aware, the only sensible way to develop flexible applications that don't bog down the browser is to make your applications behave asynchronously, and make use of callback functions to get feedback from external systems (HTTP requests, users, etc). The ActionSheet on PhoneGap is no different.

The ActionSheet is grouped into the PhoneGap "Dialog" class, and is called like so:

dialog.openButtonDialog(title, buttons..., options);

The title property lets you specify the label to show at the top of the ActionSheet. If you don't want a title, then simply pass in a null value.

The list of buttons is specified as a series of objects, which I'll describe below.

Finally, the options let you customize how the ActionSheet is displayed (via the "style" property) and lets you set an onClick handler for the entire ActionSheet.

The example above illustrates several options of the ActionSheet PhoneGap control.

  1. On a per-button basis you can specify your own onClick callback which will be run when that button is pressed.
  2. A global onClick handler can be specified in the openButtonDialog options argument, which will get called no matter what button is pressed.
  3. You can choose what the appearance of the dialog should be (currently only "opaque" and "translucent" are supported)
  4. A button requires a label property, but you can optionally specify a "type" property (can be "normal", "cancel" or "destroy").

The callback functions are simply called with two arguments, the index of the button being clicked, and the label of the button the user clicked on.  So if it's easier for you to work with array indexes, or with text labels, you can easily find out which button was pressed and when.

So go ahead and try out the ActionSheet control.  Either you can use my latest release in my branch of PhoneGap, or you can use these more advanced features once my changes have been merged in with the official branch.

  • Share/Bookmark
15Oct/09Off

In-App purchases allowed for free apps on the App Store

Finally, what we've all been waiting for.   Apple just announced that they're allowing In-App purchases for free apps, and not just paid apps. This means, as an app developer, I can develop a single app for the app store for free, but can allow my users to upgrade to the full paid version without having to split it up into a "Lite" and "Full" version.

I can't wait to apply this to my apps!

  • Share/Bookmark