Blog Archives

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 2

Posted in Code, Inside TFG, iOS, RubyMotion, Tips and Tricks

As part two of our series, Tony Issakov offers a few thoughts when developing on RubyMotion.

rubymotion

Whilst I spend a lot of time in a management role, I’m a developer at heart that cannot stop developing. Here’s a few things that I’ve come across in the RubyMotion space that may be of use.

1: Know the code you are building on

RubyMotion is a relatively young space that is filling quickly with enthusiastic Ruby developers. New gems are coming out regularly to carry over what we know from our native Ruby world and also to make new iOS capabilities more comfortable to access.

One thing to be aware of is that being a new space there are some fairly fresh pieces of code being integrated into common use and some of them haven’t had much time to mature. For this reason I suggest taking a moment to get to know the gems you are about to use.Octocat

Just as with any code, Github gives us a good place to start, checking out the most recent commit activity, the scale of the issues and hopefully checking that there’s a test suite. Whilst testing isn’t as fully fledged for RubyMotion, an attempt to test is a great start.

Reviewing how code is written has also been very informative. If you want to get some diverse exposure, start looking through BubbleWrap, the ever growing mixed bag of RubyMotion functionality. You can see anything from how to leverage the Camera through to observers with the Notification Centre. It gave me some ideas as a ruby developer of what iOS topics I needed to start researching.

2: Memory Matters

One major change moving into the RubyMotion space from a Rails one is that it’s no longer a stateless environment, pages aren’t a regularly discarded entity and what you do over time can mean something. If you don’t know about reference counting in iOS and the commonly mentioned ARC, it’s worth doing a little homework to understand what RubyMotion is doing for you. Apple provides some documentation explaining memory management, here.

One example of why it’s good to know this is I hit a show stopping moment when I started attaching view content from an 3rd party framework to my own controller objects using instance variables. The external library counted on the releasing of those objects as the app moved through multiple sessions and I was inadvertently retaining them. This ended up in some interesting crashes and the word ‘release’ is a real give away.

A protip here (offered initially to me by Jordan Maguire) was to leverage the dealloc method. If you override a class’s dealloc method, clear up your instance variables, put in a bit of logging whilst you are there and then call out to super, in theory your RubyMotion console should give you a bit of feedback that your app is being healthy about releasing it’s memory.

Another key object to figure out for this topic is WeakRef.

The need for WeakRefs comes up when you start passing delegates around and begin to form cyclic references which if not handled well, can in the least cause memory leaks. Wrapping an object in a WeakRef object gives you a programmatic way of ensuring you release an object and again look to the console for that dealloc feedback.

3: Think ‘Performance’

One of the major benefits of RubyMotion is taking a lot of ruby ideas for making code easy to write. One catch is that a lot of layers of abstraction can create the opportunity for a performance hit.

We saw this first hand when first trying gems like Teacup (a gem for layout and styling). When the gem was pretty young, people using it noticed their apps start to grind and scrolling through tables suffered a stutter. This came down to doing things in a programmatic but performance expensive way when styling table cells. From what I’ve seen many of these issues have been resolved and that has come down to both gem improvements and better patterns for developers applying code in a performance friendly way.

One paragraph that really stuck in my head on this topic was reading through the Queries section of the CDQ gem README. CDQ is a slick Core Data helper and the paragraph reads:

Core Data is designed to work efficiently when you hang on to references to specific objects and use them as you would any in-memory object, letting Core Data handle your memory usage for you. If you’re coming from a server-side rails background, this can be pretty hard to get used to, but this is a very different environment.

This sums up my very first moments of walking into RubyMotion from rails which was iOS persistence is handle by Core Data therefore Core Data equals ActiveRecord. We keep pushing the point but it’s not that Core Data isn’t ActiveRecord, its that things like persistence and what it means to each environment are very different.

4: IDE is not a bad word

Vim versus Emacs? How much finger twister can you play to do fairly amazing things with your editor? I’ve been sucked into this a few times over the years and will admit I find myself in the vim space largely because it was the editor I was raised on. In recent times I followed the Textmate to Sublime migration too. For a time though I found myself in the Java community working with IBM’s Application Developer and that’s where I came to terms with what an IDE is.

