Slide 1

Slide 1 text

@asciamanna anthonysciamanna.com @asciamanna anthonysciamanna.com Fearlessly Improving Legacy Code or: How I Learned to Stop Worrying and Love Dreadful Code Anthony Sciamanna Senior Consultant - Industrial Logic

Slide 2

Slide 2 text

@asciamanna anthonysciamanna.com Legacy code can be scary! Photo by Andrea Piacquadio

Slide 3

Slide 3 text

@asciamanna anthonysciamanna.com How do you change your perspective? https://www.industriallogic.com/training/elearning/ Industrial Logic eLearning Album - Legacy Code Working Effectively with Legacy Code - Michael Feathers ● Nine rules for characterization testing ● Inspired by the WELC book (Michael Feathers) and Industrial Logic Legacy Code eLearning

Slide 4

Slide 4 text

@asciamanna anthonysciamanna.com Characterization tests Source: Working Effectively with Legacy Code - Michael Feathers In computer programming, a characterization test (also known as Golden Master Testing) is a means to describe (characterize) the actual behavior of an existing piece of software, and therefore protect existing behavior of legacy code against unintended changes via automated testing. This term was coined by Michael Feathers. [Source: Wikipedia] Characterization Tests Golden Master Tests Pinning Tests Pin-Down Tests Scaffolding Tests Approval Tests

Slide 5

Slide 5 text

@asciamanna anthonysciamanna.com Legacy code death spiral Make the most straightforward, smallest change that feels the safest in the short term (no improvements) Design degrades further making future changes harder Need to modify convoluted, untested legacy code Creates more duplication and conditional complexity Why? ● “I don’t have time to [learn how to] improve the code.” ● “I fear I’ll break the functionality because it isn’t clear.”

Slide 6

Slide 6 text

@asciamanna anthonysciamanna.com Conditional logic and code duplication are the Yin and Yang of unmaintainable code. - Bryan Helmkamp - CEO, Code Climate “ ”

Slide 7

Slide 7 text

@asciamanna anthonysciamanna.com Why does this happen? ● Organizational pressure ● Taylorism (developers are order takers / typists) ● Managing teams by output (velocity) ● Short term speed is the only success measure ● We don’t know how / No time to learn ● Lack of agile engineering practices

Slide 8

Slide 8 text

@asciamanna anthonysciamanna.com REWRITE! ● Same team(s) ● Same (or additional) organizational pressures ● Same organizational view on software development (Taylorism) ● Never learned / practiced how to incrementally improve the code …Your rewrite is DOOMED!

Slide 9

Slide 9 text

@asciamanna anthonysciamanna.com Law of Holes Source: Wikipedia - https://en.wikipedia.org/wiki/Law_of_holes The first law of holes, or the law of holes, is an adage which states: "if you find yourself in a hole, stop digging." It is used as a metaphor, warning that when in an untenable position, it is best to stop making the situation worse

Slide 10

Slide 10 text

@asciamanna anthonysciamanna.com Team Working Agreements All new code comes with microtests All existing code gets tested when it needs to be changed

Slide 11

Slide 11 text

@asciamanna anthonysciamanna.com Music profile kata

Slide 12

Slide 12 text

@asciamanna anthonysciamanna.com Rule #1 - Clear the area ● Once the change area is identified ○ Reformat the file (automatically) ○ Use team-shared formatting and linting rules ○ Remove obvious noise in the code without needing to think about it

Slide 13

Slide 13 text

@asciamanna anthonysciamanna.com Claude Shannon - “Father of Information Theory” "Almost every problem that you come across is befuddled with all kinds of extraneous data of one sort or another; and if you can bring this problem down into the main issues, you can see more clearly what you're trying to do." Source Business Insider From his lecture “Creative Thinking” at Bell Labs - March 20, 1952 Wikipedia: Claude Shannon

Slide 14

Slide 14 text

@asciamanna anthonysciamanna.com Rule #2 - Use power tools Code Editors IDEs Provides automation tools, automated refactorings, test runners, code coverage tools

