Kill the Controllers
Kill the Controllers
A terrible great way refactor large applications.
Yes, there are models, fetched and
created by the controller
Yes, views, too. The controller makes
em!
API Queries, UI, an...
State
API
Models
Views
Layout
Storage
Controller
API
Models
Views
Controller
MVC?
MVC?❌
MQVLCS
Storage
Controller
Layout
View
Query
Model
wat
credit: LimeCoconutShake from www.skyblock.net
The benefits are many!
• Classes focus on one task
• Controllers don’t “do it all”
• Less code bloat all around
• Testable...
– Colin T.A. Gray
“Don’t quote me on any of that.”
• Layout?
• Storage? WTF is that?
• Models & Queries?It’s your call.
Again, up to you.
There’s a gem for that. ;-)
credit: Gant Laborde
• Animations
• Events
• Styles
• Imagine a controller and a view
got together and had an adorable
love child
• Move your U...
• Support for iOS and OS X
• Support for CALayer, NSMenu
• Frame and AutoLayout DSLs
• Add your own helpers just by
defini...
class LoginLayout < MK::Layout # or < MK::WindowLayout
# or < MK::MenuLayout
view :username_field
view :submit_button # @l...
def login_label_style
initial do # only apply when views are created
text 'Login'
backgroundColor UIColor.clearColor
font ...
# separate method to work with controller.topLayoutGuide
def add_constraints(controller)
constraints(self.view) do
origin ...
MotionKit Extensions
def label_style
frame from_top(:container, width: 200)
frame below(:button)
frame left_of(:other_labe...
MotionKit Extensions
Constraints
def label_style
constraints do
left.equals(:superview, :left).plus(8)
right.equals(:butto...
MotionKit Extensions
NSMenu
class MainMenu < MK::Menu
def layout
add 'File' do
add 'Open', action: 'open:', key: 'o'
add '...
MotionKit Extensions
def label_style
autoresizing_mask :pin_to_top
layer do
backgroundColor UIColor.blackColor.CGColor
end...
shadow_color UIColor.colorWithRed(0.133, green: 0.133, blue: 0.133)
text_color UIColor.colorWithRed(0.6, green: 0.6, blue:...
shadow_color '#222222'
text_color '#999999'
font 'Avenir-Medium', size: 20
line_break_mode :word_wrap
text_alignment :cent...
MotionKit::Events
Decouple your UI events
class LoginLayout < MK::Layout
def login_button_style
target.on :touch do
trigge...
Roadmap
• View Layout helpers
• Spec helpers
• Layouts (e.g. Linear flow)
• Tutorials
• Screencasts
• Documentation
– Colin T.A. Gray
“Oh yeah, Jamon I forgot to tell you.”
class LoginLayout < MK::Layout
view :username_field
view :submit_button
def layout
add Android::Widget::LinearLayout, :log...
Kill the Controllers!
• Controllers should do the minimum
amount of “paper pushing”
• UI and animations → Layout
• Talking...
DEMO
Example of a LoginController written with
Storage and Layout classes.
You can see some similar code here:
github.com/...
Colin T.A. Gray
Community Manager at HipByte
Engineer at Jukely
github.com/colinta
github.com/rubymotion/motion-kit
gem in...
Upcoming SlideShare
Loading in …5
×

Kill the Controllers, and an introduction to MotionKit

2,186 views

Published on

This presentation is in two parts. The first part goes over how I refactored the Jukely app to have better separation of concerns by breaking up the controller into a "Storage" (aka Adapter, Repository) class and a "Layout" class. This technique worked very well for me, and resulted in cleaner code, more testable classes, and controllers that were easy to understand.

I also present MotionKit, which is a gem that is designed to fulfill that "Layout" role. You can design and update your views very easily using MotionKit, and it can be used on iOS, OS X, and we already have Android support on the way!

MotionKit was written by me and Jamon Holmgren.

Published in: Software
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,186
On SlideShare
0
From Embeds
0
Number of Embeds
170
Actions
Shares
0
Downloads
8
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide
  • These ideas are used throughout programming
    Think of Sandi Metz’ “rules for developers” applied to a controller
    I was a skeptic, but came to this style working on Jukely, and it’s been great
  • These ideas are used throughout programming
    Think of Sandi Metz’ “rules for developers” applied to a controller
    I was a skeptic, but came to this style working on Jukely, and it’s been great
  • We used Parse for the Models and Queries
    UILabels and UIButtons for views
    So where does everything else go?
  • Ends up looking like this
    After refactoring, we can get to this situation
    Also not, Layout between C & V, and “Storage aka Adapter” between C & M
  • MVC doesn’t provide enough “buckets”
    Introducing: Meh kuh Vulcs
  • MVC doesn’t provide enough “buckets”
    Introducing: Meh kuh Vulcs
  • MVC doesn’t provide enough “buckets”
    Introducing: Meh kuh Vulcs
  • MVC doesn’t provide enough “buckets”
    Introducing: Meh kuh Vulcs
  • “Don’t quote me on any of that.”
  • Layouts are not just “styling code dumping grounds”.
    Share knowledge with the controller
    Animations, events, and of course styles
  • Multiple platform support
    Helpers can target any class
    AutoLayout DSL has been really popular
    Easy to add your own, or create a motion-kit-gem
  • Extend the MK::Layout class (or menu or window).
    Ideally you WON’T need to create accessor methods
    Code inside the block acts on the “current context”
  • Not really as much magic as you might think, other than the delegation stuff.
  • Check the README, it’s current the best source of information, and READMORE.md for some interesting information.

    “Oh yeah, Jamon I forgot to tell you.”
  • “Speaking of a team of laser guided fly swatters…”
  • Kill the Controllers, and an introduction to MotionKit

    1. 1. Kill the Controllers
    2. 2. Kill the Controllers A terrible great way refactor large applications.
    3. 3. Yes, there are models, fetched and created by the controller Yes, views, too. The controller makes em! API Queries, UI, animations, network availability, login status, UI events, ticket purchasing, Facebook login, caching, scrolling updates, image downloading and processing, search filters, recommendations, notifications, sharing…
    4. 4. State API Models Views Layout Storage Controller API Models Views Controller
    5. 5. MVC?
    6. 6. MVC?❌
    7. 7. MQVLCS
    8. 8. Storage Controller Layout View Query Model
    9. 9. wat credit: LimeCoconutShake from www.skyblock.net
    10. 10. The benefits are many! • Classes focus on one task • Controllers don’t “do it all” • Less code bloat all around • Testable controllers • Easier to add new features • Easier to read and understand
    11. 11. – Colin T.A. Gray “Don’t quote me on any of that.”
    12. 12. • Layout? • Storage? WTF is that? • Models & Queries?It’s your call. Again, up to you. There’s a gem for that. ;-)
    13. 13. credit: Gant Laborde
    14. 14. • Animations • Events • Styles • Imagine a controller and a view got together and had an adorable love child • Move your UI code out of your controller:
    15. 15. • Support for iOS and OS X • Support for CALayer, NSMenu • Frame and AutoLayout DSLs • Add your own helpers just by defining a class
    16. 16. class LoginLayout < MK::Layout # or < MK::WindowLayout # or < MK::MenuLayout view :username_field view :submit_button # @layout.submit_button def layout background_color UIColor.blackColor add UILabel, :login_label add UIView, :login_container do add UITextField, :username_field add UIButton, :submit_button end end end
    17. 17. def login_label_style initial do # only apply when views are created text 'Login' backgroundColor UIColor.clearColor font UIFont.boldSystemFontOfSize(40) textAlignment UITextAlignmentCenter layer do shadowRadius 20 shadowOpacity 0.5 masksToBounds false end constraints do width('100%') center_x.equals(:superview) end end end
    18. 18. # separate method to work with controller.topLayoutGuide def add_constraints(controller) constraints(self.view) do origin [0, 0] width.equals(:superview) height.equals(:superview) end constraints(:login_label) do below(controller.topLayoutGuide).plus(50) # define top_margin: 50 # below(controller.topLayoutGuide).plus(:top_margin) end end
    19. 19. MotionKit Extensions def label_style frame from_top(:container, width: 200) frame below(:button) frame left_of(:other_label) x 0 y 0 right 320 bottom '100% - 8' end Frames
    20. 20. MotionKit Extensions Constraints def label_style constraints do left.equals(:superview, :left).plus(8) right.equals(:button, :left).minus(8) top_left.equals(:superview) height.is <= 100 end end
    21. 21. MotionKit Extensions NSMenu class MainMenu < MK::Menu def layout add 'File' do add 'Open', action: 'open:', key: 'o' add 'Close', action: 'close:', key: 'w' add 'Foo', :foo_menu add 'Bar', :bar_menu do add 'Baz' end end end end
    22. 22. MotionKit Extensions def label_style autoresizing_mask :pin_to_top layer do backgroundColor UIColor.blackColor.CGColor end title 'Send' title 'Done', state: UIControlStateDisabled portrait do frame [[0, 0], [100, 100]] end landscape do frame [[20, 0], [140, 100]] end end
    23. 23. shadow_color UIColor.colorWithRed(0.133, green: 0.133, blue: 0.133) text_color UIColor.colorWithRed(0.6, green: 0.6, blue: 0.6) font UIFont.fontWithName(‘Avenir-Medium’, size: 20) line_break_mode UILineBreakModeWordWrap text_alignment NSTextAlignmentCenter baseline_adjustment UIBaselineAdjustmentNone SweetKit Uses SugarCube methods to turn this…
    24. 24. shadow_color '#222222' text_color '#999999' font 'Avenir-Medium', size: 20 line_break_mode :word_wrap text_alignment :center baseline_adjustment :none SweetKit …into this!
    25. 25. MotionKit::Events Decouple your UI events class LoginLayout < MK::Layout def login_button_style target.on :touch do trigger(:login, username_field.text.to_s, @password_field.text.to_s) end end end class LoginController < UIViewController def viewDidLoad super @layout = LoginLayout.new(root: self.view) @layout.on :login do |username, password| handle_login(username, password) end end end
    26. 26. Roadmap • View Layout helpers • Spec helpers • Layouts (e.g. Linear flow) • Tutorials • Screencasts • Documentation
    27. 27. – Colin T.A. Gray “Oh yeah, Jamon I forgot to tell you.”
    28. 28. class LoginLayout < MK::Layout view :username_field view :submit_button def layout add Android::Widget::LinearLayout, :login_container do orientation VERTICAL add Android::View::TextView, :username_field add Android::View::Button, :submit_button end end def submit_button_style text 'Login' end end MotionKit on Android
    29. 29. Kill the Controllers! • Controllers should do the minimum amount of “paper pushing” • UI and animations → Layout • Talking to the API → Storage • etc. (Misc Task → Misc Class)
    30. 30. DEMO Example of a LoginController written with Storage and Layout classes. You can see some similar code here: github.com/rubymotion/motion-kit-events
    31. 31. Colin T.A. Gray Community Manager at HipByte Engineer at Jukely github.com/colinta github.com/rubymotion/motion-kit gem install motion-kit github.com/colinta/motion-xray gem install motion-xray

    ×