Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
DRAFT: RubyMotion first impressions

Title: RubyMotion first impressions

For the last couple of days I've been playing with RubyMotion, Laurent Sansonetti's amazing new toolchain that allows developers to write fully-fledged, native Cocoa apps for iOS using MacRuby. Having seen some of what the MacRuby community is doing with it, heard what guys like Marco Arment and John Siracusa have to say about it, and having cut myself on some of its rough edges, it feels like a good time to stop and take down some first impressions.

What I like

While it's true RubyMotion isn't that much less of a black box than Xcode — in that it's still a proprietary framework that slurps in code and spits out either errors or a working iOS app — being able to configure and build a project using only a Ruby Rakefile feels much simpler and nicer.

RubyMotion's configuration DSL is simple and task-oriented, and effectively does a job that in Xcode is spread across six or seven (or more?) different .plist files or project settings. Need to add a framework or static library? In Xcode, you need to open up your project, then click a button, then search for the framework you want, then click another couple of buttons, then #import it in your code. In RubyMotion, you just add framework to an array called frameworks. I call that a win.

The project configuration also emphasizes practical needs over implementation details. To wit: it is so much easier to add custom, embedded fonts to a RubyMotion project — you just add TTF or OTF files to your resources folder and it Just Works, just like any other resource.

What's uncertain

I haven't spent enough time actually writing RubyMotion code to know whether Ruby is actually a better medium for developing Cocoa apps — if it really is removing or obviating complexity, or just hiding it.

One thing that makes me more comfortable with RM than with a higher-level framework like (say) PhoneGap is that RubyMotion isn't trying to replace Cocoa. In fact, many Ruby developers might end up frustrated with RubyMotion because the code they'd write is more accurately "Cocoa with Ruby-like syntax" than "Ruby". To me, this is a feature. Because it's not a framework, RubyMotion is less vulnerable to Apple making disruptive changes or cutting off support for some vital dependency. RubyMotion code compiles to native Objective-C/LLVM bytecode, and uses Apple's own frameworks directly.

But on the other hand, Apple's done a lot in the last few years to sand down Objective-C's rough edges. ARC has (largely) obviated the need for manual memory management, and the latest versions of the compiler and runtime have made it easier to write apps without a lot of dumb boilerplate code. We even have object literals now, for chrissakes.

Given that, what is RubyMotion actually doing to help make me more productive? Well, it's easier to work with instance variables and properties. Classes are easier to define, in that they don't need separate header files and interfaces. You never need to #import anything — in fact, require isn't available in MacRuby. In short, things require less code in RubyMotion than in Xcode and Objective-C. And, to be fair, there are also things you can do in RubyMotion, like working with Ruby blocks or metaprogramming techniques, that can't be done in Objective-C at all.

But this comes at a cost: not having Xcode means not having comprehensive code completion, which comes in handy in a framework where method signatures can run to dozens (or hundreds) of characters. It means not having a static analyzer or debugger (at least, not yet). Having header files means Xcode can help you detect syntax errors in your own APIs; obviously, lacking both headers and Xcode, RubyMotion can't. Finally, while you can use Interface Builder or the Core Data modeling tools in a RubyMotion project, it's not easy, and (for the latter, at least) requires you to also have an Xcode project around in order to create or edit those resources, which you're then responsible for compiling and copying into your project.

Many of these things may be due to RubyMotion being a very new 1.0 product, and creator Laurent Sansonetti may roll out improvements or workarounds in the coming months. And it seems possible that the overall productivity gain of being able to write concise, flexible Ruby code in your text editor of choice more than pays for what's been sacrificed. But is that better, or just different? It's too early for me to tell.

What's ugly

Marco Arment and John Siracusa both talked about RubyMotion on their 5by5 shows this week, and were generally negative. In particular, Marco seems to be of the opinion that RubyMotion developers are trying to avoid learning or understanding Objective-C, but they'd be happier in the long run if they did, not least because then they wouldn't have a huge dependency on an experimental third-party runtime that may not be around a year or two from now.

As someone who knows Cocoa/Objective-C and is interested in RubyMotion, at first I took offense at Marco's knee-jerk assumption that RubyMotionists (as one dude has already started calling them) are just looking for an easy way out. But then I look at many of the blog posts and code samples, and the absence (as far as I can tell) of experienced Cocoa people from the nascent community. And then I think it's possible Marco's absolutely right — that most RubyMotion developers are web folks trying to get out of working with a less pure, "uglier" language, and I am just an outlier.

To wit: there are a lot of people making DSLs or wrappers on top of Core Data, to make them more like ActiveModel or some other persistence framework they're familiar with from Ruby. I understand the appeal, and there are probably many ways to automate the Core Data happy-path to make one more productive. But trying to turn Core Data into ActiveRecord totally misses the point of why Core Data exists, if not some crucial differences between native app and web development. Core Data's value is in managing whole object graphs in memory, and keeping them in sync with a local data store. Calling Object#save makes sense if all you're managing is a single row of a database table, but Core Data's concerned with entire data sets. Trying to ignore Core Data's complexity is, most often, also ignoring its power.

Some of these libraries even try to do some DataMapper-like schema building in Ruby, which is awesome, but overlooks a huge Core Data constraint: managed object models created in code most often can't ever be migrated. That is, you can replace one model with a totally different one, and write a bunch of custom code to move objects from one model to the other when your app launches for the first time after a schema change, but the benefits of Apple's "lightweight migration" (which handles small, incremental changes totally automatically) are lost to you forever. I appreciate the appeal of defining schemas in Ruby instead of the Xcode modeling UI — I might even prefer it. It's just not a smart approach if you want to keep your app maintainable over the long term. But perhaps you have to have used Core Data in its native, Objective-C environment to know that.

What comes next

All that being said, I'm still intrigued. RubyMotion's configuration and build processes are so much nicer than Xcode, and so far I've been able to find workarounds for the worst rough edges. For example, I buckled down and created an Xcode project for the sole purpose of managing my Core Data models, which I can then compile and load from my project's Rakefile.

My plan right now is to go ahead and write my next iOS app in RubyMotion, starting in the next couple of weeks. I'm going to begin with a simple, feature-limited, ugly-UI prototype that I can load onto my phone and use to iterate on the design. I'll report on my progress here and on Twitter, and together we'll see how it goes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment