3. Underengineering
AKA "fast, slow, slower.... never :("
quickly deliver 1.0 release that works well for our
customers but with junky code
working on 2.0 release, junky code slows you down,
and new features are harder to implement
as junky code multiplies, people lose faith into the
system and the programmers
planning next release, you realize you can't win, and
start thinking about a total rewrite
4. Overengineering
AKA "the 'HelloWorld' pattern"
code more sophisticated that it possible future
requirements
code hard to understand for new ones
time wasted understanding and maintaining complex
code so you need to write documentation
5. Code smells
copy/paste (duplicate) code
large method/class
method-like properties
contrived complexity (patterns everywhere!)
inappropriate intimacy
unused code
dangerous if (if - else if - else if - else...)
6. Cunningham's metaphor
The technical language doesn't communicate
effectively with the vast majority of management.
Instead, Ward Cunningham's financial metaphor of
design debt works infinitely better.
Design debt occurs when you don't consistently do
three things.
1. Remove duplication.
2. Simplify your code.
3. Clarify you code's intent.
7. Cunningham's metaphor
Few systems remain completely free of design debt.
Wired as we are, humans just don't write perfect code
the first time around. We naturally accumulate design
debt. So the question becomes:
"When do you pay it down?"
8. And so, refactoring!
Refactoring is the process of changing a software
system in such a way that it does not alter the external
behavior of the code yet improves its internal
structure.
A refactoring is a "behavior-preserving transformation"
or, as Martin Fowler defines it, "a change made to the
internal structure of software to make it easier to
understand and cheaper to modify without changing its
observable behavior"
9. Why refactoring?
Code i wrote yesterday is worse that code i'm writing
today
Make it easier to add new code
Improve the design of existing code
Gain a better understanding of code
Make coding less annoying
Readability / Testability / Estensibility
bugs correction
...
10. When refactoring?
Keeping code clean is a lot like keeping a room
clean. Once your room becomes a mess, it becomes
harder to clean. The worse the mess becomes, the
less you want to clean it.
It's best to refactor continuously, rather than in
phases. When you see code that needs
improvement, improve it.
On the other hand, if your manager needs you to
finish a feature before a demo that just got
scheduled for tomorrow, finish the feature and
refactor later!
11. When NOT refactoring?
If it's working, don't change
if you have a poorly factored program
if your code isn't tested, that does what the
customer wants and has no serious bugs, leave it
alone!
performance matters...
12. How refactoring
Refactoring recipes
extract superclass/interface
rename method/property/variable
replace conditional with polymorphism
replace constructor with factory method
inline method
even more: http://www.refactoring.com/catalog
13. How refactoring
Only refactor when refactoring -- do not add feature
during refactoring.
Refactoring, or improving the design of existing code,
requires that you know what code needs improvement.
14. How refactoring
Each transformation (called a "Refactoring") does little,
but a sequence of transformations can produce a
significant restructuring.
The system is also kept fully working after each small
refactoring, reducing the chances that a system can
get seriously broken during the restructuring process.
15. How refactoring
If you want to refactor, the essential
precondition is having solid test
(Martin Fowler)
16. Test-Driven Development
Test-driven development (TDD) and continuous
refactoring enable the efficient evolution of working
code by turning programming into a dialogue.
17. Test-Driven Development
Ask: You ask a question of a system by writing a test.
Respond: You respond to the question by writing
code to pass the test.
Refine: You refine your response by consolidating
ideas, weeding out inessentials, and clarifying
ambiguities.
Repeat: You keep the dialogue going by asking the
next question.
18. Refactoring and pattern
There is a natural relation between
patterns and refactorings. Patterns
are where you want to be;
refactorings are ways to get there
from somewhere else.
(Fowler Martin)
19. Refactoring and pattern
Each pattern is a three-part rule, which expresses a
relation between a certain context, a problem, and a
solution.
There are many ways to implement a pattern. If you
don't know patterns, you're less likely to evolve great
designs. Patterns capture wisdom. Reusing that
wisdom is extremely useful, also when refactoring.
20. Readings
Refactoring: Improving the Design of Existing Code
(Martin Fowler)
Refactoring to patterns
(Joshua Kerievsky)
Design Patterns: Elements of Reusable Object-
Oriented Software
(Gang of Four)
The Pragmatic Programmer
(Andrew Hunt and David Thomas)
21. The sage final sentence
Any fool can write code
that a computer can
understand. Good
programmers write code
that humans can
understand.
(M. F.)