Upgrade to Pro — share decks privately, control downloads, hide ads and more …

How to work with
 Legacy Code - Management Summary

DonSchado
October 21, 2016

How to work with
 Legacy Code - Management Summary

This is the shorter and less technical version of: https://speakerdeck.com/donschado/how-to-work-with-legacy-rails-code

DonSchado

October 21, 2016
Tweet

More Decks by DonSchado

Other Decks in Technology

Transcript

  1. Railslove
    We love to build the web.
    How to work with

    Legacy Code
    Marco Schaden

    @donschado
    [email protected]
    21.10.2016
    Management Summary

    View full-size slide

  2. Legacy Code 21.10.2016
    Disclaimer
    The following is a summary of our own practical experiences
    enriched with opinions and knowledge of various esteemed experts
    and super heroes such as:
    Katrina Owen
    Sandi Metz
    Corey Haines
    Jay Fields
    and other respected people
    Kent Beck
    Martin Fowler
    Uncle Bob Martin
    Michael C. Feathers

    View full-size slide

  3. Legacy Code 21.10.2016
    Disclaimer
    Legacy is not about a specific technology or programming paradigm.

    Nonetheless the focus of this talk are object oriented languages and web applications.

    View full-size slide

  4. Legacy Code 21.10.2016
    Disclaimer
    Slides are available online: 

    https://speakerdeck.com/donschado
    This is the extended version

    View full-size slide

  5. Legacy Code 21.10.2016
    Why does software become “legacy”?

    View full-size slide

  6. Legacy Code 21.10.2016
    Is it the customers* fault

    by changing the requirements
    all the time?

    View full-size slide

  7. Legacy Code 21.10.2016
    Why couldn't the customer just be happy, with what they first said they need…

    View full-size slide

  8. google: IT+Project+Tree
    How the customer 

    explained it
    How the Project Leader 

    understood it
    How the Analyst designed it 
 How the Programmer 

    wrote it
    How the Business
    Consultant described it
    How the project was 

    documented
    What Operations

    deployed
    How the customer was
    billed
    How it was supported What the customer really
    needed

    View full-size slide

  9. Legacy Code 21.10.2016
    Random developer: 

    “It was not designed to do this, we need to start from scratch..."

    View full-size slide

  10. Legacy Code 21.10.2016
    Surprise: Requirements Change

    View full-size slide

  11. Legacy Code 21.10.2016
    Surprise: Requirements Change, all the time!

    View full-size slide

  12. Legacy Code 21.10.2016
    Surprise: Requirements Change, all the time!
    Software that cannot tolerate this, is simply poor designed.

    View full-size slide

  13. Hi, I’m Marco
    @donschado
    [email protected]
    Software Developer

    Master of Computer Science

    View full-size slide

  14. T
    We’re an agile team 

    and develop products for the web.
    Web applications are more than our
    daily business. We support our
    customers in close cooperation from
    the initial idea through to the launch -
    and beyond.

    View full-size slide

  15. Legacy Code 21.10.2016

    View full-size slide

  16. Legacy Code 21.10.2016
    https://www.railslove.com/jobs

    View full-size slide

  17. Legacy Code 21.10.2016

    Legacy Code vs Technical Debt
    Change
    Dependencies
    Testing
    Refactoring vs Rewrite
    Metrics

    View full-size slide

  18. Legacy Code 21.10.2016
    Legacy is not exclusively a bad thing

    View full-size slide

  19. Legacy Code 21.10.2016
    Most of us see legacy as…

    View full-size slide

  20. Legacy Code 21.10.2016
    #vintage #oldtimer #classic
    Legacy?

    View full-size slide

  21. Legacy Code 21.10.2016
    many “legacy” systems have reliably served 

    the needs of their businesses
    generating value (usually it’s the main system and the source of income…)
    people and processes depend on it
    just because code is old 

    doesn’t mean it has to be thrown away
    Some people in our industry call it legacy while the
    codebase is less than 2 years old?!
    #vintage #oldtimer #classic

    View full-size slide

  22. Legacy Code 21.10.2016
    def legacy_code

    View full-size slide

  23. Legacy Code 21.10.2016
    slang for complex, difficult to change code
    code with many dependencies
    mostly somebody else's code
    “old” code with deprecated syntax/features
    highly coupled code / “spaghetti" / ball of mud
    code you’re afraid to touch
    code without tests
    def legacy_code

    View full-size slide

  24. Legacy Code 21.10.2016
    The Michael C. Feathers definition:
    “code without tests”
    no matter how well written it is, 

    without tests you don't know 

    if a change makes it better or worse
    def legacy_code

    View full-size slide

  25. Why does software become “legacy”?

    View full-size slide

  26. Legacy Code 21.10.2016
    legacy code vs technical debt

    View full-size slide

  27. Legacy Code 21.10.2016
    legacy code vs technical debt
    *sometimes required to move projects forward

    View full-size slide

  28. Legacy Code 21.10.2016
    legacy code vs technical debt
    referring to the eventual
    consequences of any
    system design
    • complexity
    • coupling
    • hard to change
    • anti patterns
    *sometimes required to move projects forward

    View full-size slide

  29. Legacy Code 21.10.2016
    legacy code vs technical debt
    accumulating interest
    referring to the eventual
    consequences of any
    system design
    • complexity
    • coupling
    • hard to change
    • anti patterns
    *sometimes required to move projects forward

    View full-size slide

  30. Legacy Code 21.10.2016
    legacy code vs technical debt
    accumulating interest
    referring to the eventual
    consequences of any
    system design
    the result
    of unpaid debt
    • complexity
    • coupling
    • hard to change
    • anti patterns
    *sometimes required to move projects forward

    View full-size slide

  31. Legacy Code 21.10.2016
    legacy code vs technical debt
    accumulating interest
    code smells
    • metaprogramming madness
    • long parameter list
    • shotgun surgery
    • duplicated code
    • feature envy
    • large class
    • long method
    • case statements
    • complex conditionals
    referring to the eventual
    consequences of any
    system design
    the result
    of unpaid debt
    • complexity
    • coupling
    • hard to change
    • anti patterns
    *sometimes required to move projects forward

    View full-size slide

  32. Legacy Code 21.10.2016
    legacy code vs technical debt
    accumulating interest
    code smells
    refactoring
    • metaprogramming madness
    • long parameter list
    • shotgun surgery
    • duplicated code
    • feature envy
    • large class
    • long method
    • case statements
    • complex conditionals
    referring to the eventual
    consequences of any
    system design
    the result
    of unpaid debt
    • complexity
    • coupling
    • hard to change
    • anti patterns
    *sometimes required to move projects forward

    View full-size slide

  33. BLAME THE DEVELOPERS!?

    View full-size slide

  34. Legacy Code 21.10.2016
    missing (product) strategy
    conceptually poor features
    unfinished requirements
    needless complexity
    unnecessary / tough deadlines
    high fluctuation and poor on-boarding
    not enough training / further education
    doing agile wrong (yeah, we’re doing scrum/kanban we’re so agile!)
    The influence of management* on legacy:
    Even a development process that encourages code reviews and pairing

    can yield bad technical decisions which effect the whole architecture:

    View full-size slide

  35. Legacy Code 21.10.2016
    You might miss the context,
    at the time the code was written

    View full-size slide

  36. Legacy Code 21.10.2016
    Uncle Bob:
    “every 5 years, double new programmers,
    with less than 5 years experience”
    http://blog.cleancoder.com/uncle-bob/2014/06/20/MyLawn.html

    View full-size slide

  37. Legacy Code 21.10.2016
    change

    View full-size slide

  38. Legacy Code 21.10.2016
    changing legacy code
    is a big deal

    View full-size slide

  39. Legacy Code 21.10.2016
    In legacy code, it is particularly hard to come up with estimates that are
    meaningful.
    even the simplest code changes take a long time to implement (or release)
    it seems like no amount of time will be enough to understand everything
    you need to do to make a change
    Expensive

    View full-size slide

  40. Legacy Code 21.10.2016
    How much change can you afford if changes are risky?
    What changes do we have to make?
    How will we know that we've done them correctly and haven't broken
    anything?
    Risk
    Often we don't know how much of the existing behaviour is at risk 

    when we make our changes.

    View full-size slide

  41. Legacy Code 21.10.2016

    View full-size slide

  42. Legacy Code 21.10.2016
    1. Identify change points
    2. Find test points
    3. Break dependencies
    4. Write tests
    5. Make your changes and refactor
    Algorithm:
    Michael C. Feathers

    View full-size slide

  43. Legacy Code 21.10.2016
    1. Identify change points
    2. Find test points
    3. Break dependencies
    4. Write tests
    5. Make your changes and refactor
    Algorithm:
    debugger, inspect, puts, tap, raise, console.log, …
    internal vs 3rd party, 

    most obvious impediment to testing
    this can be hard for side effects

    sometime requires creative and ugly technics
    Always leave the campground cleaner than you found it
    Michael C. Feathers

    View full-size slide

  44. Legacy Code 21.10.2016
    internal vs 3rd party, 

    most obvious impediment to testing
    1. Identify change points
    2. Find test points
    3. Break dependencies
    4. Write tests
    5. Make your changes and refactor
    Algorithm:
    debugger, inspect, puts, tap, raise, console.log, …
    this can be hard for side effects

    sometime requires creative and ugly technics
    Always leave the campground cleaner than you found it
    Michael C. Feathers

    View full-size slide

  45. Legacy Code 21.10.2016
    Dependencies
    “They will try to kill you”

    View full-size slide

  46. Legacy Code 21.10.2016
    Whenever we bring up on our screens a nasty batch of tangled legacy code,
    we are experiencing the results of poor dependency management.
    Uncle Bob:

    View full-size slide

  47. Legacy Code 21.10.2016
    Uncle Bob:
    Poor dependency management leads to code that is
    hard to change, fragile, and non-reusable.
    Whenever we bring up on our screens a nasty batch of tangled legacy code,
    we are experiencing the results of poor dependency management.

    View full-size slide

  48. Legacy Code 21.10.2016
    Uncle Bob:
    Poor dependency management leads to code that is
    hard to change, fragile, and non-reusable.
    When classes depend directly on things that are hard to use in a test,
    they are hard to modify and hard to work with.
    Whenever we bring up on our screens a nasty batch of tangled legacy code,
    we are experiencing the results of poor dependency management.

    View full-size slide

  49. Legacy Code 21.10.2016
    https://cleancoders.com/videos

    View full-size slide

  50. Legacy Code 21.10.2016
    Testing
    To survive legacy code you need to maximise safety

    View full-size slide

  51. Legacy Code 21.10.2016
    2 unit tests. 0 integration tests.

    View full-size slide

  52. Legacy Code 21.10.2016
    How to

    In theory, writing a test 

    for a piece of functionality shouldn’t be too bad.
    We instantiate a class, 

    call its methods and check the results.
    What could go wrong?
    GOALS
    • complete
    • stable
    • fast
    • few

    View full-size slide

  53. Legacy Code 21.10.2016
    The method might not be accessible to the test. 

    It could be private or have some other accessibility problem.
    It might be hard to call the method because it is hard to
    construct the parameters we need to call it.
    We might need to understand first some other object that the
    method uses.
    The method might have (bad) side effects
    modifying a database
    send notification
    launching a cruise missile …
    How to
    GOALS
    • complete
    • stable
    • fast
    • few

    View full-size slide

  54. Legacy Code 21.10.2016
    Legacy Code
    is special
    Testing legacy code requires creative
    and (sometimes) ugly technics
    Break all rules if it saves $$$ during development

    View full-size slide

  55. Legacy Code 21.10.2016
    Rule of thumb for nearly every legacy system:
    What the system does is more important than what it is supposed to do.

    View full-size slide

  56. Legacy Code 21.10.2016
    The tests that we need when we want to preserve behaviour are called:
    characterization tests

    View full-size slide

  57. Legacy Code 21.10.2016
    Golden Master Testing
    wow, such fancy, very noble

    View full-size slide

  58. Legacy Code 21.10.2016
    def:
    Golden Master Testing refers to capturing the result of “a process”,

    and then comparing future runs against the saved golden master version
    to discover unexpected changes.
    So you expect, that what it does now, is correct.

    View full-size slide

  59. Legacy (Rails) Code 24.05.2016
    <<<
    The idea is:
    you get some output and save the result (snapshot)
    and every time you run the test again you compare:


    * the same: great the test pass, because everything works as before
    * different: the test fails and the human has to check the output again
    >>>

    View full-size slide

  60. Legacy Code 21.10.2016
    Golden Master Testing
    wow such dirt, very temporary

    View full-size slide

  61. Legacy Code 21.10.2016
    1. Use a piece of untested 

    undocumented code
    2. Write an assertion 

    that you know will fail
    3. Let the failure tell you 

    what the behaviour is
    4. Change the test so that it 

    expects the behaviour that
    the code produces
    5. Reason about the code 

    and exercise every branch
    Golden Master Testing:
    6. Repeat until 

    the code is covered

    View full-size slide

  62. Legacy Code 21.10.2016
    This seems to be fundamentally wrong
    Are our tests really testing anything at all?
    What if you just characterized a bug?

    View full-size slide

  63. Legacy Code 21.10.2016
    Protection for changing things => confidence to refactor
    We are trying to put in a mechanism to find bugs later.

    View full-size slide

  64. Legacy Code 21.10.2016
    Protection for changing things => confidence to refactor
    A characterization test is not a test you want to keep around.
    • You use the test to get coverage,
    • you refactor,
    • cleanup / write new specs
    • and then you throw it away!
    We are trying to put in a mechanism to find bugs later.

    View full-size slide

  65. Legacy Code 21.10.2016
    Don’t keep these highly coupled tests (or they will cost you more money than they save you)
    Use tools for partially automating this process
    Anti Pattern ahead:

    View full-size slide

  66. Legacy Code 21.10.2016

    View full-size slide

  67. Legacy Code 21.10.2016
    Test coverage analysis
    Lines of Code (no code is better than no code)
    Cyclomatic Complexity
    ABC Score (Code Smells)
    Churn
    Afferent / Efferent Coupling
    Mutation Coverage
    Metrics:
    Usually language agnostic and a helpful tool, but metrics should never be a goal:

    View full-size slide

  68. Legacy Code 21.10.2016

    View full-size slide

  69. Legacy Code 21.10.2016
    Refactoring

    View full-size slide

  70. Legacy Code 21.10.2016

    View full-size slide

  71. Legacy Code 21.10.2016
    the list of refactoring technics is just the beginning
    composing methods (extract method, replace method with object)
    moving features (move method, extract class)
    organizing data (replace hash with object, replace type code with polymorphism)
    simplifying conditional (decompose, recompose, null objects)
    making method calls simpler (separate query from modifier, replace constructor with factory)
    dealing with generalization (template method, extract module, inheritance)
    learn when to start, when to stop
    when you have “refactoring tickets” you're doing it wrong (it’s part of your work!)
    not having the time for refactoring (because of deadlines?) is usually a sign that
    you need to do some refactoring
    Refactoring: pay your bills!

    View full-size slide

  72. Legacy Code 21.10.2016
    You are likely to see new possibilities,
    REFACTOR ALL THE CODE to pursue truth and beauty...

    View full-size slide

  73. Legacy Code 21.10.2016
    DON’T.

    View full-size slide

  74. Legacy Code 21.10.2016
    A big refactoring is a recipe for disaster.
    As ugly as the mess looks now, focus on the real problems.
    When you need to add a new feature:
    add some specs to get confidence
    clean up
    add new code
    refactoring hat, feature hat
    Don't mix an unfinished refactoring with other new tasks.
    Your goal is to leave the code computing exactly the same, like you found it.
    Discipline
    Refactor when it’s necessary!
    (It will never be finished…)

    View full-size slide

  75. Legacy Code 21.10.2016
    Rewrite vs Refactoring

    View full-size slide

  76. Legacy Code 21.10.2016
    if it doesn't work at all (code has to work mostly correctly, before you refactor)
    if it is full of bugs and you cannot stabilize it
    if there are big changing requirements, the current app can't support
    if time and money are no constraints
    When is it easier to start from scratch, instead of refactoring a big mess?
    +
    +
    +
    +
    (For most developers this is the favourite choice, but it’s usually the most expensive)

    View full-size slide

  77. Legacy Code 21.10.2016
    Compromise!
    Refactor one large piece into components.

    Favour piece by piece rewrite over big bang rewrite and rebuild incrementally.
    This strategy will let you:
    • focus only on the important and critical parts
    • recover knowledge which got lost in complex code
    • preserve investments which went into the code already (time for bugfixes, requirements…)

    View full-size slide

  78. Legacy Code 21.10.2016
    Compromise!
    Refactor one large piece into components.

    Favour piece by piece rewrite over big bang rewrite and rebuild incrementally.
    What's the cost of debt?
    Which parts are less critical?
    Think of extra costs for maintenance and extension caused by overly complex code.
    This strategy will let you:
    • focus only on the important and critical parts
    • recover knowledge which got lost in complex code
    • preserve investments which went into the code already (time for bugfixes, requirements…)

    View full-size slide

  79. Legacy Code 21.10.2016
    TL;DR
    technical debt is the main reason for legacy code

    treat your legacy and former developers with respect

    the business always wins* (changing requirements)

    keep your code well tested

    break dependencies and decouple business logic

    maintenance == refactoring (pay your debt!)


    View full-size slide

  80. Railslove
    We love to build the web.
    KTHXBYE
    Questions?
    Marco Schaden

    @donschado
    [email protected]
    21.10.2016

    View full-size slide

  81. Legacy Code 21.10.2016
    Refactoring - Ruby Edition
    http://www.amazon.com/Refactoring-Ruby-Addison-Wesley-Professional/dp/0321984137
    TL;DR: http://ghendry.net/refactor.html
    Patterns of Enterprise Application Architecture
    http://www.amazon.com/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420/
    Working Effectively with Legacy Code
    http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052

    Golden Master Testing: Refactor Complicated Views Katrina Owen: July 09, 2014
    http://www.sitepoint.com/golden-master-testing-refactor-complicated-views/
    Rails Conf 2013 The Magic Tricks of Testing by Sandi Metz
    https://www.youtube.com/watch?v=URSWYvyc42M
    GORUCO 2009 - SOLID Object-Oriented Design by Sandi Metz
    https://www.youtube.com/watch?v=v-2yFMzxqwU
    Rocky Mountain Ruby 2012 - Go Ahead, Make a Mess by Sandi Metz
    https://www.youtube.com/watch?v=f5I1iyso29U

    RailsConf 2014 - Step-by-Step Refactoring Toward Ember by Brandon Hays

    https://www.youtube.com/watch?v=VMmaKj8hCR4
    Katrina Owen - 467 tests, 0 failures, 0 confidence - Railsberry 2013
    https://vimeo.com/68730418
    BathRuby 2015 - Here Be Dragons, Katrina Owen
    https://www.youtube.com/watch?v=QAUHYzC9kFM
    Cascadia Ruby Conf 2012 Therapeutic Refactoring by Katrina Owen
    https://www.youtube.com/watch?v=J4dlF0kcThQ
    RailsConf 2015 - Getting a Handle on Legacy Code
    https://www.youtube.com/watch?v=lsFFjFp7mEE
    MountainWest RubyConf 2015 - Data-Driven Refactoring
    https://www.youtube.com/watch?v=AcdliNixNhs
    Baruco 2013: Design Patterns And The Proper Cultivation Thereof, Corey Haines
    https://www.youtube.com/watch?v=vqN3TQgsXzI
    Rocky Mountain Ruby 2013 SOLID and TDD, Sitting in a by Mike Nicholaides
    https://www.youtube.com/watch?v=FidRcixHQos
    RubyConf 2009 - SOLID Ruby by: Jim Weirich
    https://www.youtube.com/watch?v=dKRbsE061u4
    content[:source]

    View full-size slide