Refactoring
by Charlie Calvert
Overview
- Coding is sometimes about adding new features.
- But refactoring is about improving your design without adding features.
- Related subjects:
- Unit Testing
- Test Driven Development
- Patterns
- Agile and XP
- UML and Agile Modeling
- At times it is hard to separate these ideas. They become interelated.
- This document is maintained on http://www.elvenware.com
Recommended Reading
Online Resources
History
- Emerged from the Smalltalk development community of the early 1980s.
- Framework developers have always done it, because they were focused on architecture.
- The Pattern movement. Implementing patterns is often a form of refactoring.
- Ward Cunningham and Kent Beck.
- Martin Fowler's book "Refactoring," which grew in part out of his work with Kent Beck.
Why we Refactor
- To promote reuse
- To make our programs as simple as possible
- To create programs that are easy to maintain
- To make it possible to develop quickly.
- To introduce patterns in our code
Unit Testing
- Refactoring, as we know, would be impossible without unit testing.
- Unit testing is the glue that holds the refactoring community together.
Basic Principles
- Test frequently
- Remove repetitious code.
- Follow the Refactorings found in Fowler's book.
- Iterative development. Many small changes: Don't build, grow. Refactor, test, refactor, test.
- Find the right design. The bigger the program, the more important Design becomes
- Use UML (or Agile Modeling) to help you find the right architecture.
- Move from big to small. One big class to many small classes. One big method to many small methods
Benefits
- Old code gets better, rather than decaying
- The code should be easier to understand and maintain.
- You can write code faster
- You can change direction more easily: Respond more readily to customer requests.
Bad practices and Code Smells
- Code Smells
- Repetition
- Complicated conditional logic (Replace with polymorphism)
- Anti-Patterns
- More smells listed at the end of this document.
Demo
- Refactoring a GUI based program
- Problem:
- Bound to VCL and CBuilder6. What about CBX? (Use MVC!)
- Repititious!
- Hard to test!
- Download example code.
What is Good Design?
- Well designed code is reusable
- Has few dependences
- Decomposable: that is, it's made up of many discrete, small parts
- As s imple as possible
- Easy to understand
- Easy to maintain
Simplicity
- From James Newkirk, "Test Driven Development in .NET.
- The is appropriate for the intended audience
- The code passes all the tests
- The code communicatines everyhing it needs to
- The code has the smallest number of classes
- The code has the smallest number of method
Refactoring as a Way of Learning Code
- When you are handed new code, begin by performing simple refactorings on it.
- As you do this, you will learn more about the code.
- Soon you will see the structure and design of the code
- And perhaps some big refactorings that you can begin by making small changes.
Design Issues
- One school of thought says do all design up front, before you code
- Obviously, if you did that, you would never refactor.
- But we rarely design correctly. We design as best we can, because it helps, but we have to expect change.
Extreme Programming
- XP suggests that we do only minimal planning with CRC cards, then start coding
- Always keep the design as simple as possible.
- Don't look for that elegant solution that will allow you to be very flexible
- Do the simplest thing that works for today's problems
- If it is not right, then refactor.
- You can dare to do this because your code is covered with tests.
Agile Modeling
- Agile modeling is closely linked to XP, but a little less extreme.
- The Unified Process, UP, was very much about creating a design up front with UML
- There is a bit of a rivarlry between UP, which managers like and programmers tend to dislike, and XP, which managers distrust, and programmers like.
- XP tended to move as far away from UML as possible.
- In Agile Modeling, the idea is to use a loose form of UML to help you design your code
- Then you write code based on these designs.
- If you run into trouble, just draw more diagrams, then create code based on those diagrams.
- In a sense, this is a halfway point between something like RUP and XP.
Patterns
Demo UML
- Using Together to implement patterns
- To view code as pictures.
Why Now?
- Refactoring is, in a sense, so obvious, that one has to ask: why now?
- There are two big things that have made it possible
- Modern IDEs with built in tools for browsing, editing and refactoring code
- Unit Testing
Modern IDEs
- IDEs like JBuilder, the next version of Delphi, or editors like Visual SlickEdit have built in refactoring tools
- Rename, move method, introduce super class, extract interface, pull up, push down are all available in modern IDEs.
- Tools like Together have had a huge impact
- Even simple class browsing tools help
- All these things make it possible for us to refactor our code much more quickly than we could before.
The Danger of Refactoring
- Changing working code is dangerous
- We must be systematic
- Martin Fowler list of possible refactorings systematicizes what could be a chaotic process
Schedules: The Time Issue
- We refactor working code
- Managers aren't going to like this.
- And they are right to distrust it: If it works, don't fix it!
- However....
- We can't work with code that is a mess.
- A classic case occurred when the Delphi team tried to move the IDE to Linux. The darn code was just not designed right to support such a move.
- Code should always be designed to support change.
- It is always right to find the best architecture.
- A good refactoring session will improve the rate at which you can develop with the refactored code.
- Think of a good framework. Can you build faster on top of a good or a bad framework?
The Database Problem
- If you are working with a big database then refactoring is difficult.
- If you refactor the data, then you have to migrate the data, and migration is complicated.
- The best you can do is try to create a very firm line between your code and your data. Abstract it as much as possible.
The Bad Code Problem
- Some code is just really bad, and can't be refactored.
- In that case, it is probably simplest to start from scratch
Types of Refactorings
Fowler outlines seven different types of refactorings:
Demo SlickEdit
- The new version of Visual Slickedit has some interesting refactoring tools
Bad Smells
Here is the list of bad smells from Martin Fowler's and Kent Beck's chapter on that subject in Refactoring.
- Duplicate code
- Extract method, extract class, pull up method, form template method
- Long method
- Extract method, replace temp with quey, replace method with method object, decompose conditional
- Large class
- Extract class, extract subclass, extract interface, replace data value with object
- Long parameter list
- Rpleace paramter with method, introduce parameter object, preserve whole object
- Divergent change (One class, called A, supports too much functionality. So changes to either B or C make you change A.)
- Shotgun surgery (One change causes lots of little changes throughout your code)
- Move method, move field, inline class
- Feature envy
- Move method, move field, extract method
- Data clumps (Related data in separate classes)
- Extract class, introduce parameter object, preserve whole object
- Primitive obsession (Using structs and other native types instead of objects)
- Replace data value with object, Extract class, Introduce parameter object, Replace array with object, repalace type code with class, repace type code with subclasses, replace type code with state strategy
- Switch statements
- Replace conditional with polymorphism, repace type code with subclasses, replace type code with state/strategy, replace parameter with explicit methods, introduce null object
- Parallel inheritance hierarchies (???)
- Lazy class (Collapse hiearchies or use inline classes if you have a class that doesn't earn its way.)
- Inline class, collapse hierarchy
- Speculative generality (Classes that are in place in case you ever need them.)
- Collapse Hierarchy, Inline class, remove parameter, rename method
- Temporary field (Fields with class scope used only in certain circumstances. Put them in a class of their own.)
- Extract class, introduce null object
- Message chain
- Middle man (Elliminate needless indirection)
- Remove middle man, inline method, replace delegation with inheritance
- Inappropriate intimacy
- Move method, move field, change bidirectional assocationto unidirectional, replace inheritance with delegation, hide delegate
- Incomplete library class
- Introduce foreign method, introduce local extension
- Data class
- Move method, encapsulate field, encapsulate collection
- Refused bequest
- replace inheritance with delegation
- Comment (Can you refactor your code to obviate the need to write the comment?)
- Extract method, introduce assertion
C++ Tools for Unit Testing
- There are many tools for Unit testing in C++. Two that stand out are:
- I've written explanations of how to install these tools