Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Sustainable Productivity: Rails vs OOP

Sustainable Productivity: Rails vs OOP

There is an ongoing debate in the Rails community as to whether properly applying certain well-known OO principles and techniques can improve the maintainability of our Rails applications as they grow.

However, often these practices differ from the traditional _Rails way_ which, after all, claims to be “optimised for programmer happiness and sustainable productivity”.

In this talk, we'll explore the different views of the community on this subject keeping the drama and the rhetoric out of the debate. We'll discuss about SOLID principles, cohesion, ceremony vs essence, data vs behaviour, indirection, testability, the framework as a detail and other related topics.

Hopefully, this talk will help you make better decisions when choosing solutions to improve the maintainability of your Rails codebase.

Luismi Cavallé

March 22, 2013
Tweet

More Decks by Luismi Cavallé

Other Decks in Programming

Transcript

  1. %3:

  2. )BNM 34QFD $VDVNCFS 1PTUHSF42- 1SFTFOUFST 4FSWJDFT $PODFSOT 3PMFT %$* .PDLT

    )FYBHPOBM %%% &3# 5FTU6OJU .Z42- $P⒎F4DSJQU
  3. !!class!Article!<!ActiveRecord::Base !!!!attr_accessor!:moderation_option ! !!!!attr_accessible!:text,!:reply_to_id,!:tag_names ! !!!!belongs_to!:topic !!!!belongs_to!:user,!!!!!:class_name!=>!Forem.user_class.to_s !!!!belongs_to!:reply_to,!:class_name!=>!"Post" ! !!!!has_many!:replies,!:class_name!!=>!"Post",

    !!!!!!!!!!!!!!!!!!!!!!!:foreign_key!=>!"reply_to_id", !!!!!!!!!!!!!!!!!!!!!!!:dependent!!!=>!:nullify !!!! !!!!has_many!:taggings !!!!has_many!:tags,!:through!=>!:taggings ! !!!!validates!:text,!:presence!=>!true ! !!!!delegate!:forum,!:to!=>!:topic ! !!!!after_create!:set_topic_last_post_at !!!!after_create!:skip_pending_review !!!!after_save!:email_topic_subscribers ! !!!!class!<<!self !!!!!!def!by_created_at !!!!!!!!order!:created_at !!!!!!end ! !!!!!!def!pending_review !!!!!!!!where!:state!=>!'pending_review' !!!!!!end ! !!!!!!def!spam !!!!!!!!where!:state!=>!'spam' !!!!!!end !!!!!! !!!!!!def!tagged_with(tag) !!!!!!!!joins(:taggings!=>!:tags).where(:tags!=>!{!:name!=>!tag!}) !!!!!!end ! !!!!!!def!visible !!!!!!!!joins(:topic).where(:forem_topics!=>!{!:hidden!=>!false!}) !!!!!!end !!!!end !!!! !!!!def!tag_names=(tag_list) !!!!!!assign_tag_list!tag_list !!!!end ! !!!!private ! !!!!def!subscribe_replier !!!!!!if!topic!&&!user !!!!!!!!topic.subscribe_user(user.id) !!!!!!end !!!!end ! !!!!def!set_topic_last_post_at !!!!!!topic.update_attribute(:last_post_at,!created_at) !!!!end ! !!!!def!blacklist_user !!!!!!user.update_attribute(:forem_state,!"spam")!if!user !!!!end !!!! !!!!def!assign_tag_list(tag_list) !!!!!!tag_names!=!tag_list.gsub(/\s+/,!"").split(",") !!!!!!existing!=!self.tags.map!{|t|!t.name!} !!!!!!(existing!@!tag_names).each!do!|name| !!!!!!!!self.tags.delete!Tag.find_by_name(name) !!!!!!end !!!!!!tag_names.each!do!|name| !!!!!!!!self.tags!<<!Tag.find_or_create_by_name(name) !!!!!!end! !!!!end !!end
  4. !!!!end !!!!def!pending_review !!!!!!where!:state!=>!'pending_review' !!!!end !!!!def!spam !!!!!!where!:state!=>!'spam' !!!!end !!!! !!!!def!tagged_with(tag) !!!!!!joins(:taggings!=>!:tags).where(:tags!=>!{!:name!=>!tag!})

    !!!!end !!!!def!visible !!!!!!joins(:topic).where(:forem_topics!=>!{!:hidden!=>!false!}) !!!!end !!end !! !!def!tag_names=(tag_list) !!!!assign_tag_list!tag_list !!end !!private
  5. !!class!Article!<!ActiveRecord::Base !!!!attr_accessor!:moderation_option ! !!!!attr_accessible!:text,!:reply_to_id,!:tag_names ! !!!!belongs_to!:topic !!!!belongs_to!:user,!!!!!:class_name!=>!Forem.user_class.to_s !!!!belongs_to!:reply_to,!:class_name!=>!"Post" ! !!!!has_many!:replies,!:class_name!!=>!"Post",

    !!!!!!!!!!!!!!!!!!!!!!!:foreign_key!=>!"reply_to_id", !!!!!!!!!!!!!!!!!!!!!!!:dependent!!!=>!:nullify !!!! !!!!has_many!:taggings !!!!has_many!:tags,!:through!=>!:taggings ! !!!!validates!:text,!:presence!=>!true ! !!!!delegate!:forum,!:to!=>!:topic ! !!!!after_create!:set_topic_last_post_at !!!!after_create!:skip_pending_review !!!!after_save!:email_topic_subscribers ! !!!!class!<<!self !!!!!!def!by_created_at !!!!!!!!order!:created_at !!!!!!end ! !!!!!!def!pending_review !!!!!!!!where!:state!=>!'pending_review' !!!!!!end ! !!!!!!def!spam !!!!!!!!where!:state!=>!'spam' !!!!!!end !!!!!! !!!!!!def!tagged_with(tag) !!!!!!!!joins(:taggings!=>!:tags).where(:tags!=>!{!:name!=>!tag!}) !!!!!!end ! !!!!!!def!visible !!!!!!!!joins(:topic).where(:forem_topics!=>!{!:hidden!=>!false!}) !!!!!!end !!!!end !!!! !!!!def!tag_names=(tag_list) !!!!!!assign_tag_list!tag_list !!!!end ! !!!!private ! !!!!def!subscribe_replier !!!!!!if!topic!&&!user !!!!!!!!topic.subscribe_user(user.id) !!!!!!end !!!!end ! !!!!def!set_topic_last_post_at !!!!!!topic.update_attribute(:last_post_at,!created_at) !!!!end ! !!!!def!blacklist_user !!!!!!user.update_attribute(:forem_state,!"spam")!if!user !!!!end !!!! !!!!def!assign_tag_list(tag_list) !!!!!!tag_names!=!tag_list.gsub(/\s+/,!"").split(",") !!!!!!existing!=!self.tags.map!{|t|!t.name!} !!!!!!(existing!@!tag_names).each!do!|name| !!!!!!!!self.tags.delete!Tag.find_by_name(name) !!!!!!end !!!!!!tag_names.each!do!|name| !!!!!!!!self.tags!<<!Tag.find_or_create_by_name(name) !!!!!!end! !!!!end !!end
  6. module!Taggable !!extend!ActiveSupport::Concern !!included!do !!!!has_many!:taggings !!!!has_many!:tags,!through:!:taggings !!!!scope!:tagged_with,!1>(tag_name)!do !!!!!!joins(:tags).where(tags:!{!name:!tag_name!})! !!!!end !!end !!def!tag_list

    !!!!tags.pluck(:name).join(',!') !!end !!def!tag_list=(tag_list) !!!!assign_tag_list!tag_list !!end !!private !!def!assign_tag_list(tag_list) !!!!tag_names!=!tag_list.split(',').map(&:strip).uniq !!!!self.tags!=!tag_names.map!do!|tag_name|! !!!!!!Tag.where(name:!tag_name).first_or_initialize !!!!end !!end end
  7. 109 ________________________ 8 ________________________ SRP: The Single Responsibility Principle None

    but Buddha himself must take the responsibility of giving out occult secrets... — E. Cobham Brewer 1810–1897. Dictionary of Phrase and Fable. 1898. This principle was described in the work of Tom DeMarco1 and Meilir Page-Jones2. They called it cohesion. They defined cohesion as the functional relatedness of the elements of a 1. [DeMarco79], p310 2. [PageJones88], Chapter 6, p82. https://docs.google.com/file/d/0ByOwmqah_nuGNHEtcU5OekdDMkk/edit
  8. 149 ________________________ 9 ________________________ SRP: The Single Responsibility Principle None

    but Buddha himself must take the responsibility of giving out occult secrets... — E. Cobham Brewer 1810–1897. Dictionary of Phrase and Fable. 1898. This principle was described in the work of Tom DeMarco1 and Meilir Page-Jones2. They called it cohesion. As we’ll see in Chapter 21, we have a more specific definition of cohe- sion at the package level. However, at the class level the definition is similar. SRP: The Single Responsibility Principle THERE SHOULD NEVER BE MORE THAN ONE REASON FOR A CLASS TO CHANGE. Consider the bowling game from Chapter 6. For most of its development the Game class was handling two separate responsibilities. It was keeping track of the current frame, and it was calculating the score. In the end, RCM and RSK separated these two responsibilities into two classes. The Game kept the responsibility to keep track of frames, and the Scorer got the responsibility to calculate the score. (see page 85.) 1. [DeMarco79], p310 2. [PageJones88], Chapter 6, p82. http://www.objectmentor.com/resources/articles/srp.pdf
  9. tomed to thinking of responsibility in groups. For exampl in

    Listing 9-1. Most of us will agree that this interface look functions it declares are certainly functions belonging to a However, there are two responsibilities being shown connection management. The second is data communicatio tions manage the connection of the modem, while the send cate data. Listing 9-1 Modem.java -- SRP Violation interface Modem { public void dial(String pno); public void hangup(); public void send(char c); public char recv(); }
  10. However, there are two responsibilities being sho onnection management. The

    second is data communic ons manage the connection of the modem, while the s te data. Should these two responsibilities be separated? A wo sets of functions have almost nothing in common. nt reasons. Moreover, they will be called from compl ons that use them. Those different parts will change fo }
  11. ng shown here. The first responsibility is munication. The dial

    and hangup func- e the send and recv functions communi- ated? Almost certainly they should. The mmon. They’ll certainly change for differ- completely different parts of the applica- ange for different reasons as well.
  12. However, there are two responsibilities being show connection management. The

    second is data communica tions manage the connection of the modem, while the se cate data. Should these two responsibilities be separated? Tha tion is changing. If the application changes in ways that a tion functions, then the design will smell of Rigidity b public void Dial(string pno); public void Hangup(); public void Send(char c); public char Recv(); } Listing 8-1 (Continued) Modem.cs -- SRP Violation
  13. However, there are two responsibilities being sho onnection management. The

    second is data communi ons manage the connection of the modem, while the s ate data. Should these two responsibilities be separated? T on is changing. If the application changes in ways tha on functions, then the design will smell of Rigidity nd read will have to be recompiled and redeployed m e two responsibilities should be separated as shown pplications from coupling the two responsibilities.
  14. However, there are two responsibilities being shown here. The first

    responsibility is connection management. The second is data communication. The dial and hangup func- tions manage the connection of the modem, while the send and recv functions communi- cate data. Should these two responsibilities be separated? That depends upon how the applica- tion is changing. If the application changes in ways that affect the signature of the connec- tion functions, then the design will smell of Rigidity because the classes that call send and read will have to be recompiled and redeployed more often than we like. In that case the two responsibilities should be separated as shown in Figure 8-3. This keeps the client applications from coupling the two responsibilities. public void Dial(string pno); public void Hangup(); public void Send(char c); public char Recv(); } Modem.cs -- SRP Violation + send(:char) + recv() : char Data Channel + dial(pno : String) + hangup() Connection «interface» «interface» WAT!
  15. If, on the other hand, the application is not changing

    in ways that cause the the two responsibilities to change at differen times, then there is no need to separate them. Indeed, separating them would smell of Needless Complexity. There is a corrolary here. An axis of change is only an axis of change if the changes actually occurr. It is not wise to apply the SRP, or any other principle for that matter, if there is no symptom. Figure 8-3 Separated Modem Interface + recv() : char + hangup() Modem Implementation
  16. If, on the other hand, the application is not changing

    in ways that cause the the two responsibilities to change at differen times, then there is no need to separate them. Indeed, separating them would smell of Needless Complexity. There is a corrolary here. An axis of change is only an axis of change if the changes actually occurr. It is not wise to apply the SRP, or any other principle for that matter, if there is no symptom. Figure 8-3 Separated Modem Interface + recv() : char + hangup() Modem Implementation
  17. If, on the other hand, the application is not changing

    in ways that cause the the two responsibilities to change at differen times, then there is no need to separate them. Indeed, separating them would smell of Needless Complexity. There is a corrolary here. An axis of change is only an axis of change if the changes actually occurr. It is not wise to apply the SRP, or any other principle for that matter, if there is no symptom. Figure 8-3 Separated Modem Interface Modem Implementation
  18. hand, the application is not changing i hange at differen

    times, then there is no uld smell of Needless Complexity. olary here. An axis of change is only an s not wise to apply the SRP, or any oth . Separated Modem Interface
  19. 4/3

  20. s a d g h D c w f t

    i n a c t £È £x £{ £Î £Ó ££ £ä ™ n Ç È x { Î Ó £ œ}ÓʜvÊ̅iÊ Õ“LiÀʜvÊ œ“«œ˜i˜ÌÃÊ *iÀʘÌi}À>Ìi`Ê՘V̈œ˜ 9i>À £™x™ £™Èä £™È£ £™ÈÓ £™ÈÎ £™È{ £™Èx £™ÈÈ £™ÈÇ £™Èn £™È™ £™Çä £™Ç£ £™ÇÓ £™ÇÎ £™Ç{ £™Çx
  21. Psychological Review © by the American Psychological Association Vol. 101,

    No. 2, 343-352 For personal use only--not for distribution. The Magical Number Seven, Plus or Minus Two Some Limits on Our Capacity for Processing Information George A. Miller Harvard University This paper was first read as an Invited Address before the Eastern Psychological Association in Philadelphia on April 15, 1955. Preparation of the paper was supported by the Harvard Psycho-Acoustic Laboratory under Contract N5ori-76 between Harvard University and the Office of Naval Research, U.S. Navy (Project NR 142-201, Report PNR-174). Reproduction for any purpose of the U.S. Government is permitted. Received: May 4, 1955 My problem is that I have been persecuted by an integer. For seven years this number has followed me around, has intruded in my most private data, and has assaulted me from the pages of our most public journals. This number assumes a variety of disguises, being sometimes a little larger and sometimes a little smaller than usual, but never changing so much as to be unrecognizable. The persistence with which this number plagues me is far more than a random accident. There is, to quote a famous senator, a design behind it, some pattern governing its appearances. Either there really is something unusual about the number or else I am suffering from delusions of persecution.
  22. ./app/models/concerns/availability.rb:89:in!`reference_program' ./app/models/concerns/availability.rb:87:in!`reference_program' ./app/models/scheduling.rb:220:in!`reference_program' ./app/models/rule.rb:171:in!`process_rule_schedulings!' ./app/models/rule.rb:170:in!`process_rule_schedulings!' ./app/models/rule.rb:60:in!`apply' ./app/controllers/rules_controller.rb:29:in!`update' ./app/models/user.rb:38:in!`with_current' ./app/controllers/application_controller.rb:70:in!`with_current_user' ./spec/acceptance/support/auth.rb:24:in!`call'

    ./lib/params_api_parser.rb:14:in!`call' ./spec/acceptance/support/webrat_compatibility.rb:164:in!`post' (eval):2:in!`send' (eval):2:in!`click_button' ./spec/acceptance/edit_vod_scheduling_rules_spec.rb:151 ./spec/acceptance/support/webrat_compatibility.rb:38:in!`call' ./spec/acceptance/support/webrat_compatibility.rb:38:in!`within' ./spec/acceptance/support/webrat_compatibility.rb:37:in!`within' ./spec/acceptance/edit_vod_scheduling_rules_spec.rb:148
  23. RAILS AS SHE IS SPOKE (BY GILES BOWKETT) HOW RAILS

    BREAKS OBJECT-ORIENTED THEORY, AND WHY IT WORKS ANYWAY COPYRIGHT 2012 GILES BOWKETT http://railsoopbook.com
  24. )BNM 34QFD $VDVNCFS 1PTUHSF42- 1SFTFOUFST 4FSWJDFT $PODFSOT 3PMFT %$* .PDLT

    )FYBHPOBM %%% &3# 5FTU6OJU .Z42- $P⒎F4DSJQU