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