One Android App, Two Different Markets (Nook vs. Amazon)

Android , Android development , Mobile devices No Comments »

Facts:

  • My Quick Shopper app is a fairly simple app for creating a current shopping list from reusable items I designed based on my own shopping list habits.  It is currently optimized for 7-inch tablets.
  • It became available on the Barnes and Noble Nook app market on October 28th at a price of $1.  On the Nook app market, the search term "shopping" returns 4 results for apps focused on shopping lists or the act of shopping.
  • It became available on the Amazon App Store around November 26th, also at a price of $1.  In the Amazon App Store, the search term "shopping" returns over 400 results.
  • If Quick Shopper was highlighted or advertised in some way on either market, I am unaware of it.
  • The sales numbers for the first 30 days in each app market:
    • Amazon - 4 sales
    • Nook - 478 sales
  • 478 > 4 (by a lot).
  • I know of at least one other developer who sees higher sales of his same app in the Nook market over the Amazon market.

Thoughts:

The most likely cause of the vast difference in sales is that my app has very little competition in the Nook market, while in the Amazon App Store it's simply lost in a sea of similar apps, some of which are free.

But since I'm not the only app developer who's seeing more success in the Nook market than they are in the Amazon App Store, there may be other factors at work.  The Nook app market exists solely to provide apps for the Nook Color and the newer Nook Tablet:  anyone using that market knows that any app they see is (supposedly) designed for use on those tablets.  The Amazon App Store on the other hand caters to Android phones and standard Android tablets in addition to Amazon's own Kindle Fire, so perhaps the phone-targeted apps get more of the attention and the ratings because of the wider install base.

It may also have something to do with the buying habits of the different audiences.  I attended a web-based presentation given by a Nook evangelist who said that their studies showed Nook owners were far more willing to pay for apps than the average Android user (or something to that effect; I forget exactly what the slide said).  The sales numbers I've seen would seem to support that claim.

Of course, this is just my experience. If other developers are seeing similar results or perhaps even the opposite, I'd like to hear about it.

Announcing tableSnapshots: A ColdFusion Tool For Preserving and Reverting Database Table Data

CFML , ColdFusion 2 Comments »

Several months ago, I was doing some functional testing on a web application that was taking forever.  Each run of the test resulted in changes to the data in several tables, and in order to reset the test I had to go into the tables and undo the changes.  It occurred to me that it would be nice to have a tool or script that could preserve the current table data and then later write that version of the data back to the tables.

That marked the beginning of the tableSnapshots tool.

Read more...

dirtyFields jQuery Plugin Updated To Fix jQuery 1.6 Compatibility Issue

Downloads , JavaScript , jQuery No Comments »

A few days ago, I received an e-mail informing me that there was a bug in my dirtyFields jQuery plugin having to do with the plugin's evaluation of checkbox and radio button state (the plugin lets you track the state of form elements and highlight changes).

At first, I didn't see the problem and didn't understand the need for the code suggestion he provided because the demo file included in the plugin download worked just fine.  But then I realized that the demo was coded to use an older version of jQuery (the plugin is over 2 years old now), and once I updated the demo to use jQuery 1.7 I could see the problem.

I had coded the plugin to use the jQuery attr() function to check the selection state of checkboxes, radio buttons, and the option elements in <select> elements.  Prior to jQuery 1.6, code like myCheckbox.attr("checked") would return a Boolean value based on whether the checkbox was currently checked or not.  But that changed in jQuery 1.6: now (in 1.6 and higher), myCheckbox.attr("checked") only returns the initial value of the "checked" attribute of the element ("checked" rather than "true"), and returns undefined if the checkbox/radio button element does not possess the checked attribute at all.  The same hold true for the "selected" attribute of option elements.  In jQuery 1.6 and higher, the new prop() function is designed to return the current state of the selected attribute (this change to jQuery is in fact described on the API page for prop()).

So I updated the plugin to use the is() function in conjunction with the ":checked" and ":selected" selectors to evaluate checkbox, radio button, and option state, since that method works with both older and newer versions of jQuery.  The new version of the plugin is available from its dedicated download page and from GitHub.

Quick Tip: Avoid Joining Query of Queries (QofQs) Within Loops

CFML , ColdFusion 3 Comments »

Every ColdFusion developer who spends a lot of time working with queries knows that if you have to run a unique query for every iteration of a loop, you should (whenever possible) use a <cfquery> to acquire the entire set of records prior to the loop and then query against that recordset using a Query of Queries (QofQ):

<cfquery name="qryMain" datasource="myDatabase">
    select a.field1, a.field2, b.field7 ...
    from table1 a, table2 b
    where a.field1= b.field2
</cfquery>

<cfloop index="j" from="1" to="1000">
    ....
    <cfset calculatedVal= thisVal + thatVal />
    
    <cfquery name="qrySub" dbtype="query">
        select field2, field7 ...
        from qryMain
        where field1= <cfqueryparam value="#calculatedVal#" cfsqltype="cf_sql_numeric" />
    </cfquery>
    ...
</cfloop>

...That way, you're querying the recordset in memory 1,000 times instead of making 1,000 calls to the database.

Yesterday I was asked to look at an old report that wasn't performing well anymore now that the database tables being queried had grown much larger. While it was designed to use QofQ data within the loop, the QofQ in the loop was doing a join between two recordsets stored in memory:

<cfquery name="dbQry1" datasource="myDatabase">
    select a.field1, a.field2, a.field3, b.field4, b.field5
    from table1 a, table2 b
    where a.field1= b.field2
    ...
