Software Dev Process Lecture Notes - Part 4 Lesson 5 - Software Refactoring
Refactoring
- Process of applying transformations to a program so as to obtain a refactored program.
- Improved design but with same functionality as the original program
- Semantics preserving
- Goal: keep program readable, understandable, and maintainable
- Key feature: behavior preserving
- How can we guarantee that?
- No guarantees, but you can test it!
- If you have a good test suite, that helps a lot.
- Remember, there are no guarantees from testing alone.
Why Refactor?
- Requirements change
- often need to change design to acommodate
- Design needs to be improved
- new feature, more maintainable, etc
- Sloppiness / laziness of developers
- copy/paste programming abstracted into classes or libraries
History of Refactoring
- Refactoring is something that programmers have always done
- Especially important for object-oriented languages
- but useful for all languages
- Opdyke’s PhD Thesis (1990) discusses refacotring for SMALLTALK
- Increasingly popular recently due to agile development adoption
- Fowler’s Book - Improving the Design of Existing Code
- Catalog of refactorings
- List of bad smells
- Guidelines on when to apply refactoring
- Examples of code before and after
Types of Refacotring
- Massive list, we will only cover a few
- Collapse Hierarchy
- A superclass and subclass are tgoo similar
- Consolidate Conditional Expression
- Set of conditionals with the same result
- each check is different but the result is the same
- Combine and extract checks
- Decompose Conditionals
- A conditional statement is particularly complex
- Might be too hard to parse why something does or doesn’t happen
- Extract condition to method call, leverage method name to explain what you’re trying to test for
- Extract Class
- a class may wind up doing the work of two or more, due to code evolution
- creat a new class and move there the relevant fields/methods
- Inline Class
- inverse of extracting a class
- A class may wind up not doing much
- move its features into another class and delete this one
- Extract Method
- most common of the ones we’ve covered
- cohesive code fragment in a large method
- create a method using that fragment, and call that method where needed
How to Refactor
- Full length demo shown here. View video itself for refesher
- Uses demo of Eclipse. Ugh.
Refactoring Risks
- Powerful too, but…
- May introduce subtle faults
- Should not be abused
- performed only when needed
- should be used very carefully on systems in production
Cost of Refactoring
- May be free with good tooling
- But often requires manual work, which costs
- Test development and maintenance, especially those built or added to specifically for a refactoring effort
- Documentation maintenance - changes to names or interfaces must be updated in docs, and that takes effort too
When Not to Refactor
- When code is broken
- Refactoring is not about fixing broken code, it’s about design of code
- Refactoring should never change code behavior, so can’t fix broken code
- When a deadline is close
- time spent on refactoring doesn’t advance features
- risk of regression errors increases risk of missing a deadline
- When there is no reason to!
Bad Smells
- What are bad smells?
- Symptoms in code that may indicate deeper problems
- Usually not bugs, don’t impair function
- But indicate weaknesses in design
- Duplicated Code
- Same piece of code replicated in multiple places
- common from copy/paste programming
- fixed by extract method refactoring
- Long method
- extract method
- decompose conditional
- shorten and break down method to make it more cohesive
- Large class
- extract class or subclass
- break down class to multiple, each with more cohesive functionality
- Shotgun surgery
- every time a change is made, have to go to many classes
- functionality is spread among classes, too much coupling and too little cohesion
- move method/field, inline class
- bring related functionality together, remove dependencies between classes
- Feature envy
- refers to a method that seems more interested in a class other than the one it belongs to
- extract method, move method to class it is referencing
- decreases coupling between classes