Module 1. Introducing Course: Refactoring
Overview Definition Principles Building Tests Bad Smells in Code
Definition 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. It is a disciplined way to clean up code that minimizes the chances of introducing bugs. In essence when you refactor you are improving the design of the code after it has been written.
Defining Refactoring Refactoring (noun): a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior. Refactor (verb): to restructure software by applying a series of refactorings without changing its observable behavior.
Individuals and interactions over processes and tools Working software over comprehensive documentation Customer collaboration over contract negotiation documentation Responding to change over following a plan
Building on the Foundations Laid by Others Ward Cunningham Kent Beck Ralph Johnson Bill Opdyke John Brant Don Roberts Martin Fowler
Demo: IDE Conduct Refactoring with IDE
Lesson: Principles in Refactoring Why? When? What? Indirection and Refactoring Problems with Refactoring Refactoring and Design and Performance The Environment for Refactoring Two approaches Thinking in Refactoring
Why Should You Refactor? Refactoring Improves the Design of Software Refactoring Makes Software Easier to Understand Refactoring Helps You Find Bugs Refactoring Helps You Program Faster Refactoring Makes coding less annoying
When Should You Refactor? Refactor When You Add Function Refactor When You Need to Fix a Bug Refactor As You Do a Code Review The Rule of Three (Don Roberts)
What Do I Tell My Manager? Good Manager Bad Manager Design Debt (Ward Cunningham) “Not fix what ain't broken“ Ask: "How many months in a row do you not pay down your debt?" (show your credit card)
Indirection and Refactoring To enable sharing of logic To explain intention and implementation separately To isolate change To encode conditional logic
Problems with Refactoring Hard to see that greatly improves your productivity Databases Changing Interfaces Design Changes That Are Difficult to Refactor When Shouldn't You Refactor?
Refactoring and Design and Performance Upfront design vs Extreme Programming Only refactoring does work, it is not the most efficient A greater movement toward simplicity of design How difficult is it going to be to refactor a simple solution into the flexible solution? Refactoring and Performance “With design I can think very fast, but my thinking is full of little holes” Alistair Cockburn
Breakthrough
The Environment for Refactoring Team or Partner Tests Testing Framework CRC Cards or UML Sketches Configuration and Version Control Sophisticated IDE
Two approaches Code-First Refactoring Test-First Refactoring Combination method
Thinking in Refactoring november(20, 2005)java.util.Calendar c = java.util.Calendar.getInstance(); c.set(2005, java.util.Calendar.NOVEMBER, 20); c.getTime(); Many Eyes Human-Readable Code
Rules Keeping It Clean Small Steps Design Debt «Any fool can write code that a computer can understand. Good programmers write code that humans can understand» Martin Fowler, Refactoring: Improving the Design of Existing Code
Exercise: Inside a Refactoring Create Extract Method Refactoring Pick a refactoring and identify a place where the approach builds in small steps even though larger steps could work.
Exercise Discussion Small Steps Simple Design passes all tests communication no duplication fewest classes and methods
Lesson: Building Tests The Value of Self-testing Code The xUnit Testing Framework Test Location Tips
The Value of Self-testing Code The essential precondition is time Greatly speeds your programming Fully automatic A powerful bug detector Prime technique for Refactoring Type: inline, friend, reflection
JUnit import junit.framework.TestCase; public class MyTest extends TestCase { public void test () { … public class MyMain { public static void main (String[] args) { new junit.textui.TestRunner().doRun(new MatcherTest());
NUnit using NUnit.Framework; [TestFixture] public class DatabaseFixture { [SetUp] public void CreateDatabaseObjects() {... } … [Test] public void ReadOneObject() {... } }
The NUnit Testing Framework
Test Location Within Classes Another Solution + public interfaces Another Solution + Reflection
Tips Run your tests frequently Testing should be risk driven It is better to write and run incomplete tests than not to run complete tests Think of the boundary conditions Use exceptions Testing can't catch all bugs, but most ones
Demo: jUnit test Demonstration
Lesson: Bad Smells in Code Definition Simple Design Design Principles Smells Catalog Database Smells Architectures Smells
Bad Smells in Code Smells (especially code smells) are warning signs about potential problems in code. If it stinks, change it. Grandma Beck, discussing child-rearing philosophy
Simple Design Runs all the tests. Has no duplicated logic. Be wary of hidden duplication like parallel class hierarchies. States every intention important to the programmers. Has the fewest possible classes and methods. —Beck, Extreme Programming Explained, p. 57
Design Principles DRY : Don’t Repeat Yourself SCP : Speaking Code OCP : Open Closed LSP : Liskov Substitution DIP : Dependency Inversion ISP : Interface Segregation REP : Reuse/Release Equivalency CRP : Common Reuse CCP : Common Closure ADP : Acyclic Dependencies SDP : Stable Dependencies SAP : Stable Abstractions TDA : Tell, Don’t Ask SOC : Separation Of Concerns Stefan Rock. Refactoring in Large Software. 2006
Some depends Methods <= 30 code lines A Class <= 30 methods A Package <= 30 classes Subsystems <= 30 packages System <= 30 subsystems 3-10 Layers Methods <= 10 code lines A Class <= 10 methods A Package <= 10 classes Subsystems <= 10 packages System <= 10 subsystems 3-10 Layers
Smells Catalog
Smells Catalog (1/3) 1. Duplicated Code 2. Long Method 3. Large Class 4. Long Parameter List 5. Divergent Change 6. Shotgun Surgery 7. Feature Envy 8. Data Clumps 9. Primitive Obsession 10. Switch Statements 11. Parallel Inheritance Hierarchies
Smells Catalog (2/3) 12. Lazy Class 13. Speculative Generality 14. Temporary Field 15. Message Chains 16. Middle Man 17. Inappropriate Intimacy 18. Alternative Classes with Different Interfaces 19. Incomplete Library Class 20. Data Class 21. Refused Bequest 22. Comments
Smells Catalog (3/3) 23. Conditional Complexity 24. Indecent Exposure 25. Solution Sprawl 26. Combination Explosion 27. Oddball Solution
Test Smells (Code) Obscure test Conditional test logic Hard to test code Test code duplicated Test Logic in Production … Visit “Test-Driven Development Course”
Database Smells Multipurpose column. Multipurpose table. Redundant data. Tables with too many columns. Tables with too many rows. "Smart" columns. Fear of change. Visit “Database Refactoring Course”
Architectures Smells Dependency graphs Inheritance hierarchies Packages Subsystems Layers
SA4J: Dependencies
NDepend
Software visualization Sotograph JDepend / NDepend Eclipse Metrics Plugin, JDepend4Eclipse Dr. Freud SonarJ ClassCycle SA4J
Management Smells Absentee Manager All you have is a Hammer Golden Child Leader not Manager / Manager not Leader Metric Abuse Road to Nowhere …
Smell - its name Symptoms — cues that help you spot it Causes — notes on how it might happen What to do — possible refactorings Payoff — the ways your code will improve Contraindications — when not to fix it
Exercise: Real Project Review real project Smells list
Review Definition Principles Building Tests Bad Smells in Code