When I started to explore RubyMotion and got sucked into the “What editors can I use next?” game, I dabbled with RubyMine and was a little surprised. IDEs for me in the past have meant memory bloat and user interface lag but the JetBrains guys have done a great job optimising resource usage and letting you customise behavior.

Ruby_on_Rails_IDE____JetBrains_RubyMine

Why bring this up for RubyMotion? For many who are looking for some form of visual assistance, a nice refactoring capability, a debugger that is interactive, a spec runner that is visual, this might be a good tool for you to consider to give you a safety-net as you develop. This is absolutely not for everyone but I generally take all the help I can get and regularly swap back and forth between command line and visual tools depending on the task at hand.

5: The simulator is not the device

The iOS simulator is rather amazing in what it offers. A highly performant version of the device that you can swap between device types, screens, resolutions and even simulate events with. With all this it does lure you into believing it’ll be an effortless trip to the device but we found there are a few catches.

The first was that sometimes the simulator outperformed the phone and this is due to the simulator having the full resources of the host available to it. A few of our animations that were smooth on the simulator stuttered slightly and it was during a series of changes that it occurred.iOS_Simulator_User_Guide__About_iOS_Simulator

Another situation was when using external Objective C libraries, it’s possible for the library to have different branches of code depending on the environment meaning that the code you run in the simulator is not necessarily the code you will run on the device. In one extreme case we actually needed to set some custom build flags for the app to even compile for the device.

So the recommendation here is run on the device and frequently enough that if the app has some unusual explosion you aren’t left wondering which of the many gems you just added or commits you just made has cause the issue.

RubyMotion: Under the hood

Posted in Code, iOS, RubyMotion, Tips and Tricks

Some time ago I was working on a RubyMotion app and was called over to look at a colleague’s screen only to find an amazing visual.

Just as Firefox jumped on to the scene with a 3D view of a web page, the team at RevealApp presented to me an exploded view of one of our RubyMotion iOS apps. 3D rotation of many wired frame borders and the ability to click through the views to review settings was amazing. Since then a few new players have come along so here’s a quick recap of how you might see what’s going on under the hood.

1: SugarCube

https://github.com/rubymotion/sugarcube

As a very light weight entrant to the field, SugarCube is a RubyMotion gem that provides a lot of syntactic sugar and utility methods. It includes a nice little command called ‘tree’. This was one of the first mechanisms I ever used in gaining insight into how my app was being put together and is still a bit of a reflex when digging around in the console.

This means of seeing the UI structure in code might be a little harder to interpret at first but it’s nice that without any other frameworks or apps you can see what’s going on.

1__bundled_rake_BUILD_ENV_development_frank_symbiote__sim_

So to sum it up, it’s a console tool with a super easy install and requiring no external software to review the results. This is a great place to start debugging your views.

2: Motion Xray

https://github.com/colinta/motion-xray

Stepping up the visual feedback is Motion Xray. This is the only gem I haven’t personally used but I’ve included it as it’s purpose is to get insight into the current view of the app, in the app itself.

This brings a great level of portability as there’s no need for bridging between external software and internal frameworks. It’s all just in the app. It does make me a little nervous that to view my view code I’m changing my view code but I can see the niche that this plugin aims to fill.

motion-xray

3: Frank and Symbiote

http://www.testingwithfrank.com/

This one really surprised me. Working with Frank is something we’ve been dabbling with for years and it’s definitely growing on me as I feel the need to gain more confidence in how my user interface is behaving. In the past I’ve used the calabash console to help me understand how to access view components for my tests but I recently stumbled on Symbiote which is part of Frank.

Frank opens up a communications gateway for sending tests to the device or simulator and Symbiote piggy backs this getting a full view of what the interface looks like on demand. This in itself is impressive but it then renders that out to a webpage with an interactive console.

This tool is tailored towards making writing tests easier but I loved that it was a means of seeing my app state with just a browser on the side. My experience with it so far has been limited but there is definite potential.

Check out this article (Inspect the State of Your Running iOS App’s UI With Symbiote – Pete Hodgson) for a really great overview of this.

Frank is very easy to install, and so in turn was Symbiote.

Symbiote

4: Reveal App

http://revealapp.com/

This is where the excitement began and at the fully fledged highly visual editor end of the spectrum. A separate app is run to do all the viewing and editing. A framework gets included in your app to open up a bridge for communication (much like Frank).

