Presentation is loading. Please wait.

Presentation is loading. Please wait.

© S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.1 9. Refactoring Refactoring  What is it?  Why is it necessary?  Examples  Tool support Refactoring.

Similar presentations


Presentation on theme: "© S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.1 9. Refactoring Refactoring  What is it?  Why is it necessary?  Examples  Tool support Refactoring."— Presentation transcript:

1 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.1 9. Refactoring Refactoring  What is it?  Why is it necessary?  Examples  Tool support Refactoring Strategy  Code Smells  Examples of Cure Refactoring and Reverse Engineering  Refactor to Understand Tool Demonstrations  Smalltalk  Java Conclusion

2 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.2 The Reengineering Life-Cycle Requirements Designs Code (0) requirement analysis (1) model capture (2) problem detection (3) problem resolution (4) program transformation issues Tool support Failure proof

3 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.3 What is Refactoring? “The process of changing a software system in such a way that it does not alter the external behaviour of the code, yet improves its internal structure” [Fowl99a] “A behaviour-preserving source-to-source program transformatio”n [Robe98a] “A change to the system that leaves its behaviour unchanged, but enhances some non-functional quality - simplicity, flexibility, understandability, …” [Beck99a]

4 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.4 Typical Refactorings Class RefactoringsMethod RefactoringsAttribute Refactorings add (sub)class to hierarchy add method to classadd variable to class rename classrename methodrename variable remove classremove methodremove variable push method downpush variable down push method uppush variable up add parameter to methodcreate accessors move method to componentabstract variable extract code in new method These simple refactorings can be combined to provide bigger restructurings such as the introduction of design patterns.

5 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.5 Why Refactoring? “Grow, don’t build software” Fred Brooks Some argue that good design does not lead to code needing refactoring, but in reality  Extremely difficult to get the design right the first time  You cannot fully understand the problem domain  You cannot understand user requirements, if the user does!  You cannot really plan how the system will evolve in five years  Original design is often inadequate  System becomes brittle, difficult to change Refactoring helps you to  Manipulate code in a safe environment (behavior preserving)  Recreate a situation where evolution is possible  Understand existing code

6 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.6 Refactoring and OO Object-Oriented Programming  emphasize the possibility of changes  rapid development cycle  incremental definition Frameworks  family of products from the same skeletons or kernel  reuse of functionality However  software evolves, grows and... dies if not taken care of This is where refactoring comes in

7 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.7 Examples of Refactoring Analysis AddClass  simple  namespace use and static references between class structure Rename Method  existence of similar methods  references of method definitions  references of calls

8 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.8 Add Class Add Class (new name, package, superclasses, subclasses) Preconditions  no class or global variable exists with new name in the same scope  subclasses are all subclasses of all superclasses  [Smalltalk] superclasses and subclasses cannot be metaclasses Postconditions  new class is added into the hierarchy with superclasses as superclasses and subclasses as subclasses  new class has name new name  subclasses inherit from new class and not anymore from superclasses Considerations: Abstractness

9 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.9 Rename Method: Do It Yourself Do it yourself approach Check if a method does not exist in the class and superclass/subclasses with the same “name” Browse all the implementers (method definitions) Browse all the senders (method invocations) Edit and rename all implementers Edit and rename all senders Remove all implementers Test Automated refactoring is better !

10 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.10 Rename Method (method, newname) Preconditions  no method exists with the signature implied by new name in the inheritance hierarchy that contains method  [Smalltalk] no methods with same signature as method outside the inheritance hierarchy of method  [Java] method is not a constructor Postconditions  method has new name  relevant methods in the inheritance hierarchy have new name  invocations of changed method are updated to new name Other Considerations  Statically/Dynamically Typed Languages => Scope of the renaming

11 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.11 Which Refactoring Tools? Change Efficient Refactoring  Source-to-source program transformation  Behaviour preserving => improve the program structure Programming Environment  Fast edit-compile-run cycles  Integrated into your environment  Support small-scale reverse engineering activities => convenient for “local” ameliorations Failure Proof Regression Testing  Repeating past tests  Tests require no user interaction  Tests are deterministic  Answer per test is yes / no => verify if improved structure does not damage previous work Configuration & Version Management  keep track of versions that represent project milestones => possibility to go back to previous version

12 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.12 Some Tools Refactoring Browser (in VisualWorks Smalltalk, Dolphin, Squeak, IBMSmalltalk since 1995) http://www.cincom.com/smalltalk http://www.cincom.com/smalltalk Java Refactorings in Eclipse http://www.eclipse.org (also available in other Java environments) http://www.eclipse.org

