Skip to content

Instantly share code, notes, and snippets.

@jacklynrose
Last active August 29, 2015 13:57
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jacklynrose/9409243 to your computer and use it in GitHub Desktop.
Save jacklynrose/9409243 to your computer and use it in GitHub Desktop.
Ideas on how to write RubyMotion apps the "Rails" way

RubyMotion The "Rails" Way

This is a current proposal that I'd like your feedback on for how we can clean up how we write RubyMotion applications. It's purely conceptual at the moment, and there would have to be some framework development to make this work the way described here.

Please submit your feedback, as a joint effort we can clean up our RubyMotion applications and make it easier for Rails developers to expand their skills into RubyMotion development.

Goals

The main points of this are:

  1. Find a RubyMotion project structure where parts of the projects can be related to similar Rails parts
  2. Build a framework to support this that works for both iOS and OS X
  3. Take advantage of helper libraries where possible, likely RMQ, CDQ, and/or BubbleWrap
  4. Come up with new conceptual design patterns if need be
  5. Abstract some of the differences between iOS and OS X applications

Concepts

Controllers

The difference between controllers in Rails where they handle mutliple different actions versues in iOS and OS X where controllers are focused solely on one screen/window/set of views can trip developers up a lot. I don't suggest a move to the Rails way of doing things completely, but maybe we can really focus the controller's responsibilities on bringing in model data and getting the view ready for display.

class MainViewController < RMRailsController::Base
  view MainView
  delegate MainDelegate
  stylesheet MainStylesheet
  
  def setup
    delegate.data[:posts] = Post.all
  end
end

In this setup, view will create an instance of MainView in the loadView method and assign it to self.view, and style it using the stylesheet assigned with stylesheet. The view would then have it's delegate assigned to be an instance of the class assigned by delegate. The delegate would basically act like the JavaScript in a web application handling interaction, of course some helpers would need to be provided for being able to access to controllers things happen in so that it doesn't have to hold references to it.

In the setup method would go the kinds of things you would find in index, show, or any of the other Rails controller method defintions, though data would have to be assigned to the delegate so that it has access to it.

This setup reflects basic Rails app structures:

  • Controller = Controller
  • View = View (already well defined)
  • Stylesheet = Stylesheet (already well defined)
  • Delegate = Scripts
  • Model = Model (already well defined)

Delegates

class MainDelegate < RMRailsDelegate::Base
  def myView(myView, viewForSomePostition:position)
    SectionView.style do |v|
      v.title = self.data[:posts][position].title
      v.content = self.data[:posts][position].content
    end
  end
  
  def myView(myView, sectionSelectedAtPosition:position)
    navigate_to(DetailViewController, post: self.data[:posts][position])
  end
end

Further Ideas

This is just early days for this so far, I'd love to hear your ideas. Currently the proposed solution would likely only handle VERY simple applications, and would likely have trouble working well on OS X too. Please share your thoughts.

@colinta
Copy link

colinta commented Mar 7, 2014

This is, indeed, a very different direction from what I've been taking these days, as far as wrappers and controller design are concerned. I see a lot of "ProMotion"-style ideas in here, but I think ProMotion remains more similar to plain Cocoa code.

And while OSX is VERY similar, it also has a feeling of being VERY different. It's a much older system, lots of legacy there. Hard to describe why/how, but it's a different beast, so heads up there.

Anyway, my worry in taking this approach - and it's just a worry, I'm not saying it can't be done! - is that by making the controller more "rails" like you could inadvertently put up an impediment to learning the CocoaTouch frameworks. ProMotion gets dangerously close to this line, but like I said I think it leans towards behaving much like a plain UIViewController.

On a positive note, there is a huge advantage to having a more "rails like" system, just for familiarity if nothing else. But something like this was attempted long ago, with the "Three20" project, which was ultimately abandoned. It had a Router and things to make the app feel "web server like", but in the end people banged their heads against it in frustration and gave up on it.

So I would approach the problem like this:

  • start with a simple Rails blog; browse and detail actions.
  • on iOS this would probably be a screen with a UITableView to browse, and then a detail screen.
  • what are the "actors" in the rails app? not the classes, but the things that do work. That would be the router, middleware, the index method, the Blog model, the template, and any javascript on the front end.
  • now, where are those actors on iOS?

Models are models, and views are pretty much views, but that index method that fetches the list of blogs? That doesn't belong in a view-controller! You should use a Storage class for that, which keeps your controller light and testable.

I propose that the JavaScript code on a webpage is the actor that is most similar to a UIViewController. It deals with state changes in much the same way a UIViewController does.

I don't have a conclusion per se, but I hope these ramblings are helpful! Take em with a grain of salt; it's just MY take on things. 😃

@kemiller
Copy link

kemiller commented Mar 7, 2014

Thanks for starting the converstation! My two bits:

They key factors that made rails rails were, in no particular order:

  1. Convention over configuration.
  2. Tight top-to-bottom integration.
  3. Sensible defaults.
  4. Scaffolding. (Ease of getting started and "demoability".)
  5. Pragmatic. Avoidance of "architecture astronautics" and a willingness to let implementation details leak through abstractions.

