Mobile, Handheld Computing Devices: Where Does the Web Developer Fit In?

Recently, I was involved in a lively discussion at a ColdFusion and Flex developer conference (BFusion/BFlex) held on the campus of Indiana University in beautiful Bloomington, Indiana. Michael Labriola led the discussion, which took place during his keynote presentation, between a panel of many other developers who are active in the ColdFusion and/or Flex communities. Sometimes it's difficult to articulate your thoughts at the time of a discussion, hence I'm using this medium to do a sort of brain flush at the moment. I'm doing this also because I think the topic of discussion is an important one to consider for those of us who primarily develop applications for the web.

As for expanding the definition of 'who' actually develops applications for the web, I hope to include anyone who is involved in the process of creating rich internet applications (stakeholders, account executives, creative's, designers, developers, etc.).

Mobile Phone vs. Handheld Device

First, I think it's important for 'web' developers to try to disassociate the word 'mobile' from the word 'phone.' I myself prefer to use the word 'handheld' when referring to any type of 'mobile' device. 'Handheld' feels much more inclusive to me than 'mobile.' Whereas 'mobile,' while by itself is probably a more appropriate descriptor, can be more exclusive sounding due to its association with the more specific type of handheld device commonly known as a 'cell phone.' So when I use the word 'handheld,' I am attempting to include 'any type of compact, portable computing device.' I am purposely using a broad definition here since mobile phones only constitute one slice of the larger 'handheld, mobile computing' marketplace.

Don't Hate Apple Because Their Beautiful

Let's face it, Apple has definitely shaken up the market with their lineup of handheld devices including the iPhone and iPod touch. Whether you love, hate or are indifferent to Apple's handheld products, you can't deny that Apple's use of interface design and touchscreen technology has transformed the way other companies are designing and building handheld devices. Not to mention the number of features and available applications! I'm sure that there have been, and will continue to be, many conversations around conference tables about what works, what doesn't work and how the iPhone and iPod touch interfaces can be improved upon. Rather than throw my own subjective opinions into the mix at the moment, I will say that as an iPhone user, I certainly have my list of gripes. However, Apple has most certainly revolutionized how people can actually use a handheld device and interact with each other, the web and beyond.

Application Distribution

Take a moment to review this list of digital distribution platforms for mobile devices from Wikipedia. Considering the fact that the Apple App Store opened on July 10, 2008 and as of September 28, 2009 there are over 85,000 third-party applications available and over 2 billion application downloads to iPhone and iPod touch users, I'd argue Apple has definitely made some in-roads with software developers and end-users alike. Compare that with Google's Android Market with 10,200 applications as of September 2009 and you just might agree.

I'm not suggesting that the model Apple used to create their 'Application Empire' is the right one, but without a doubt, they appear to be doing something right. I most definitely don't agree with some of their practices, but one can't deny their level of success when compared to any other digital distribution platform.

Distributing Handheld Applications via the Web

As of today, reliably deploying an application on the web that is specifically targeted to handheld devices with a web browser is extremely difficult to do, assuming you want to offer anything more than some basic text and a few form fields. While work is currently being done to improve standards on 'technologies to enable Web access anywhere, anytime, using any device,' developers are pretty much left in the rain waiting for handheld manufacturers to adopt these standards and turn them into practices.

Once again, Apple has made significant strides in getting their handheld users online. In AdMob's Mobile Metrics August 2009 report, iPhone's worldwide operating system share has grown from 33 percent to 40 percent in the preceding six months. In addition, iPhone represented 50 percent of US smartphone usage in AdMob's network in August 2009, followed by RIM and Android devices at 14 and 13 percent, respectively.

What truly makes these numbers phenomenal is that Apple's handheld devices actually account for less than 15% of the overall Smartphone OS Market Share. Yet, this small group of users account for half of the US smartphone usage within AdMobs's network. This information more than suggests, it screams that iPhone and iPod touch users are actually using their handheld devices to go online.

As a side note however, it is frustrating that Adobe Flash is not yet supported on Apple's iPhone or iPod touch. Sure, efforts have been made so that iPhone and iPod touch applications can be developed with Flash and ActionScript 3, but users still won't be able to view Flash content delivered via the browser. To be clear, this is not the fault of Adobe. Apple, for whatever reason(s), has chosen not to support Flash at this time.

Final Thoughts

I think it's important for those of us who primarily develop applications for the web to continue our discussions and thoughts on how we can better address the needs of the ever-growing handheld device marketplace.

I believe we can learn from Apple's strengths and weaknesses to find and improve a model of 'handheld application development and distribution.'

I think if designers and developers can learn how to better account for users of handheld devices regardless of whether or not they visit a web site, overall usability can be improved for these users as they look for goods, services and/or information.

These are merely thoughts, and obviously they're constantly evolving ... even while I've been writing this article. I hope my thoughts also inspire you to think about this topic and look forward to reading and/or hearing your thoughts on this subject as well.


I don't work for Apple nor have I received any compensation from Apple for writing this article. I wouldn't mind it if they decided to do so, but as of the date of publication, this has not actually happened. Finally, no handheld devices were harmed in the writing of this article.

MySpace Can Update Your Twitter Status ... Who Cares?

MySpace has announced users can now automatically sync their status updates with Twitter. Is having the ability to create a "Global Social Status" (yes, you can use that ... I just made it up) really such a good thing?

Not long ago I ran across an application in Facebook that would pull in my Twitter updates and automagically update my Facebook status. I quickly learned that this was not exactly the best idea in the world (and I'll tell you why in a moment), so I'm not so certain the efforts of MySpace are going to bring about any kind of improvements in the social media communities.

Let's think about this for a minute ... if you're a friend of mine on Facebook (or MySpace) AND you follow me on Twitter ... do you really want to read my status updates everywhere you go? For serious, does it make sense to "shotgun" your updates to every single social community you belong to? I think not.

Sure, there are rare occasions that you might want to do this ... but I say resist the temptation! I've found that for the most part, people I follow on Twitter are a completely different group of people than I have on Facebook. Sure, there is some overlap and that's to be expected, but the vast majority of people I know of Facebook (or MySpace) are people I've actually met, am friends with, family with, grew up with, you get the picture. Many of the people (and/or companies) I follow on Twitter are people I've never personally met (although many I hope to meet someday) but we share some commonalities ... maybe it's programming, maybe it's music, maybe it's geography. You know?

Where I'm going with this is that something I might "tweet" about may not necessarily be something I want to update my "Global Social Status" with. The audiences are completely different and often warrant their own unique message, even if the messages are very similar.

The flip side to this is if you like to Twitter ... and you know who you are ... you have the potential of overwhelming your family and friends with updates like "RT @stevewithington CF9 is the bees knees ... I have ORM, do you?" or "This site rocks: #muracms #mura #coldfusion #sql"

Heck, I don't know about you, but I already get a little irritated having to scroll through things like "Help Me on Mafia Wars" or the ever popular "Steve Withington took the 'What Kind of Car Are You?' quiz and got the result: You're a 1969 Bitchin' Camaro. Read more ..."

So if you're goal in life is to annoy the crap out of people in your social communities, then go right ahead and applaud the efforts of MySpace and others in their quest to become THE place to go to update your Global Social Status. In the mean time, I'll continue along, grumbling and complaining about silly things like this.

Using ColdFusion to Handle HTTP 404 Page Not Found Errors

This article will not address the onMissingTemplate method which only runs when a CFML page does not exist (i.e., wwwroot/directory/thisPageDoesNotExist.cfm). In addition, this article will not address using custom headers or a .htaccess file with Apache. This article will address those other "page not found" errors often found in Windows hosted environments.

Let's start by assuming someone tries to visit, or and neither the directory, nor the page actually exist on your site. Or, better yet, you've just spent months building a new, dynamic site for a client using ColdFusion and their old site was an old, yucky plain HTML site with pages everywhere. Now, your client, who's a little savvy in the SEO department, (that's search engine optimization for you non-seo-knowing folk), has requested you setup redirects for each of his old pages to the new ones you've created.

If you're anything like me, I used to dread the thought of taking care of this. I used to spend a ton of time on this by creating a separate page for each of the "old" pages and directories, then using either JavaScript to handle the redirects (if the old page was vanilla HTML) or the "old" dynamic language (i.e., ASP, PHP, etc.) to create custom headers, etc. Regardless, it was a major pain to do this, especially because it cluttered my site with a bunch of extra files that were essentially useless.

Then, I had one of those "light bulb moments." I thought, "Hey, I'm already using a custom tag to handle 'page not found' requests, so if I could somehow capture the requested page, match it against a list of 'known-to-be-missing' pages, then I could code a way to forward to the 'new' destination." Sounds simple enough, eh?

For those of us using a shared-host provider such as CrystalTech or HostMySite, they're kind enough to allow us to create custom pages to handle certain HTTP errors, such as 404. It's usually found in the service provider's "control panel" under something like "IIS > Custom Error Pages." Once there, you usually have three options to pick from: 1) Default, 2) File and 3) URL. In most cases, "Default" loads the standard error page provided by our friends at Microsoft. "File" is just that, a flat, static, HTML page. What we want to use is "URL," so that we can use ColdFusion to help us out. In fact, I'll be nice and even provide a link to both CrystalTech's process and HostMySite's process. But before you do this, you'll need to at least set up a .CFM file somewhere on your site so you know what to enter into the URL path, right? So for now, let's assume you've created a file call "404.cfm" and placed in a directory structure like so: "/extensions/customtags/404.cfm"

So, assuming you've got your custom error page setup properly, you will now be able to capture a query string which contains the "requested URL" that really didn't exist. The easiest way to test this would be to enter this code onto your 404.cfm file, upload it to your site, then try a non-existent directory such as

<cfset request.queryString = getPageContext().getRequest().getQueryString() />
<cfabort />

You should see something like this: "404;"

There's some great information coming through here. First, you'll notice that you're receiving the error number (404). Next, you'll see your domain also includes the port number being used. For example, if using HTTP, then you will most likely see the number 80, or if your using HTTPS, then you should probably see 443.

For this next part, you might have to adjust this if you ever use a colon ( : ) in your directory or page naming conventions (this is not generally used, so I wouldn't expect this to be much of an issue).

Look again at the query string that we've been given, what we really want to grab is everything after the port number. Or, the absolute path to the page or directory being requested. So this is what I came up with:

<!--- perform some manipulations to the 'requested url' to get at the actual request --->
<cfif isDefined("request.queryString")>
    <cfset requestedPage = listlast(request.queryString, ":") />
<cfif len(trim(requestedPage))>
    <!--- after removing everything before the port, we now need to remove the port number --->
    <cfset requestedPage = listdeleteat(requestedPage, "1", "/") />
    <!--- quick fix to create an absolute path from the site root to the requested page --->
    <cfset requestedPage = "/" & requestedPage />
<cfabort />

So, now if we use the same url we tried earlier, I should see something like: "/abcd/" Now, I've got a variable that I can use to match against to see if this is a "known" directory or page from our old site. Now we just need something to handle the "matching" and then receive a response to make decisions against.

Luckily, I've created a rather simple .CFC which can easily be modified to accommodate any "known" directories and/or pages, including .ASP, .PHP, etc.


    Document:        /extensions/components/redirect.cfc
    Author:            Steve Withington
    Creation Date:    12/30/2008
    Copyright:        (c) 2008 Stephen J. Withington, Jr. |
    Purpose:        Handles redirects of old pages to new ones.

    METHODS/VAR:    1) getLocation() / newLocation
    Revision Log:    
    MM/DD/YYYY - sjw - comments.


<cfcomponent displayname="Handles redirects" hint="Pass me an old location, I'll give you the new location." output="no">

    <!---    1) getLocation()    --->
    <cffunction name="getLocation"
                    displayname="Get a new location for old links."

        <cfargument name="oldLocation" required="false" default="" />
        <cfset var newLocation = "" />
        <cfswitch expression="#arguments.oldLocation#">

            <cfcase value="/index.html">
                <cfset newLocation = "/index.cfm" />

            <cfcase value="/about/news/default.php,/about/news/,/about/news">
                <cfset newLocation = "/news/index.cfm" />

            <cfcase value="/contact-us.asp">
                <cfset newLocation = "/contact/index.cfm" />

                <cfset newLocation = "" />

        <cfreturn newLocation />