13 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.13 Top Ten of Code Bad Smells (i) " If it stinks, change it" Grandma Beck Duplicated Code Long Method Large Class (Too many responsibilities) Long Parameter List (Object is missing) Case Statement (Missing polymorphism) Divergent Change (Same class changes differently depending on addition) Shotgun Surgery (Little changes distributed over too many objects)

14 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.14 Top Ten of Code Bad Smells (ii) Feature Envy (Method needing too much information from another object) Data Clumps (Data always use together (x,y -> point)) Parallel Inheritance Hierarchies (Changes in one hierarchy require change in another hierarchy) Lazy Class (Does not do too much) Middle Man (Class with too many delegating methods) Temporary Field (Attributes only used under very specific circumstances) Message Chains (Coupled classes, internal representation dependencies) Data Classes (Only accessors)

15 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.15 Unit Testing How can I trust that the changes did not destroy something? What is my confidence in the system?

16 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.16 Tests Tests represent your trust in the system Build them incrementally  Do not need to focus on everything  When a new bug shows up, write a test Even better write them before the code  Act as your first client, better interface Active documentation always in sync

17 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.17 Testing Style “The style here is to write a few lines of code, then a test that should run, or even better, to write a test that won't run, then write the code that will make it run.” write unit tests that thoroughly test a single class write tests as you develop (even before you implement) write tests for every new piece of functionality “Developers should spend 25-50% of their time developing tests.”

18 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.18 But I can’t cover everything! Sure! Nobody can but When someone discovers a defect in your code, first write a test that demonstrates the defect.  Then debug until the test succeeds. “Whenever you are tempted to type something into a print statement or a debugger expression, write it as a test instead.” Martin Fowler

19 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.19 Good Tests Repeatable No human intervention “self-described” Change less often than the system Tells a story

20 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.20 JUnit Junit (inspired by Sunit) is a simple “testing framework” that provides: classes for writing Test Cases and Test Suites methods for setting up and cleaning up test data (“fixtures”) methods for making assertions textual and graphical tools for running tests JUnit distinguishes between failures and errors: A failure is a failed assertion, i.e., an anticipated problem that you test. An error is a condition you didn’t check for.

21 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.21 The JUnit Framework

22 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.22 A Testing Scenario The framework calls the test methods that you define for your test cases.

23 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.23 Example: Testing Set Class: SetTestCase superclass: TestCase instance variable: empty full SetTestCase>>setUp empty := Set new. full := Set with: #abc with: 5 The setUp is the context in which each test is run.

