Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Growing Rails Apps - Dmitry Zhlobo | Ruby Meditation #23

54 views

Published on

Talk at Ruby Meditation #23
September 23, Odessa
2018

Published in: Technology
  • Be the first to comment

  • Be the first to like this

Growing Rails Apps - Dmitry Zhlobo | Ruby Meditation #23

  1. 1. Growing Rails Apps with ❤ from datarockets
  2. 2. Easy to start •Requirements are simple •First steps are simple artist:ManuCornet
  3. 3. Hard to maintain •Edge cases start to appear •New features are more complicated •Codebase become bigger and harder to maintain artist:ManuCornet
  4. 4. We use the wrong tools • Callbacks in models and controllers and suppressing them • Fat models • Default scopes • Custom actions in controllers
  5. 5. Photo by Terra Evans
  6. 6. We have better tools • Form Objects • Service Objects • Trailblazer • DRY framework • ROM
  7. 7. Code Organization
  8. 8. Code Organization 176 files
  9. 9. 176?
  10. 10. Flat Models Structure post_action_type.rb
 post_action.rb
 post_analyzer.rb
 post_custom_fields.rb
 post_detail.rb
 post_mover.rb
 post_reply.rb
 post_revision.rb
 post_search_data.rb
 post_stat.rb
 post_timing.rb
 post_upload.rb
 post.rb
  11. 11. Flat Models Structure post_action_type.rb
 post_action.rb
 post_analyzer.rb
 post_custom_fields.rb
 post_detail.rb
 post_mover.rb
 post_reply.rb
 post_revision.rb
 post_search_data.rb
 post_stat.rb
 post_timing.rb
 post_upload.rb
 post.rb class Post < ActiveRecord::Base
 has_many :post_uploads
 has_many :uploads, through: :post_ has_many :post_details
 has_many :post_revisions
 # ...
 end
 

  12. 12. Flat Models Structure post_action_type.rb
 post_action.rb
 post_analyzer.rb
 post_custom_fields.rb
 post_detail.rb
 post_mover.rb
 post_reply.rb
 post_revision.rb
 post_search_data.rb
 post_stat.rb
 post_timing.rb
 post_upload.rb
 post.rb class Post < ActiveRecord::Base
 has_many :post_uploads
 has_many :uploads, through: :post_ has_many :post_details
 has_many :post_revisions
 # ...
 end
 
 
 post.post_details
 
 post.post_revisions
  13. 13. Namespace Your Models class Post
 has_many :details
 has_many :uploads, class_name: "Post::Upload"
 end
 
 class Post::Detail # post/detail.rb
 belongs_to :post
 end
 
 class Post::Upload # post/upload.rb
 belongs_to :post
 belongs_to :upload, class_name: "::Upload"
 end
  14. 14. Namespace Your Models post_action_type.rb
 post_action.rb
 post_analyzer.rb
 post_custom_fields.rb
 post_detail.rb
 post_mover.rb
 post_reply.rb
 post_revision.rb
 post_search_data.rb
 post_stat.rb
 post_timing.rb
 post_upload.rb
 post.rb post/
 action/
 type.rb
 action.rb
 analyzer.rb
 custom_fields.rb
 detail.rb
 mover.rb
 reply.rb
 revision.rb
 search_data.rb
 stat.rb
 timing.rb
 upload.rb
 post.rb
  15. 15. Namespace Your Models post/
 post.rb
  16. 16. Controllers $ cat app/controllers/users_controller.rb | wc -l 1097
  17. 17. 1097?
  18. 18. Custom Actions resources :users do
 put "suspend"
 put "unsuspend"
 
 put "grant_moderation"
 put "revoke_moderation"
 
 # ...
 end

  19. 19. Resourceful Routes resources :users do
 put "suspend"
 put "unsuspend"
 end resources :users do
 resource :suspension, 
 only: [:create, :destroy]
 end
  20. 20. Resourceful Routes resources :users do
 put "suspend"
 put "unsuspend"
 end resources :users do
 resource :suspension, 
 only: [:create, :destroy]
 end DELETE /users/:user_id/suspension suspensions#destroy
 POST /users/:user_id/suspension suspensions#create
  21. 21. Resourceful Routes resources :users do
 put "suspend"
 put "unsuspend"
 end resources :users do
 resource :suspension, 
 only: [:create, :destroy]
 end DELETE /users/:user_id/suspension suspensions#destroy
 POST /users/:user_id/suspension suspensions#create app/controllers/
 users_controller.rb
 suspensions_controller.rb
  22. 22. Resourceful Routes resources :users do
 put "suspend"
 put "unsuspend"
 end resources :users do
 resource :suspension, 
 only: [:create, :destroy]
 end DELETE /users/:user_id/suspension suspensions#destroy
 POST /users/:user_id/suspension suspensions#create app/controllers/
 users_controller.rb
 suspensions_controller.rb 😕
  23. 23. Resourceful Routes resources :users do
 scope module: :users do
 resource :suspension, only: [:create, :destroy]
 resource :moderation_permission, only: [:create, :destroy] end
 end
 
 app/controllers/
 users/
 suspensions_controller.rb
 moderator_permissions_controller.rb
 users_controller.rb
  24. 24. Long Actions def index
 @rss_posts = posts.map do |post|
 { description: rss_description_for(post), title: post.titl end
 end
 
 def rss_description_for(post)
 post.body.truncate(256) + info_about_likes(post)
 end
 
 def info_about_likes(post)
 end
  25. 25. Long Actions def index
 @rss_posts = RssPosts.new(posts)
 end

  26. 26. class RssPosts
 def each
 @posts.each do |post| 
 yield { description: rss_description_for(post), title: p end
 end
 
 private
 
 def rss_description_for(post)
 post.body.truncate(256) + info_about_likes(post)
 end
 
 def info_about_likes(post)
 end
 end
  27. 27. class RssPosts
 def each
 @posts.each do |post| 
 yield { description: rss_description_for(post), title: p end
 end
 
 private
 
 def rss_description_for(post)
 post.body.truncate(256) + info_about_likes(post)
 end
 
 def info_about_likes(post)
 end
 end 💩
  28. 28. class RssPosts # rss_posts.rb
 def each
 @posts.each do |post| 
 yield Post.new(post)
 end
 end
 end
 
 class RssPosts::Post # rss_posts/post.rb
 def description
 @post.body + info_about_likes
 end
 
 def info_about_likes
 end
 end
  29. 29. Organize Your Code rss_posts/
 post.rb
 rss_posts.rb
  30. 30. – Your Coworker “It makes no sense to create one more class and one more file instead of creating one private method”
  31. 31. Sandi Metz Rules 1. Classes can be no longer than one hundred lines of code. 2. Methods can be no longer than five lines of code. 3. Pass no more than four parameters into a method. Hash options are parameters. 4. Controllers can instantiate only one object. Therefore view can only know about one instance variable and views should only send messages to that object.
  32. 32. Dima’s Rule Don’t send parameters to private methods. Consider creating a separate class.
  33. 33. POODR
  34. 34. Quick Recap •Namespace models •Namespace controllers and keep them small •Namespace service classes and keep them clean
  35. 35. Thank you! with ❤ from datarockets twitter.com/dzhlobo
 
 fb.com/dima.zhlobo
 
 vk.com/datarockets

×