$30 off During Our Annual Pro Sale. View Details »

How I architected my big Rails app for success! (ConFoo 2014)

How I architected my big Rails app for success! (ConFoo 2014)

Benjamin Smith

February 28, 2014
Tweet

More Decks by Benjamin Smith

Other Decks in Technology

Transcript

  1. How I architected my
    big Rails app for
    success!
    Friday, February 28, 14

    View Slide

  2. How I architected my
    big Rails app for
    success!
    Benjamin Smith
    Friday, February 28, 14

    View Slide

  3. How I architected my
    big Rails app for
    success!
    Benjamin Smith
    Friday, February 28, 14

    View Slide

  4. How I architected my
    big Rails app for
    success!
    Benjamin Smith
    Friday, February 28, 14

    View Slide

  5. How I architected my
    big Rails app for
    success!
    Benjamin Smith
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  6. MVC
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  7. once upon a time
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  8. success
    Friday, February 28, 14

    View Slide

  9. long project
    Friday, February 28, 14

    View Slide

  10. big dev team
    Friday, February 28, 14

    View Slide

  11. lots of codez
    Friday, February 28, 14

    View Slide

  12. scalable
    Friday, February 28, 14

    View Slide

  13. big bang release
    Friday, February 28, 14

    View Slide

  14. success
    • long project
    • big dev team
    • lots of code
    • scalable
    • big 1st release
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  15. a grain of salt
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  16. success
    • long project
    • big dev team
    • lots of code
    • scalable
    • big 1st release
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  17. engines
    Friday, February 28, 14

    View Slide

  18. engines-ish
    Friday, February 28, 14

    View Slide

  19. Friday, February 28, 14

    View Slide

  20. @benjamin_smith
    Friday, February 28, 14

    View Slide

  21. @benjamin_smith
    Friday, February 28, 14

    View Slide

  22. a little background
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  23. the product
    • Multimedia content publishing
    • A social network
    • iOS app for consumers (using JSON API)
    • CMS (web interface) for admins
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  24. started simple
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  25. Friday, February 28, 14

    View Slide

  26. Friday, February 28, 14

    View Slide

  27. Friday, February 28, 14

    View Slide

  28. Friday, February 28, 14

    View Slide

  29. Friday, February 28, 14

    View Slide

  30. Friday, February 28, 14

    View Slide

  31. Friday, February 28, 14

    View Slide

  32. Friday, February 28, 14

    View Slide

  33. Friday, February 28, 14

    View Slide

  34. not too bad
    Friday, February 28, 14

    View Slide

  35. Friday, February 28, 14

    View Slide

  36. TRIED TO DO
    ^
    Friday, February 28, 14

    View Slide

  37. Friday, February 28, 14

    View Slide

  38. Friday, February 28, 14

    View Slide

  39. Friday, February 28, 14

    View Slide

  40. Friday, February 28, 14

    View Slide

  41. Friday, February 28, 14

    View Slide

  42. Friday, February 28, 14

    View Slide

  43. Friday, February 28, 14

    View Slide

  44. Friday, February 28, 14

    View Slide

  45. but why stop there?
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  46. Friday, February 28, 14

    View Slide

  47. Friday, February 28, 14

    View Slide

  48. Friday, February 28, 14

    View Slide

  49. Friday, February 28, 14

    View Slide

  50. Friday, February 28, 14

    View Slide

  51. Friday, February 28, 14

    View Slide

  52. Friday, February 28, 14

    View Slide

  53. Friday, February 28, 14

    View Slide

  54. Dependencies
    Friday, February 28, 14

    View Slide

  55. Web
    Engines
    Dependencies
    Friday, February 28, 14

    View Slide

  56. Web
    Engines
    Domain
    Engines
    Dependencies
    Friday, February 28, 14

    View Slide

  57. Web
    Engines
    Domain
    Engines
    Dependencies
    Friday, February 28, 14

    View Slide

  58. Dependencies
    Friday, February 28, 14

    View Slide

  59. Friday, February 28, 14

    View Slide

  60. @benjamin_smith
    Friday, February 28, 14

    View Slide

  61. how to get started
    Friday, February 28, 14

    View Slide

  62. rails plugin new engine_name --mountable
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  63. gem "engine_name",

    path: "path/to/engine_name"
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  64. mount EngineName::Engine => "/engine_name",
    :as => "engine_name"
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  65. bundle gem gem_name
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  66. gem "gem_name",

    path: "path/to/gem_name"
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  67. rails plugin new engine_name --mountable
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  68. rails plugin new engine_template --mountable
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  69. s/engine_template/new_engine_name/g
    s/EngineTemplate/NewEngineName/g
    for file in $(find . -name "*engine_template*")
    do
    mv $file `echo $file | sed s/engine_template/$1/`
    done
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  70. s/gem_template/new_gem_name/g
    s/GemTemplate/NewGemName/g
    for file in $(find . -name "*gem_template*")
    do
    mv $file `echo $file | sed s/gem_template/$1/`
    done
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  71. got it?
    got it?
    Friday, February 28, 14

    View Slide

  72. engines the right way
    Friday, February 28, 14

    View Slide

  73. self contained engines
    • all tables namespaced
    • migrations
    • tests
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  74. table namespacing
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  75. Friday, February 28, 14

    View Slide

  76. Friday, February 28, 14

    View Slide

  77. Friday, February 28, 14

    View Slide

  78. Friday, February 28, 14

    View Slide

  79. Friday, February 28, 14

    View Slide

  80. migrations inside
    engines
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  81. rake your_engine_name:install:migrations
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  82. module EngineWithMigrations
    class Engine < ::Rails::Engine
    isolate_namespace EngineWithMigrations
    initializer :append_migrations do |app|
    unless app.root.to_s.match root.to_s
    app.config.paths["db/migrate"] +=
    config.paths["db/migrate"].expanded
    end
    end
    end
    end
    http://pivotallabs.com/leave-your-migrations-in-your-rails-
    engines/
    Friday, February 28, 14

    View Slide

  83. one table per migration
    http://pivotallabs.com/moving-db-tables-between-rails-
    engines/
    Friday, February 28, 14

    View Slide

  84. testing the engines in
    isolation
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  85. Friday, February 28, 14

    View Slide

  86. engines the right way
    Friday, February 28, 14

    View Slide

  87. self contained engines
    • all tables namespaced
    • migrations
    • tests
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  88. no circular
    dependencies
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  89. Friday, February 28, 14

    View Slide

  90. Friday, February 28, 14

    View Slide

  91. Friday, February 28, 14

    View Slide

  92. class User < ActiveRecord::Base
    has_many :posts
    end
    class Post < ActiveRecord::Base
    belongs_to :user
    end
    Friday, February 28, 14

    View Slide

  93. Friday, February 28, 14

    View Slide

  94. domain api
    Friday, February 28, 14

    View Slide

  95. domain api
    • simple classes to wrap ActiveRecord calls
    • take as input: params or ids
    • output PORO
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  96. class UserManager
    def find_by_id(id)
    User.new(UserRecord.find(id))
    end
    private
    class UserRecord < ActiveRecord::Base
    validates :email, presence: true
    end
    end
    Friday, February 28, 14

    View Slide

  97. class UserManager
    def find_by_id(id)
    User.new(UserRecord.find(id))
    end
    private
    class UserRecord < ActiveRecord::Base
    validates :email, presence: true
    end
    end
    Friday, February 28, 14

    View Slide

  98. class UserManager
    def find_by_id(id)
    User.new(UserRecord.find(id))
    end
    private
    class UserRecord < ActiveRecord::Base
    validates :email, presence: true
    end
    end
    Friday, February 28, 14

    View Slide

  99. class UserManager
    def find_by_id(id)
    User.new(UserRecord.find(id))
    end
    private
    class UserRecord < ActiveRecord::Base
    validates :email, presence: true
    end
    end
    class User
    def initialize(user_record)
    self.email = user_record.email
    end
    end
    Friday, February 28, 14

    View Slide

  100. that’s a lie
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  101. it’s called the
    Data Mapper
    pattern
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  102. Friday, February 28, 14

    View Slide

  103. @user.posts @post.user
    Friday, February 28, 14

    View Slide

  104. class PostManager
    def find_all_by_user_id(user_id)
    PostRecord.where(user_id: user_id)
    # ... convert to PORO ...
    end
    end
    Friday, February 28, 14

    View Slide

  105. class PostManager
    def find_all_by_user_id(user_id)
    PostRecord.where(user_id: user_id)
    # ... convert to PORO ...
    end
    end
    post_manager = PostManager.new
    @posts = post_manager.find_all_by_user_id(@user.id)
    Friday, February 28, 14

    View Slide

  106. Friday, February 28, 14

    View Slide

  107. Friday, February 28, 14

    View Slide

  108. class UserManager
    def find_by_id(id)
    User.new(UserRecord.find(id))
    end
    end
    Friday, February 28, 14

    View Slide

  109. class UserManager
    def find_by_id(id)
    User.new(UserRecord.find(id))
    end
    end
    user_manager = UserManager.new
    author = user_manager.find_by_id(@post.user_id)
    Friday, February 28, 14

    View Slide

  110. Friday, February 28, 14

    View Slide

  111. Friday, February 28, 14

    View Slide

  112. engines the right way
    Friday, February 28, 14

    View Slide

  113. no circular
    dependencies
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  114. started simple
    Friday, February 28, 14

    View Slide

  115. Friday, February 28, 14

    View Slide

  116. Friday, February 28, 14

    View Slide

  117. Friday, February 28, 14

    View Slide

  118. Friday, February 28, 14

    View Slide

  119. I live my life one green
    build at a time
    Friday, February 28, 14

    View Slide

  120. Friday, February 28, 14

    View Slide

  121. Friday, February 28, 14

    View Slide

  122. Friday, February 28, 14

    View Slide

  123. git whatchanged origin/master..
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  124. Friday, February 28, 14

    View Slide

  125. how did it work out?
    Friday, February 28, 14

    View Slide

  126. Friday, February 28, 14

    View Slide

  127. engines are a pain...
    • LOW velocity for first 4-6 weeks
    • client worries
    • opposite of Rails
    • one pair to start is a MUST
    • some technical hurtles
    • must be diligent about refactoring
    • monkey patching Rails
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  128. Friday, February 28, 14

    View Slide

  129. ... but they get better
    • no slow down in development time
    • they age well
    • easier parallel development
    • potential for scaling
    • smart and fast build scripts
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  130. thumbs up
    @benjamin_smith
    Friday, February 28, 14

    View Slide

  131. Friday, February 28, 14

    View Slide

  132. class UserManager
    def find_by_id(id)
    User.new(UserRecord.find(id))
    end
    private
    class UserRecord < ActiveRecord::Base
    validates :email, presence: true
    end
    end
    Friday, February 28, 14

    View Slide

  133. thanks
    Friday, February 28, 14

    View Slide

  134. more infoz:
    @benjamin_smith
    http://pivotallabs.com/tag/rails-application-suites/
    https://speakerdeck.com/benjaminleesmith/
    Friday, February 28, 14

    View Slide