Now, we just need to invoke the ColdFusion Component to see if there's a match.

<!--- check to see if the page requested matches any 'known' pages from the old site --->

    <cfinvoke component="extensions.components.redirect" method="getLocation" returnvariable="newLocation">

        <cfif isDefined("requestedPage") and len(trim(requestedPage))>
            <cfinvokeargument name="oldLocation" value="#requestedPage#" />


    <cfif isDefined("newLocation") and len(trim(newLocation))>
        <cfset newPage = newLocation />

        <cfset newPage = "" />


As you can see, if no match has been found, a variable called "newPage" is merely left blank. So, now we can write a little more code to accommodate both "known-to-be-missing" and "truly-unknown-and-really-missing" directories and pages. If a page is "known-to-be-missing", I can pass a search engine friendly header so that everything runs as smoothly as possible.

Here's the final document, aside from the .CFC above which should be kept separate.

<            c    f    silent>
<ma<tch! u-rl-=---"--^-(---[-a---zA---Z-0----9-/----]-+-)-$--"- i-g-no-r-e-C-a--s--e--=--"--f--a-ls-e"- -/-->
--    -        -    -    --------------<-co--n-di-t-i-o-n-s- -l-o-g-i-c-a-l-G-ro-up-in-g-="---Ma-t-ch-Al-l-"-->-
    Document<:ad    d     inp/ute=xt"e{nDsOiCoUMnEsNT_R/OcOuTs}t{oUmRtLags}/40"4. cmfamt
