105
A Critical Look at Fixtures Jim Weirich Chief Scientist EdgeCase LLC @jimweirich Copyright 2009, Jim Weirich All Rights Reserved

A Critical Look at Fixtures

Embed Size (px)

Citation preview

Page 1: A Critical Look at Fixtures

A Critical Look at Fixtures

Jim WeirichChief ScientistEdgeCase LLC@jimweirich

Copyright 2009, Jim WeirichAll Rights Reserved

Page 2: A Critical Look at Fixtures

Fixtures:Who Likes ‘Em?

Page 3: A Critical Look at Fixtures

Why?

Page 4: A Critical Look at Fixtures

<<insert apology here>>

Page 5: A Critical Look at Fixtures

The Grand Unified Theory of Software

Development

Jim WeirichChief ScientistEdgeCase LLC@jimweirich

Copyright 2009, Jim WeirichAll Rights Reserved

Page 6: A Critical Look at Fixtures

GUT

Page 7: A Critical Look at Fixtures

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

Page 8: A Critical Look at Fixtures

Some Principles ...

• SOLID

•Law of Demeter

•DRY

•Small Methods

•Design by Contract

Page 9: A Critical Look at Fixtures

1978

Page 10: A Critical Look at Fixtures

Coupling & Cohesion

Page 11: A Critical Look at Fixtures

NoCoupling

DataCoupling

StampCoupling

ControlCoupling

ExternalCoupling

CommonCoupling

ContentCoupling

Types of Coupling

Page 12: A Critical Look at Fixtures

NoCoupling

DataCoupling

StampCoupling

ControlCoupling

ExternalCoupling

CommonCoupling

ContentCoupling

Less Coupling(good)

MoreCoupling

(bad)

Types of Coupling

Page 13: A Critical Look at Fixtures

NoCoupling

DataCoupling

StampCoupling

ControlCoupling

ExternalCoupling

CommonCoupling

ContentCoupling

Page 14: A Critical Look at Fixtures

NoCoupling

DataCoupling

StampCoupling

ControlCoupling

ExternalCoupling

CommonCoupling

ContentCoupling

Page 15: A Critical Look at Fixtures

NoCoupling

DataCoupling

StampCoupling

ControlCoupling

ExternalCoupling

CommonCoupling

ContentCoupling

Global Data}

Local Data}

Page 16: A Critical Look at Fixtures

NoCoupling

DataCoupling

StampCoupling

ControlCoupling

ExternalCoupling

CommonCoupling

ContentCoupling

Global Data}

Local Data}SimpleData

StructuredData

Page 17: A Critical Look at Fixtures

NoCoupling

DataCoupling

StampCoupling

ControlCoupling

ExternalCoupling

CommonCoupling

ContentCoupling

Page 18: A Critical Look at Fixtures

Control Coupling

• Method has a “flag” parameter

• The flag controls which algorithm to use

Page 19: A Critical Look at Fixtures

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.

Page 20: A Critical Look at Fixtures

Control Coupling

Array.instance_methods

Page 21: A Critical Look at Fixtures

Control Coupling

Array.instance_methodsArray.instance_methods(true)Array.instance_methods(false)

Page 22: A Critical Look at Fixtures

Control Coupling

Array.instance_methodsArray.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.

Page 23: A Critical Look at Fixtures

Control Coupling

Array.instance_methodsArray.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.

Page 24: A Critical Look at Fixtures

Another Example?

Page 25: A Critical Look at Fixtures

Control Coupling

Customer.find(:first, ...)Customer.find(:all, ...)

Page 26: A Critical Look at Fixtures

Control Coupling

Customer.find(:first, ...)Customer.find(:all, ...)

Returns object

Returns list of objects

Page 27: A Critical Look at Fixtures

Myer’s Classifications were ‘OK’

Page 28: A Critical Look at Fixtures

Failed to extend well to Objects and Dynamic Languages

Page 29: A Critical Look at Fixtures

1996

Page 30: A Critical Look at Fixtures

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.

Page 31: A Critical Look at Fixtures

Connascence

