RubyMotion

TDDing iOS Apps for fun and profit with RubyMotion

TDDing iOS Apps for fun and profit with RubyMotion

by Brian Sam-Bodden

The video titled 'TDDing iOS Apps for Fun and Profit with RubyMotion,' presented by Brian Sam-Bodden at RailsConf 2013, explores the use of RubyMotion as an alternative approach to iOS app development, particularly for developers comfortable with Ruby and Test-Driven Development (TDD).

Key Points Discussed:
- Introduction to Brian Sam-Bodden and his background in programming, emphasizing his struggles with traditional iOS development environments like Xcode and Objective-C.
- The allure of RubyMotion, a Ruby-based toolchain for developing iOS applications that simplifies the process by leveraging Ruby's flexible syntax and dynamic typing. RubyMotion helps bridge the gap for Rubyists looking to venture into iOS app development.
- A comparison between traditional iOS programming approaches and the RubyMotion experience, highlighting the pleasantness of working with Ruby's style versus the complexity of Xcode.
- TDD and BDD methodologies in RubyMotion: Brian emphasizes the significance of testing in the development cycle and points out a culture of limited testing in native iOS apps. RubyMotion's TDD capabilities are illustrated through practical examples and demos, showcasing how to test models and controllers.
- A live coding demonstration where Brian builds a simple iOS app named 'Okona,' showcasing how to integrate RubyMotion with TDD practices. During this demo, he highlights various examples of testing and how failures lead to discoveries about both RubyMotion and iOS APIs.
- Tools and libraries utilized in development, such as MacBacon for testing and MotionModel for managing local storage. The discussion underscores the expanding ecosystem of gems available for RubyMotion.
- Concludes with encouragement for Ruby developers to embrace RubyMotion as a viable and exciting way to develop native iOS apps. He shares resources, reminds viewers of the RubyMotion's affordability, and invites them to check out sample code on GitHub.
- Ultimately, Brian delivers an optimistic message about the accessibility of iOS development for Rubyists, empowering them to explore and create rich mobile applications without the steep learning curve typically associated with Objective-C and Xcode.

Takeaways:
- RubyMotion provides a smoother, more integrated development experience for Ruby developers venturing into iOS application creation.
- Emphasizing TDD not only enhances the reliability of applications but also aids in deeper learning of new tools and languages like RubyMotion.
- There is a growing community and resource availability around RubyMotion which supports developers transitioning from web development to iOS development.

