Blog Archives

Using FactoryGirl to easily create complex data sets in Rails

Posted in Code, Inside TFG, Ruby on Rails

I use FactoryGirl for setting up data in my application. FactoryGirl gives you all the tools you need to quickly and easily create data for models in your application. Leveraging ffaker you can make realistic looking, randomized data.

Often, you will have complex associations between objects in your system that can be a pain to factory up. I’ve frequently seen people use individual factories to build up these relationships. The amount of work required to set these associations up quickly gets tedious and turns your code into an unreadable mess.

In this article, I will run through some features of FactoryGirl that you can leverage to easily create complex associations.

Transient Attributes

One of the features I use most in FactoryGirl is the transient attributes. Transient attributes allow you to pass in data that isn’t an attribute on the model. I frequently use transient attributes to allow me to use a single FactoryGirl call to create multiple objects.

For example, say you have two models, User and Role. A User has one Role. You might do something like:

role = FactoryGirl.create(:role, name: “Head Buster”)
user = FactoryGirl.create(:user, role: role)

Using transient attributes you could define the following factory:

factory :user do
  transient do
    role_name “admin”
  end

  role do
    Role.find_by(name: role_name) || FactoryGirl.create(:role, name: role_name)
  end
end

which would then allow you to do:

user = FactoryGirl.create(:user, role_name: “Head Buster”)

Traits

Another of my favourite features is traits. You could solve the scenario above using traits by doing something like:

factory :user do
  trait :head_buster do
    role do
      Role.find_by(name: “Head Buster”) || FactoryGirl.create(:role, name: “Head Buster”)
    end
  end
end

which would then allow you to do:

user = FactoryGirl.create(:user, :head_buster)

I’ve found that the power of traits expands exponentially with the complexity of the model they are trying to map. The more states your model can be in, and the more data it has attached to it, the more you’ll be able to use traits to simplify data creation. Try to abstract any state that an object can be in into a trait to simplify usage.

Callbacks

Callbacks in FactoryGirl are also extremely useful. They work hand in hand with transient attributes and traits to allow you perform any non-obvious setup in your factories.

Let’s imagine an app which has the following models:

  • User
  • Book
  • UserReadBook (Join between User and Book, indicating the user has read this book)
  • WishlistBook (Join between User and Book, indicating the user added this book to their Wishlist)

Out of the box, if you wanted to create one of each type of object, you might have some FactoryGirl calls like:

user = FactoryGirl.create(:user)
book = FactoryGirl.create(:book)
FactoryGirl.create(:user_read_book, user: user, book: book)
FactoryGirl.create(:wishlist_book, user: user, book: book)

Let’s say we have a function on User: #related_books, which returns all Books that the User has read or added to their wishlist. Our RSpec tests for such a function might look like:

describe '#related_books' do
  subject(:related_books) { user.related_books }
  let(:user) { FactoryGirl.create(:user) }

  it "includes books this user has read" do
    expect(related_books).to include(FactoryGirl.create(:user_read_book, user: user).book)
  end
  it "includes books this user has added to their wishlist" do
    expect(related_books).to include(FactoryGirl.create(:wishlist_book, user: user).book)
  end
  it "doesn't include books read by other users" do
    expect(related_books).not_to include(FactoryGirl.create(:user_read_book).book)
  end
  it "doesn't include books other users have added to their wishlist" do
    expect(related_books).not_to include(FactoryGirl.create(:wishlist_book).book)
  end
end

Doesn’t look TOO bad. I REALLY don’t like having to tack the .book on the end there. I also don’t like that I’m not directly creating the type of object I want returned in my test. Personally, I think it makes the tests harder to understand. The bigger problem is when we need to refactor.

What happens when requirements change and we have to add in a VideoGame model? Now we change the UserReadBook and WishlistBook models to be polymorphic so they can also hold VideoGames. As a result, we rename the models to UserCompletedItem and WishlistItem.

It’s extremely likely we’ll used the original join table factories in multiple places to test other scopes, searching functions, and more. As a consequence, we have to update all our specs to use the updated join table name. Doesn’t this last step seem like an unnecessary pain in the ass?

What we should have done is used our factories to abstract the concept of wishlisting or reading a Book. Our tests generally want to ensure that there is a specific type of relationship between a Book and a User, but they shouldn’t really need to care about the specifics of it. Let’s look at how factories can help us.

The first thing I do when trying to abstract these concepts is work out the interface I want in my factories. In the case above, I’d like to be able to write:

FactoryGirl.create(:book, read_by: user) # and
FactoryGirl.create(:book, wishlisted_by: user)

I can support this interface using transient attributes and factory callbacks. I can update to my Book factory to look like:

FactoryGirl.define do
  factory :book do
    transient do
      read_by nil
      wishlisted_by nil
      # nil is a sensible default, we don't want our factories creating
      # extra data unnecessarily. It slows your test suite down
    end

    after(:create) do |book, factory|
      if factory.read_by
        FactoryGirl.create(:user_read_book, book: book, user: factory.read_by)
      end
      if factory.wishlisted_by
        FactoryGirl.create(:wishlist_book, book: book, user: factory.wishlisted_by)
      end
    end
  end