c    hAuTtypheo=r:"            ISsDtievree Wcittohirnyg"t iognnor
eC    aseC=r"fealatsieon" neDgaatet="etr:ue    " 12/>/
30    /        2        008
    Copyrig<ht:/c    o    nd(itcio) 2n0s08>
S    t        e    p    hen J. Withingto<na,c tJiro.n |t ywpew=w".Reswrtitee"p uhrl=e"n/wiitnhdienxg.ctfmo{nU.RcLo}m
/    P>u
r    p        o    se:        Handles req<ue/srtulse f>o
r     m    i    ssing pages <(H/TrTuP l4e0s4)>
        Notes:            Tes<t/rew ritteh>
is     se    t up befo<rdee fuasuiltnDogcu meintn >
a             live envir<ofnimleenst. >
Th    e             404 custom e<rrermoovre vpalaueg=e" inndeex.ecdfsm "t o/ >b
                                    set up <iandd vIalIueS= ("iondrex .cvfmi" a />
c    o        ntrol panel <in/ a ftihilrde-psart>y
        hosted environment).
    Revision <Log/:de    f
aul    tDMocMume/ntDD>
/Y    YYY - sjw - comment<s.

<!--- scope local variables --->
<cfparam name="requestedPage" default="" />
<cfparam name="newPage" default="" />
<!--- use a little of the underlying java to grab the queryString --->
<cfset request.queryString = getPageContext().getRequest().getQueryString() />
<!--- perform some manipulations to the 'requested url' to get at the actual request --->
<cfif isDefined("request.querystring")>
    <cfset requestedPage = listlast(request.queryString, ":") />
