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

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

6d48d3849102b57bbc1462c0da0b3866?s=128

Benjamin Smith

February 20, 2014
Tweet

Transcript

  1. How I architected my big Rails app for success! Thursday,

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

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

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

    Smith Thursday, February 20, 14
  5. Thursday, February 20, 14

  6. Thursday, February 20, 14

  7. Hacking with Gems Benjamin Smith Thursday, February 20, 14

  8. Thursday, February 20, 14

  9. How I architected my big Rails app for success! Benjamin

    Smith @benjamin_smith Thursday, February 20, 14
  10. MVC @benjamin_smith Thursday, February 20, 14

  11. once upon a time @benjamin_smith Thursday, February 20, 14

  12. success Thursday, February 20, 14

  13. long project Thursday, February 20, 14

  14. big dev team Thursday, February 20, 14

  15. lots of codez Thursday, February 20, 14

  16. scalable Thursday, February 20, 14

  17. big bang release Thursday, February 20, 14

  18. success • long project • big dev team • lots

    of code • scalable • big 1st release @benjamin_smith Thursday, February 20, 14
  19. a grain of salt @benjamin_smith Thursday, February 20, 14

  20. success • long project • big dev team • lots

    of code • scalable • big 1st release @benjamin_smith Thursday, February 20, 14
  21. engines Thursday, February 20, 14

  22. engines-ish Thursday, February 20, 14

  23. Thursday, February 20, 14

  24. @benjamin_smith Thursday, February 20, 14

  25. @benjamin_smith Thursday, February 20, 14

  26. a little background @benjamin_smith Thursday, February 20, 14

  27. the product • Multimedia content publishing • A social network

    • iOS app for consumers (using JSON API) • CMS (Rails) for admins @benjamin_smith Thursday, February 20, 14
  28. started simple @benjamin_smith Thursday, February 20, 14

  29. Thursday, February 20, 14

  30. Thursday, February 20, 14

  31. Thursday, February 20, 14

  32. Thursday, February 20, 14

  33. Thursday, February 20, 14

  34. Thursday, February 20, 14

  35. Thursday, February 20, 14

  36. Thursday, February 20, 14

  37. Thursday, February 20, 14

  38. not too bad Thursday, February 20, 14

  39. Thursday, February 20, 14

  40. TRIED TO DO ^ Thursday, February 20, 14

  41. Thursday, February 20, 14

  42. Thursday, February 20, 14

  43. Thursday, February 20, 14

  44. Thursday, February 20, 14

  45. Thursday, February 20, 14

  46. Thursday, February 20, 14

  47. Thursday, February 20, 14

  48. Thursday, February 20, 14

  49. but why stop there? @benjamin_smith Thursday, February 20, 14

  50. Thursday, February 20, 14

  51. Thursday, February 20, 14

  52. Thursday, February 20, 14

  53. Thursday, February 20, 14

  54. Thursday, February 20, 14

  55. Thursday, February 20, 14

  56. Thursday, February 20, 14

  57. Thursday, February 20, 14

  58. Dependencies Thursday, February 20, 14

  59. Web Engines Dependencies Thursday, February 20, 14

  60. Web Engines Domain Engines Dependencies Thursday, February 20, 14

  61. Web Engines Domain Engines Dependencies Thursday, February 20, 14

  62. Dependencies Thursday, February 20, 14

  63. Thursday, February 20, 14

  64. @benjamin_smith Thursday, February 20, 14

  65. how to get started Thursday, February 20, 14

  66. rails plugin new engine_name --mountable @benjamin_smith Thursday, February 20, 14

  67. gem "engine_name", path: "path/to/engine_name" @benjamin_smith Thursday, February 20, 14

  68. mount EngineName::Engine => "/engine_name", :as => "engine_name" @benjamin_smith Thursday, February

    20, 14
  69. bundle gem gem_name @benjamin_smith Thursday, February 20, 14

  70. gem "gem_name", path: "path/to/gem_name" @benjamin_smith Thursday, February 20, 14

  71. rails plugin new engine_name --mountable @benjamin_smith Thursday, February 20, 14

  72. rails plugin new engine_template --mountable @benjamin_smith Thursday, February 20, 14

  73. 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 Thursday, February 20, 14
  74. 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 Thursday, February 20, 14
  75. got it? got it? Thursday, February 20, 14

  76. engines the right way Thursday, February 20, 14

  77. self contained engines • all tables namespaced • migrations •

    tests @benjamin_smith Thursday, February 20, 14
  78. table namespacing @benjamin_smith Thursday, February 20, 14

  79. Thursday, February 20, 14

  80. Thursday, February 20, 14

  81. Thursday, February 20, 14

  82. Thursday, February 20, 14

  83. Thursday, February 20, 14

  84. migrations inside engines @benjamin_smith Thursday, February 20, 14

  85. rake your_engine_name:install:migrations @benjamin_smith Thursday, February 20, 14

  86. 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/ Thursday, February 20, 14
  87. one table per migration http://pivotallabs.com/moving-db-tables-between-rails- engines/ Thursday, February 20, 14

  88. testing the engines in isolation @benjamin_smith Thursday, February 20, 14

  89. Thursday, February 20, 14

  90. engines the right way Thursday, February 20, 14

  91. self contained engines • all tables namespaced • migrations •

    tests @benjamin_smith Thursday, February 20, 14
  92. no circular dependencies @benjamin_smith Thursday, February 20, 14

  93. Thursday, February 20, 14

  94. Thursday, February 20, 14

  95. Thursday, February 20, 14

  96. class User < ActiveRecord::Base has_many :posts end class Post <

    ActiveRecord::Base belongs_to :user end Thursday, February 20, 14
  97. Thursday, February 20, 14

  98. domain api Thursday, February 20, 14

  99. domain api • simple classes to wrap ActiveRecord calls •

    take as input: params or ids • output PORO @benjamin_smith Thursday, February 20, 14
  100. class UserManager def find_by_id(id) User.new(UserRecord.find(id)) end private class UserRecord <

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

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

    ActiveRecord::Base validates :email, presence: true end end Thursday, February 20, 14
  103. 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 Thursday, February 20, 14
  104. that’s a lie @benjamin_smith Thursday, February 20, 14

  105. it’s called the Data Mapper pattern @benjamin_smith Thursday, February 20,

    14
  106. Thursday, February 20, 14

  107. @user.posts @post.user Thursday, February 20, 14

  108. class PostManager def find_all_by_user_id(user_id) PostRecord.where(user_id: user_id) # ... convert to

    PORO ... end end Thursday, February 20, 14
  109. 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) Thursday, February 20, 14
  110. Thursday, February 20, 14

  111. Thursday, February 20, 14

  112. class UserManager def find_by_id(id) User.new(UserRecord.find(id)) end end Thursday, February 20,

    14
  113. 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) Thursday, February 20, 14
  114. Thursday, February 20, 14

  115. Thursday, February 20, 14

  116. engines the right way Thursday, February 20, 14

  117. no circular dependencies @benjamin_smith Thursday, February 20, 14

  118. started simple Thursday, February 20, 14

  119. Thursday, February 20, 14

  120. Thursday, February 20, 14

  121. Thursday, February 20, 14

  122. Thursday, February 20, 14

  123. I live my life one green build at a time

    Thursday, February 20, 14
  124. Thursday, February 20, 14

  125. Thursday, February 20, 14

  126. Thursday, February 20, 14

  127. git whatchanged origin/master.. @benjamin_smith Thursday, February 20, 14

  128. Thursday, February 20, 14

  129. how did it work out? Thursday, February 20, 14

  130. Thursday, February 20, 14

  131. 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 Thursday, February 20, 14
  132. Thursday, February 20, 14

  133. ... 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 Thursday, February 20, 14
  134. thumbs up @benjamin_smith Thursday, February 20, 14

  135. Thursday, February 20, 14

  136. class UserManager def find_by_id(id) User.new(UserRecord.find(id)) end private class UserRecord <

    ActiveRecord::Base validates :email, presence: true end end Thursday, February 20, 14
  137. thanks Thursday, February 20, 14

  138. more infoz: @benjamin_smith http://pivotallabs.com/tag/rails-application-suites/ https://speakerdeck.com/benjaminleesmith/ Thursday, February 20, 14