end

Here’s what I like about abstracting the concept of reading or wishlisting a Book using factories:

Simpler Tests

Our tests are no longer loaded with implementation details of joining the Book and User. This is especially useful in even more complex relationships. Basically, if my test is checking that a book is returned, I only ever want to create a Book. I don’t want to have to creating multiple other models.

Reduced cost of refactoring

When we have to update the join between Book and User, we only need to update one factory instead of every test that had instantiated one of the renamed join tables.

More concise tests

Although in my example I used a one liner for getting a read or wishlisted Book, in reality the syntax you’d probably see is:

user = FactoryGirl.create(:user)
book = FactoryGirl.create(:book)
FactoryGirl.create(:user_read_book, user: user, book: book)
FactoryGirl.create(:wishlist_book, user: user, book: book)

Which with the factory above could be reduced to:

user = FactoryGirl.create(:user)
book = FactoryGirl.create(:book, read_by: user, wishlisted_by: user)

This may not seem like much, but it can build up. Recently I made a similar refactoring in a spec file that contained 10 such blocks. That amounted to 20 fewer LoC or around 5% fewer LoC in the spec file. Also, had I written my factory that way originally I would had to type a hell of a lot less, too.

Here’s what my specs would look like with my updated factories:

describe '#related_books' do
  subject(:related_books) { user.related_books }

  let(:user)       { FactoryGirl.create(:user) }
  let(:other_user) { FactoryGirl.create(:user) }
  it "includes books this user has read" do
    expect(related_books).to include(FactoryGirl.create(:book, read_by: user))
  end
  it "includes books this user has added to their wishlist" do
    expect(related_books).to include(FactoryGirl.create(:book, wishlisted_by: user))
  end
  it "doesn't include books read by other users" do
    expect(related_books).not_to include(FactoryGirl.create(:book, read_by: other_user))
  end
  it "doesn't include books other users have added to their wishlist" do
    expect(related_books).not_to include(FactoryGirl.create(:book, wishlisted_by: other_user)
  end
end

Wrapping up

So using traits, transient attributes, and callbacks we can make our FactoryGirl factories do a lot more of the heavy lifting for us.

We can also abstract complex associations to reduce the cost of refactoring and increase the readability of our tests.

Although those are my favourite feature, they don’t cover everything FactoryGirl offers. I’d recommend going through the FactoryGirl documentation and thinking about what you can do to get more out of factories in your code.

 

Should my company choose RubyMotion or Swift?

Posted in Inside TFG, iOS, RubyMotion, Swift

One of the most highly debated topics at The Frontier Group over the last two years has been whether to use RubyMotion or Objective C for iOS development.

There were a tremendous amount of reasons for and against both RubyMotion and Objective C. In the end we settled on RubyMotion, reasoning that we could learn Cocoa Touch and iOS faster using Ruby than Objective-C. In hindsight, I think it was the correct decision. If you are a Ruby on Rails developer looking to make the jump to iOS, RubyMotion is a great place to start, even if you want to move to Swift later.

When Swift was announced I was intrigued. To me, Swift looked like Ruby and C# had a beautiful strongly-typed baby. Swift’s improved syntax was the push I needed to vote in favour of moving from RubyMotion.

At this point the great debate came to an end. After two awesome years with RubyMotion, The Frontier Group decided to become a Swift shop. I will outline the main factors we considered in this post. Hopefully they can assist you in your decision making process.

A note about RubyMotion

RubyMotion is production ready and extremely enjoyable to use in development of iOS applications.

I want to make something abundantly clear. RubyMotion is awesome. I have launched many apps using RubyMotion. Despite what you may have read RubyMotion is 100% production ready. You can integrate RubyMotion with Interface Builder, CoreData, and every Cocoa Touch SDK easily. RubyMotion is not some hacky workaround, it is a native solution. Apps made in RubyMotion are just as fast and responsive as their Objective-C and Swift counterparts. 

In RubyMotion I’ve successfully used many frameworks in Cocoa Touch. From custom drawing and animation, to Facebook, Twitter, maps, location services, music players, the camera and more. There is the occasional bug, but I’m yet to find one that can’t be worked around trivially.

RubyMotion has improvements and updates released every couple of months. A majority of the updates include impressive improvements to the speed of compile time and commonly used functions. I believe the latest update (2.32) reduced compile time by 40%. 

One thing you should understand – making good iOS apps is more about understanding how the user will interact with the app than it is writing code. It doesn’t matter whether you use RubyMotion or Swift if you can’t provide a good user experience.

The majority of the coding of an iOS app (I’d say 90%) is about understanding how the SDK works. So if you “master” RubyMotion over the course of a couple of years, by virtue of my previous statement you would have had to “master” Cocoa Touch. So 90% of your work is already done if you need to move over to Swift. You would just have to learn a little bit about Swift and get in the mindset of writing in a typed language.

When moving from RubyMotion to Swift I would estimate it took me two weeks to get back to full productivity. The learning curve moving to Swift was minimal, even for someone who hadn’t coded professionally in a strongly typed language. Due to my level of experience with Cocoa Touch I could get into the swing of things easily. 

So…if RubyMotion is so great, why is TFG moving away from it? Let’s have a look.

RubyMotion or Swift?

There were a couple of points that always came up when discussing whether TFG would be a RubyMotion or Swift/Objective C shop. Here’s a verbose run through of each, if you don’t have time to do heavy reading, skip to the bottom for a summary.

Learning a new language: Weakly Typed vs Strongly Typed

Your company needs to think about how the learning curve of moving to a typed language will affect your bottom line if none of your developers have experience with typed languages.

RubyMotion: At TFG, we had a high level of experience with Ruby via Ruby on Rails. So there was no time spent learning new syntax for RubyMotion. I knew all the string and array functions in Ruby, how to declare functions, and how to do sneaky things with blocks. When I started RubyMotion, I only had to learn a new framework (Cocoa Touch), rather than learning a new language (Swift), framework (Cocoa Touch), and bloated toolset (Xcode). That had a huge positive impact on my delivery time and app quality.

Swift: Moving to a strongly typed language like Swift would require some acclimation for our developers. It would open us up to lots of time spent thrashing around trying to solve basic syntax problems.

At first it felt like my hands were tied behind my back because I didn’t know how to do basic things. With Swift being a new language there isn’t the wealth of stack overflow and other posts with solutions to basic problems. I had to solve a lot of problems myself via trial and error and beta level compiler error messages. So our concerns that learning a new language would be costly were definitely warranted. There will always be teething issues when learning new languages – this is not unique to Swift.

However, if you are coming from a company with lots of experience with a typed language then you may have an easier time picking up Swift than RubyMotion. It really depends on your company’s background.

Development Environment: Xcode vs command line and text editor

Your company needs to bear in mind how its developers like to work. If nobody likes the type of environment provided by RubyMotion, they’ll hate working with it and productivity and morale will drop. On the other hand, if your developers hate using IDEs then they may prefer not to use Xcode’s development environment and may not like the idea of moving to Swift.

RubyMotion: RubyMotion apps can be completely built with just your favourite text editor and a Bash prompt. You do not need to interact with the Xcode UI directly at any stage if you don’t want to. I mentioned above you can use the IB gem to use Interface Builder if you want. I would recommend looking into it. Implementing autolayout is trivial using IB, and a serious pain to write manually with code. Although there are libraries that attempt to work around it. like MotionKit (teacup’s progeny) and the much older motion-layout.

Swift: You can use Swift without having to rely on Xcode as your primary editor.

If you don’t use storyboards or xibs, you don’t need to use Interface Builder. Interfaces can be built entirely in code. However, the API for manually writing autolayout constraints is laborious. Interface Builder does a fantastic job of implementing autolayout and it is a breeze to use after the initial learning curve.

The crux of the matter is that an aversion to using Xcode should not prevent you from looking into Swift. However, I think any iOS developer would be well served by becoming proficient in using Xcode.

Xcode is likely where you will end up if you choose Swift development. Make sure that your development team can get on board with that.

Some other things you should look at when determining how your team will enjoy the development environment:

  • Syntax of the language. Objective C was a no-go for me. Swift has a much more readable syntax. RubyMotion is even better (I love you, Ruby).
  • Availability of 3rd party plugins. RubyMotion has access to some Ruby gems AND all the Cocoapods via motion-cocoapods, Swift has access to Cocoapods).
  • Testing frameworks available. RubyMotion has MacBacon which is a fairly stripped down RSpec clone for unit testing. You have access to tools like motion-calabash for interface testing. Look at the last updated dates for those libraries, they are old and dusty. I’m not up to speed on the pimpest testing available in Swift and Xcode, so I’ll leave that topic for now. You will need to do your own research and make your own judgements. 

