Update 2009-05-05: Saw this talk again today at RailsConf and had a chance to fill in some missing pieces…
Is there a grand unified theory of software development? Principles: SOLID Law of Demeter Method chains not good - only talk to objects in local environment. DRY Small Methods Design by Contract Myer on Coupling: old, imperfect model that doesn't extend well to dynamic languages. From best to worst: No coupling Data coupling Data local to two modules: simple data Stamp coupling Data local to two modules: structured data Control coupling Method usually has a "flag" parameter that controls which algorithm it uses ex: Array.instance_methods(true) #What does true mean?! ActiveRecord#find (:first, :all, etc.) External coupling Global data: simple data Common coupling Global data: structured data Content coupling Connascence Things that are born together, and change together. A change in one requires a corresponding change in the other. Originally applied to software by Meilir Page-Jones in early 90's. Connascence of Name: class Customer def email; blah; end end def send_mail(customer) customer.email #Change Customer#email's name, you must update this call. end Rule of Locality: Connascence of name between method parameter and a reference in the same method doesn't matter at all. Connascence of name between two separate libraries matters a lot. It's why APIs must be frozen. Connascence of Position: :orders => {"3" => "1", "5" => "2"} [ [ Order.find(3), true], [ Order.find(5), false ] ] Order of parameters decides behavior. Really bad: def process(order, expedite, confirmation_number, ...); blah; end [order, true, 2374] Easy to forget order of parameters, especially if you're passing 3, ' Better: class OrderDisposition attr_reader :order attr_reader :expedite attr_reader :confirmation_number end Methods that take hash parameters are better than positional arguments, because each argument is labelled and can be re-ordered or omitted. Degree matters: Some types of connascence are worse than others. Connascence of Name better than Connascence of Position. Rule of Degree: Convert higher degrees of connascence into weaker forms. Example: refactor from positional method params to an options hash with named keys (CoP -> CoN). Connascence of Meaning Consider "magic numbers" (these are bad): <input type="checkbox" value="2"> if params[:med][id] == "2" #Have to do case-like statement in totally different module. @medication.given = false end Contranascence Things conflicting with each other. (Always in name?) #my_xml_lib module Kernel; def node; end; end #my_graph_lib module Kernel; def node; end; end #Conflict! Example is classes that must be namespaced to avoid conflict (XML::Node, YAML::Node) Connascence of Algorithm: Logic repeated in multiple places - not DRY. Bad: def add_check_digit(digits); digits + ((10 - digits.foobar{|d| d + 5} % 10).to_s; end def check?(digits) check_sum(digits.foobar{|d| d + 5}) == 10; end Change digits.foobar{|d| d + 5} in one place, you must change it in both places. Better not forget! Better: def add_check_digit(digits); digits + ((10 - foobar(digits) % 10).to_s; end def check?(digits) foobar(digits) == 10; end def foobar(digits); blah; end #Shared routine Change the shared routine, and you change the logic everywhere you need to. Connascence of Timing Race conditions. Bad if called from multiple threads: def increment @amount += 1 end Use Java-like synchronized declarations on methods to ensure they are thread-safe. Connascence of Type See What Every Programmer Should Know About Object Oriented Design, Meilir Page-Jones Connascence of Execution See What Every Programmer Should Know About Object Oriented Design, Meilir Page-Jones Connascence of Value See What Every Programmer Should Know About Object Oriented Design, Meilir Page-Jones Connascence of Identity See What Every Programmer Should Know About Object Oriented Design, Meilir Page-Jones