Thursday, February 24, 2011

Review of AWS SDK for Android (SimpleDB)

So development of my Android app, PayNanny, continues and I'm at the point where I can make some observations about the AWS SDK for Android (Beta release). Note that of the 4 AWS services (S3, SimpleDB, SNS, and SQS), I'm only using the SimpleDB API. I won't bore you with how easy it is to make a free AWS account but believe me, it's easy.

First off, I'm so happy I don't have to write an HTTP library or any of the framework necessary for code on a mobile device to interact with a cloud database Isn't is awesome that this is all that's required to add an entry to a SimpleDB domain (similar to a table) is:


List attributes = new ArrayList(5);
attributes.add(new ReplaceableAttribute().withName("date").withValue(date));
// more lines of attributes.add

PutAttributesRequest request = new PutAttributesRequest("timelog", UUID.randomUUID().toString(), attributes);

AmazonSimpleDB mDB = new AmazonSimpleDBClient(credentials);
mDB.putAttributes(request);


Everything's taken care of (well, except transaction handling as SimpleDB is NoSQL) and it keeps your code compact and easy to read. Most of my utilization of the AWS SDK follows in the same vein and I heavily reference the AmazonSimpleDBClient class. I kept the database structure very flat to use SimpleDB the way it's supposed to be used. For instance, I've combined some things which would usually be different fields in an RDBMS into 1 attribute. Once I get this value from the database, I parse it according to the schema I designed.

Like any database-centric app, you're going to loop around your search results often so you'll take your List, pull out each Item, and look at the Attributes like:


// itemList is a List
for(Item item : itemList) {
    List attributeList = item.getAttributes();
    String itemName = item.getName();

    // parse attribute list and sort the data
    for(Attribute a : attributeList) {


It can get a little monotonous and having a bunch of nested loops always makes me nervous but what are you going to do.

SimpleDB is typeless - everything gets stored as a string. I find this to be good and bad. I liked not being so limited in what I had to send to the database but it makes writing optimized queries more difficult. Instead of writing an RDBMS SQL statement saying "get me all data between the dates of 1/2/11 and 1/8/11", I had to code a SimpleDB statement saying "get me all data with the date 1/2/11 or 1/3/11 or 1/4/11 or 1/5/11 or 1/6/11 or 1/7/11 or 1/8/11". So in effect, SimpleDB is pushing a bunch of logic that would usually be handled by the database server into the application code. Mobile devices are pretty fast but I'd rather some server farm in Oregon or wherever do this work than my Droid. Zero padding and offsetting numbers allows for some of this RDBMS functionality but I didn't utilize that in my code.

One major feature lacking in the API is access to the AWS Identify and Access Management (IAM), which is a vital requirement for those who wish to deploy Android apps without giving away your keys. In the meantime, check out the awskeyserver project, which does a good job providing this funtionality via Google App Engine.

I haven't made up my mind about the NoSQL concept. While I won't have to deal with the data consistency issues inherent in this design, I appreciate that the strong consistency option is built into SelectRequests. I don't think NoSQL databases wouldn work for, say, financial applications that need to keep track of a transaction but I don't see why it wouldn't be fine for a social app that needs to scale. Whenever I write stuff like that, I'm reminded of Ted Dziuba's great anti-NoSQL piece which includes the words "You Are Not Google".

Overall, I'm satisfied with this API and the performance I'm getting (for free, mind you). Once my app goes Beta, I hope to have more insights.

Saturday, February 19, 2011

Native Client - where web apps and native apps meet

I was motivated by a web apps presentation by Seth Ladd, a Google Chrome developer advocate, to write a short white paper why my organization should be moving in this direction. But it's hard to get around the fact that native apps still beat the pants off of web apps in many functional areas. Until this week, I wasn't aware Google was working on Native Client, a way to run native compiled code directly in the browser. This certainly makes sense if Chrome is to become a major OS.

I don't think I'm brave enough to fool around with the developer release SDK right now - I'm busy working on my Android app - but once it goes beta it'll be worth a look.

Tuesday, February 8, 2011

PayNanny

PayNanny is a household employer payroll app I'm working on for Android devices. So far, the only functionality I've built consists of a way for the user to "log in" (identification only - no authentication yet), create/delete/edit employee names, and link or delink their account with another.

I've open sourced it on github.

Saturday, January 29, 2011

NoSQL databases - now with SQL!

So I'm writing an app and wanted to take the opportunity to see what the NoSQL buzz was all about. By no means would I need to scale to the level most programmers expect when they employ NoSQL (like Netflix) but I think I've worked with RDBMS enough (though it's been awhile). Ted Dziuba has a pretty funny critique of the NoSQL craze here.

Amazon Web Services (AWS) SimpleDB was a perfect fit - not only is it free for small fish like me but the new AWS Android SDK includes SimpleDB support. I'm not interested in writing a bunch of HTTP libraries - the AWS Android API does everything for me.

The big knock against NoSQL is its data consistency. You're not always guaranteed to get the data you're expecting. SimpleDB counters with a Consistent Read option which I'm employing. You give up a little speed but for a small app like mine it's a no-brainer. But there are no transactions to track so there's still some risk.

Another surprise was SimpleDB's support of SQl through SelectRequest. You can't do stuff like JOINs (these kinds of "advanced" operations are handled in application code) but it's convenient when you need to pull a targeted set of data.

Special shout out to the folk(s) who made sdbtool, a Firefox plug in that let's you interact with your SimpleDB account.

Here are a couple snippets from my class which handles SimpleDB interaction. Connecting is as easy as:

BasicAWSCredentials credentials;
Properties properties = new Properties();
try {
properties.load(getClass().getResourceAsStream(AWS_PROPERTIES));

String accessKeyId = properties.getProperty("accessKey");
String secretKey = properties.getProperty("secretKey");

// some boring error checking

credentials = new BasicAWSCredentials( properties.getProperty( "accessKey" ), properties.getProperty( "secretKey" ) );
// note mDB is an AmazonSimpleDBClient
mDB = new AmazonSimpleDBClient(credentials);
}

Executing queries and putting results in a List is fairly easy:

SelectRequest selectRequest = new SelectRequest("select * from accounts where m_username = '" + username + "'").withConsistentRead(true);
SelectResult selectResult = mDB.select(selectRequest);
List resultList = selectResult.getItems();

I'm able to really take advantage of the API simplicity when adding stuff to the database. NoSQL architectures seem to be pretty great for these types of actions (as long as the data gets there!).

List attributes = new ArrayList(1);
attributes.add(new ReplaceableAttribute().withName("m_username").withValue( username));
PutAttributesRequest request = new PutAttributesRequest("accounts", username, attributes);
mDB.putAttributes(request);

You know, if data consistency is critical, you could keep querying the database until your data is positively there...

Sunday, January 23, 2011

Super simple identification code

So I'm working on an Android app and I really don't care about authentication (yet) but need a way to identify a user. I can assume the user will have at least 1 google (or gmail) account and I'm also going to leverage off the Google App Engine for many services. I'll probably add in the AuthToken functionality eventually - hopefully the Authentication features of Android and Google App Engine will continue to improve in the meantime.

So here's a class that extends ListActivity:


Account[] mAccts;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.main);

// get google/gmail accounts
AccountManager acctMan = AccountManager.get(this);
mAccts = acctMan.getAccountsByType("com.google");

// put the account names into a String[]
String[] acctnames = new String[mAccts.length];
for (int i=0; i< mAccts.length; i++) {
acctnames[i] = mAccts[i].name;
}

this.setListAdapter(new ArrayAdapter(this, R.layout.accts_row, acctnames));
}


That will show the user a list of their Google accounts. Here's the onListItemClick:


super.onListItemClick(l, v, position, id);

// find the account clicked and send the intent on its way
Account acct = mAccts[position];
Intent i = new Intent(this, PayMain.class);
i.putExtra(PayMain.KEY_ACCT, acct);
startActivity(i);


In your target activity class (PayMain in this case), the account will be bundled into the Intent.

The XML files are basic for ListActivity programs. Make sure you ask for GET_ACCOUNTS permission in AndroidManifest.xml (plus USE_CREDENTIALS and INTERNET if you're going to get an AuthToken).

I ran this on my Droid X with 2 gmail accounts and it works fine. Works with no Google accounts also (says the user needs to get a Google account and try again). Having problems adding an account to the emulator. I believe I'm supposed to do it through Dev Tools but can't seem to get it to work. I'm able to add a gmail account to the email app but it's not added to the system as a real account. Plus I can't locate any good documentation of Dev Tools. Strange...

Monday, January 17, 2011

Dropbox - the way cloud apps should be

Very impressed with the functionality and ease of use of Dropbox, a revolutionary step forward in how data can be shared across multiple devices. In 4 minutes, I installed the app on my Ubuntu (Maverick Meerkat) netbook and Droid X (Froyo) phone and was passing files back and forth. I feel so stupid emailing myself just to get files from one place to another - this should resolve that problem for good. The web UI is perfect and feels a lot like a Google app. Much respect.

Sunday, January 16, 2011

And finally, Notepad Example #3

The final example changes the manner in which data is passed between the Add/Edit activity and the main activity. Instead of packing them in the extras Bundle, the data is pulled from the database. So, note my first note from the Exercise 2 entry. I failed to consider what would happen when pausing the activity for whatever reason. Here are some random thoughts:
  • Not loving the ContextMenu: Doesn't seem to be an intuitive way to access operations but I'll keep an open mind. I would prefer to offer the "Delete Note" option as a button in the NodeEdit activity.
  • Moving the SQLiteDatabase object to the NoteEdit activity makes perfect sense. I just wonder if all those reads/writes introduces risk of lag, particularly when a remote/cloud data storage solution is used.