Development Environment: Instruments Support

RubyMotion doesn’t have the same support for Instruments that Swift does.

When I was tracking down memory leaks in RubyMotion apps I had to do it manually. The only Instruments that I could use were for checking total app memory and CPU usage. That and a combination of handily places puts statements in dealloc calls were what allowed me to solve all the memory issues I had in the cornucopia of RubyMotion apps I worked on.

If you really love tools like Instruments, Swift will win hands down. However, if you’re a “get your hands dirty” type like me, there are other ways to resolve your issues.

Development Environment: Debugging

Stack traces from RubyMotion can be pretty damn useless

I have nothing to say in favour of the stack traces RubyMotion provides. Sometimes you get a stack trace, sometimes you don’t. I’m guessing depending on which thread the process was running. When you do, sometimes the stack trace appears to be pointing to re-allocated memory and no longer has any useful information for you.

If you rely on stack traces for your debugging, RubyMotion is inferior to Swift. It never stopped me from fixing bugs, but I’m a fairly experienced developer. I think newbie devs will have a really hard time debugging RubyMotion apps. You have to know where to look for bugs.

Don’t get me wrong, for any memory issue in either language you’re going to have a hard time in the beginning.

Development Environment: REPL vs ‘REPL’

The REPL in RubyMotion allows you full access to your app – you can change views, update CoreData instances, test your classes out, and check instance variable values. The REPL in Swift is nowhere near as powerful at the moment.

