Month / May, 2016

App of the Month 5: Journal 2

Quick update on what I have accomplished this month, with heavy emphasis on the “quick”.

As I mentioned in the previous blog post, this month’s project is the backend service for my upcoming mobile app/service. The goal of the app/service is to make deciding on a restaurant for dinner much easier.

At this point I would consider this month a success. I have written essentially the minimum viable product (MVP) for the server. The server is able to create new users, request info about a user, generate suggestions for a user, and mark a given suggestion as used. Further, when generating suggestions, the server will not return the same suggestion again.

These features are all that is necessary for the mobile app to be written and proven out. However, there are some obvious missing bits that would eventually need to be fleshed out. For example, there is no real personalization going on, just raw suggestions for restaurants located near where the user has set his/her address. Further, there will need to be an automated job to properly mark a restaurant as suggestible again, since the service can’t only suggest a place once ever. Unless you live in a city like NYC there is going to be a need to have a replenishing pool of restaurants to suggest.

I look forward to showing everyone the mobile app in the coming month!

App of the Month 5: Journal 1

Hey, so this is the second blog entry of this month. That is pretty good compared to the past. But, still just the first for this project. Which is of course pretty sad. No matter now, gotta keep moving!

This month I’m gonna kind of bend the rules I set out at the first of the year. How? Well, this project is going to be a two month project. The catch though is that in this first month I’m going to do the server side of the project this month and next month will be the mobile app. This made the most sense for a few reasons. One reason is that this is the most ambitious project I’ve taken on yet, which I’ll cover in a little bit. The other, and probably most important, is this month was pretty crazy in various ways, like visiting NYC for two full weeks.

At this point, you dear reader probably are really anxious to know the project. Fear not for I will reveal that now, kind of: an app/service to help the user find a good place to eat.

Yeah. That is pretty broad. To be more specific, the objective is to solve the problem of too many choices when looking for a place to have dinner in a large city. I have numerous times found myself in the position of not having dinner plans, then when the wife and I try to pick a restaurant to try we become paralyzed with all of the options. This app/service will provide a limited number of options to the user making the decision easier.

Of course this can’t be completely random so there will need to be some secret sauce in picking the suggestions. What will those be? Honestly I’m not entirely sure. I would love proposals on which to base dining location suggestions. Please leave me those proposals in the comments or on Twitter.

App of the Month 4: Journal 1

Wow, that is a terrible record of blogging about this project. But, fear not, I did actually complete an app this month. It is again an Alexa skill. This skill is essentially your iPhone’s Find My Friends app, but with the ability to ask Alexa where your friends are.

However, this isn’t a general purpose app. This app works only for my wife and I. Why? Because I didn’t want to do the work of putting together a real back end service that could generalize to the wider public. In order to do that I would have had to provided users of ways to identify themselves to other users and then verify who can find the location of who. That would have been just asking for various privacy issues. Instead, I’m only going to support the use case of us two. By doing so I can hard code numerous values and avoid worrying about privacy.

Well then, you might be wondering how it works. To be honest, it is a giant hack. It is a mix of managed resources on AWS (Amazon Web Services), a private server on DigitalOcean, and a custom iOS app. I’ll explain how it all works real quickly, but first let’s start with a diagram:

              ┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
              │Alexa Skills Kit │    │  Amazon Lambda  │    │  Custom Server  │    │     iOS App     │
              └─────────────────┘    └─────────────────┘    └─────────────────┘    └─────────────────┘
                       │                      │                      │                      │
 ─────────────────────*│                      │                      │                      │
     User Requests     │                      │                      │                      │
       Location        │─────┐                │                      │                      │
                       │     │   Alexa        │                      │                      │
                       │     │  Parses        │                      │                      │
                       │*────┘  Request       │                      │                      │
                       │                      │                      │                      │
                       │─────────────────────*│                      │                      │
                       │    Send Parsed       │                      │                      │
                       │     Request to       │─────────────────────*│                      │
                       │       Lambda         │  Request Location    │                      │
                       │                      │  of Specific User    │─────────────────────*│
                       │                      │                      │  Send Silent Push    │
                       │                      │                      │    Notification      │─────┐
                       │                      │                      │                      │     │  Get One
                       │                      │                      │                      │     │   Time
                       │                      │                      │                      │*────┘ Location
                       │                      │                      │                      │
                       │                      │                      │*─────────────────────│
                       │                      │                      │   Send Location      │
                       │                      │                      │    Coordinates       │
                       │                      │                      │                      │
                       │                      │                      │─────┐    Reverse     │
                       │                      │                      │     │    Geocode     │
                       │                      │                      │     │   Location     │
                       │                      │                      │*────┘  Coordinates   │
                       │                      │                      │                      │
                       │                      │*─────────────────────│                      │
                       │                      │    Send Resolved     │                      │
                       │*─────────────────────│    Address String    │                      │
                       │    Construct Text    │                      │                      │
*───────────────────── │     Response and     │                      │                      │
   Vocalize Address    │   Return to Alexa    │                      │                      │
       to User         │                      │                      │                      │
                       │                      │                      │                      │
                       ▼                      ▼                      ▼                      ▼

                      time

The process is this:

  1. The user says “Alexa, ask Location Finder to find Andrew”
  2. The Alexa service (“Alexa”) parses that vocal request and sends a formatted request to the AWS Lambda (“lambda”) function
  3. Lambda then makes a request to a specific end point on my private DigitalOcean server (“server”) that kicks off a node.js process.
  4. The server then asks the AWS SNS to send a silent push notification to the iOS app (“app”). This notification includes nothing but the endpoint that the server is listening on for a response. At this point the server just waits for a response on that endpoint or times out after a certain period of time if no response is received.
  5. The app launches in the background and makes a one time location request using the -[CLLocationManager requestLocation] method that was added in iOS 9. This method will return a pretty close location.
  6. The app then sends the latitude and longitude coordinates that the manager determined back to the endpoint specified in the notification.
  7. The server takes those coordinates and uses the Geocod.io reverse geocoding API to determine what the actual human readable street address is.
  8. The server sends this street address back to the lambda function.
  9. The lambda function constructs the required response format for Alexa and sends that back to Alexa.
  10. Alexa reads out the response to the user.

Is this the most efficient system? No. Does it matter? Definitely not. What does matter is it works for what I want and proves out my concept.

About the only challenge I really had with this project is a new protection that Apple introduced with silent notifications, namely to prevent exactly what I’m doing. 🙂 Silent notifications were added to the system to allow apps to download content in the background based on information sent by a remote server. This is essentially what the “background app refresh” setting on your phone enables. Many apps like email clients use it to get fresh content periodically. That way, when a user opens the app there is new stuff. However, there is always a few bad apples. In this case, those bad apples were using silent notifications to nefariously get user locations EXACTLY like I’m doing which is pretty sneaky. To combat that, Apple implemented what seems like throttling of silent notifications and even explicitly not delivering them if an app has been manually killed by a user.

Otherwise, this was a pretty fun project. I got to dig deeper into learning async processing on the server side using node.js, promises, and file system observing. In fact, I learned enough that I’m going to open source the code. Yay! You can read my pretty terrible node.js code on github. Pull request are welcome.