2. What is refactoring?
• An individual Refactoring is a software change:
To make it easier to understand
To make it cheaper to modify
Without changing its observable behavior
• It’s based on a self-checking suite of test (<1 minute)
• = ∑ small steps
• Start Run Test Run Test Run Test
Note: Changes are Committed after every green status
Step a
Few minutes
Step b
Few minutes
Step c
Few minutes
Step b again
Few minutes
4. When to refactor?
• Best time is just before I need to “touch” it (after investing some
time trying to understand it)
• Add a new feature
• Fix a bug
• In a code review
• Several aims:
• Comprehension refactoring
• Preparatory refactoring
A B
5. When NOT to refactor?
• It’s easier to rewrite it
• When I don´t need to modify it
• In case I found a large refactoring vs small new
feature. It depends, there is a tradeoff. I certainly
refactor:
• If it makes my new feature easier to implement
• If this is a code I visit frequently
6. What do I tell my manager?
• Don´t try to justify with moral reasons: “Clean code”, “Good
programming practice”, …
• Don´t schedule weeks of pure refactoring
I don´t put time on my plans to do refactoring. Most refactoring
happens while I’m adding features or fixing bugs
• Depends on your manager. Is he a techy manager?
• Yes Isn’t hard to justify.
• No Just don´t tell.
7. How do I get a solid test suite?
• It’s risk driven activity:
• Don´t test every public method.
• 100% coverage ≠ test suite quality
• Write tests to try to find bugs (now or in the future).
• Write test in areas that I´m worried about going wrong.
• Write tests for all the things should do, and for any condition that might cause the class to
fail
• First happy path, and then test at boundaries.
• Write test (on your contracts / APIs), so they don´t depend on your
implementation details.
• Otherwise I can spend more time changing the tests than the code under test
8. FAQ:
• Software Limits (API)
• Databases
• Feature branches
• Legacy code. See Book “Working Effectively with Legacy Code” from
Michael Feathers
• Architecture: Simple design / Incremental design / YAGNI
/Evolutionary architecture
9. The most useful to learn first
Refactorings Before After
Extract/Inline Function Lines of code [intention is not clear] f()
Extract/Inline Variable Expression: a * b + c const product = a*b
Change Function Declaration f(a,b) newName(a,b) or f(a) or f(a,b,c)
Encapsulate Variable alpha=23 setAlpha(a)
alpha()
Introduce Parameter Object f(min,max) range = new Range(min,max)
f(range)
Combine Functions into Class f1(), f2(), … Class X{ f1() f2() }
Combine Functions into
Transform
calculateBase(aReading)
calculateCharge(aReading)
enrichReading(original) {
const result= _.cloneDeep(original)
result.base=calculateBase(result)
result.charge=calculateCharge(result)
Split Phase Long Function f() f(){
priceOrder()
calculateShipping() }
Refactoring List I:
Note: Red ones are the opposite
10. Encapsulation Moving Features Organising Data
Encapsulate Record Move Function Split Variable
Encapsulate Collection Move Field Rename Field
Replace primitive with
Object
Move Statements into Functions
Move Statements to Callers
Replace derived variable with Query
Replace temp with Query Replace Inline code with existing
function call
Change Reference to Value
Change Value to Reference
Extract / Inline Class Slide statements
Hide Delegate
Remove Middle Man
Split loop
Substitute algorithm Replace loop with pipeline
Remove dead code
Hide secrets (data structures). Mainly for mutable data
Modularity: Only understand a small part to make a change
Data Structure are the key to understand what’s going on
Refactoring List II:
11. Simplifying conditional logic Refactoring APIs Dealing with Inheritance
Decompose conditional Separate Query from modifier Pull up / Push down method
Consolidate conditional
expression
Parameterize function Pull up / Push down field
Replace nested conditional with
guard clauses
Remove flag argument Pull up constructor body
Replace contional with
Polymorphism
Preserve Whole Object Replace type code with subclasses
Remove subclass
Introduce special case Replace Parameter with query
Replace Query with Parameter
Extract Superclass
Introduce Assertion Remove Setting method Collapse Hierarchy
Replace constructor with Factory function Replace subclass with delegate
Replace Function with Command Object
Replace command object with function
Replace superclass with delegate
Much of the complexity of programs lies in conditional logic
APIs are the module joints. Make it easy to understand / use
Inheritance can only be played once
Refactoring List III:
12.
13. • And now let’s go on with the kata:
martinsson/BugsZero-Kata
Editor's Notes
Any fool can write code that a computer can understand. Good programmers write code that humans can understand
Modify = Add new features / fix bugs
No new functionality, no new tests
Ej: When Refactoring don´t think about performance optimization
In a code review pair programming is recommended
API Rename
Mark old function as deprecated, pass-through to the new one.
Database:
Use data migration scripts & versioning
Refactoring are separated over several consecutive production releases
Branches
Feature branches last < 1 day (CI)
Break large features into smaller chunks
Use Feature flags
Merges: The larger the feature branch, the more complicated
Merges: The larger the feature branch, the less refactoring (as merges are more complicated)
Legacy code:
Refactoring can be a fantastic tool to understand it. But there is a common lack of tests.
Refactor step by step, not all at once
Refactor more in areas you visit frequently
Architecture:
Architecture before coding. And put flexibility mechanism into SW Slow down my ability to react to change
Build SW that solves ONLY the currently understood needs. As my understanding changes I use Refactoring to adapt to those new demands.