RubyMotion: If you’re like me and you love to make live changes to your app to test out how font sizes will look or add data on the fly, you’re going to want to use RubyMotion.

Swift: The REPL in Swift is almost pointless to me. There were some interesting demos in the WWDC talk, but I have not been able to make it do anything useful. 

Community

RubyMotion has less conferences, user groups, and developers than Swift. Swift’s community will grow faster than RubyMotion’s.

RubyMotion: RubyMotion is relatively young, and still pretty niche. Early on we saw some big hitters like the BaseCamp app embrace RubyMotion, but RubyMotion really hasn’t become mainstream. As a result, the amount of media related to RubyMotion is quite small. One thing to keep in mind is that it will be much harder to replace RubyMotion developers than it would be to replace Swift developers (who will shortly be a dime a dozen). This could also affect things like salary, but I don’t really want to go down the supply and demand path.

Want to have a look at some of the community sources for RubyMotion? Check their official blog and the google group. You could also join the /r/rubymotion subreddit, sign up to the RubyMotion dispatch or MotionInMotion. If you’re new to RubyMotion, you should read Clay Allsop’s RubyMotion Tutorial. 

If conferences are your thing, keep an eye out for #inspect next year, as it has already come and gone for 2014.

Another note on community – RubyMotion belongs to the Ruby community. I’ve seen RubyMotion talks popping up at Ruby conferences as well, like Laurent Sansonetti doing a talk at Ruby Kaigi 2014.

Swift: Although Swift is even younger than Rubymotion, it is the new in vogue programming language for iOS and Apple approved. I think it’s a safe assumption to make that over the next couple of years Objective C developers will be making the move to Swift. There will be a lot more user groups, meetups, and conferences aimed exclusively at Swift developers than there will ever be for RubyMotion.

Apple have an official Swift blog that is updated every couple of weeks so far. As Swift is very new I can’t really point to any great sources of information yet. There are plenty out there, I just haven’t had the time to comb through them and sort the good from the bad.

If you want to talk conferences, you aren’t going to get much bigger than WWDC – follow this link to see all the talks from 2014. Lots of Swift content there.

On the other hand: There are tonnes of resources regarding iOS development that cater for both RubyMotion and Swift developers. The iOS Dev Weekly is a great newsletter to subscribe to, for example. RubyMotion developers can also learn a lot from WWDC talks about Cocoa Touch specific topics. Although they’ll have to convert the code samples from Swift.

Regarding hiring Swift and RubyMotion devs…TFG has hired Objective C developers before to work on RubyMotion projects. It didn’t go well. Developers can often be dogmatic, and I think you’ll find that some people beat the “one true language” drum a little too hard. Depending on where you live, you might not be able to find any local RubyMotion developers. If you only have one developer on RubyMotion, consider whether you can afford to have your bus factor that low.

One very important thing to keep in mind regarding community size is the number of open source contributors. Rails developers are used to standing on the backs of giants. Rails itself is open source and constantly updating. We also rely on tonnes of other gems to build our apps as efficiently as possible (for example: devise for authentication).

In small communities these gems have less people to work on them. This means gems will be updated less frequently, and will have less feedback used to fix bugs and build improvements.

Documentation

The Cocoa Touch documentation is written using Swift and Objective C samples.

All the code you’ll find in the extremely well written Apple docs is written using Swift and Objective C sample. If you’re writing Swift you can copy it into your code. In RubyMotion you will need to convert it into RubyMotion code first. This may not sound like a huge deal until you consider the how verbose some of the Cocoa Touch methods are and how often you’ll have to convert them.

This can be very difficult for RubyMotion beginners with little Cocoa Touch experience. It tripped up some of the developers at TFG early on.

Summary