24 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.24 Tests… SetTestCase>>testAdd empty add: 5. self assert: (empty includes: 5). SetTestCase>>testOccurrences self assert: (empty occurrenceOf: 0) = 0. self assert: (full occurrencesOf: 5) = 1. full add: 5. Self assert: (full occurrencesOf: 5) = 1 SetTestCase>>testRemove full remove: 5. self assert: (full includes: #abc). self deny: (full includes: 5)

25 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.25 Test and Refactorings Tests can cover places where you have to manually change the code  Changing 3 by 33, nil but NewObject new Tests let you been more aggressive to change and improve your code

26 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.26 Refactoring and Reverse Engineering Requirements Designs Code (0) requirement analysis (1) model capture (2) problem detection (3) problem resolution (4) program transformation (1) Model capture issues Tool support (Failure proof)

27 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.27 Refactor To Understand Obvious Programs hard to read => Programs hard to understand => Programs hard to modify Programs with duplicated logic are hard to understand Programs with complex conditionals are hard to understand Programs hard to modify Refactoring code creates and supports the understanding Renaming instance variables helps understanding methods Renaming methods helps understanding responsibility Iterations are necessary The refactored code does not have to be used!

28 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.28 Case Study: Refactor to Understand We want to know if a tool that analyses source code extracts the right information. Context: parser creates objects representing the source code entities parameterised by level of detail 0: classes, methods,... 4: classes, methods, attributes, accesses, invocations, …Problem: We need to understand the way entities are created... but the code is unclear and full of duplication.

29 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.29 Example classWithMethodsOnly: aSmalltalkClass isMetaClass: isMetaClass classDefName := self assessClassNameFor: aSmalltalkClass isMetaClass: isMetaClass. classDef := self makeFClassNamed: classDefName. self assessClassAttributesFor: classDef smalltalkClass: aSmalltalkClass isMetaClass: isMetaClass. "--inheritance--" (self haveExplicitMetaClasses not & isMetaClass) ifFalse: [aSmalltalkClass superclass isNil ifFalse: [ | superclassDefName | "Check for the occasion of a nil subclass" superclassDefName := self assessClassNameFor: aSmalltalkClass superclass isMetaClass: isMetaClass. self makeFInheritanceSuperclass: superclassDefName subclass: classDefName]]. (self haveExplicitMetaClasses not & isMetaClass) ifTrue: [classDefName := (classDefName, '_class') asSymbol]. "--method-definitions--" aSmalltalkClass selectors do: [:methodName | | method | method := self makeFMethodNamed: methodName hasClassScope: (isMetaClass & (haveExplicitMetaClasses not)) onClassNamed: classDef name…

30 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.30 After Some Refactorings classWithMethodsOnly: aSmalltalkClass self reifyClassFor: aSmalltalkClass. self reifyInheritanceFor: aSmalltalkClass. self reifyAllMethodsOf: aSmalltalkClass reifyClassFor: aSmalltalkClass classDefName := self classNameFor: aSmalltalkClass isMetaClass: self isMetaClass. classDef := self makeFClassNamed: classDefName. self inferClassPropertiesFor: classDef smalltalkClass: aSmalltalkClass isMetaClass: self isMetaClass reifyMethodFor: aSmalltalkClass withName: methodName | method | method := self makeMethodNamed: methodName hasClassScope: self isMetaClass & self haveExplicitMetaClasses not onClassNamed: classDef name. self inferMethodPropertiesFor: method class: classDef smalltalkClass: aSmalltalkClass isMetaClass: self isMetaClass.

31 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.31 Assessing code duplication with Duploc Before refactoring After refactoring

32 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.32 Obstacles to Refactoring Complexity Changing design is hard Understanding code is hard Possibility to introduce errors Run tests if possible Build tests Clean first Then add new functionality Cultural Issues Producing negative lines of code, what an idea! “We pay you to add new features, not to improve the code!” If it ain’t broke, don’t fix it “We do not have a problem, this is our software!“

33 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.33 Obstacles to Refactoring Performance Refactoring may slow down the execution The secret to write fast software: “Write tunable software first then tune it” Typically only 10% of your system consumes 90% of the resources so just focus on 10 %. Refactorings help to localize the part that need change Refactorings help to concentrate the optimizations Development is always under time pressure Refactoring takes time Refactoring better right after a software release

34 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.34 Conclusion: Know-when & Know-how Know when is as important as know-how Refactored designs are more complex Use “code smells” as symptoms Rule of the thumb: “Once and Only Once” (Kent Beck)

35 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.35 Further Information More about code smells and refactoring Book on refactoring [Fowl99a] http://www.refactoring.com http://www.refactoring.com Discussion site on code smells http://c2.com/cgi/wiki?CodeSmell http://c2.com/cgi/wiki?CodeSmell

36 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.36 Two Low-Level Cures Long methods A method is the smallest unit of overriding Extract pieces as smaller method Comments are good delimiters Not Intention Revealing Methods Rename Method setType: aType "compute and store the variable type" self addTypeList: (ArrayType with: aType). currentType := (currentType computeTypes: (ArrayType with: aVal)) => computeAndStoreType: aType self addTypeList: (ArrayType with: aType). currentType := (currentType computeTypes: (ArrayType with: aType))

37 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.37 One High-Level Cure: Duplicated Code “Say everything exactly once” Kent Beck Duplicated code makes the system harder to understand and to maintain In the same class Extract Method Between two sibling subclasses Extract Method Push identical methods up to common superclass Form Template Method Between unrelated class Create common superclass Move to Component Extract Component (e.g., Strategy)

38 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.38 Other High-Level Cures God Class Find logical sub-components (set of working methods/instance variables) Move methods and instance variables into components Two possibilities Extract Component => delegation = “Extract Class” in [ Fowl99a ] Extract Subclass

39 © S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.39 Nested Conditionals New cases should ideally not require changing existing code May apply the State / Strategy / NullObject pattern Use dynamic dispatch Define subclasses Define abstract method in superclass Put every leg into an overriding subclass method


Download ppt "© S. Demeyer, S. Ducasse, O. Nierstrasz Chapter.1 9. Refactoring Refactoring  What is it?  Why is it necessary?  Examples  Tool support Refactoring."

Similar presentations


Ads by Google