Two pieces of software share connascence when a changes in one requires a corresponding change in the other.

Page 32: A Critical Look at Fixtures

CoN

Page 33: A Critical Look at Fixtures

class Customer def email ... endend

def send_mail(customer) customer.email ...end

Page 34: A Critical Look at Fixtures

class Customer def email ... endend

def send_mail(customer) customer.email ...end

Page 35: A Critical Look at Fixtures

class Customer def email ... endend

def send_mail(customer) customer.email ...end

Connascence of Name

Page 36: A Critical Look at Fixtures

create_table “customers” do |t| t.column :email, :string ...end

def send_mail(customer) customer.email ...end

Connascence of Name

Page 37: A Critical Look at Fixtures

class Customer def email ... endend

def send_mail(customer) customer.email ...end

Another example?

Connascence of Name

Page 38: A Critical Look at Fixtures

class Customer def email ... endend

def send_mail(customer) customer.email ...end

Connascence of Name

Another example?

X

Page 39: A Critical Look at Fixtures

class Customer def email ... endend

def send_mail(customer) customer.email ...end

Connascence of Name

Another example?

Page 40: A Critical Look at Fixtures

Locality Matters

Page 41: A Critical Look at Fixtures

StrongerConnascence

WeakerConnascence

Rule of Locality

Page 42: A Critical Look at Fixtures

Rule of Locality

As the distance between software elements increases,

use weaker forms of connascence.

Page 43: A Critical Look at Fixtures

CoP

Page 44: A Critical Look at Fixtures

:orders => { “3” => “1”, “5” => “2”}

[ [ Order.find(3), true ], [ Order.find(5), false ],]

Translate params hashto

A List of Pairs

Page 45: A Critical Look at Fixtures

def process_orders(list_of_pairs) list_of_pairs.each do |order, expedite| # handle an order endend

[ [ Order.find(3), true ], [ Order.find(5), false ],]

Order of the datawithin the pairis significant

Page 46: A Critical Look at Fixtures

class OrdersController def build_order_list(params) [order, flag] endend

class Orders def process_orders(pairs) pairs.each do |order, flag| ... end endend

Page 47: A Critical Look at Fixtures

class OrdersController def build_order_list(params) [order, flag] endend

class Orders def process_orders(pairs) pairs.each do |order, flag| ... end endend

Connascence of Position

Page 48: A Critical Look at Fixtures

Consider

Page 49: A Critical Look at Fixtures

[ order, expedite ]

Low Degree of CoP

Page 50: A Critical Look at Fixtures

[ order, expedite, confirmation_number, ordered_date, expiration, special ]

High Degree of CoP

Page 51: A Critical Look at Fixtures

class OrderDisposition attr_reader :order, :expedite, :confirmation_number, :ordered_date, :expiration, :special ...end

CoP CoN

Page 52: A Critical Look at Fixtures

Degree Matters

Page 53: A Critical Look at Fixtures

CoN < CoP

Page 54: A Critical Look at Fixtures

Rule of Degree

Convert high degrees of connascenceinto

weaker forms of connascence

Page 55: A Critical Look at Fixtures

Another Example?

Page 56: A Critical Look at Fixtures

def find(conditions, ordered_by) ...end

Customers.find( [“last_name = ?”, “Weirich”], “age”)

Page 57: A Critical Look at Fixtures

def find(conditions, ordered_by, limit, offset, selected) ...end

Customers.find( [“last_name = ?”, “Weirich”], “age”, 12, 24, [‘first_name’, ‘last_name’])

Page 58: A Critical Look at Fixtures

def find(options={}) ...end

Customers.find( :conditions => [“last_name = ?”, “Weirich”], :order_by => “age”, :limit => 12, :offset => 24, :select => [‘first_name’, ‘last_name’])

CoP CoN

Page 59: A Critical Look at Fixtures

Another Example?

Page 60: A Critical Look at Fixtures

def test_user_can_do_something_interesting user = User.find(:first) ...end

Connascence of Position

Page 61: A Critical Look at Fixtures

def test_user_can_do_something_interesting user = User.find_by_name(“Jim”) ...end