RubyMotion Swift
Production ready? 100% 100%
Language Weakly Typed (variant of Ruby) Strongly Typed
Integration with Xcode and Interface Builder Good, thanks to the IB gem. Great, there’s still some missing functionality as of Xcode 6 GM (like the refactor function).
Integration with Instruments Poor, you can get basic system usage but not much more Great
Integration with Cocoa touch Good, some issues now and then Great
Debugging Average. It’s not terrible but finding memory leaks is a manual process without Instruments support Good. Stack traces are relevant. Memory issues can be tracked down using instruments
REPL Great Poor at the moment
Maintainers Small. There’s a tiny bus factor keeping RubyMotion (the toolchain) alive. If Laurent et al decide they no longer want to support RubyMotion you’re out of luck. Swift is supported by one of the wealthiest companies on the planet (Apple). After Apple adopted Objective C they proceeded to significantly upgrade it. It feels safe to assume that Swift will continuously get upgraded by Apple.
Community Small, but active Hard to say at the moment due to Swift’s recent release. If we assume it will be as big as Objective C’s – Large.
Conferences Few (#inspect being the primary, but Ruby conferences often contain RubyMotion talks) Many. WWDC has general Cocoa Touch information but primarily Swift focussed
Employment Opportunities Fewer Many
3rd party plugins Plenty of RubyMotion gems, access to CocoaPods via motion-cocoapods Access to CocoaPods
Stack Overflow posts Few for RubyMotion, lots for Objective C that need to be converted Few for Swift, lots for Objective C that need to be converted. This will change over time in favour of Swift.

Making a decision

At TFG, we looked at everything we knew about our company and developers and decided we wanted to move forward with Swift. Personally, I was very excited to learn a new language. I reasoned that knowing more languages would make me a better developer and benefit TFG. I think this has proven true in only a few short months.

There are pros and cons for both RubyMotion and Swift. As a company, you need to sit down and decide what’s important to you before moving forward with a decision. Neither choice is objectively better.

Further Reading:

Reflecting on RubyMotion Experiences – Part 1

Posted in Featured, Inside TFG, Ruby on Rails, RubyMotion

At The Frontier Group we develop native and hybrid mobile apps for both iOS and Android. I’ve been developing in RubyMotion since late 2012 and as we begin our 6th RubyMotion app at The Frontier Group, collectively having put over 3000 hours into this technology I have a couple of quick tips for fresh Rails to RubyMotion converts:

rubymotion

1: Forget everything you know about Rails

It’s tempting when you start RubyMotion to assume that since you’re vaguely familiar with MVC that you’ll be able to slap together a fairly decent iOS app. However, MVC in Cocoa Touch and MVC in Rails are completely different.

My advice: Don’t even think of controllers in Rails when you’re trying to build a controller in Cocoa Touch.

Before you start, have a couple of reads through the excellent Apple documentation on view controllers.

Another practice that tripped me up was how used I was to not having any state in Rails applications. That is, in Rails, if you get user input and you don’t need to discard it, you’re probably going to dump it in your database if you want to be able to use it somewhere.

In Cocoa Touch, and really in any client applications, state behaves a lot differently. Data plays a much different role. Persisting data is a fairly expensive operation and is usually not necessary. Many of the apps you make will just be frontends consuming an API. Keep in mind that the way you interact with data will be very different: Objects will persist beyond a single page load.rails

Another interesting idea you might want to familiarize yourselves with is that views in Cocoa Touch are first class citizens. In Rails, we tend to use the terms views and templates interchangeably. I think many Rails developers would benefit from looking up the term ViewModel. Anyway, that’s another post entirely.

In Rails, views are largely just templates. You jam data in, and out pops some markup for the user to see.

In Cocoa Touch, views are entire classes of their own, complete with state and behaviour. You can do a lot in the way of organising your system by leveraging these powerful objects. Have a read about Cocoa Touch views in Apple’s online documentation.

2: Adopt the Cocoa Touch culture

Remember when Rails started getting traction and all the PHP developers jumped over and started writing PHP in Ruby on Rails? Raw SQL everywhere, 12000 LoC controllers, and testless classes in every corner of the app.

I get the feeling that the Rails to RubyMotion expats are doing the same. One of the most egregious practices that RubyMotioners seem to be embracing is the use of snake_case. Have a look at the ProMotion library as an example. ProMotion has created a bunch of mappings between the Cocoa Touch camelCased methods and provided a snake_cased equivalent.

So instead of using Cocoa Touch’s viewDidLoad method, ProMotion wants you to use on_load.

I have a bunch of problems with this practice. Firstly: Cocoa Touch already provides a `viewDidLoad` method, complete with comprehensive documentation, and tonnes of examples available online. Good luck to a newbie developer who isn’t aware that `on_load` and `viewDidLoad` are equivalent, trying to find out how to use the method effectively.

Secondly: What does having snake_case get us here? It feels a lot like a bunch of Rails programmers refusing to let go. Ruby on its own, and in the context of Rails, uses snake_case as a standard. A standard, not a requirement. However: we aren’t working in straight Ruby, nor are we working in Rails. We’re using RubyMotion, a Ruby toolchain that communicates directly with Cocoa Touch. Cocoa Touch, of course, being a massive framework written in Obj-C that uses camelCase as a standard.

If you move to another country, you learn their language. I think it’s the same idea here. We are trying to work in the Cocoa Touch land, so we should use camelCase. Where snake_case has the only benefit of looking familiar to Rubyists and Rails devs, it has the drawbacks of forcing you to either:

Write an interface to all of Cocoa Touch that changes every single method from camelCase to having a snake_case equivalent, or
Mix and match your snake_case methods with Cocoa Touch’s camelCase method.

Both of these options are bad.

The first option requires a tonne of superfluous work that could be avoided by just adopting camelCase (just for the record – Matz won’t track you down and break your legs if you do that!).

The second option requires you to have an inconsistent interface – which is undesirable, to say the least. Consistency is key for writing easily understandable and maintainable code.

My final point on this topic: If you’re ever trying to solve a problem in your app, remember that firstly you should be looking for solutions in the context of Cocoa Touch, not RubyMotion. There are very few bugs you’ll encounter that are actually caused by RubyMotion. For the most part, it’s just going to be you using Cocoa Touch in ways it isn’t meant to be used.

3: Learn some Obj-C

Obj-C looks like the syntax was derived at random from a bag of broken glass, barbed wire, and salt. However, it’s the backbone of the framework you’re working in, so it behooves you to spend some time learning it. There are a lot of benefits, and the main one is this:

XCode

You’re frequently going to have to convert Obj-C code to RubyMotion. You’ll need to understand how Obj-C works to do this.

Here’s another – if you’re going to use CocoaPods, you’re going to need to be able to debug them. This brings me to my next point.

4: Use CocoaPods

CocoaPods is a bundler inspired dependency manager. As a Rails developer the idea should be pretty familiar to you.

CocoaPods has been around since 2011, so suffice it to say anything you need to do can probably be done by one CocoaPod or another.

Think outside the RubyMotion box. You can and should leverage CocoaPods in order to speed up the development of your apps.

Cocoa controls is a good resource for staying up to date on the latest CocoaPods.

RubyMotion’s motion-cocoapods makes using CocoaPods super simple, give it a try!

Here’s a couple of CocoaPods that will give you an idea of how useful they can be:

  • If you’ve ever tried loading remote images in to UITableViewCells, you’ve probably noticed that it can be a real pain. SDWebImage provides an easy to use interface for solving this issue, by providing both downloading and caching of remote images.
  • In client apps, you’re going to have to find a way to communicate to the user that the app is waiting for a remote service. You could spend 15 minutes writing your own loader class, or you could use the wonderful MBProgressHUD.

You can search for CocoaPods on the CocoaPods homepage.

This is the first part of a series on our experiences at The Frontier Group.

Writing a good README

Posted in Inside TFG, Tips and Tricks

What’s the problem?

As a developer, you’ll work on hundreds of different projects in your career. The biggest pain in the ass when changing projects is having to get started in a new development environment. If you’re moving to a different Rails project you have to install new Rubies and bundle – plus you might need to install Redis, Solr or jam your public key on a server somewhere. Even worse, after bundling you notice this is a Rails 2.3 project not a Rails 3.2 and you haven’t worked with Rails 2.3 for years and can’t remember how to start a server.

Then you have to work out who is in charge of this damn project and bug them to find out why your PostgreSQL is complaining about some “PostGIS” thing you’ve never heard of. Once you get that sorted you run the specs to see what shape the app is in and half your tests fail because you’re missing some `config/some_random_config.yml` file. You talk to the guy in charge of the project and he tells you to scp it from the staging environment. “But dude, how do I even get to the staging environment? What server is it on?”. Turns out it’s on an Amazon server and you need a special permissions file to be able to access it.

Imagine this process happens 12 months after anybody has ever worked on the project and the last girl to hack on the codebase has long since left the company. Your company has just lost months of her gaining knowledge that you now have to re-acquire. Knowledge that should have been documented somewhere so it wasn’t lost.

What’s the solution?

Although I did reveal the solution in the title (because I’m a bad writer, sorry) – the answer to the question is to write and maintain a comprehensive README file.

How do I write a good README?

Writing a good README is easy. You just need to know what information is required for developers to use and understand the application. Here’s some Rails-centric information I include in the READMEs I write for The Frontier Group:

README: General Information

The “General Information” section should give a new developer an idea of what the project is about and who is involved with it.

Information you might want to include is:

  • The name of the project
  • The name and contact details of the client and any 3rd party vendors
  • The names of the developers on the project
  • A brief description of the project, you should include the answer to the age-old question “What problem is this project solving?”
  • An outline of the technologies in the project. e.g.: Framework (Rails/iOS/Android/Gameboy Colour), programming language, database, ORM.
  • Links to any related projects (e.g.: Is this a Rails API that has corresponding iOS and Android clients?)
  • Links to online tools related to the application (e.g.: Links to the Basecamp project, a link to the dropbox where all the wireframes are stored, a link to the Pivotal Tracker project)

README: Getting Started

The “Getting Started” section outlines the process of getting the app installed and usable for a developer. I define ‘usable’ in this context as able to login to the application and access all of the functionality available.

Information you might want to include is:

  • A detailed spin-up process. This should include:
    • Instructions on installing any software the application is dependent on: e.g.: wkhtmltopdf, PostgreSQL, XQuartz.
    • Instructions on running the app. For rails apps you’ll want to include the rake db:create db:migrate db:seed process here, as well as instructions on starting a server (e.g. are we using pow, or just the default `rails s`)
  • A list of credentials that can be used to log in with each user type in the system and ideally the URL that a developer can log in from.
  • Any information about subdomains in the app (e.g.: api.myapp.dev/)

When writing instructions pretend you’re writing them for someone who knows next to nothing about developing in the framework/language your application uses.

README: Testing

All you need to include in the “Testing” section is the commands to run any of the test suites you have (e.g.: RSpec, Jasmine, Cucumber, Spinach) and any setup you need to do before-hand (e.g.: rake db:test:prepare). This section will be small but vital.

README: Staging and Production environments

The staging and production environment sections (one section per environment) should provide any information a developer might need to know about these environments.

Information you might want to include is:

  • Which server is the application on? Is it on Amazon Sydney? A server in the office? A data-centre down the road?
  • How can a developer connect to the server? Do they need particular permissions? Who do they need to talk to to get those permissions?
  • Where on the server is the application located
  • What is the deploy process for this server
  • Are there any other services on the box related to the app a developer will need to know about? Any cron jobs? Some Resque workers?

Maintaining the README

Worst case scenario, you don’t maintain a README. You’ll burn in developer hell, sorry.

Slightly better than that, your changes to the README will be reactive – you’ve had to work out how to install some required software and you’ve put the details of doing that in the README for future developers.

If you’re having to make reactive changes, you’re probably spending 30 minutes that another developer already had to spend working out a solution to the same problem. This equates to 30 completely wasted minutes that could have been spent implementing a feature for your client.

In an ideal world, maintaining the README is proactive and becomes part of your development life-cycle. As an example, your development life-cycle could look like this:

  1. Plan feature
  2. Write tests
  3. Implement functionality
  4. Update README if required
  5. Get code reviewed and ensure all your tests pass
  6. Merge your feature

What am I getting by writing a good README?

With a comprehensive, well-written README any developer should be able to hop on to your project and begin hacking away within 10 minutes. If you consider that over the course of developing an app you’ll likely see multiple developers set up the app multiple times, you’ll cumulatively save hours of developer time with just minutes of work.

Importantly: If you can set yourself up with this fantastic habit early, other developers will love working with you. Documentation is what separates us from the animals, ladies and gentlemen.

I recommend you invest 30 minutes of your week updating the READMEs of the projects you’re working on. You may not see any benefits straight away, but in 12-18 months time whoever has to maintain that code will be thankful you did it. Spoiler alert – that person will probably be you.

HTTP Status Codes and RESTful API crafting

Posted in Agile Development, Code, Inside TFG, Ruby on Rails, Tips and Tricks

These days there’s a lot of money in mobile applications – and where there’s money and new technologies there’s web developers primed and ready to argue about how best to implement these new technologies.

As one of this dedicated crowd I’ve found myself recently working with a lot of Rails RESTful APIs that talk to my mobile applications. This has given me the opportunity to both create my own RESTful APIs and use RESTful APIs written by other developers.

As a result, I’ve gained a much better understanding of the HTTP Status Codes and how they can help you write both better APIs and client applications.

For clarity, I use the term ‘client’ to refer to the mobile application that is communicating with the Rails RESTful API backend.

When I say API I’m referring to a Rails RESTful API.

Before I begin, here are some good sites for reading up on the HTTP Status Codes:

  1. ietf.org (Internet Engineering Task Force) RFC2616
  2. w3.org RFC2616
  3. httpstatus.es
  4. Wikipedia List of HTTP Status Codes
  5. REST Patterns HTTP Status Codes

Here’s a good article by Alex Rogriguez over at IBM from 2008 on REST APIs. If you aren’t clear on what a RESTful API actually is give Alex’s article a read.

Here’s an example on how Twitter handles HTTP Status Codes and a RESTful API

For more examples you can do a quick Google Search and you’ll find the REST API docs from Microsoft and Dropbox, among others.

Finally, for the super-keen, here’s a list of the stackoverflow questions on ‘rest’ and ‘api’ sorted by votes.

Now, back on point!

Why are Status Codes important?

The status code works hand-in-hand with the response body to help the client application process the request.

Status codes tell the client application what it needs to do with the response in general terms.

For example, if your API returns a 401 you know you need a logged in user. If the API returns a 403 you know the user you’re working with doesn’t have sufficient authorization. If the API returns a 418 you know that the API is telling you it’s a teapot and was probably written by knobs.

The response body will tell your client application in specifics what it needs to do with the response. If the client is trying to update a record and the API responds with a 400, the response body will inform the client why the request failed. On the other hand, if the API responds with a 200 the response body will provide the client with the updated entity.

That seems pretty straight forward, right? The difficulty lies in when the API returns a status code and a response body that don’t match up.

I worked with an API that returned a 200 status code but the response body had an errors array in it. That was an absolute trip – I had to parse the response body and look for the presence of content in an errors array first. Then I called an error handler from within the success callback of a jQuery ajax function. This is an example of a bad RESTful API. I hope by reading the remainder of this article you can avoid doing that.

Which status codes should I be using?

As long as you’re not too pedantic status codes are easy to work with when writing an API.

Here’s a rough guide to how I handle mine:

(For the purpose of all of the examples below, any response content I refer to will be as JSON.)

(2xx) Success Codes

200 OK

The 200 OK status code can be your go-to for any successful response. There are many success codes but for a very basic API I’ve found the 200 *can* be expressive enough. The distinction between 200 and the other success codes hasn’t proved valuable in my APIs so far.

See the IETF docs on the 200 status code.

However, some other Success Codes you might be interested in:

  1. 201 Created for when you’re creating a new resource.
  2. 202 Accepted for when you’ve successfully set the request to be performed in a background task. Useful if your client is requesting something on the API that is time-consuming and you don’t want the client to have to wait.

What should I return in the 200 response content?

The content of the response is dependent on the HTTP Method used in the request.

Quoting from the IETF RFC2616 docs:

GET an entity corresponding to the requested resource is sent in the response;
POST an entity describing or containing the result of the action;

So consider an example where you are performing a request something like:

GET api.example.com/1/users?pirate_or_developer=true

Your response JSON will look like:

[{id: 1, name: 'Jordan'}, {id:2, name: 'Guybrush'}]

This JSON should allow the client to update all the records they have that match the records provided in the response. Possibly, it will also allow the client to determine which records have been deleted and can prune its local storage accordingly.

Now, consider an example where you are updating a resource with a request like:

PUT api.example.com/1/users/1

Your response JSON will look like:

{id: 1, name: 'Jordan'}

This allows the client to update its data for the record.

(4xx) Client Error Codes

Here I’ll cover the 3 client error codes I find myself using most in my APIs:

400 Bad Request

The 400 Bad Request status indicates that the request ‘could not be understood by the server due to malformed syntax’. See the IETF docs

There is also the 422 Unprocessable Entity status code that appears to be popular for roughly the same purpose. I’ve read from a couple of sources that since the 422 is part of the WebDAV extension that 400 is preferable over 422. I don’t have the knowledge to weigh in on this argument. Perhaps someone can enlighten us in the comments section.

Some examples scenarios I’ve used an API to return a 400 for:

  1. The client is trying to create a resource with data that fails validation rules on the API
  2. The client is requesting resources using invalid params (e.g.: the date is malformed)
  3. The client request is missing fields the API requires as indicated in the thoroughly written docs! (e.g.: a search might require an end date is a start date is passed through)

What should I return in the 400 response content?

The response of a 400 will depend on why the request failed.

Likely, you’ll want to keep a consistent format across all API end-points. I nest my failure reasons in an errors attribute in the JSON.

As an example, let’s say the client request failed because the name provided was too long. The API will respond with:

{errors: {name: "must be fewer than 18 characters"}}

In fact, given this is being returned with a 400 status code, you can probably do away with the errors wrapper entirely and only return:

{name: "must be fewer than 18 characters"}

The only important thing is to be consistent across your API in how you represent these errors.

401 Unauthorized

The 401 Unauthorized status indicates that the request had missing/invalid authentication credentials. See the IETF docs.

To demonstrate the use of the 401 in an API, I’ll use one of my apps as an example.

In the client application we have a login screen for entering email/password to log in. On all other pages in the application we use token-based authentication (each request must have an token passed through that is checked by the API before performing any request). When the client successfully logs in the API passes a token back that can be persisted on the client device.

In this scenario, the API will return a 401 if:

  1. The client app attempts to authenticate a user by passing invalid username or password
  2. The client app makes a request to an action that requires authentication without providing the token (To be honest, I think this has only ever happened to me in development)
  3. The client app makes a request to an action that requires authentication providing an invalid token (For example: the user tries to log in to the client app after their user has been disabled on the API)

What should I return in the 401 response content?

I’ve found that so far I’ll just return one of:

{errors: {invalid_credentials: 'Authentication credentials provided were invalid'}}

or

{errors: {no_token: 'No authentication token was provided in request'}}

or

{errors: {invalid_token: 'Token provided was invalid'}}

403 Forbidden

The 403 Forbidden status indicates that although the request was valid the action requested failed authorization constraints. See the IETF docs.

Pretty straight forward scenario: user x tries to update resource y. User x is not authorized to update resource y.

As a note, if you are making a client where you strictly control the interactions with the API I feel that your client ever getting an authorization error is at best a code smell but more likely it’s actually just a bug.

Consider an interface that has a button that the user can interact with which returns a message like ‘You are not authorized to perform this action’. Ideally, in a mobile interface the user should never see an authorization error message since it’s not something the user can do anything to fix.

What should I return in the 401 response content?

The API will return a string with a simple error message like:

{errors: {authorization: 'You are not authorized to perform this action'}}

What about the rest of the client error status codes?

So I’ve given you the top 3 error status codes I use in a bit more detail but that’s not an exhaustive guide to the error codes. Here’s a whirlwind summary of the remaining error codes that I’ve used in my APIs:

  1. 404 Not Found for when the URL is wrong or the requested resource does not exist.
  2. 410 Gone for when the resource has been permanently (and intentionally) deleted. This informs the client application that it should remove any references to the resource in question.

Summary

I hope I’ve provided some insight into the various status codes you can leverage to create an accurate, informative API. I also hope I’ve illustrated the strong relationship between the status code and the response body and the importance of providing a descriptive response body.

If you have any thoughts or disagree with me on this let me know in the comments and we can discuss!

Thanks for reading.

Search Posts

Featured Posts

Categories

Archives

View more archives