00:00:16.560 All right, hello everybody! I'm Brian Sam-Bodden and first of all, smile. All right, so um.
00:00:25.519 Whoa! I'm here to talk about RubyMotion, and I titled this talk 'TDD in iOS Apps for Fun and Profit with RubyMotion.' The profit part hasn't arrived yet; I'm working on that, but I'm having a lot of fun with it.
00:00:30.640 Let me tell you a little bit about me. I'm not from Portland. Actually, this is awesome to be the last session of the conference. I hope you enjoyed the conference. I had a great time, and I hope to see you next year.
00:00:42.440 I am a longtime programmer and have gone through pretty much every language you can think of. I started with Lisp, which lasted about three months before we ran out of money, and then I ended up doing Java for a long time. In 2005, I met DHH here at OSCON.
00:01:08.000 I was talking about a clone of Rails, and he promptly made fun of me. Fast forward a year later, I was running my own Rails company. What do you know? I live in Phoenix. I'm not in the witness protection program, which seems to be the tendency in Phoenix.
00:01:36.880 I want to start with some confessions: I'm an Apple fanboy. There should be no reason a 41-year-old man has a white leather case on his iPhone. But you know, I've been paying that price willingly.
00:01:54.799 I work with Ruby every day; we're a Rails consultancy, and we do TDD (Test Driven Development) for our clients, using agile practices—the whole shebang. Before that, I used to do desktop applications back in the 90s with Borland Delphi. Do you guys remember that? Remember 4GLs?
00:02:28.480 I really wanted to create iPhone and iPad applications, but Apple wants you to use Xcode. And Xcode took me back in time to those Delphi and Visual Basic days; it felt pretty retro.
00:02:54.560 I tried it, but I just couldn’t get myself to go back to that mode of operation—basically dragging and clicking and connecting things with dropdowns. It just didn't feel right; it felt like a complex environment where there was no flow.
00:03:13.480 Everything about it slowed me down. Trying to do simple things typically resulted in me actually restarting the application from scratch.
00:03:24.560 Then there's Objective-C. I know there's a lot of people who really like the language, but for me, I’ve done C, C++, and Java. It felt like a weird combination of some good things that turned out pretty bad, like a Rosemary's Baby version of a programming language.
00:03:44.920 So I tried it, but I couldn’t do it. Then I heard about something called RubyMotion. Actually, let me rewind a little bit. I found MacRuby because I wanted to create beautiful apps on the desktop for the Mac, so I started playing with MacRuby, which is a Ruby interpreter for the Mac.
00:04:05.720 I built upon Objective-C, but luckily somebody else did that work, not me. However, there were a lot of constraints that iOS imposes which would not allow you to build an iOS app with MacRuby.
00:04:31.680 Therefore, someone created RubyMotion, which you can think of as a fork of MacRuby that deals with the restrictions imposed by iOS on the environment.
00:04:48.479 RubyMotion is a commercial product, but it is relatively cheap at $199. If you stick with me till the end of the session, I’ll give you a surprise slide.
00:05:10.039 The source is available, but not all of it; there are some parts hidden from the public. However, there are contributors doing open-source work for RubyMotion. A lot of gems and DSLs are appearing to help us deal with the sometimes complex nature of iOS development.
00:05:41.680 They’ve titled it a Ruby-based toolchain for iOS. It is based on MacRuby but targets iOS, compiling and creating binary artifacts that you can send to the App Store and sell.
00:06:05.920 RubyMotion was created by Lawrence Santini—I'm probably mispronouncing his name, but I'm sure he'll be okay with it. He worked at Apple for seven years, focusing on iLife and OS X, so he knows the environment well. He was also a Rubyist on the side.
00:06:40.360 MacRuby came out of his effort, as well as a few other people. His gripe was that Xcode just isn’t a good environment for dealing with MacRuby.
00:06:52.760 When I was playing with MacRuby, I was using TextMate or Vim, because I didn't like Xcode either. Xcode appears complex and beautiful initially, but after a couple of hours of struggling with it, it just didn't work for me.
00:07:06.360 So who is RubyMotion's target audience? It’s really for us. If you are an expert in Xcode, Objective-C, and iOS development, you will probably laugh at RubyMotion because it's a language you may not understand, following processes you are not used to.
00:07:30.560 One of the things I started doing when I began working with iOS was trying to determine how they do their test-driven development, and they barely test at all. It seems testing has devolved into user testing and throwing things over the fence for luck, reminiscent of the old QA Department approach.
00:08:05.439 I can’t work that way anymore; it’s been too long since I adopted better habits. So, RubyMotion is aimed at Rubyists who might not know iOS at all.
00:08:20.400 That was me; I started learning the iOS APIs through the lens of RubyMotion. Web developers should feel pretty comfortable with RubyMotion since it provides a Rails-like development experience.
00:08:45.560 You’ll see that we have models, views, and controllers, and there are gems that provide APIs to make each of these MVC stack areas more digestible. Also, you can use whatever shell you prefer to work in.
00:09:03.760 You can write tests, fail them, pass them, and progress along your design and development process in that way. So TDD (Test-Driven Development) and BDD (Behavior-Driven Development) complement RubyMotion.
00:09:24.480 It might not be as fluid and agile as a modern Rails application yet, as we've evolved our processes over the years, but we are getting there.
00:09:50.360 My goal for this session was to prove to myself that I could practice TDD with a RubyMotion app. So let's jump a little off-track for a second. An obvious question comes up: why not just build a web application?
00:10:11.560 Users still get this tactile responsiveness from native applications that they don’t seem to achieve from HTML5 web apps. I'm not going to spend too much time on this, but I left a few graphs you can take a look at.
00:10:52.000 I think that to hit the market, having an HTML5 application is quite good, but learn how your users interact with your application. Eventually, you might want to target a native application if your domain requires it.
00:11:15.200 If you're dealing with gaming or using any of the hardware devices on the phone, you probably want to go native.
00:11:32.480 Now, let's do our first example: a Hello World in French. I hope that's right! I'm going to show you a quick slide about RubyMotion, which is encapsulated in the motion command.
00:11:48.320 Using the motion command, which is reminiscent of the Rails command, you can create your applications. In this simple example, I'm creating a Hello World application.
00:12:05.680 RubyMotion also supports rapid development. As you create a RubyMotion application, there are a set of Rake tasks available for different purposes.
00:12:34.560 You can build for specific devices, for the simulator, and run your tests. In most cases, you'll use Rake to run the application live and RSpec to actually execute your tests.
00:12:53.680 Those are typically the two commands I use throughout the day while building iOS apps. So, I have a cheat sheet for my demo, and I have the simulator right on screen.
00:13:15.480 The first thing I’m going to do is show you the version of RubyMotion that I’m running, and then I'm going to create my first RubyMotion application.
00:13:53.920 But if I run the right command, it's rapidly going to fail because I'm not in the directory of my application. This is that moment as a presenter where you're like 'Oops!' So, let me cd into the directory.
00:14:12.200 This application does nothing at this point, but as you can see, it launched the application on the simulator. If I exit out of the application, you can see that the icon for the app has been created.
00:14:34.000 The only problem is that it doesn’t have a single view, so you end up with a blank screen. Now, let me run it one more time—notice that my console is now sitting at a prompt.
00:14:57.760 That’s the REPL (Read-Eval-Print Loop) of RubyMotion, which is like the IRB or Rails console. That became my experimental lab to learn about iOS.
00:15:14.440 You know what the number one method you call on a class you don't know? It's often to figure out what methods are available! Typically, I started digging into the iOS APIs through the console, experimenting with different options.
00:15:41.280 The nice thing about the console is that whatever you do there reflects live on the simulator. So, let me take some of my examples and show you what’s going on.
00:16:07.679 The first thing you notice is that the 'self' object is 'main,' just like in many interpreters. I'm going to create something called an alert.
00:16:28.599 An alert is essentially a UIAlertView. It’s one of the iOS classes we use to create pop-up dialogues. I’m going to set some values including a title and a message.
00:16:50.720 Now I can go ahead and show my alert! And that’s the cool thing about it: yay! One dialogue on an iPhone app—awesome!
00:17:03.760 I know it looks simplistic, but having that feedback loop allowed me to actually learn iOS. I’m not an expert by any stretch of the imagination, but it has helped me to delve into something that once felt so foreign.
00:17:24.160 I can also dismiss that alert so it's a pretty simple environment to learn about iOS. If you're a Ruby developer and you've been wanting to learn about iOS, to me, this is the best vehicle you could find.
00:17:53.760 And it's only $199, so let’s go back to the slides for a moment. Again, that’s my primary reason to love RubyMotion: it's the REPL—that console allows you to explore the RubyMotion and iOS APIs.
00:18:20.320 RubyMotion essentially creates a thin wrapper around all of the classes available in iOS, similar to how JRuby and MacRuby operate. The REPL was what initially drew me into this platform.
00:18:52.480 You can interact with the running iOS application, learning and discovering along the way. Now, let me tell you about my second reason to like RubyMotion: bacon! Who doesn’t like bacon?
00:19:14.320 In particular, RubyMotion uses something called MacBacon, which is a small clone of RSpec. It's not completely syntax-wise a 1:1 match with RSpec, but it’s the framework we'll use for BDD and TDD with RubyMotion.
00:19:35.320 Here’s a little slice of MacBacon: you'll see that you have a describe block with a string indicating the context. Then you have before blocks like in most BDD frameworks.
00:20:01.360 You have your 'it' examples, so for example, an array should be empty or should not include certain things. There’s more fluid API chaining similar to RSpec.
00:20:22.280 Now, RubyMotion TDD highlights for the upcoming demo include that all testing is done with the red-green-refactor cycle for iOS.
00:20:40.440 Sometimes, this isn't as easy as it sounds. The RubyMotion environment is meant to test units; the largest unit you can test is a controller.
00:21:07.760 If you’re testing transitions from one controller to another, you need to go with something outside RubyMotion—like Cucumber. There are a few products out there that function similarly.
00:21:30.400 I'm using two libraries for this demo: MotionModel—an ActiveRecord-like clone for iOS applications using a simple local storage mechanism—and FormMotion, which implements a simple form for iOS.
00:21:51.840 I’m a fairly lazy developer, so I look for ways to declare a model and then create a form for data input in the app. I'm using both libraries combined for the demo.
00:22:16.760 There are now likely hundreds of gems available, covering everything from 2D gaming to handling various hardware devices on the phone.
00:22:37.240 Let’s take a look at the second demo. I have an application called 'Okona,' which according to Google Translate means 'done.' But I’m not sure if it means completed with a task or just done as in a mistake.
00:23:02.920 The application is on GitHub, so if you get a copy of RubyMotion, you can grab it and play with it. This is what it looks like.
00:23:28.880 I'm using a get presenter, which allows me to fast forward through my commits. Notice how I have a large list of commits; I'm going to show you the initial commit.
00:23:55.440 By default, a new RubyMotion application has pretty much nothing—it includes an application delegate, which is your entry point into the iOS stack.
00:24:16.360 From there, you wire up your controllers, views, and models to present something to the user. The only test it includes checks for the presence of a window.
00:24:43.440 Now, I’ll run those tests, and you’ll see that I have a failed test. I believe Lauren intended for people to start at the red state of TDD and then start building the application from there.
00:25:06.920 But most examples I've found follow the iOS mantra: not testing or testing after the fact. If you have a powerful environment like Ruby and Rails, I think you should use it for TDD.
00:25:32.880 Now let me move forward to my first passing test. My first test says that I should have a window. I'm trying to pass the built-in test that comes with RubyMotion.
00:25:57.680 To do that, I just added a window inside the delegate. You can see some syntactical things that may look foreign to a Rubyist. For example, the word 'alloc' means to allocate memory.
00:26:21.080 You might remember 'malloc' from C and C++. In this case, I’m creating an instance variable called window and initializing it to fill the entire screen.
00:26:47.200 If I run my application now, you will see that it's still a blank screen, but it has one window—it’s just blank.
00:27:10.680 Now I’ll fast forward; this is a to-do application. I was aiming to build a simple list of to-dos with a due date and a boolean indicating if they are completed.
00:27:31.840 So I'm going to fast forward to my first failing test for real functionality—commit number five—which tests if it displays the given to-dos.
00:27:52.680 Let’s go to number five and run my test; I should see the test fail. Ignore the stack trace.
00:28:14.000 Now, with TDD, one of the challenges for newcomers is where to start. Sometimes you might try to start with something too complex.
00:28:37.360 With RubyMotion development, I decided to test something simple, like whether the to-do controller exists. Even if it’s a silly test, it’s a start.
00:28:55.960 Typically, I add a test stating the to-dos controller should exist. The original application test, which checks for the presence of one window, is now passing.
00:29:12.320 However, my test for displaying the given to-dos is still failing. Let’s now fast forward to the next commit where I implement the minimal code needed to pass that test.
00:29:32.080 For that, I actually used the console to learn how to show a table of data on an iOS application.
00:29:48.600 It turns out, there's a UI Table View, and that's where I started exploring. This exploration process involved digging into the APIs through the console.
00:30:05.920 You’ll see memory errors as you experiment, but eventually, you flesh it out to understand and build an app.
00:30:22.640 Let me show you the code to pass that test. I’m going to make it smaller.
00:30:44.640 I have my window as before, then I'm creating a table—which is a UI Table View. My table view also takes up the full width and height of the screen.
00:31:03.440 I created a simple array of items I should buy for my pantry. Then I created a data source object that the table view will use to get its data.
00:31:21.120 Notice that I'm implementing two methods here: number of rows in section and cell for row at index path. This will allow the table to ask how many elements it contains.
00:31:41.680 This is a good stopping point to discuss the weird syntax you're seeing. First, notice that there is a lot of camel case, which is different from the snake case we're used to in Ruby.
00:32:02.240 The methods are direct translations from the Objective-C signature. Objective-C has a concept of pseudo-named parameters, which Ruby 2.0 would have with named parameters.
00:32:22.720 In this case, the cell for row at index path method has a colon for index path, representing one of those named parameters.
00:32:43.440 For most people, it might seem like you're overwriting the same method, but in reality, it’s a completely different signature, and the RubyMotion interpreter handles it.
00:33:04.520 So, within my to-do data source, there's an array called data. When the table views ask for data, it will return a UITableViewCell.
00:33:26.360 This all comes from exploration through the console. I’ll run the test to show you where we’re at.
00:33:50.240 Now we have a clean passing set of specs. If we run the application, it’s not very exciting right now, but I have a table of data, and believe me, when I got to this point, I felt accomplished.
00:34:07.760 I was thrilled to have built an iOS application, feeling like I was mastering my domain. Give me a couple of weeks, and I’ll be rich!
00:34:36.400 Now, let me show you something exciting. If I run the tests, RubyMotion executes them and creates an application that represents the state of those tests at that moment.
00:35:02.760 So, running this again, it executes one swift test. But, if you have a comprehensive suite, when you click this application, it allows you to save snapshots of it, producing artifacts of your test suite.
00:35:26.720 I think that’s pretty cool—it's kind of like seeing a capybara running through a website, clarifying the path of behavior in your application.
00:35:41.760 Now that you've seen the TDD cycle with iOS and RubyMotion, let’s fast forward to a few later commits.
00:35:55.800 I’ll show you my development with FormMotion. Let me go to commit number 26.
00:36:12.480 Unfortunately, things get compiled—we're talking about object linking and embedding, processes we forget about while using Ruby.
00:36:31.680 With this framework, I've fleshed out my test suite to be a bit more comprehensive, now featuring a to-do controller, and my model.
00:36:50.320 Initially, I wanted the simplest possible failure—ensuring the model exists in the first place. I'm also checking that it provides names, descriptions, due dates, and validates them.
00:37:08.480 Now I can check to see if the to-dos controller shows the correct label for a given to-do. Let me quickly show you how that test looks.
00:37:25.680 I heard clapping, which means time is up—but let me finish. Here’s my to-do spec, which outlines a very simple model object.
00:37:47.840 And here’s my extended to-do controller spec—let me run this so you can see what we have so far, and then I’ll move quickly to the final commit.
00:38:02.760 Notice that I've started learning various aspects of iOS from the warning messages that appear in the console.
00:38:19.040 Even though I have practically every iOS book in print, I’ve only read snippets of each. Yet, this environment has been the best for learning.
00:38:36.560 Now I have a model backed by local storage for all my to-dos, and I'm using a FormMotion to provide a simple form, shown here.
00:38:55.760 Now, let me fast forward to my last commit to show you how it ended up.
00:39:18.720 There are 34 commits in total. It has been a fantastic experience building this example for the presentation. I learned a lot, clarifying things I thought I knew.
00:39:35.760 Here’s the final specification set—it’s compiling now, and I can see that it's coming.
00:39:50.640 The only problem with RubyMotion during presentations is that compiling time can be considerable. But now I have a slightly more complex test suite.
00:40:10.680 Now let me run the final version of my 'Okona' application. Notice I added decorations and a new button for creating to-dos.
00:40:27.760 It’s now more complete than before. When I save my new to-do, it gets placed at the bottom of the list—perhaps I should adjust it to appear at the top instead.
00:40:45.640 If I modify an existing item, it should reflect that.
00:41:02.240 Oh, what happened? I broke it! Well, that’s the reality of live coding.
00:41:18.360 But again, iOS is no longer a frontier too far for a Rubyist to travel to. I feel pretty comfortable with the environment now.
00:41:36.760 The syntax might be different, but the moment I come across a class I don't understand, I see many examples written in Objective-C that now translate directly to RubyMotion after just a few months of work.
00:41:58.360 It’s a viable avenue for building cool iOS apps. Let me show you some resources.
00:42:16.920 There’s a plethora of wrappers available for nearly everything you need for RubyMotion and iOS development.
00:42:41.000 Basecamp for iPhone is built on RubyMotion, combining some Rails components and a RubyMotion app.
00:43:05.040 Furthermore, numerous beautiful applications are built using RubyMotion—like apps tailored for the London subway, helping users find where to go and when trains arrive.
00:43:25.720 I didn’t have time to polish my example, but that’s probably the next step for me. Send me an email, and Lauren will give you a 15% discount on RubyMotion.
00:43:52.600 So do the math—about $14.
00:44:06.680 All the sample code is on my GitHub repository. I’m also planning to gather my experiences into an ebook about building RubyMotion applications in various genres, including games.
00:44:25.680 Any questions? Alright, well, thank you very much!