"My guiding light is Kent Beck's rules of Simple Design
It's time to stop refactoring when the code makes a reasonable stab at meeting those goals, and when any further changes would add no further benefit."
--from an interview about his refactoring book(with the best cover illustration ever for a programming book).
each logic change req's coding changes only to parts of big class Extract Class
one logic change req's coding changes in many classes Move Method Move Field or Extract Class or Inline Class
put things together that change together Move Method
YAGNI violations (only tests call this code!) Collapse Hierarchy or Inline Class or Inline Module or Remove Parameter or Rename Method
only used sometimes in its class Extract Class or Introduce Null Object or Replace Method with Method Object
chain of method calls on same object Hide Delegate or Extract Method
when everything is delegated, remove delegation Inline Method or Replace Delegation with Hierarchy
between 2 classes Move Method or Move Field or Change Bidirectional Association to Unidirectional or Extract Class or Hide Delegate or Replace Inheritance with Delegation
doing same thing in more than one method Rename Method or Move Method or Extract Module
a class with attributes but no methods Remove Setting Method or Hide Method or Encapsulate Collection or Move Method to get logic from user of class into class
only if subclass tries to block methods of super Replace Inheritance with Delegation
if they compensate for bad code. good ones say why not what Extract Method or Rename Method or Introduce Assertion
Replace Dynamic Receptor with Dynamic Method Definition or Extract Method or Isolate Dynamic Receptor
when method body is clear enough move it out of method
remove temp var by replacing references w/ the expression
means replace temp variable with method call returning same value
when many method calls on same object, chain them
replace complex expression w/ temp var named well to explain expression logic
don't re-use temp var names for different purposes
don't change what object a parameter points to
make very long method w/many local vars into object w/instance vars where one of its attributes is the object it's acting on
rewrite ugly method with better algorithm
select, reject, map, inject, etc. instead of loops
if only middle of method varies, combine into one method with block parameter
like attr_reader, to make very common functions declarative
make params into hash at end of param list. see pg 144 for Class.hash_initializer to load them all into instance vars
if it would be easier to understand as simple parameters
if parameter never uses its default, remove it
use define_method or def_each (pg 154) or instance_exec or class annotation for repetitive method definitions
use define_method rather than method_missing
isolate method_missing in its own class
for speed, expand scope of string to be eval'd
if some methods and some state
fold tiny class into class that uses it
replace mgr = john.department.manager w/ john.manager so person object has def manager; @department.manager; end
replace mgr = john.manager w/ john.department.manager
use getter/setter rather than @var
ex: phone num was primitive, needs to be collection of fields and methods
ex: simple customer object different for each order, each customer needs to be a single object that is referenced by each order
an immutable reference object could become a data object
when each elem means something different
when each elem means something different
to couple 2 classes with pointer and backpointer (needs explicit test for backpointer)
remove backpointer
ex PI = 3.14159
do not return a collection because it could be changed outside object: return copy of collection. do not have setter for collection: have add/remove
class to serve as proxy between data record and rest of program
most of class is based on checking type variable, so have different subclasses for each type (assumes type known at object creation)
lots of shared logic, some different by type so mixin diff module for each instance to hold different logic like this: def type_code=(X); extend(X); end
lots of shared logic, some different by type so may need to change type at runtime where instance variable is a state/strategy object to hold the different logic
if subclass very simple move its logic into the class
ex: def emails; @emails ||= []; end
ex: def initialize; @emails = []; end
make multi-part conditional expression into method named after its purpose
use || rather than ternary, use return rather than conditional
make method of conditions if many conditions give same result
extract any code duplicated in all branches of conditional
use break or return for multiple exits from loop
use return if x for special cases, then do standard case
different classes with same method name rather than conditional
if many checks for nil, make a new class (possibly a singleton) that accepts same messages as real one and returns appropriate value eg, MissingPerson or UnknownCustomer
in an assertions module
when name does not express purpose
if it's not used, that is
separate methods for return value and change state
combine similar methods that vary by one or a few values into one method
ex: switch.turn_on, switch.turn_off rather than switch.change_state(true/false)
send object as parameter, not its attributes
if parameter just contains result of method call
to combine many parameters into one object parameter
if not used, that is
making it private
complex create method rather than initialize, possibly returns objects of different class
raise an exception rather than using own error codes
exceptions should be used only in exceptional cases
between OO code and complex or non-OO API
like a DSL for using the gateway
move it farther up the method call stack (to superclass, usually)
move it lower on the method call stack (to classthat uses it)
if some methods and no state
fold tiny module into class that uses it
if some methods/state used only in some cases, and if delegation not a better idea
to share behavior of different classes
if class and subclass very similar, combine them
sequence of steps in superclass method, steps defined in subclass methods
esp if subclass of collection using few methods of collection, instead define those methods using Forwardable
when too many methods are delegated
when a class is never instantiated
if two sets of responsibilities, use two hierarchies and delegation
Make each record type a data object with attributes and no methods. Put all remaining procedural code into one class. Refactor.
make fat models
each special case becomes a subclass