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

This Old Pony: Working with Legacy Django Projects

This Old Pony: Working with Legacy Django Projects

DjangoCon 2016: "Legacy" is a word that produces fear in many software developers. However it means nothing more than software that already exists, and you're probably working with it already, admit it or not. We'll take a tour through what legacy Django projects look like, how to approach them, and how to work on them while keeping your wits.

Ben Lopatin

July 20, 2016
Tweet

More Decks by Ben Lopatin

Other Decks in Programming

Transcript

  1. This Old Pony
    DjangoCon US 2016- Ben Lopatin
    Working with legacy Django projects

    View Slide

  2. Partner and developer
    // Wellfire Interactive
    @bennylope
    [email protected]fire.co

    View Slide

  3. Legacy software?

    View Slide

  4. View Slide

  5. View Slide

  6. View Slide

  7. What is “legacy”?

    View Slide

  8. Code someone else
    wrote

    View Slide

  9. View Slide

  10. Code that has no tests

    View Slide

  11. View Slide

  12. Software that’s in
    production

    View Slide

  13. View Slide

  14. Written software
    is an investment

    View Slide

  15. Ugly, old systems
    deliver value

    View Slide

  16. The world runs on
    legacy software

    View Slide

  17. What is legacy
    Django?

    View Slide

  18. View Slide

  19. 0 tests run in 0 seconds

    View Slide

  20. Not radically unique

    View Slide

  21. Some assumptions

    View Slide

  22. Goal: improve code in
    discrete steps

    View Slide

  23. View Slide

  24. This is the right way.

    View Slide

  25. This is the right way.
    This is some good ideas.

    View Slide

  26. View Slide

  27. Code Review

    View Slide

  28. Why?

    View Slide

  29. Step 0:
    Ask questions

    View Slide

  30. Talk to people

    View Slide

  31. What’s it supposed to do?
    What does it do?
    Known bugs?
    Planned features?

    View Slide

  32. Reading the code

    View Slide

  33. Confusing areas
    Architecture
    Code smell
    Style
    &c.

    View Slide

  34. Tools

    View Slide

  35. flake8
    PyCharm
    pylint

    View Slide

  36. Logging

    View Slide

  37. Understand
    production errors

    View Slide

  38. try:
    do_some_stuff()
    make_some_calls()
    except:
    pass # TODO: handle this! (Chris)

    View Slide

  39. try:
    do_some_stuff()
    make_some_calls()
    except:
    logger.exception("Chris's error")

    View Slide

  40. Testing

    View Slide

  41. Why?

    View Slide

  42. View Slide

  43. Fix bugs
    Guide development
    Deployment confidence

    View Slide

  44. Tests provide
    information about
    code quality.

    View Slide

  45. Test suite scenarios

    View Slide

  46. Great tests!
    No tests!
    Bad tests
    Slow tests!

    View Slide

  47. Great tests!

    View Slide

  48. No tests!

    View Slide

  49. Bad tests!

    View Slide

  50. Slow tests!

    View Slide

  51. Prioritizing new tests

    View Slide

  52. Bugs

    View Slide

  53. Smoke tests
    View-centric integration tests

    View Slide

  54. New features

    View Slide

  55. Refactoring

    View Slide

  56. Upgrading

    View Slide

  57. Backwards
    incompatibilities

    View Slide

  58. Superpower:
    tox

    View Slide

  59. tox
    tox tox
    tox
    tox
    tox
    tox
    tox
    tox
    tox
    tox tox
    tox

    View Slide

  60. [tox]
    envlist =
    flake8,
    deployed,
    py27-django{19,18,17}
    [testenv]
    setenv =
    PYTHONPATH = {toxinidir}
    commands = python manage.py test
    deps =
    django17: Django>=1.7,<1.8
    django18: Django>=1.8,<1.9
    django19: Django>=1.9,<1.10
    -r{toxinidir}/requirements/base.txt

    View Slide

  61. Goal: LTS

    View Slide

  62. Dependencies

    View Slide

  63. Tight integration
    with obsolete libraries

    View Slide

  64. Unnecessary version
    [over]-specification

    View Slide

  65. Version support
    mismatches

    View Slide

  66. View Slide

  67. {

    View Slide

  68. {
    Version
    Compatibility

    View Slide

  69. View Slide

  70. Upgrade!

    View Slide

  71. View Slide

  72. Solutions

    View Slide

  73. Patch and pray
    (upstream)

    View Slide

  74. Fork

    View Slide

  75. Extract what you used

    View Slide

  76. Remove/replace

    View Slide

  77. pur
    pip-tools

    View Slide

  78. $ pur -r requirements.txt
    Updated flask: 0.9 -> 0.10.1
    Updated sqlalchemy: 0.9.10 -> 1.0.12
    Updated alembic: 0.8.4 -> 0.8.6
    All requirements up-to-date.

    View Slide

  79. Issues

    View Slide

  80. Formatting

    View Slide

  81. View Slide

  82. autopep8
    PyCharm

    View Slide

  83. Settings

    View Slide

  84. Secrets!

    View Slide

  85. bandit

    View Slide

  86. One big app

    View Slide

  87. View Slide

  88. Solution:
    Break up apps

    View Slide

  89. Big views
    (lots o’ logic)

    View Slide

  90. “Fat models”

    View Slide

  91. Humongous managers

    View Slide

  92. Expansive forms

    View Slide

  93. Not just views

    View Slide

  94. Seek to minimize scope
    of changes, continually.

    View Slide

  95. Refactor as you go

    View Slide

  96. New feature?
    New app!

    View Slide

  97. Feature uses old code?
    Refactor old code.

    View Slide

  98. What didn’t we talk
    about?

    View Slide

  99. Continuous integration
    Automated deployment
    Configuration management
    Documentation
    Security

    View Slide

  100. The End

    View Slide

  101. I am ready for your questions

    View Slide