I found in the early beta stages when I was heavily using this, there were occasional connection issues. The framework broadcasts its presence via Bonjour so you should see your device or simulator appear in the list of possible connections. This type of connection process (when it worked) was nice and simple when moving between device and simulator as there were no config files or settings to worry about.

Once in the app with your screen wire framed and ready for editing, the ability to see and change things is phenomenal. Anyone who is used to tweaking the visuals of a web page at a browser console will feel right at home with this kind of tool. Nudging UI by pixels, changing colouring, messing with opacity. All of these are ready to go.

The only downside to this product has been it’s final price. The licensing is not cheap but so far in my experience this is by far the most powerful tool of its kind.

Reveal_App

5: Spark Inspector

http://sparkinspector.com/

After loving Reveal App I took a quick moment to see what else was out in this space and was stunned to find another contender. Spark Inspector at this time feels like a lighter weight version of Reveal. It’s not as fully loaded with features and modifiable fields but it does have a lot of the key parts like a very visual 2D and 3D representation of your app.

I found that the cocoapod installed without any issues, the connections worked first time and generally this was actually a little easier to get going than my early RevealApp experience. The main area of weakness at this time is that not everything is as easy to access and edit as I found in Reveal. It does feel like you can get a little out of sync with the remote UI and it has a few more general quirks as you modify values.

The major redeeming factor to this is it’s price. At time of writing Reveal cost a bit over four times the price of Spark Inspector so if you find Reveal is out of your budgetary league, this may be an alternative.

Spark_Inspector_and_Spark_Inspector_-_Runtime_Inspection_for_iOS_Apps

6: iOS Hierarchy Viewer

https://github.com/glock45/iOS-Hierarchy-Viewer

As a last minute entrant I was really impressed to stumble over this git repo that looks to be doing things a lot like Symbiote using a web page as the external viewing tool. Looking over the Readme it feels like the install will be harder to get through than Spark or Reveal but there’s a cocoapod and it turned out to be rather painless.

The UI is raw in appearance but comprehensive in details. It feels very much like an insight into the state of the UI rather than the editable side that Reveal gives you.

One surprised was the Core Data addition which with an additional line of code gives you a quick view of the state of your data. Having recently been using cdq I tested this and it worked just as expected showing me a table of my data. This is a very interesting addition putting that little bit more at your finger tips but the lack of edit on the views does make this app more about insight than nudging visuals into place.

In Summary

It’s wonderful to see such a diverse set of tools becoming available to developers. Between a RubyMotion console and the many tools on offer, a developer can get a quick understanding of the visual architecture they are working within and even nudge it in the right direction before making a final change. Given we at times rely on the default apple controls and views it’s also good to understand exactly why things are placed where they are or how many views really do make up a button.

As I was writing this article I found this stack overflow thread covering this topic and picking up pretty much all of the above mentioned tools so if you are looking to hear how some others have found these tools, this may be a place to start.

Also as one closing pro-tip – don’t run too many of these together as not surprisingly my app got a little unstable when spinning up the simulator and multiple apps all tried to start up servers and broadcast messages. Also keep in mind that running the specs instance of a RubyMotion app might clash with your main app if you are swapping back and forth.  If things start to misbehave you might need to restart your simulator or close down apps that are in the background.

If you know of any other apps that haven’t been discussed, let us know.

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.

Let’s Talk About RubyMotion

Posted in Code, Inside TFG, iPhone, RubyMotion

We’ve just launched Take5 Feedback and its mobile app. This is the fourth mobile app that The Frontier Group has launched, that I’ve worked on.

Previously, we had been using a combination of PhoneGap and SpineJS. This helped us get into the iOS market while still using tools we were familiar with as web developers. After releasing a few apps using PhoneGap and SpineJS, we found that we were consistently spending time during app development fixing things like scrolling, tap events propagating to other views and transition animations. This coupled with the less-than-fantastic debugging tools made us feel that perhaps we needed to re-evaluate our technology choices.

This time we decided to kick it up a notch by moving to RubyMotion. (Bam!).