Slide 15

Slide 15 text

@asciamanna anthonysciamanna.com Arlo Belshee’s Core Six Refactorings You should never have to do these things: ● Format your code ● Type basic language stuff / get things precisely right ● Look up what refactorings you can use and their keystrokes Source: https://arlobelshee.com/the-core-6-refactorings/

Slide 16

Slide 16 text

@asciamanna anthonysciamanna.com Rule #3 - Call it in a test harness ● Can you create the object you want to test? ● Can you call the method with null arguments? ● Call method under test with simple arguments to start (then elaborate) xUnit framework, unit testing framework, or Approval Tests https://github.com/approvals https://approvaltests.com/

Slide 17

Slide 17 text

@asciamanna anthonysciamanna.com Rule #4 - Use tests to get to testability ● Probe existing behavior with tests ● DO NOT spend time trying to figure out complicated, obfuscated logic Try this… Not that…

Slide 18

Slide 18 text

@asciamanna anthonysciamanna.com Rule #5 - Let assertion failures expose the behavior ● Assert null to discover results ● Write assertions for actual results Agile in a Flash - Tim Ottinger & Jeff Langr Source: Working Effectively with Legacy Code - Michael Feathers

Slide 19

Slide 19 text

@asciamanna anthonysciamanna.com Rule #6 - Examine inputs and outputs ● Are the outputs for a single pass covered in assertions? ● “Outputs” could be void calls on dependencies ● How many possible input combinations are there? (Helps to give you an idea of the number of tests you’ll need)

Slide 20

Slide 20 text

@asciamanna anthonysciamanna.com Rule #7 - Use code coverage to drive input variation ● Vary inputs to cover more of the legacy code ● Track progress via code coverage ● Look for hidden branches - regex matches, LINQ chaining (C#), streams (Java) ● Tools: Console Writing & Debugger

Slide 21

Slide 21 text

@asciamanna anthonysciamanna.com Rule #8 - Use automated refactoring to create seams ● Seams allow for breaking dependencies and getting to testability ● Exploit seams by replacing objects with test doubles (object seams) ● Addresses the Legacy Code Dilemma

Slide 22

Slide 22 text

@asciamanna anthonysciamanna.com Legacy Code Dilemma “When we change code we should have tests in place. To put tests in place we often have to change code.” -Michael Feathers Source: Working Effectively with Legacy Code - Michael Feathers

Slide 23

Slide 23 text

@asciamanna anthonysciamanna.com Seams A seam is a place where you can alter behavior in your program without editing it Every seam has an enabling point, a place where you can make the decision to use one behavior or another Source: Working Effectively with Legacy Code - Michael Feathers We introduce test doubles to exploit object seams

Slide 24

Slide 24 text

@asciamanna anthonysciamanna.com Rule #9 - Don’t fix bugs ● You do want to fix them, just not now ● Characterize the bug’s behavior instead

Slide 25

Slide 25 text

@asciamanna anthonysciamanna.com Next - Refactor and Introduce Microtests ● Once legacy code is characterized (including bug behavior)... ○ Refactor production code ○ Cover in microtests ○ Delete or refactor characterization tests ○ Fix identified bugs

Slide 26

Slide 26 text

@asciamanna anthonysciamanna.com Microtests Microtests are micro in size, run in milliseconds, and test a micro-behavior. They are fast and cheap, and you can run the tests thousands of times without false negatives. Because they are so small they are very easy to scan and understand

Slide 27

Slide 27 text

@asciamanna anthonysciamanna.com Microtests Don’t ● Access a database ● Access the network ● Access the filesystem ● Depend on other tests ● Require a complex environment to run in ● Require a deployed app to test against

Slide 28

Slide 28 text

@asciamanna anthonysciamanna.com @asciamanna anthonysciamanna.com Contact Info: Anthony Sciamanna - anthony@industriallogic.com Twitter: @asciamanna Web: anthonysciamanna.com This talk: https://bit.ly/phillyxp-legacy-code Thank you!