We’ve been building Briquette at Bearded1 on and off since December 2010. When beginning the project, we chose to use MacRuby as a way to make the project more accessible to our developers that weren’t familiar with Objective-C, and to explore a possible future of native Mac OS X (and iOS) development.
For building new Mac apps, I would recommend MacRuby without hesitation. It delivers on the promise of bringing the best aspects of Ruby to native, desktop app development. Abstracting away from Objective-C’s sometimes-too-verbose syntax is often a joy, and it’s useful to have access to the complete library of both Cocoa frameworks and Ruby gems2. It’s a young framework that’s getting better by the day, and the good has consistently outweighed the bad.
But there are drawbacks, especially when using Xcode heavily. I want to touch on some areas that I feel have often been ignored, or covered inadequately, and pour a little cold water on the heads of anyone starting a MacRuby project. But just a little.
Objective-C: It’s Not Optional
One of our goals in choosing MacRuby was to simplify the learning process for developers with minimal experience with Objective-C and Apple’s frameworks. In practice, though, one can’t get by with zero knowledge of Cocoa APIs before diving into the Ruby wrapper.
Cocoa is a verbose framework. It’s actually one of the things I find most attractive about it. Xcode does everything it can to enhance the experience of coding with excellent method suggestions and code completion for Objective-C, but is unable to help in Ruby files. This lack of help, coupled with the need to have a grasp of delegates, actions, outlets, and XIBs/Interface Builder, makes MacRuby more difficult for someone coming from a purely Ruby background.
Deployment in the Walled Garden
Submitting to the Mac App Store can be a complicated process, even when using only vanilla frameworks. MacRuby (and Apple) have made this a moving target, whether it’s Xcode’s failure to sign binaries, MacRuby embedding itself incorrectly, or other build inconsistencies.
With Xcode 4.1, our current process is this:
- Archive project with Xcode
- Export archive from Xcode’s organizer
- Embed MacRuby’s framework and compile the Ruby code from the command line
- Manually code-sign app
- Manually build installer package and submit with Application Loader
This process has actually gotten more complex over time, and it’s unclear where the fault lies in that. Initially, all building, embedding and compiling took place via Xcode actions, but over time, each step has broken down.
If you’re having any issues deploying, feel free to ping me on Twitter. It might be the subject of an upcoming blog post.
Blindly Debugging
Let’s look at an issue I just had to track down in the production build of Briquette.
1
| |
That’s not a great error message: rb_main.rb is the root Ruby file of a MacRuby application, and the interpreter (in)correctly catches errors there. Maybe the stack trace will help more…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | |
That narrows it down a little more. I can at least identify that it’s coming from my Room.rb model (lines 8-10). Better, but not great. The .rbo file extension is a compiled Ruby file, and as expected, being compiled wasn’t its life goal. It’s currently difficult to get good debugging symbols out of compiled Ruby, and the alternative — shipping uncompiled code — is a scary prospect3.
Even while developing, your tools will be limited. You can’t pause your application and step through Ruby code, since the built-in debugger isn’t designed to work with an interpreted language. The working solution is to use the tried-and-true print statement to query application state: effective, but far less valuable than Xcode’s advanced debugging (and profiling) tools.
At RubyConf this past weekend, @brixen’s talk about Nikita and Ruby tools included a great quip:
Ruby has the best tools
Debugging Ruby has never been a pleasurable experience, and it’s no different here. Hopefully future updates to MacRuby can address this with better Xcode integration.
Memory, or a Lack Thereof
@briquetteapp I like you but are you sure you need this much memory? d.pr/tggu
@briquetteapp Any upcoming changes around the memory consumption issue? It’s bad here: http://t.co/ay015aI
Tell me about it, guys. No, we certainly don’t need all that memory. Honestly, we’re still trying to track this one down, though we’ve squashed quite a few bugs recently. The crux of the issue is that when profiling, as with debugging, we can’t use standard tools to examine what objects our application is leaking. Instruments, Apple’s profiling tool, isn’t aware of Ruby objects and considers them all leaks, making it difficult to extract real data.
The other potential snag is that using MacRuby forces you to require garbage collection in your application. Apple’s garbage collector is lacking, and not all Cocoa frameworks are garbage collection safe. Xcode 4.1, with the new LLVM compiler, does an excellent job of tracking down the latter issue in Cocoa libraries, but determining the source of leaks otherwise is nearly impossible.
Our memory issues could be due to our use of Webkit4, bugs in Apple’s garbage collector, leaks in MacRuby itself, or bad design in our Ruby code. There’s just no easy way to find out. I can say with certainty that MacRuby claims ~70-100MB of RAM per process. Where does the rest of it go? We’ll let you know.
Well That Sounds Awful
It’s not.
No really, it isn’t.
This isn’t a condemnation of MacRuby or its effectiveness as a framework. As a developer mapping my Ruby knowledge onto my Objective-C and Cocoa experience, I found some surprises along the way. I do want new MacRuby developers to be informed about potential pitfalls, and be ready for whatever challenges come their way. Despite the setbacks, MacRuby enabled us to rapidly prototype and iterate on an idea, and easily build and submit it to the App Store.
-
Bearded is where I work. It’ll be on the “About” page once that’s live, but if you’re impatient, check out the great work of all the Beardeds at http://bearded.com.↩
-
Some gems won’t work quite right. As MacRuby is an implementation distinct from the standard MRI Ruby, compatability issues can arise.↩
-
You can certainly ship a MacRuby app with uncompiled Ruby files, but it exposes any Ruby source code used by your application. See? Petrifying!↩
-
Seriously, Webkit is a bad citizen. Have you used Safari lately?↩