How I architected my big Rails app for success! (RMR 2013)

6d48d3849102b57bbc1462c0da0b3866?s=47 Benjamin Smith
September 26, 2013

How I architected my big Rails app for success! (RMR 2013)

6d48d3849102b57bbc1462c0da0b3866?s=128

Benjamin Smith

September 26, 2013
Tweet

Transcript

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

    September 26, 13
  2. How I architected my big Rails app for success! Benjamin

    Smith Thursday, September 26, 13
  3. How I architected my big Rails app for success! Benjamin

    Smith Thursday, September 26, 13
  4. How I architected my big Rails app for success! Benjamin

    Smith @benjamin_smith Thursday, September 26, 13
  5. M @benjamin_smith Thursday, September 26, 13

  6. M V @benjamin_smith Thursday, September 26, 13

  7. M C V @benjamin_smith Thursday, September 26, 13

  8. once upon a time @benjamin_smith Thursday, September 26, 13

  9. success Thursday, September 26, 13

  10. long project Thursday, September 26, 13

  11. big dev team Thursday, September 26, 13

  12. lots of codez Thursday, September 26, 13

  13. scalable Thursday, September 26, 13

  14. big bang release Thursday, September 26, 13

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

    of code • scalable • big 1st release @benjamin_smith Thursday, September 26, 13
  16. a grain of salt @benjamin_smith Thursday, September 26, 13

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

    of code • scalable • big 1st release @benjamin_smith Thursday, September 26, 13
  18. engines Thursday, September 26, 13

  19. engines-ish Thursday, September 26, 13

  20. Thursday, September 26, 13

  21. @benjamin_smith Thursday, September 26, 13

  22. @benjamin_smith Thursday, September 26, 13

  23. a little background @benjamin_smith Thursday, September 26, 13

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

    • iOS app for consumers (using JSON API) • CMS (Rails) for admins @benjamin_smith Thursday, September 26, 13
  25. started simple @benjamin_smith Thursday, September 26, 13

  26. Thursday, September 26, 13

  27. Thursday, September 26, 13

  28. Thursday, September 26, 13

  29. Thursday, September 26, 13

  30. Thursday, September 26, 13

  31. Thursday, September 26, 13

  32. Thursday, September 26, 13

  33. Thursday, September 26, 13

  34. Thursday, September 26, 13

  35. not too bad Thursday, September 26, 13

  36. Thursday, September 26, 13

  37. Thursday, September 26, 13

  38. Thursday, September 26, 13

  39. Thursday, September 26, 13

  40. Thursday, September 26, 13

  41. Thursday, September 26, 13

  42. Thursday, September 26, 13

  43. Thursday, September 26, 13

  44. Thursday, September 26, 13

  45. but why stop there? @benjamin_smith Thursday, September 26, 13

  46. Thursday, September 26, 13

  47. Thursday, September 26, 13

  48. Thursday, September 26, 13

  49. Thursday, September 26, 13

  50. Thursday, September 26, 13

  51. Thursday, September 26, 13

  52. Thursday, September 26, 13

  53. Thursday, September 26, 13

  54. Dependencies Thursday, September 26, 13

  55. Web Engines Dependencies Thursday, September 26, 13

  56. Web Engines Domain Engines Dependencies Thursday, September 26, 13

  57. Web Engines Domain Engines Dependencies Thursday, September 26, 13

  58. Dependencies Thursday, September 26, 13

  59. Thursday, September 26, 13

  60. @benjamin_smith Thursday, September 26, 13

  61. how to get started Thursday, September 26, 13

  62. rails plugin new engine_name --mountable @benjamin_smith Thursday, September 26, 13

  63. gem "engine_name", path: "path/to/engine_name" @benjamin_smith Thursday, September 26, 13

  64. mount EngineName::Engine => "/engine_name", :as => "engine_name" @benjamin_smith Thursday, September

    26, 13
  65. bundle gem gem_name @benjamin_smith Thursday, September 26, 13

  66. gem "gem_name", path: "path/to/gem_name" @benjamin_smith Thursday, September 26, 13

  67. rails plugin new engine_name --mountable @benjamin_smith Thursday, September 26, 13

  68. rails plugin new engine_template --mountable @benjamin_smith Thursday, September 26, 13

  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 Thursday, September 26, 13
  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 Thursday, September 26, 13
  71. got it? got it? Thursday, September 26, 13

  72. engines the right way Thursday, September 26, 13

  73. fully contained engines • all tables namespaced • migrations •

    tests @benjamin_smith Thursday, September 26, 13
  74. table namespacing @benjamin_smith Thursday, September 26, 13

  75. Thursday, September 26, 13

  76. Thursday, September 26, 13

  77. Thursday, September 26, 13

  78. Thursday, September 26, 13

  79. Thursday, September 26, 13

  80. migrations inside engines @benjamin_smith Thursday, September 26, 13

  81. rake your_engine_name:install:migrations @benjamin_smith Thursday, September 26, 13

  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/ Thursday, September 26, 13
  83. one table per migration http://pivotallabs.com/moving-db-tables-between-rails- engines/ Thursday, September 26, 13

  84. testing the engines in isolation @benjamin_smith Thursday, September 26, 13

  85. Thursday, September 26, 13

  86. engines the right way Thursday, September 26, 13

  87. fully contained engines • all tables namespaced • migrations •

    tests @benjamin_smith Thursday, September 26, 13
  88. no circular dependencies @benjamin_smith Thursday, September 26, 13

  89. Thursday, September 26, 13

  90. Thursday, September 26, 13

  91. Thursday, September 26, 13

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

    ActiveRecord::Base belongs_to :user end Thursday, September 26, 13
  93. Thursday, September 26, 13

  94. domain api Thursday, September 26, 13

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

    take as input: params or ids • output PORO @benjamin_smith Thursday, September 26, 13
  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 Thursday, September 26, 13
  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 Thursday, September 26, 13
  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 Thursday, September 26, 13
  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 Thursday, September 26, 13
  100. that’s a lie @benjamin_smith Thursday, September 26, 13

  101. it’s called the Data Mapper pattern @benjamin_smith Thursday, September 26,

    13
  102. Thursday, September 26, 13

  103. @user.posts @post.user Thursday, September 26, 13

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

    PORO ... end end Thursday, September 26, 13
  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) Thursday, September 26, 13
  106. Thursday, September 26, 13

  107. Thursday, September 26, 13

  108. class UserManager def find_by_id(id) User.new(UserRecord.find(id)) end end Thursday, September 26,

    13
  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) Thursday, September 26, 13
  110. Thursday, September 26, 13

  111. Thursday, September 26, 13

  112. engines the right way Thursday, September 26, 13

  113. no circular dependencies @benjamin_smith Thursday, September 26, 13

  114. started simple Thursday, September 26, 13

  115. Thursday, September 26, 13

  116. Thursday, September 26, 13

  117. Thursday, September 26, 13

  118. Thursday, September 26, 13

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

    Thursday, September 26, 13
  120. Thursday, September 26, 13

  121. Thursday, September 26, 13

  122. Thursday, September 26, 13

  123. git whatchanged origin/master.. @benjamin_smith Thursday, September 26, 13

  124. Thursday, September 26, 13

  125. how did it work out? Thursday, September 26, 13

  126. Thursday, September 26, 13

  127. engines are a pain... • LOW velocity for weeks (4-6)

    • 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, September 26, 13
  128. Thursday, September 26, 13

  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 Thursday, September 26, 13
  130. thumbs up @benjamin_smith Thursday, September 26, 13

  131. Thursday, September 26, 13

  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 Thursday, September 26, 13
  133. thanks Thursday, September 26, 13

  134. more infoz: @benjamin_smith http://pivotallabs.com/tag/rails-application-suites/ Thursday, September 26, 13