Connascence of Position

Page 62: A Critical Look at Fixtures

CoM

Page 63: A Critical Look at Fixtures

<input type="checkbox" value="2" /><input type="checkbox" value="1" />

Page 64: A Critical Look at Fixtures

<input type="checkbox" value="2" /><input type="checkbox" value="1" />

Page 65: A Critical Look at Fixtures

<input type="checkbox" value="2" /><input type="checkbox" value="1" />

if params[:med][id] == "1" mark_given(id)elsif params[:med][id] == "2" mark_not_given(id)end

Page 66: A Critical Look at Fixtures

<input type="checkbox" value="2" /><input type="checkbox" value="1" />

if params[:med][id] == "1" mark_given(id)elsif params[:med][id] == "2" mark_not_given(id)end

Connascence of Meaning

Page 67: A Critical Look at Fixtures

MED_GIVEN = "1"MED_NOT_GIVEN = "2"

Connascence of Meaning

Page 68: A Critical Look at Fixtures

<input type="checkbox" value="<%= MED_GIVEN %>" /><input type="checkbox" value="<%= MED_NOT_GIVEN %>" />

if params[:med][id] == MED_GIVEN mark_given(id)elsif params[:med][id] == MED_NOT_GIVEN mark_not_given(id)end

CoM CoNMED_GIVEN = "1"MED_NOT_GIVEN = "2"

Page 69: A Critical Look at Fixtures

<input type="checkbox" value="<%= MED_GIVEN %>" /><input type="checkbox" value="<%= MED_NOT_GIVEN %>" />

if params[:med][id] == MED_GIVEN mark_given(id)elsif params[:med][id] == MED_NOT_GIVEN mark_not_given(id)end

CoM CoNMED_GIVEN = “1”MED_NOT_GIVEN = “2”

Page 70: A Critical Look at Fixtures

CN

Page 71: A Critical Look at Fixtures

MED_GIVEN = "1"

MED_NOT_GIVEN = "2"

Revisit

Page 72: A Critical Look at Fixtures

MED_GIVEN = "1"

MED_NOT_GIVEN = "2"

Page 73: A Critical Look at Fixtures

MED_GIVEN = "1"

MED_NOT_GIVEN = "1"X

Page 74: A Critical Look at Fixtures

MED_GIVEN = "1"

MED_NOT_GIVEN = "1"XContranascence

Page 75: A Critical Look at Fixtures

Another Example?

Page 76: A Critical Look at Fixtures

class Node ...end

My XML Library

Contranascence

Page 77: A Critical Look at Fixtures

class Node ...end

My XML Library

class Node ...end

Your Graphing Library

Contranascence

Page 78: A Critical Look at Fixtures

class Node ...end

My XML Library

class Node ...end

Your Graphing Library

Contranascence

Page 79: A Critical Look at Fixtures

module MyXml class Node ... endend

My XML Library

module YourGraphing class Node ... endend

Your Graphing Library

Contranascence

Page 80: A Critical Look at Fixtures

irb/slex.rb:92: class Nodetkextlib/blt/tree.rb:15: class Node < TkObjecttkextlib/blt/treeview.rb:18: class Node < TkObjecttkextlib/blt/treeview.rb:966: class Node < TkObjecttkextlib/bwidget/tree.rb:13: class Node < TkObjecttkextlib/bwidget/tree.rb:262: class Nodexmlrpc/parser.rb:17: class Nodeyaml/syck.rb:14: class Node

Contranascence

Page 81: A Critical Look at Fixtures

Another Example?

Page 82: A Critical Look at Fixtures

module Kernel def to_node ... endend

My XML Library

module Kernel def to_node ... endend

Your Graphing Library

Contranascence

Page 83: A Critical Look at Fixtures

module Kernel def to_node ... endend

My XML Library

module Kernel def to_node ... endend

Your Graphing Library

Contranascence

X

Page 84: A Critical Look at Fixtures

Selector Namespaces

Contranascence

(Ruby 2 ?)

Page 85: A Critical Look at Fixtures