</cfquery>

<cfquery name="dbQry2" datasource="myDatabase">
    select c.field1, c.field6, d.field9
    from table3 c, table4 d
    where c.field1= d.field3
    ...
</cfquery>

<cfloop index="j" from="1" to="1000">
    ....
    <cfset calculatedVal= thisVal + thatVal />
    
    <cfquery name="qrySub" dbtype="query">
        select dbQry1.field2, dbQry1.field3, dbQry2.field6, dbQry2.field9
        from dbQry1, dbQry2
        where dbQry1.field1= dbQry2.field1
        and dbQry.field2 > <cfqueryparam value="#calculatedVal#" cfsqltype="cf_sql_numeric" />
        ...
    </cfquery>
    ...
</cfloop>

I discovered that if I created a third QofQ that took care of the join outside of the loop, and queried that new recordset within the loop, the per-iteration performance improved dramatically:

<cfquery name="dbQry1" datasource="myDatabase">
    select a.field1, a.field2, a.field3, b.field4, b.field5
    from table1 a, table2 b
    where a.field1= b.field2
    ...
</cfquery>

<cfquery name="dbQry2" datasource="myDatabase">
    select c.field1, c.field6, d.field9
    from table3 c, table4 d
    where c.field1= d.field3
    ...
</cfquery>

<cfquery name="qryMasterSub" dbtype="query">
    select dbQry1.field2, dbQry1.field3, dbQry2.field6, dbQry2.field9
    from dbQry1, dbQry2
    where dbQry1.field1= dbQry2.field1
</cfquery>


<cfloop index="j" from="1" to="1000">
    ....
    <cfset calculatedVal= thisVal + thatVal />
    
    <cfquery name="qrySub" dbtype="query">
        select field2, field3, field6, field9
        from qryMasterSub
        where field2 > <cfqueryparam value="#calculatedVal#" cfsqltype="cf_sql_numeric" />
        ...
    </cfquery>
    ...
</cfloop>

It makes sense when you think about it, but I had just never considered that join operations would affect QofQs so drastically.

Two Thoughts On Today's Adobe MAX (2011) Day One Keynote

Adobe , Miscellaneous , Technology 2 Comments »

I'm not going to try and summarize the keynote:  you can either watch the replay at http://www.max.adobe.com/online/ or read a brief synopsis at http://max.adobe.com/news/2011/keynote_day1.html.

My first thought is actually about some news that wasn't part of the keynote, but was announced on the Internet during the keynote:  Adobe's acquisition of PhoneGapPhoneGap is an application framework that allows developers to build mobile apps using web technologies (HTML, CSS, and Javascript) and the PhoneGap API (to access particular device functions like geolocation, the camera, internal storage, etc) and then package and deploy those apps such that they work on most mobile operating systems (Android, IOS, Blackberry, and a few others).

What struck me about that news was that it means Adobe now provides two ways for app developers to develop cross-platform apps.  If a developer is already familiar with Flash and Flex development, they can build mobile apps using Flash Builder and Adobe AIR.  If the developer is more skilled with web design and programming, they can build apps using PhoneGap.  In both cases, the end result is an app that runs natively on your device of choice (IOS, Android, whatever).

First of all, it's yet another example of Adobe's willingness to support both Flash and HTML5 as development platforms going forward.  A number of tech analysts contend that Adobe's development of new tools that play nice with HTML5 is a capitulation of some kind to the way the industry is moving.  I don't see it that way: Adobe may be synonymous with Flash, but it's never been all about Flash with them.  They have always supplied the tools that the digital and web creation markets have demanded, just as any sane company would, regardless of what their internal preferences might be.

The other thing about the PhoneGap acquisition is that it will expand the number of developers using Adobe tools and technologies to create mobile apps for both Android and IOS.  And now suddenly Adobe potentially a big player in the smartphone and tablet space, not by release their own mobile OS or mobile hardware, but by providing the tools to any developer who wants to write on any and all of these platforms.  To be clear, at the moment there are certain kinds of apps or app functions that a developer would want or need to develop in native OS code, but as the Adobe tools provide ways to overcome those limitations (such as the ability to include native code extensions in Flash/AIR apps), the number of reasons for writing an app in native OS code (and hence writing a second version for deployment on another platform) are going to become fewer and fewer.

My second observation regarding the keynote concerns the suite of touch-optimized mobile apps - the Adobe Touch Apps - coming in November to Android devices and later to IOS devices.  While some of the apps are geared more towards visual designers, the Proto wireframing app is something I could use in the design phase of my web and mobile application work, and, well, who wouldn't want a touch-optimized version of Photoshop to use to mess around with their photos?

And that's when the thought occurred to me:  here were some apps that I could use to be productive with a tablet.  I'm an application developer who writes code.  I have access to two tablets and I don't use either of them to write code or generate digital content of any kind.  For me, tablets have always been digital consumption devices (something Amazon seems to recognize with their new Kindle Fire tablet) for viewing video, looking at pictures, or reading web pages or books, and kinda superfluous given I can do all that and much more with a laptop (to be clear, I do love my Nook Color as an e-reader, but I rarely use it to surf the web or anything else).

But the apps Adobe showed off today made me feel like I would in fact want to use them on a tablet, because they were designed specifically with tablets and touch-interaction in mind, not as desktop apps shrunk into a mobile form factor.  That to me is a step in the right direction, and it's apps like those that are going to grow the tablet market by making the tablet experience more compelling.