For those who haven’t heard about RubyMotion, it’s a library that lets you write native iOS apps in Ruby which is then compiled down into Objective-C. As most of us at The Frontier Group are Ruby developers, this felt like a technology well worth exploring. After working with it for a few months, I think it’s the way to go for us moving forward. Now, let’s talk a little about RubyMotion.

Off the bat, one of the big advantages of RubyMotion is that you’re writing native apps in Ruby and not in Objective-C. I’ve found that Objective-C is not an intuitive language and certainly nowhere near as readable as Ruby (especially when method chaining looks like array declaration shudders). One thing RubyMotion has ported over from Objective-C that I do like is the named parameter which makes method declaration/invocation much more readable. For example, let’s say I have a method that generates a receipt and takes a the date of the purchase and the amount in cents as parameters.

In regular Ruby it would be declared something like this:

def generate_receipt date, amount
  # Do something...
end

Now this method could conceivably be called like this:

square = generate_receipt('3/3/2013', 100)

In RubyMotion, however, using named parameters the same declaration/invocation looks like this:

def generateReceiptForDate date, andAmount: amount
  # Do something...
end
square = generateReceiptForDate('3/3/2013', andAmount: amount)

As you can see, it gives the parameters passed in more meaning during the method invocation. Now most Rubyists won’t call methods with “magic numbers/strings” and you can achieve the same thing in < Ruby 2.0 by accepting a hash but I think this is a nice little addition.

Next I’d like to discuss generating and organizing views. MVC in iOS is a little different from MVC in Ruby on Rails, in that views are a little more tightly coupled to the controller. View elements are ultimately defined and positioned in the controller. Those elements will rely on methods which should be defined in the controller as they deal with event handling and navigation. Let’s take a simple example. I want a screen to have a table and when I tap a row I want to navigate to another screen.

class ExampleController < UIViewController

  REUSE_IDENTIFIER = 'example'

  TABLE_FRAME = CGRectMake(0,0,300,400)
  TABLE_ROW_HEIGHT = 30

  def viewDidLoad
    @data = [1,2,3,4]
    table = UITableView.alloc.initWithFrame(TABLE_FRAME)
    table.delegate = self
    table.dataSource = self
    table.rowHeight = TABLE_ROW_HEIGHT
    self.addSubview table
  end

  def tableView(tableView, cellForRowAtIndexPath: indexPath)
    cell = tableView.dequeueReusableCellWithIdentifier(@reuseIdentifier)
    cell ||= UITableCell.alloc.initWithStyle(UITableViewCellStyleDefault,
    reuseIdentifier: REUSE_IDENTIFIER)
    cell.textLabel.text = @data[indexPath.row]
    cell
  end

  def tableView(tableView, didSelectRowAtIndexPath:indexPath)
    tableView.deselectRowAtIndexPath(indexPath, animated: true)
    self.navigationController.pushViewController(AnotherController.new, animated: true)
  end

  def tableView(tableView, numberOfRowsInSection: section)
    @data.count
  end
end

As you can see we’ve got a mix of view level logic (positioning the table on the screen and defining what a row will look like) and controller level logic (setting the data source and the navigational behavior). This makes views and controllers coupled a little tighter than you might be used to. This can lead to extremely fat controllers when you have many elements on the screen each with its own position, look, feel and event handlers. A pattern I found that has worked for me is to have a subclass of a UIView that is responsible for drawing all the elements on a given screen. Let look at an example.

Let’s start by creating our own UIView where we define our table and its look and feel.

class ExampleView < UIView

  TABLE_FRAME = CGRectMake(0,0,300,400)
  TABLE_ROW_HEIGHT = 30

  attr_accessible :table

  def initWithFrame frame
    super
    setupTable
    self
  end

  private

  def setupTable
    @table = UITableView.alloc.initWithFrame(TABLE_FRAME)
    @table.rowHeight = TABLE_ROW_HEIGHT
    self.addSubview @table
  end

end

