Una Critica a Rails by Luca Guidi

1,081 views
1,015 views

Published on

Un profondo punto di vista sul perché Ruby on Rails ha rivoluzionato lo sviluppo web.

Questo talk focalizzerà la sua attenzione sul “Golden Path” di Rails, sui motivi del suo successo, sui problemi più comuni, e su come le sue API possano essere migliorate.

Impareremo a trarre beneficio da uno strumento tanto potente quanto pericoloso, di come mitigare le implicazioni architetturali, di design e testabilità delle vostre applicazioni, migliorando la qualità del codice..

Published in: Technology, Education
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,081
On SlideShare
0
From Embeds
0
Number of Embeds
23
Actions
Shares
0
Downloads
3
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Una Critica a Rails by Luca Guidi

  1. 1. March 22nd, 2013A Rails Criticismhow i learned to stop worrying about the Golden Path Luca Guidi
  2. 2. AGENDAintro
  3. 3. Luca Guidi Senior Developer at Litmus @jodosha - http//lucag uidi.com
  4. 4. litmusBeautiful Email previews Campaig n analytics Spam filter tests HTML code analysis And many other..
  5. 5. Why Railshas revolutionized web development? (IMHO)
  6. 6. Why Rails has revolutionized web development?Convention Over Config uration (IMHO) :)
  7. 7. Why Rails has revolutionized web development?Dynamic and innovative Convention Over Config uration ecosystem (IMHO) :)
  8. 8. Why Rails has revolutionized web development?Dynamic and innovative Convention Over Productivity and Developer uration Config Happiness ecosystem (IMHO) :)
  9. 9. ..butThe Framework is almost ten years old
  10. 10. ..butTheLot of Legacy Code A Framework is almost ten years old is around
  11. 11. ..butTheLot of Legacymajor A Frameworkais Code Upgrades to almost release years old ten are *painful* is around
  12. 12. AGENDAintro problems
  13. 13. Active RecordActiveRecord
  14. 14. Active RecordModels != Records
  15. 15. Active Record Encapsulation violations1 if article.statearticle.published? 1 unless != published2 article.update_attribute(state: published) 2 article.publish!3 end 3 end 4 # not completely right...
  16. 16. Active Record Encapsulation violations1 if article.statearticle.published? 1 unless != published2 article.update_attribute(state: published) 2 article.publish!3 end 3 end 4 # not completely right...
  17. 17. Active Record Encapsulation violations1 if article.statearticle.published? 1 unless != published2 article.update_attribute(state: published) 2 article.publish!3 end 3 end 4 # not completely right...
  18. 18. Active Record Tell, Don’t Ask12 violations article.publish! unless article.published? # article.publish! push the implementation3 end # into the model4 # not completely right...
  19. 19. Active Record Tell, Don’t Ask violations1 article.publish! unless article.published?2 # article.publish! push the implementation3 end # into the model4 # not completely right...
  20. 20. Active Record Tell, Don’t Ask violations1 article.publish! unless article.published?2 # article.publish! push the implementation3 end # into the model4 # not completely right...
  21. 21. Active Record2 Implicit vs Explicit API1 class Post < ActiveRecord::Base 1 Post.where(state:published). 1 Post.most_recent_published def self.most_recent_published(limit = 5)3 2published.recent(limit).order(created_at DESC) order(created_at DESC).4 end5 3 limit(5)6 private7 scope :published, ->() { where(state: published) }8 scope :recent, ->(n) { limit(n) }9 end
  22. 22. Active Record Implicit vs Explicit API1 class Post < ActiveRecord::Base2 1 Post.where(state:published). 1 Post.most_recent_published def self.most_recent_published(limit = 5)3 2published.recent(limit).order(created_at DESC) order(created_at DESC).4 end5 3 limit(5)6 private7 scope :published, ->() { where(state: published) }8 scope :recent, ->(n) { limit(n) }9 end
  23. 23. Active Record Implicit vs Explicit API1 class Post < ActiveRecord::Base2 1 Post.where(state:published). 1 Post.most_recent_published def self.most_recent_published(limit = 5)3 2published.recent(limit).order(created_at DESC) order(created_at DESC).4 end5 3 limit(5)6 private7 scope :published, ->() { where(state: published) }8 scope :recent, ->(n) { limit(n) }9 end
  24. 24. Active Record Implicit vs Explicit API1 class Post < ActiveRecord::Base2 1 Post.where(state:published). 1 Post.most_recent_published def self.most_recent_published(limit = 5)3 2published.recent(limit).order(created_at DESC) order(created_at DESC).4 end5 3 limit(5)6 private7 scope :published, ->() { where(state: published) }8 scope :recent, ->(n) { limit(n) }9 end
  25. 25. Active RecordCallbacks abuse Non-persistence logic is tight to the persistence life cycle. Eg. Sending emails
  26. 26. Active RecordTestability issues Micheal Feathers
  27. 27. Active RecordA test is not a unit test if it talks Testability issues to a database. Micheal Feathers
  28. 28. Action Controller ActionController It doesn’t affect too much your architecture, but it has strange OOP design.
  29. 29. Action Controller1 class PostsController < ApplicationController2 before_filter :authenticate Frankenstein Controllers34 def new5 end67 def create8 @post = Post.new(params[:post])910 if @post.save11 redirect_to post_url(@post), notice: Yay!12 else13 render :new14 end15 end16 end
  30. 30. Action Controller Frankenstein Controllers1 class PostsController < ApplicationController2 before_filter :authenticate34 def new5 end67 def create8 @post = Post.new(params[:post])910 if @post.save11 redirect_to post_url(@post), notice: Yay!12 else13 render :new14 end15 end16 end
  31. 31. Action Controller Frankenstein Controllers1 class PostsController < ApplicationController2 before_filter :authenticate34 def new5 end67 def create8 @post = Post.new(params[:post])910 if @post.save11 redirect_to post_url(@post), notice: Yay!12 else13 render :new14 end15 end16 end
  32. 32. Action Controller Frankenstein Controllers1 class PostsController < ApplicationController2 before_filter :authenticate34 def new5 end67 def create8 @post = Post.new(params[:post])910 if @post.save11 redirect_to post_url(@post), notice: Yay!12 else13 render :new14 end15 end16 end
  33. 33. Action Controller Frankenstein Controllers1 class PostsController < ApplicationController2 before_filter :authenticate34 def new5 end67 def create8 @post = Post.new(params[:post])910 if @post.save11 redirect_to post_url(@post), notice: Yay!12 else13 render :new14 end15 end16 end
  34. 34. Action Controller Frankenstein Controllers1 class PostsController < ApplicationController2 before_filter :authenticate34 def new5 end67 def create8 @post = Post.new(params[:post])910 if @post.save11 redirect_to post_url(@post), notice: Yay!12 else13 render :new14 end15 end16 end
  35. 35. Action Controller1 class PostsController < ApplicationController2 # ... Odd classes34 def create5 @post = Post.new(params[:post])67 if @post.save8 # ...9 else10 # ...11 end12 end13 end
  36. 36. Action Controller Odd classes1 class PostsController < ApplicationController2 # ...34 def create5 @post = Post.new(params[:post])67 if @post.save8 # ...9 else10 # ...11 end12 end13 end
  37. 37. Action Controller Odd classes1 class PostsController < ApplicationController2 # ...34 def create5 @post = Post.new(params[:post])67 if @post.save8 # ...9 else10 # ...11 end12 end13 end
  38. 38. Action Controller Odd classes1 class PostsController < ApplicationController2 # ...34 def create5 @post = Post.new(params[:post])67 if @post.save8 # ...9 else10 # ...11 end12 end13 end
  39. 39. Action Controller34 Encapsulation violations1 class PostsController < ApplicationController2 # ... def create5 @post = Post.new(params[:post])6 # ...7 end8 end
  40. 40. Action Controller Encapsulation violations1 class PostsController < ApplicationController2 # ...34 def create5 @post = Post.new(params[:post])6 # ...7 end8 end
  41. 41. Action Controller1 describe PostsController do Testability issues2 it assigns @posts do3 Post.should_receive(:most_recent_published).4 and_return(posts = [mock])5 get :index67 expect(assigns(:posts)).to eq(posts)8 end9 end
  42. 42. Action Controller Testability issues1 describe PostsController do2 it assigns @posts do3 Post.should_receive(:most_recent_published).4 and_return(posts = [mock])5 get :index67 expect(assigns(:posts)).to eq(posts)8 end9 end
  43. 43. Action Controller Testability issues1 describe PostsController do2 it assigns @posts do3 Post.should_receive(:most_recent_published).4 and_return(posts = [mock])5 get :index67 expect(assigns(:posts)).to eq(posts)8 end9 end
  44. 44. Action Controller Testability issues1 describe PostsController do2 it assigns @posts do3 Post.should_receive(:most_recent_published).4 and_return(posts = [mock])5 get :index67 expect(assigns(:posts)).to eq(posts)8 end9 end
  45. 45. Action Controller Testability issues1 describe PostsController do2 it assigns @posts do3 Post.should_receive(:most_recent_published).4 and_return(posts = [mock])5 get :index67 expect(assigns(:posts)).to eq(posts)8 end9 end
  46. 46. Action Controller Testability issues1 describe PostsController do2 it assigns @posts do3 Post.should_receive(:most_recent_published).4 and_return(posts = [mock])5 get :index67 expect(assigns(:posts)).to eq(posts)8 end9 end
  47. 47. Action ViewActionView
  48. 48. Action View Views aren’t views (but templates with logic)Without “real” views (or In an ideal world wepresenters), we’re tempted to shouldn’t test ourpush presentational methods templates.into the models.
  49. 49. Action View Helpers are functional programming1 def user_full_name(user)2 [ user.first_name, user.last_name ].join( )3 end45 url_for6 # vs Half-assed way to solve7 Url.for presentational problems in8 ActionView.9 posts_url
  50. 50. Action View Helpers are functional programming1 def user_full_name(user)2 [ user.first_name, user.last_name ].join( )3 end45 url_for6 # vs Half-assed way to solve7 Url.for presentational problems in8 ActionView.9 posts_url
  51. 51. Ruby on RailsRuby on Rails
  52. 52. Ruby on RailsRails isn’t a framework, but an application template
  53. 53. Ruby on RailsRails is multi-paradig m as Ruby is.
  54. 54. AGENDAintro problems solutions
  55. 55. SolutionsDecouple your logic fromActiveRecord as much as possible. AR is focused on data, but OOP is about behavior.
  56. 56. Solutions Don’t think inActiveRecord terms. Database is a detail, forget about associations, scopes, validations..
  57. 57. SolutionsLet your public API to declare intents. Let your design to emerge via TDD.
  58. 58. Solutions Keep methods andaccessors private as much as possible. Public APIs are hard to maintain as the codebase and the team grows.
  59. 59. SolutionsSkinny controllers and skinny models. Use ser vice objects or DCI, they are easier and faster to test.
  60. 60. SolutionsDon’t be afraid to extract ad-hoc classes forspecific responsibilities. Inner classes are your friends, they help you with details, and aren’t part of your public API.
  61. 61. SolutionsUse DIY presenters They will help you to keep your models clean from presentational logic.
  62. 62. SolutionsRefactor, refactor, refactor.
  63. 63. AGENDAintro problems solutions conclusion
  64. 64. Q&A
  65. 65. me@lucag uidi.com @jodoshahttps://speakerdeck.com/jodosha/a-rails-criticism Except where otherwise noted, this work is licensed under: http://creativecommons.org/licenses/by-nc-sa/3.0/

×