Wednesday, May 20, 2015

Udacity Course: Developing Scalable Apps in Java

My new position focuses on cloud development, with an emphasis on Google App Engine.  I wanted to get up and running quickly, so I worked through this course from Udacity.  Prior to this course, I'd only worked on one other App Engine project, which was basically an expansion on the Google Backend API Walkthrough.  I'd previously used the Google Plugin for Eclipse, however this project uses the App Engine maven plugin, so that was different.  Overall I thought it was a good course.  Naturally, nothing involving Eclipse can go smoothly the first time, but after a couple hiccups, I was off and running.



Unit 1 is basically just history and overview information.  Magnus goes over basic concepts and does a couple interviews.  Personally I found Magnus's over the top style a bit off putting, but he isn't too terrible.

Unit 2 starts to get more into the technical details.  They guide you through setting up the app engine project on the developer console, setting up Java, Eclipse, and Maven, and get you started with a super basic Hello World type cloud endpoints application.  They walk you through creating a new project using Maven archtypes, which are basically templates.

One hiccup I ran into here was that there is a bug in the version of the AppEngine plugin used with the project (1.9.4).  When I tried to run the Hello Endpoints project, whether through the front end or through the api explorer, it was trying to hit the appspot website instead of the dev server on my local machine.  Updating pom.xml to use 1.9.19 instead solved the problem. Make sure to update your target runtime in <<blahblah>>

There are a number of places in the Hello Endpoints pom.xml file where 1.9.4 is specified, so just do a find-replace

Make sure to update your targeted runtime.  If it isn't there, you may need to build once for Maven to download the new version.
Also ran into a tricky issue with my coworker, Tony, who is working through the course on a Mac. Every time we tried to run the appengine:devserver Maven build, it would hang upon executing Java. So apparently, OSX requires certain frameworks (Swing and GWT if I remember right) to execute on thread 0, so there is a parameter that gets passed to java by maven that ensures this (XStartOnFirstThread).  I was convinced this was the culprit, and sure enough when we ran it in the command line, we got a different error (something about the port not being open).  But when we ran the Maven build it would always run with the first thread parameter.  Tony suggested we try changing the ports... and then like magic it worked.  Not sure why that worked, but it did and I was just glad to finally have him up and running lol.

Uncommenting these lines in his pom.xml file got us over the hump.
Once Eclipse and friends are set up, we actually get into some real code.  A handful of videos deal with the Hello Endpoints, then we are introduced to Conference Central.  The frontend is built in Angular, but none of the front end code is really touched anywhere in this course, it focuses pretty exclusively on the backend Java api.

Units 3 and 4 cover using Cloud Datastore.  In Datastore, you don't have "Tables", "Rows" and "Fields", instead you have "Kinds", "Entities", and "Properties", which map pretty closely to the respective relational DB concepts (but not perfectly).  This course uses Objectify to manage getting Entities into the Datastore.  Creating a new "Kind" to store in the Datastore involves several steps:

  • register the class with the objectify service (don't forget!)
  • annotate the class you with to store with @Entity
  • if you want the object to be cached in memcache, annotate the class with @Cache
  • annotate the field that will act as the unique id with @Id
  • annotate any fields that you will wish to query with @Index
  • if the entity is going to have a parent (think foreign key), you must store the parent key and annotate it with @Parent
  • create an object. Give it a unique key, either manually, or by allocating one with ObjectifyFactory.allocateId([ancestorKey], Entity.class).  If the entity has a parent, include it's key in the call to allocateId, otherwise the ancestorKey is optional.
  • save the object with the ObjectifyService like so: ofy().save(entity);

Getting objects out of the datastore is a matter of calling ofy().load().key(entityKey).now();  You can query a kind by calling ofy().load().type(Entity.class)... adding the appropriate calls to filter() and order() to get your data looking right.  There are a number of rules you have to follow, but it isn't too onerous.  Probably the most cumbersome aspect of creating queries is the need for indexes for every multi-property query.  Their conference query example queries on 5 properties (name, month, maxAttendies, topics, and city), which required creating 14 index entries.

[MATH ALERT] Normally having 5 keys, if you wanted EVERY possible composite index, you would need (2ⁿ - 1) - n - 1 keys, because their are 2ⁿ - 1 subsets, but you don't need to specify single key subsets, only composite keys (so subtract n), and we don't care about the empty set (so subtract one more).  In my case, one key (name) just needed to be tacked on to every combination of the other four, so really it was just (2ⁿ - 1) - 1 with n equals 4 (can't subtract the single key sets because with "name" they aren't single keys anymore, dig?)... so 2^4 - 2 = 16 - 2 = 14 ... sweet I actually got it right (whew).  So the lesson here is, if you want to dynamically search on 10 different properties, you are going to need 2^10 - 12 =   1012 different composite indexes O_o ... You might want to write an app or script to do that for you... or, you know, use a relational database... just sayin...

The last bit they cover is using Transactions, so you can do multiple operations that fail or succeed together (helpful if you want to keep your data consistent)

Unit 5 mostly covers memcache, task queues, and cron jobs.  Memcache can save you hits to the datastore, which is helpful to keep your quota down, and also makes your app more responsive.  Using Memcache with Objectify is as simple as setting the @Cache annotation on the entity class, but they also cover using the cache api directly.  Memcache really is just a key/value store, so adding something to Memcache is as simple as calling MemcacheService.put(key, value), while getting something from Memcache is, you guessed it, MemcacheService.get(key). Simple.

To demonstrate task queues, we create a servlet to do the actual work (which is, in itself, a useful exercise for those who haven't dealt with servlets).  Using a servlet requires a bit of configuration in the web.xml file, and we set up some security to make sure only the app and the developer can call it. For the course we set up a task to send a confirmation email.

Setting up our task servlet
Finally, cron jobs are set up in the cron.xml.  With a cron job, we can set a task (specified by a url) to be run on a regular schedule.  This is what cron.xml looks like:


The syntax for <schedule> is very specific, so make sure to check the documentation.

A word on the developers console.  Cron jobs, task queues, and DataStore can all be monitored easily from the developers console, and the logging functionality can be a godsend for debugging.  Here are screens of datastore, cron, memcache, and logging:





Unit 6 is a high level overview of Mobile apps, and basically just consists of a demo of the Conference Central Android app.  They cover how to create an Android app id, which is helpful, but they don't cover coding for the Android platform.

The final projects tasks us with creating "Sessions" for conferences.  I got really frustrated with this one because I couldn't get my entities (Sessions) to save... until I figured out that I needed to register the Session class with the Objectify service (see note above about not forgetting to register your classes!).  Created a task to send a confirmation email when a session was created, and queries to search for sessions based on Conference (ancestor), speaker, and session type.  It was a good exercise, but I was pretty funned out by the time I finished so I didn't mess with the last couple details (creating a "wishlist").

Overall I found this to be an excellent hands-on introduction to Google App Engine development in Java, and I fully recommend it.  Hopefully the over the top style doesn't make blood shoot out of your eyes and smoke come out your ears lol.






No comments:

Post a Comment