Native Cocoa is ok at 4, but only if you use XCode, arguably somewhat OK at 2, and absolutely terrible at the rest. RM just inherits that legacy, by default, minus XCode. We've collectively started on 1 and 3, RMQ/CDQ at least do some of 4, and ProMotion is aiming at 2, at least, and probably all 5. But we could definitely use at least one framework that hits all of them.

The particulars of M, V, and C are less important. I agree with Colin and would rather see terminology/behavior that streamlines, but is fundamentally compatible with Cocoa, if for no other reason than that when people go out looking for help, they're still going to find a lot of Objective C examples, and it'll go better if there's not an extra mental translation they have to do. iOS/mobile is really different from the web, despite there being some analogous pieces, and I'd aim to help smooth the transition, rather than attempt to pretend it's not there...

@kemiller
Copy link

kemiller commented Mar 7, 2014

Also, modules are probably better, so you can take advantage of all the specialized controllers and views out there. When I have a little more time I can make some specific examples...

@jacklynrose
Copy link
Author

@colinta I definitely share the concern of making it too hard to access the Cocoa/Cocoa Touch side of things, I guess I didn't express though that things like RMRailsController::Base wouldn't completely abstract everything away, it would be fairly lightweight and just be a subclass of UIViewController/NSWindowController, and you could define the viewDidLoad methods and such as normal.

On the topic of Three20, I want to avoid the "make it web-server like" path, and just make it easier to mentally define what an object relates to in Rails, vs actually making it exactly like Rails, no need for a router or other actors, it doesn't make sense outside of web servers.

@kemiller convention over configuration is something I had in mind, but hadn't thought through too much on how it would surface in the code, but @andyjeffries had a great point of making that view, delegate, and stylesheet stuff something like that where there is a sensible default from naming conventions.

I have an idea, but would like to know exactly what you're thinking, could you elaborate further on points 2 and 5?

@jacklynrose
Copy link
Author

I've coded up a VERY quick example using the idea @colinta put forward of creating a blogging app. So not even close to production ready, but it's a good starting point.

https://github.com/FluffyJack/RMRailsBlog

@jacklynrose
Copy link
Author

I've implemented the basics and started a gem, except no navigate_to yet, just what we're talking about above, so everything can be included as modules if need be, and there is some convention over configuration stuff.

https://github.com/FluffyJack/motion-momentum
https://rubygems.org/gems/motion-momentum

@neerajsingh0101
Copy link

When I started learning RubyMotion the biggest change was understanding MVC in RubyMotion world. We use the same terminology in Rails world but MVC in RubyMotion has much different meaning.

I guess a good video/resource explaining the responsibilities of controller in RubyMotion world will help a bit.

Overall I like the direction of https://github.com/FluffyJack/RMRailsBlog . Nice work.

@twerth
Copy link

twerth commented Mar 11, 2014

What Ken and Colin said makes sense to me.

Some random thoughts:

I would not do OS X and iOS, that seems like you'd have to dive to the lowest common denominator. IMO do iOS, then fork OS X later.

I think you can get a lot of what Rails originally had by just choosing the libraries, sensible defaults, and generators.

I personally don't see a problem with how controllers and views are in the SDK. For Rails developers, they just need to be educated a little. When I'm teaching people, once I explain how controllers and views are different from Rails they "get" it pretty fast. I wish they were named "screens" and "controls" which would remove some of the confusion, as they are not analogous.

Modules are nice if you want to separate your behavior from your controller. Some people also like to separate their layouts from their stylesheets or controllers. People like to get fancy with their libraries, but really classes and modules can do a lot.

@wndxlori
Copy link

Ok, I'll put in my 2 cents worth. (And thanks to all for the thoughtful commentary thus far)

Web development vs mobile development vs desktop development are different enough to make me resist trying to find a "one framework fits all" solution. I've worked in all these areas over the years, and they really are different.

That said, the power of the Rails way remains very enticing. But we need to think about the reasons that Rails is so appealing. Now @kemiller broke it all down quite nicely, but let me sum it back up.

Rails is popular and powerful because it is OPINIONATED. There is "one true way" (sort of, I'll get back to that) to put Rails web apps together, using the supported bits and pieces. And, for better or worse, that is the way the majority of people build apps using Rails. Over time, those bits and pieces have changed, as new (perhaps) better ways of doing stuff are found. But at any one time, you could do a "rails new app", and generate a scaffold, and have a functional app up and running in very short order.

Even though there is "one true way", Steve Klabnick's article on the "two default stacks" demonstrates the flexibility of the Rails way, while pointing out that a second default stack exists, and is almost as opinionated as the first one:
http://words.steveklabnik.com/rails-has-two-default-stacks

So, IMO, what RubyMotion is lacking at the moment, is this well defined, relatively complete, opinionated stack. Or even two stacks. Something that is built right in to the "motion create" command, that lays out a nice set of gems that can be used to build a basic app, maybe even with some scaffolding.

I know all the creators of all the awesome gems we are using will now be getting nervous (will my precious be picked?), but I think there is room for all of the options, as long as we remain as flexible and pluggable as Rails has become. But I'd really like to see an opinionated stack emerge as the default. And I think the iOS stack will be different than the OSX stack.

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