RefactoringSlide 2When to refactorDesign vs. codingThe refactoring environmentA personal viewBack to refactoringExample 1: switch statementsExample 1, continuedExample 1, improvedHow is this an improvement?JUnit testsBad Smell ExamplesEclipse refactoringsThe EndJan 13, 2019Refactoring2RefactoringRefactoring is:restructuring (rearranging) code......in a series of small, semantics-preserving transformations (i.e. the code keeps working)......in order to make the code easier to maintain and modifyRefactoring is not just any old restructuringYou need to keep the code workingYou need small steps that preserve semanticsYou need to have unit tests to prove the code worksThere are numerous well-known refactoring techniquesYou should be at least somewhat familiar with these before inventing your own3When to refactorYou should refactor:Any time that you see a better way to do things“Better” means making the code easier to understand and to modify in the futureYou can do so without breaking the codeUnit tests are essential for thisYou should not refactor:Stable code (code that won’t ever need to change)Someone else’s codeUnless you’ve inherited it (and now it’s yours)4Design vs. coding“Design” is the process of determining, in detail, what the finished product will be and how it will be put together“Coding” is following the planIn traditional engineering (building bridges), design is perhaps 15% of the total effortIn software engineering, design is 85-90% of the total effortBy comparison, coding is cheap5The refactoring environmentTraditional software engineering is modeled after traditional engineering practices (= design first, then code)Assumptions:The desired end product can be determined in advanceWorkers of a given type (plumbers, electricians, etc.) are interchangeable“Agile” software engineering is based on different assumptions:Requirements (and therefore design) change as users become acquainted with the softwareProgrammers are professionals with varying skills and knowledgeProgrammers are in the best position for making design decisionsRefactoring is fundamental to agile programmingRefactoring is sometimes necessary in a traditional process, when the design is found to be flawed6A personal viewIn my opinion,Design, because it is a lot more creative than simple coding, is also a lot more funAdmittedly, “more fun” is not necessarily “better”...but it does help you retain good programmersMost small to medium-sized projects could benefit from an agile programming approachWe don’t yet know about large projectsMost programming methodologies attempt to turn everyone into a mediocre programmerSadly, this is probably an improvement in generalThese methodologies work less well when you have some very good programmers7Back to refactoringWhen should you refactor?Any time you find that you can improve the design of existing codeYou detect a “bad smell” (an indication that something is wrong) in the codeWhen can you refactor?You should be in a supportive environment (agile programming team, or doing your own work)You should have an adequate set of unit tests8Example 1: switch statementsswitch statements are very rare in properly designed object-oriented codeTherefore, a switch statement is a simple and easily detected “bad smell”Of course, not all uses of switch are badA switch statement should not be used to distinguish between various kinds of objectThere are several well-defined refactorings for this caseThe simplest is the creation of subclasses9Example 1, continuedclass Animal { final int MAMMAL = 0, BIRD = 1, REPTILE = 2; int myKind; // set in constructor ... String getSkin() { switch (myKind) { case MAMMAL: return "hair"; case BIRD: return "feathers"; case REPTILE: return "scales"; default: return "integument"; } }}10Example 1, improvedclass Animal { String getSkin() { return "integument"; }}class Mammal extends Animal { String getSkin() { return "hair"; }}class Bird extends Animal { String getSkin() { return "feathers"; }}class Reptile extends Animal { String getSkin() { return "scales"; }}11How is this an improvement?Adding a new animal type, such as Amphibian, does not require revising and recompiling existing codeMammals, birds, and reptiles are likely to differ in other ways, and we’ve already separated them out (so we won’t need more switch statements)We’ve gotten rid of the flags we needed to tell one kind of animal from anotherBasically, we’re now using Objects the way they were meant to be used12JUnit testsAs we refactor, we need to run JUnit tests to ensure that we haven’t introduced errorspublic void testGetSkin() {assertEquals("hair", myMammal.getSkin());assertEquals("feathers", myBird.getSkin());assertEquals("scales", myReptile.getSkin());assertEquals("integument", myAnimal.getSkin());}This should work equally well with either implementationThe setUp() method of the test fixture may need to be modified13Bad Smell ExamplesYou should refactor any time you detect a “bad smell” in the codeExamples of bad smells include:Duplicate Code Long MethodsLarge ClassesLong Parameter ListsMulti location code changesFeature EnvyData ClumpsPrimitive ObsessionWe will discuss most or all of these later14Eclipse refactoringsEclipse can perform several refactorings for you:Rename (just about anything)Change method signatureMove class to another packagePull up (into a superclass)Push down (into subclasses)Extract interfaceGeneralize typesUse supertype where possibleInfer generic type argumentsInline method callExtract methodExtract local variableExtract constantIntroduce parameterIntroduce factoryConvert local variable to fieldEncapsulate field15The
View Full Document