<cfif len(trim(requestedPage))>
    <!--- after removing everything before the port, we now need to remove the port number --->
    <cfset requestedPage = listdeleteat(requestedPage, "1", "/") />
    <!--- quick fix to create an absolute path from the site root to the requested page --->
    <cfset requestedPage = "/" & requestedPage />
<!--- check to see if the page requested matches any 'known' pages from the old site --->
    <cfinvoke component="extensions.components.redirect" method="getLocation" returnvariable="newLocation">
    <cfif isDefined("requestedPage") and len(trim(requestedPage))>
        <cfinvokeargument name="oldLocation" value="#requestedPage#" />
    <cfif isDefined("newLocation") and len(trim(newLocation))>
        <cfset newPage = newLocation />
        <cfset newPage = "" />
<cfif isDefined("newPage") and len(trim(newPage))>
<!--- requested page is a known 'old page' from prior site --->
<html xmlns="">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<cfheader statuscode="301" statustext="Moved permanently" />
<cfheader name="Location" value="" />
<title>This page has moved to<cfoutput>#newPage#</cfoutput></title>
This page has moved to <cfoutput><a href=""></a></cfoutput>
<!--- requested page is NOT a known 'old page' from prior site and doesn't exist --->
<cf_layout     title="Hmm, the page you're looking for can't be found."
                description="Hmm, the page you're looking for can't be found. You may have clicked a bad link or mistyped the web address.">

    <h1>Hmm, the page you're looking for can't be found.</h1>
    <p>You may have clicked a bad link or mistyped the web address.</p>
        <li><a href="/">Return home</a></li>
        <li><a href="javascript:history.back();">Go back to the previous page</a></li>

As you can see, I like to use a custom tag to handle the layout of my pages, etc. You can find out more about that at Raymond Camden's site.

I hope this helps a fellow ColdFusion developer. Thanks for reading!

More Entries

© 2017, Stephen J. Withington, Jr.  |  BlogCFC was created by Raymond Camden – Version 5.9.004

Creative Commons License  |  This work is licensed under a Creative Commons Attribution 3.0 Unported License.  |  Hosted by