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         │                      │                      │                      │
                       │                      │                      │                      │
                       ▼                      ▼                      ▼                      ▼


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 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.

App of the Month 3: Journal 3

Well then, I’ve been especially terrible this month about updating everyone on my status. So bad in fact, I missed the announcement of having successfully completing the app and submitting to Amazon for review. Let’s do just that then.

I completed my simple Alexa Skill last week and submitted to Amazon for review. The skill does exactly what I said I wanted — users can submit six word stories and listen to other stories that other users have submitted. In that way, this was a successful project for this month.

However, the app got rejected. Turns out I did a terrible job actually going through the documented steps for submission and missed some extremely simple testing steps to ensure the skill would pass review. As such, the skill got rejected. Thankfully though, Amazon’s review process provides an extremely detailed rejection email with exactly what parts of the review failed. This includes the actions taken along with the resulting errors. Without this, I probably would have just shrugged my shoulders and claimed the project a half success. With this email though, I took the time today to fix those errors and resubmit the skill.

Looking back, probably the most interesting part of the skill was that I used node.js to write both the Amazon Lambda skill part and also the back end service that I have running on a DigitalOcean virtual server. This was the first “real” project I’ve ever written using Javascript, let alone node. It turned out to be not too terrible a process. Probably the worst part is that for some reason I cannot SFTP into my virtual server so I could not connect my instance of PhpStorm and use the IDE. This meant I resorted to using Vim and some basic syntax highlighting plugins to try and get things done. That turned out to be pretty okay and I may keep trying to get better at Vim; but, I will continue to try and figure out why I cannot get SFTP to work. If I can do that, then I’m sure working on future web projects will be even better.

App of the Month 3: Journal 2

Editor’s note: this was written last week and somehow missed the actual transition from editing platform to actual posting. Oh well, here it is now.

Delays seem to be the norm now for me this month. This month just has been a bit on the wild side. Especially on the work front. Lots and lots going on there, which ends up just making me tired and not really interested in sitting in front of the computer when I get home. But, that’s not the right attitude to take when I’ve got a deadline to meet. It doesn’t work at work, and it doesn’t work here.

At this point, I’ve spent a lot of my time working on this product just learning about the Alexa platform. Which is paying off in some ways. The past few days I’ve been researching how does the Alexa service communicate with the actual server/code that produces the spoken responses. This has been illuminating.

Turns out that it is a pretty straightforward JSON series of requests and responses. This is great because it means the information is easy-ish to understand, and also that putting together the response feels pretty native in Javascript.

Oh yeah, that’s also a bit of learning for me — I don’t really know the idioms of programming in Javascript. I don’t think this is really slowing me down any, just another point to learn.

The Project

As I mentioned before, the project this month is to build an Alexa Skill that lets users share six word stories. The concept of the six word story is not original to me, but rather is pretty well known.

How are these stories shared though using Alexa? Well, I’m thinking of having a few rolling collections of like 100 stories that get updated as users add new stories. For example: say a user wants Alexa to add the story Someone knocked but I couldn't answer. That would get sent to the back end as the collection of six word. The back end would then pick from some set of existing collections of stories, say there are 10. Each collection would then have a list of 100 stories. When this new entry gets added to the story, the current oldest in that collection is then removed. If in the same conversation with Alexa the user wants to hear the collection that her story was added to, then Alexa will read back those 100.

Obviously there could be some awkwardness in reading 600 words from Alexa. It may turn out that she should only read the most recent 10, which would then mean I should have (according to that example above), 100 collections of 10 stories.

At this point I have some simple storage within the same conversation working, and it is pretty entertaining. Next is to get some persistence layer working, then basic logic to prevent more than some limit of stories per collection.

App of the Month 2: Journal 7, The Follow Up

I wanted to let everyone know that my app got approved! You will be able to find it starting today at here! I am pretty darn proud of how it turned out. While a simple app, I does everything I wanted with a little extra thrown in for simple analytics.