CoA

Page 86: A Critical Look at Fixtures

“314159728”add_check_digit(“31415972”)

check?(“ 314159728”)

check?(“ 314159723”)

true

false

Page 87: A Critical Look at Fixtures

def add_check_digit(digits) check_sum = digits.split(//). inject(0) { |r, n| r + n.to_i } % 10 digits + ((10 - check_sum) % 10).to_send

def check?(digits) check_sum = digits.split(//). inject(0) { |r, n| r + n.to_i } % 10 check_sum == 0 end

Page 88: A Critical Look at Fixtures

def add_check_digit(digits) check_sum = digits.split(//). inject(0) { |r, n| r + n.to_i } % 10 digits + ((10 - check_sum) % 10).to_send

def check?(digits) check_sum = digits.split(//). inject(0) { |r, n| r + n.to_i } % 10 check_sum == 0 end

Page 89: A Critical Look at Fixtures

def add_check_digit(digits) check_sum = digits.split(//). inject(0) { |r, n| r + n.to_i } % 10 digits + ((10 - check_sum) % 10).to_send

def check?(digits) check_sum = digits.split(//). inject(0) { |r, n| r + n.to_i } % 10 check_sum == 0 end

Connascence of Algorithm

Page 90: A Critical Look at Fixtures

def add_check_digit(digits) digits + ((10 - check_sum(digits)) % 10).to_send

def check?(digits) check_sum(digits) == 0 end

CoA CoN

def check_sum(digits) check_sum = digits.split(//). inject(0) { |r, n| r + n.to_i } % 10end

Page 91: A Critical Look at Fixtures

def add_check_digit(digits) digits + ((10 - check_sum(digits)) % 10).to_send

def check?(digits) check_sum(digits) == 0 end

DRY

def check_sum(digits) digits.split(//). inject(0) { |r, n| r + n.to_i } % 10end

Page 92: A Critical Look at Fixtures

So, Back to Fixtures

Page 93: A Critical Look at Fixtures

jim: id: 1 name: Jim password_hash: jwSamN1gljMBA role_id: 2

admin: id: 1 name: adminworker: id: 2 name: worker

Page 94: A Critical Look at Fixtures

jim: name: Jim password_hash: jwSamN1gljMBA role: admin

admin: name: adminworker: name: worker

Eliminate IDs(CoP => CoN)

Page 95: A Critical Look at Fixtures

jim: name: Jim password_hash: <%=“password”.crypt(“jw”)%> role: admin

admin: name: adminworker: name: worker

Eliminate Literals(CoA => CoN)

Page 96: A Critical Look at Fixtures

What Else?

Page 97: A Critical Look at Fixtures

def test_finder workers = User.find_all_workers assert_equal 2, workers.sizeend

adam: role: workerbill: role: worker

Page 98: A Critical Look at Fixtures

def test_finder workers = User.find_all_workers assert_equal 2, workers.sizeend

adam: role: workerbill: role: workercarl: worker: worker

Page 99: A Critical Look at Fixtures

def test_finder workers = User.find_all_workers assert_equal 2, workers.sizeend

adam: role: workerbill: role: workercarl: worker: worker

Rule of Locality

Page 100: A Critical Look at Fixtures

Solution?

Page 101: A Critical Look at Fixtures

Lots!

• Fixture Scenarios

• Factory Girl

• Foundry (Jeremy McAnally)

•Roll Your Own

Page 102: A Critical Look at Fixtures

Summary

Page 103: A Critical Look at Fixtures

Connascence• Static

• Connascence of Name

• Connascence of Type

• Connascence of Meaning

• Connascence of Algorithm

• Connascence of Position

• Dynamic

• Connascence of Execution

• Connascence of Timing

• Connascence of Value

• Connascence of Identity

• Contranascence

• Rule of Locality

• Rule of Degree

Rules

Page 104: A Critical Look at Fixtures

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

Page 105: A Critical Look at Fixtures

Thank You!git://github.com/jimweirich/presentation_connascence.git

Copyright 2009 by Jim Weirich, Some Rights Reserved