Test Driven Lasse Koskela Chapter 3: Refactoring in Small Steps Paul Ammann http://cs.gmu.edu/~pammann/ Overview • Exploring a Potential Solution • Changing Design in a Controlled Manner • Taking the New Design Further The Most Powerful Designs Are Always the Result of a Continuous Process of Simplification and Refinement. 7/1/2016 2 Recalling the Problem • Existing Design Replaced Variables Via Simple Matching – For all variables v, replace ${v} with its value: result = result.replaceAll(regex, entry.getValue()) • Failing test: @Before sets template value to “${one}, ${two}, ${three}” @Test public void variablesGetProcessedJustOnce() throws Exception { template.set(“one”, “${one}”); template.set(“two”, “${three}”); template.set(“three”, “${two}”); assertTemplateEvaluatesTo(“${one}, ${three}”, ${two}); } Tweaking the Current Design Won’t Make This Test Pass. 7/1/2016 3 Exploring A Potential Solution • Exploring a “Segment” Solution for Templates • Prototyping with Spikes – A Spike is A Detour to Learn – In Template Example, Learning is About regex • Learning by Writing Tests – Need to Figure Out An API? • Write Some Test Code That Uses The API • RegexlearningTest • Example Spike for Learning an API – Note Koskela’s Misunderstanding of the Role of Parentheses • Simple Here: We’re Finding Variables in a Template – Compiling Regex Patterns, Matching Expressions Get Smarter On The Side, Then Apply 7/1/2016 4 Changing Design in Controlled Manner • Creating an Alternative Implementation – Starting With the Low Hanging Fruit • TDD Development of a Template Parser – Removing Duplication From Tests • Refactoring Is Always Important – Applying Learning From the Spike • Final Code Version (note Segment class, originally String) private void append(String segment, StringBuilder result) { if (isVariable(segment) { evaluateVariable(segment, result); } // dispatching else { result.append(segment);} } • Koskela Refactors Substantially – TemplateParse.java Now We Can Parse; Next Step Is To Use Parser 7/1/2016 5 Changing Design in a Controlled Manner - Continued • Switching Over Safely – Adopting the New Implementation • Recoding the evaluate() method – Cleaning Up By Extracting Methods • Pull Out The Old Stuff That ‘s No Longer Relevant • Result is new Template Class – Template.java No New Functionality, But Definitely Refactored 7/1/2016 6 Taking the New Design Further • Keeping Things Compatible – Building on Existing Functionality • Note equals(), hashCode() treatment in Segment classes – Any Worries About This? • Segment, PlainText , Variable – Refactoring Logic into Objects • Tell, Don’t Ask! • Motivation for Segment class – Making the Switchover – Getting Caught By the Safety Net • Adding Exceptional Behavior! – Deleting Dead Code and Further Clean Up Test Set Makes Requirements Concrete 7/1/2016 7