Monday, September 9, 2013

Researching a Bug by Monkeypatching devise_oauth2_providable

My Rails app was throwing seemingly random 400 errors back to its associated iOS application, and I couldn't find any detail in the logs (thanks heroku/Obama).

I really wanted to see what the Rails app was sending back to the phone so I could better identify the issue instead of guessing, so I had a couple ideas:

  1. See the logs on the phone
  2. Add something to the rails app to log the error
    1. Change Rails' BadRequest error class to output the response body
    2. Monkeypatch the devise_oauth2_providable gem to output the body

Non-Starter

The first option wasn't really feasible because the error wasn't registering as an exception, and therefore not getting caught by Flurry. Second, it's a pain to extract the application logs from the phone itself, especially if it's from a user.

Failed Attempt

The second option looked more probable because we could update the server code much faster than pushing a new iOS version to Apple; however, I wasn't too sure where to start when it came to digging into Rails or the gem.

My first hunch was to try to add a #puts to ActionController or some other class involved in the HTTP request, but this would have to be pretty deep into the Rails code and would need to check the status of each request.

Next, I actually tried to overwrite ActiveResource::BadRequest to kick out the response body; however it wasn't showing up in my tests, so I started to think that these 400 errors weren't being thrown by the core Rails app.

My Solution

My next clue came from the integration tests for devise_oauth2_providable, which showed the gem returning 400 for several different parameter issues, each with a different message sent in the response body. So in order to dump the response to the logs, I patched in a single method into the gem's error handling code and added it to a file in the Rails initializer directory.

It may not be particularly pretty, but this now gives us insight into the causes of our 400 errors, which we can use to fix up the iOS app and improve our user experience.

Friday, August 30, 2013

Code School: Try Objective-C Review

I just finished Code School's course named "Try Objective-C", which runs you through the basic syntax of the language.

The course's presentation as a game gave me the pleasant feeling I was making progress, and I picked up on the Smalltalk-style message passing pretty quickly (felt similar to learning Clojure syntax).

My main stumbling block is its similarity to C (and as a strict superset to the C language, you can actually compile C code in the Objective-C compiler and include C code in Obj-C classes). Coming from Ruby, I am still getting used to type declaration, but the real kicker is that Objective-C treats C types differently than Objective-C types, so there can be runtime/compile-time errors because you're not declaring variables correctly, or they can't interact directly with types from the other language.

My rubyist alarm went off as well when the lesson had us check whether a class responded to a certain method. I just need to remind myself that I'm not writing Ruby, and Objective-C has to solve problems in its own way.

I'm sure there are additional topics to cover when learning Objective-C, but having gone through this first course, I think I can move into the iOS courses with less trepidation.

Step one in my quest to learn Objective-C is checked off. Now on to more in-depth lessons in the language and maybe even a full-fledged project.

Updating Uncoil

Earlier this week, I was in search of a project to work on, and I decided to dig through some of my old code to see if it could be improved. Unsurprisingly, my first ruby gem, uncoil, screamed and pleaded for some attention.

After looking through my old code, I decided to refactor the gem to clean up some of my noob mistakes from several years ago.

The plan:

  • Move each API interaction into its own module (bitly, isgd, other all get modules)
    • This also strips out a ton of code from the main Uncoil class
  • Create an Expander facade to hide all of the different expander methods
    • People can add additional modules and the end user is none-the-wiser
  • Delete the VCR api data and test with fresh api data to confirm functionality
  • Bump the minor version number
    • Since this is only changing the implementation, it shouldn't change the major version

I am part-way through the refactoring right now, and will announce when I've pushed the new gem version.