A Critical Look at Fixtures

640 views

Published on

Published in: Technology, Business
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
640
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
7
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

A Critical Look at Fixtures

  1. 1. A Critical Look at Fixtures Jim Weirich Chief Scientist EdgeCase LLC @jimweirich Copyright 2009, Jim Weirich All Rights Reserved
  2. 2. Fixtures: Who Likes ‘Em?
  3. 3. Why?
  4. 4. <<insert apology here>>
  5. 5. The Grand Unified Theory of Software Development Jim Weirich Chief Scientist EdgeCase LLC @jimweirich Copyright 2009, Jim Weirich All Rights Reserved
  6. 6. GUT
  7. 7. Principle a. a comprehensive and fundamental law, doctrine, or assumption b. (1) a rule or code of conduct (2) habitual devotion to right principles <a man of principle> c. the laws or facts of nature underlying the working of an artificial device
  8. 8. Some Principles ... • SOLID • Law of Demeter • DRY • Small Methods • Design by Contract
  9. 9. 1978
  10. 10. Coupling & Cohesion
  11. 11. No Types of Coupling Data Coupling Coupling Stamp Coupling Control Coupling External Coupling Common Coupling Content Coupling
  12. 12. No Types of Less Coupling Coupling Data Coupling (good) Coupling Stamp Coupling Control Coupling External Coupling Common More Coupling Coupling Content (bad) Coupling
  13. 13. No Coupling Data Coupling Stamp Coupling Control Coupling External Coupling Common Coupling Content Coupling
  14. 14. No Coupling Data Coupling Stamp Coupling Control Coupling External Coupling Common Coupling Content Coupling
  15. 15. No Coupling } Data Coupling Local Data Stamp Coupling Control Coupling } External Coupling Global Data Common Coupling Content Coupling
  16. 16. No Coupling } Simple Data Coupling Data Local Data Stamp Coupling Control Coupling } External Structured Coupling Data Global Data Common Coupling Content Coupling
  17. 17. No Coupling Data Coupling Stamp Coupling Control Coupling External Coupling Common Coupling Content Coupling
  18. 18. Control Coupling • Method has a “flag” parameter • The flag controls which algorithm to use
  19. 19. Control Coupling • Method has a “flag” parameter • The flag controls which algorithm to use • Symptoms • The word “OR” in description • Flag value is arbitrary and not related to problem domain.
  20. 20. Control Coupling Array.instance_methods
  21. 21. Control Coupling Array.instance_methods Array.instance_methods(true) Array.instance_methods(false)
  22. 22. Control Coupling Array.instance_methods Array.instance_methods(true) Array.instance_methods(false) ... the instance methods in mod are returned, otherwise the methods in mod and mod's superclasses are returned.
  23. 23. Control Coupling Array.instance_methods Array.instance_methods(true) Array.instance_methods(false) ... the instance methods in mod are returned, otherwise the methods in mod and mod's superclasses are returned.
  24. 24. Another Example?
  25. 25. Control Coupling Customer.find(:first, ...) Customer.find(:all, ...)
  26. 26. Control Coupling Returns object Customer.find(:first, ...) Customer.find(:all, ...) Returns list of objects
  27. 27. Myer’s Classifications were ‘OK’
  28. 28. Failed to extend well to Objects and Dynamic Languages
  29. 29. 1996
  30. 30. Connascence 1. The common birth of two or more at the same tome; production of two or more together. 2. That which is born or produced with another. 3. The act of growing together.
  31. 31. Connascence Two pieces of software share connascence when a changes in one requires a corresponding change in the other.
  32. 32. CoN
  33. 33. class Customer def email ... end end def send_mail(customer) customer.email ... end
  34. 34. class Customer def email ... end end def send_mail(customer) customer.email ... end
  35. 35. Connascence of Name class Customer def email ... end end def send_mail(customer) customer.email ... end
  36. 36. Connascence of Name create_table “customers” do |t| t.column :email, :string ... end def send_mail(customer) customer.email ... end
  37. 37. Connascence of Name Another example? class Customer def email ... end end def send_mail(customer) customer.email ... end
  38. 38. Connascence of Name Another example? class Customer X def email ... end end def send_mail(customer) customer.email ... end
  39. 39. Connascence of Name Another example? class Customer def email ... end end def send_mail(customer) customer.email ... end
  40. 40. Locality Matters
  41. 41. Rule of Locality Stronger Connascence Weaker Connascence
  42. 42. Rule of Locality As the distance between software elements increases, use weaker forms of connascence.
  43. 43. CoP
  44. 44. :orders => { “3” => “1”, “5” => “2” } Translate params hash to A List of Pairs [ [ Order.find(3), true ], [ Order.find(5), false ], ]
  45. 45. def process_orders(list_of_pairs) list_of_pairs.each do |order, expedite| # handle an order end end Order of the data within the pair is significant [ [ Order.find(3), true ], [ Order.find(5), false ], ]
  46. 46. class OrdersController def build_order_list(params) [order, flag] end end class Orders def process_orders(pairs) pairs.each do |order, flag| ... end end end
  47. 47. Connascence of Position class OrdersController def build_order_list(params) [order, flag] end end class Orders def process_orders(pairs) pairs.each do |order, flag| ... end end end
  48. 48. Consider
  49. 49. Low Degree of CoP [ order, expedite ]
  50. 50. High Degree of CoP [ order, expedite, confirmation_number, ordered_date, expiration, special ]
  51. 51. CoP CoN class OrderDisposition attr_reader :order, :expedite, :confirmation_number, :ordered_date, :expiration, :special ... end
  52. 52. Degree Matters
  53. 53. CoN < CoP
  54. 54. Rule of Degree Convert high degrees of connascence into weaker forms of connascence
  55. 55. Another Example?
  56. 56. Customers.find( [“last_name = ?”, “Weirich”], “age”) def find(conditions, ordered_by) ... end
  57. 57. Customers.find( [“last_name = ?”, “Weirich”], “age”, 12, 24, [‘first_name’, ‘last_name’]) def find(conditions, ordered_by, limit, offset, selected) ... end
  58. 58. CoP CoN Customers.find( :conditions => [“last_name = ?”, “Weirich”], :order_by => “age”, :limit => 12, :offset => 24, :select => [‘first_name’, ‘last_name’]) def find(options={}) ... end
  59. 59. Another Example?
  60. 60. Connascence of Position def test_user_can_do_something_interesting user = User.find(:first) ... end
  61. 61. Connascence of Position def test_user_can_do_something_interesting user = User.find_by_name(“Jim”) ... end
  62. 62. CoM
  63. 63. <input type=quot;checkboxquot; value=quot;2quot; /> <input type=quot;checkboxquot; value=quot;1quot; />
  64. 64. <input type=quot;checkboxquot; value=quot;2quot; /> <input type=quot;checkboxquot; value=quot;1quot; />
  65. 65. <input type=quot;checkboxquot; value=quot;2quot; /> <input type=quot;checkboxquot; value=quot;1quot; /> if params[:med][id] == quot;1quot; mark_given(id) elsif params[:med][id] == quot;2quot; mark_not_given(id) end
  66. 66. Connascence of Meaning <input type=quot;checkboxquot; value=quot;2quot; /> <input type=quot;checkboxquot; value=quot;1quot; /> if params[:med][id] == quot;1quot; mark_given(id) elsif params[:med][id] == quot;2quot; mark_not_given(id) end
  67. 67. Connascence of Meaning MED_GIVEN = quot;1quot; MED_NOT_GIVEN = quot;2quot;
  68. 68. CoM CoN MED_GIVEN = quot;1quot; MED_NOT_GIVEN = quot;2quot; <input type=quot;checkboxquot; value=quot;<%= MED_GIVEN %>quot; /> <input type=quot;checkboxquot; value=quot;<%= MED_NOT_GIVEN %>quot; /> if params[:med][id] == MED_GIVEN mark_given(id) elsif params[:med][id] == MED_NOT_GIVEN mark_not_given(id) end
  69. 69. CoM CoN MED_GIVEN = “1” MED_NOT_GIVEN = “2” <input type=quot;checkboxquot; value=quot;<%= MED_GIVEN %>quot; /> <input type=quot;checkboxquot; value=quot;<%= MED_NOT_GIVEN %>quot; /> if params[:med][id] == MED_GIVEN mark_given(id) elsif params[:med][id] == MED_NOT_GIVEN mark_not_given(id) end
  70. 70. CN
  71. 71. Revisit MED_GIVEN = quot;1quot; MED_NOT_GIVEN = quot;2quot;
  72. 72. MED_GIVEN = quot;1quot; MED_NOT_GIVEN = quot;2quot;
  73. 73. X MED_GIVEN = quot;1quot; MED_NOT_GIVEN = quot;1quot;
  74. 74. Contranascence X MED_GIVEN = quot;1quot; MED_NOT_GIVEN = quot;1quot;
  75. 75. Another Example?
  76. 76. Contranascence My XML Library class Node ... end
  77. 77. Contranascence My XML Library Your Graphing Library class Node class Node ... ... end end
  78. 78. Contranascence My XML Library Your Graphing Library class Node class Node ... ... end end
  79. 79. Contranascence My XML Library Your Graphing Library module MyXml module YourGraphing class Node class Node ... ... end end end end
  80. 80. Contranascence irb/slex.rb:92: class Node tkextlib/blt/tree.rb:15: class Node < TkObject tkextlib/blt/treeview.rb:18: class Node < TkObject tkextlib/blt/treeview.rb:966: class Node < TkObject tkextlib/bwidget/tree.rb:13: class Node < TkObject tkextlib/bwidget/tree.rb:262: class Node xmlrpc/parser.rb:17: class Node yaml/syck.rb:14: class Node
  81. 81. Another Example?
  82. 82. Contranascence My XML Library Your Graphing Library module Kernel module Kernel def to_node def to_node ... ... end end end end
  83. 83. Contranascence X My XML Library Your Graphing Library module Kernel module Kernel def to_node def to_node ... ... end end end end
  84. 84. Contranascence Selector Namespaces (Ruby 2 ?)
  85. 85. CoA
  86. 86. add_check_digit(“31415972”) “314159728” check?(“ 314159728”) true check?(“ 314159723”) false
  87. 87. def add_check_digit(digits) check_sum = digits.split(//). inject(0) { |r, n| r + n.to_i } % 10 digits + ((10 - check_sum) % 10).to_s end def check?(digits) check_sum = digits.split(//). inject(0) { |r, n| r + n.to_i } % 10 check_sum == 0 end
  88. 88. def add_check_digit(digits) check_sum = digits.split(//). inject(0) { |r, n| r + n.to_i } % 10 digits + ((10 - check_sum) % 10).to_s end def check?(digits) check_sum = digits.split(//). inject(0) { |r, n| r + n.to_i } % 10 check_sum == 0 end
  89. 89. Connascence of Algorithm def add_check_digit(digits) check_sum = digits.split(//). inject(0) { |r, n| r + n.to_i } % 10 digits + ((10 - check_sum) % 10).to_s end def check?(digits) check_sum = digits.split(//). inject(0) { |r, n| r + n.to_i } % 10 check_sum == 0 end
  90. 90. CoA CoN def add_check_digit(digits) digits + ((10 - check_sum(digits)) % 10).to_s end def check?(digits) check_sum(digits) == 0 end def check_sum(digits) check_sum = digits.split(//). inject(0) { |r, n| r + n.to_i } % 10 end
  91. 91. DRY def add_check_digit(digits) digits + ((10 - check_sum(digits)) % 10).to_s end def check?(digits) check_sum(digits) == 0 end def check_sum(digits) digits.split(//). inject(0) { |r, n| r + n.to_i } % 10 end
  92. 92. So, Back to Fixtures
  93. 93. jim: id: 1 name: Jim password_hash: jwSamN1gljMBA role_id: 2 admin: id: 1 name: admin worker: id: 2 name: worker
  94. 94. Eliminate IDs (CoP => CoN) jim: name: Jim password_hash: jwSamN1gljMBA role: admin admin: name: admin worker: name: worker
  95. 95. Eliminate Literals (CoA => CoN) jim: name: Jim password_hash: <%=“password”.crypt(“jw”)%> role: admin admin: name: admin worker: name: worker
  96. 96. What Else?
  97. 97. adam: role: worker bill: role: worker def test_finder workers = User.find_all_workers assert_equal 2, workers.size end
  98. 98. adam: role: worker bill: role: worker carl: worker: worker def test_finder workers = User.find_all_workers assert_equal 2, workers.size end
  99. 99. Rule of Locality adam: role: worker bill: role: worker carl: worker: worker def test_finder workers = User.find_all_workers assert_equal 2, workers.size end
  100. 100. Solution?
  101. 101. Lots! • Fixture Scenarios • Factory Girl • Foundry (Jeremy McAnally) • Roll Your Own
  102. 102. Summary
  103. 103. Connascence • • Static Dynamic • • Connascence of Name Connascence of Execution • • Connascence of Type Connascence of Timing • • Connascence of Meaning Connascence of Value • • Connascence of Algorithm Connascence of Identity • • Connascence of Position Contranascence Rules • Rule of Locality • Rule of Degree
  104. 104. References • What Every Programmer Should Know About Object Oriented Design, Meilir Page-Jones • Fundamentals of Object-Oriented Design in UML, Meilir Page-Jones • Composite/Structured Design, Glenford Myers • Reliable Software Through Composite Design, Glenford Myers • Agile Software Development, Principles, Patterns, and Practices, Robert Martin • Object-Oriented Software Construction, Bertrand Meyer • The Pragmatic Programmer: From Journeyman to Master, Andy Hunt & Dave Thomas
  105. 105. Thank You! git://github.com/jimweirich/presentation_connascence.git Copyright 2009 by Jim Weirich, Some Rights Reserved

×