class ExampleController < UIViewController

  REUSE_IDENTIFIER = 'example'

  def viewDidLoad
    @data = [1,2,3,4]
    self.view = ExampleView.alloc.initWithFrame(view.frame)
    self.view.table.delegate = self
    self.view.table.dataSource = self
  end

  def tableView(tableView, cellForRowAtIndexPath: indexPath)
    cell = tableView.dequeueReusableCellWithIdentifier(@reuseIdentifier)
    cell ||= UITableCell.alloc.initWithStyle(UITableViewCellStyleDefault,
    reuseIdentifier: REUSE_IDENTIFIER)
    cell.textLabel.text = @data[indexPath.row]
    cell
  end

  def tableView(tableView, didSelectRowAtIndexPath:indexPath)
    tableView.deselectRowAtIndexPath(indexPath, animated: true)
    self.navigationController.pushViewController(AnotherController.new, animated: true)
  end

  def tableView(tableView, numberOfRowsInSection: section)
    @data.count
  end

end

Ok so now the responsibility for drawing the table (and any other element) is localized to the ExampleView class and the data manipulation and navigation logic is in the controller which is looking better. We can neaten this up further by making the view responsible for assigning delegates.

Let’s start by creating a new parent view that stores an object which will be the delegate for all elements within the view. In this example the delegate is the ExampleController.

class UIViewWithDelegate < UIView

  attr_accessor :controllerDelegate

  def initWithFrame(frame, andDelegate: delegate)
    self.initWithFrame(frame)
    self.controllerDelegate = delegate
    self
  end

end

Now that we have this class our ExampleView class can inherit from it, allowing the ExampleView to set the delegates for any elements inside it.

class ExampleView < UIViewWithDelegate

  TABLE_FRAME = CGRectMake(0,0,300,400)
  TABLE_ROW_HEIGHT = 30

  attr_accessible :table

  def initWithFrame(frame, andDelegate: delegate)
    super
    setupTable
    self
  end

  private

  def setupTable
    table = UITableView.alloc.initWithFrame(TABLE_FRAME)
    table.delegate = self.controllerDelegate
    table.dataSource = self.controllerDelegate
    self.addSubview table
  end

end

class ExampleController < UIViewController

  REUSE_IDENTIFIER = 'example'

  def viewDidLoad
    @data = [1,2,3,4]
    self.view = ExampleView.alloc.initWithFrame(view.frame)
  end

  def tableView(tableView, cellForRowAtIndexPath: indexPath)
    cell = tableView.dequeueReusableCellWithIdentifier(@reuseIdentifier)
    cell ||= UITableCell.alloc.initWithStyle(UITableViewCellStyleDefault,
    reuseIdentifier: REUSE_IDENTIFIER)
    cell.textLabel.text = @data[indexPath.row]
    cell
  end

  def tableView(tableView, didSelectRowAtIndexPath:indexPath)
    tableView.deselectRowAtIndexPath(indexPath, animated: true)
    self.navigationController.pushViewController(AnotherController.new, animated: true)
  end

  def tableView(tableView, numberOfRowsInSection: section)
    @data.count
  end

end

This has separated the view and controller logic out a little more and our controller is a little thinner. This becomes more useful as the number of elements on your screen increases. The one drawback I found was that my views were ending up with walls of constants defining positions, fonts, etc. Creating subclasses for individual elements that include the position/look/feel, would solve the problem, however you’ll end up with a lot of singleton classes.

Now a little on automated testing. Automated testing is generally a big part of any of the applications we develop. This time however, I found the experience to be so much more costly than testing in a Rails world. When I started developing the app I was aiming for the level of automated coverage we have in our Rails environments. As I attempted to achieve this, I kept hitting road blocks with either the testing framework not behaving as expected, or the mocking libraries placing a significant impact on the code being tested. After some discussion, we decided that due to the simplicity of this app we could achieve an acceptable level of quality and coverage by manual user testing. From this experience though we now know areas that can be improved and are currently developing our skills and tools to ensure that as our apps increase in complexity, we are able to ensure our code quality.

I could write so much more about RubyMotion and the different technical challenges I faced during the development process, but I really just wanted to give my overall impressions. I think it’s a good choice for any Rubyist wanting to venture in iOS development. In combination with the Apple developer docs, which are fantastic, it lets you learn the iOS framework while programming in a language that you’re comfortable with. It’s a well maintained library with the RubyMotion team making constant improvements. My only real criticisms are with the testing and debugging tools not feeling as flexible and as powerful as I’m used to in the Rails environment, but like I’ve said, these tools are being continually developed and improved, and have no doubt these tools will get better with time.

Search Posts

Featured Posts

Categories

Archives

View more archives