While I understand the cost may put some off, I am willing to take that hit. After looking at the options available at various price points, I think this app offers a lot of value. Other apps limit you to how many exercises or workouts you can create, this app gives you complete freedom. Other apps have in app purchases for useful features, this app gives you everything for the one price.

I would love it if you dropped me a line here in the comments, via email, or as a review in the store. I like hearing feedback and how I can make improvements in future apps.

App of the Month 2: Journal 5

Remember that time where I said I had completed an app of the month project? That was cool. We all were super excited, there was cheers-ing, high-fiving, and overall merriment was attained.

That hasn’t changed, but I’ve decided what the next step for this app will be — some analytics. Yay! Exciting!

I’m going to start with just local analytics. They will not likely be very in depth. My goal will be to aggregate just how many workouts you have started, how many fully completed, how many cards are completed for each workout. Additionally, what exercises are done, how many reps total, average number per workout completed.

Overall, this will be pretty basic information that right now will be available only to the user. If there is time, I might consider asking permission to upload statistics in a non-identifiable manner so that I can maybe do some analysis of how many users there are, how much they use the app, and what exercises are the most popular (which will require some kind of normalized naming method).

So yeah, that’s my next step. Thoughts? Suggestions? Tools I should consider? Leave a message in the comments here, on Facebook, Twitter, or even open an issue on the Bitbucket repo.

App of the Month 2: Dev Journal 4

And that’s it! I’ve hit feature complete on the app. The user can add exercises, group those into workouts, pick a workout, and swipe through the cards to see the reps of a given exercise. Time to kick back and bask in the glow of meeting a goal!

The code is still available on bitbucket here, so please feel free to peruse it and create pull requests. Or not, that’s cool too.

What’s Next

I think my next step is to just take an evening and spend it with my wife, because she deserves all of my attention. Or, at least spend as much time as she can stand to spend with me. 🙂

After that though, I will probably go in and try to create some simple but inspired artistic direction for this. Right now everything is super barren and plain, but that was the point. I might give Sketch another shot, see if anything inspires me. Likely I’ll try to find some simple icons for a few of the buttons, and spruce up the animation for the collection view a little.

Additionally, I want to add some analytics now that the app is complete. It is super simple, so the data acquisition should be “straight forward”. LOL, data.

App of the Month 2: Dev Journal 3

Short entry today, just a quick recap of what I got done last night. Yesterday I announced that I had open sourced the code and design file for the app, which is my first time doing something like this (I think). I am relatively nervous about how that will go, but after a day and no interest, there will likely be no one else ever to see this code.

Last night wasn’t a super productive night, but I did get around to factoring the persistence layer out. That means I have a consistent interface for getting the saved values the user has created. Additionally I started the work on actually doing a workout. Right now I just have the setup for the user to pick one of their existing workouts or let the app randomly generate the workout.

App of the Month 2: Dev Journal 2

Dang, that was a bit of a long break between entries, sorry about that. That may have caused some of you to think I had fallen off the wagon in this goal, but I assure you that is far from the truth. I am still going to strong and have a solid plan for this month. The intervening time between entries was due to a little travel for work.

What have I accomplished so far? Well, I started on visual designs and development. However, after working on the visuals for a night, I came to the conclusion I have no real inspiration for the appearance of this app. By the end of my time I had some silly swipe based interaction cooked up, but it was pretty crappy. I have since scrapped that, but not updated the designs. I’m just flying by the seat of my pants with design now.

Which leads me to the second part of this — the development I’ve completed. I have some of the “harder” parts completed. Those parts being adding new exercises and creating the workouts from those exercises. Additionally deletion is supported of exercises and workouts. Of note: deleting an exercise that is in use by a workout is fine and has no impact on any workouts, that kind of complexity isn’t worth my time. 🙂

Lastly, I was asked by a coworker if I would open source my project from last month when I completed it. I decided that one I would not because I did not want to. The decision was not based on being “scared” of what others think of the code (I know there are not good parts in there) but more because I just had no interest in it. This month though, I’m going to. In fact, the project is already on Bitbucket! Please feel free and give it a look over. If you have improvements you want to add, go for it! Got an idea for a sweet visual style? Awesome! Do it!