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

Boost Maintainability

D16bc1f94b17ddc794c2dfb48ef59456?s=47 Mosky
June 03, 2016

Boost Maintainability

In your codebase, to understand a random line, how many lines do you need to read back? Cloud you make it zero?

This talk will start with the impact of the maintainability, define the maintainability as “to understand a random line, the lines you need to read back”, show the practical techniques to make it zero, or nearly zero, and finally, reach the goal: boost the maintainability.

It's the revision of “Beyond the Style Guides” [1] and the talk at PyCon TW 2016 [2], PyCon APAC/KR 2016 [3], and GDG DevFest Taipei 2016 [4].

[1]: https://speakerdeck.com/mosky/beyond-the-style-guides
[2]: https://tw.pycon.org/2016
[3]: https://www.pycon.kr/2016apac/
[4]: https://devfest-taipei-3cbee.firebaseapp.com/

D16bc1f94b17ddc794c2dfb48ef59456?s=128

Mosky

June 03, 2016
Tweet

Transcript

  1. Boost Maintainability

  2. File "api.py", line 101, in generate_response next_page = page +

    1 TypeError: must be str, not int
  3. page + 1 ?

  4. page = make_html(...) next_page = page + 1 !

  5. We read lines randomly. ” “

  6. page_html = make_html(...) next_page_no = page_no+1 ✓

  7. page_html + 1 !

  8. — Joel on Software Making wrong code look wrong ”

  9. —Joel on Software Making Wrong Code Look Wrong • “Making

    Wrong Code Look Wrong” • http://bit.ly/joel-wrong • This talk will be more systemic than it. • But exception is good, IMO.
  10. Maintainability

  11. To understand a random line, the lines you need to

    read back. ” “
  12. Time is just

  13. ❤ Python & Open Source Mosky • Backend Lead at

    Pinkoi. • Has spoken at: • PyCons in TW, JP, SG, HK, KR, MY, COSCUPs, and TEDx, etc. • Countless hours on teaching Python. • Own Python packages: • ZIPCodeTW, MoSQL, Clime, etc. • http://mosky.tw/
  14. Boost Maintainability • “Maintainability” • Lines need to read back.

    • Making It Zero • Progressive From Zero
  15. Making It Zero

  16. The Dominant Rule

  17. Be consistent & exact. ” “

  18. user = User(user_id) buyer = user_id

  19. buyer = User(user_id) buyer_id = user_id ✓

  20. result = ... result = ...

  21. resp = ... parsed_dict = ... ✓

  22. Get a dictionary, please.

  23. Ops Clues

  24. page = ... △

  25. page_no = ... page_html = ... ✓

  26. requested_fields & allowed_fields ?

  27. set(requested_fields) & allowed_field_set ✓

  28. user = User(...) user = {} ?

  29. user = User(...) user_dict = {} ✓

  30. resp = requests.get(...)

  31. resp.text resp.json ?

  32. resp.text resp.json() !

  33. resp.text resp.parse_as_json() ✓

  34. Req.is_secure()

  35. is_secure = True

  36. with_tls = True req_is_secure = True ✓

  37. to_use_tls = True secure = True ✓

  38. The General Rules Ops Clues • Clue the ops you

    should use. • _no: numeric. • <plural>: sequence, usually is mutable sequence (list). • _<type>: if no intuitive way. • _<abstract type>: • _seq: for sequence. • _gen: for generator. • More: collections.abc – Python Docs.
  39. For Callable Ops Clues • <verb>_ = imperative sentence. •

    <yes-no question> → boolean. • to_<thing> → thing. • from_<thing> ← thing.
  40. For Boolean Ops Clues • The normal objects took the

    nouns. • The callables took <verb>_ and <yes-no question>. • We have: • <preposition>_ • <simple sentence> • to_<verb>_ • <adj>
  41. For Return Value Ops Clues • Clue the return value:

    • get_page_no → numeric which >= 1. • query_user → user object. • parse_to_tree → tree object.
  42. Avoid None and Null Ops Clues • Consider: • user

    = query_user(uid) user.is_valid() • Then query_user returns None. • Boom! An AttributeError! ∵ None supports almost no op. • Accept an exception? • Y: Just raise when you wanna return None. • N: Use a dummy object like a dummy user or an empty str, etc.
  43. tmpl = '<p>{}</p>' tmpl.format(name)

  44. name = '<script>...</script>' !

  45. tmpl_html = ... tmpl_html.format( escape_to_html(name) ) ✓

  46. arg = parse(arg) ?

  47. arg_dict = parse(arg_json) ✓

  48. str/x Ops Clues • _key: str/key (of a dict). •

    'lowercase_n_underscore' • _json: str/json. • JSON is a string, not dict. • _url: str/url. • Clue percent-encoding; avoid URL injection. • _html: str/html. • Avoid XSS. • _sql: str/sql. • Avoid SQL injection.
  49. numeric/x Ops Clues • _no: number, #. • ≥ 1.

    • _idx: index. • ≥ 0. • Or just i, j, k. • _secs • It's seconds! • _pct • n = 10% n_pct = 10 • _month, _day, ... • Use month_str if in string.
  50. Structure Clues

  51. users ?

  52. users = { 'mosky': 'mosky.tw@gmail.com', ... }

  53. uid_email_dict = { 'mosky': 'mosky.tw@gmail.com', ... }

  54. uid_email_dict ✓

  55. uid_email_pairs = ... uid_email_dict = dict(↖) ✓

  56. # select uid, email for uid, email in uid_email_pairs: ...

  57. For Dict & Tuple Structure Clues • <key>_<value>_dict • For

    tuples: • _pair: 2-tuple. • _pairs: 2-tuples. • <1st>_<2nd>_<3rd>_tuple: n-tuple.
  58. Others

  59. “Don't use me!” • _<name> • Don't use when out

    of: • A module. • A class. • Don't guarantee the behavior. • Make it easier to trace and refactor. Private Clues
  60. “Should I cache it?” Performance Clues • get_ / set_:

    memory op. • parse_ / calc_ : CPU-bound op. • query_: IO-bound op. • query_or_get_: IO-bound op with cache.
  61. Progressive From Zero

  62. Paragraph & Section

  63. def request_or_get(url): if has_cache(url): return get_cache(url) content = request(url) set_cache(url,

    content) return content
  64. # check arguments ... ... # query from tables ...

    ... ... ... # transform ...
  65. With Blank Line and Comment Paragraph & Section • Like

    writing in Markdown. • Paragraph: • A paragraph contains no blank line. • A blank line separates paragraphs. • Section: • A section contains paragraphs. • A comment with blank line separates sections.
  66. Line Units Up

  67. Func A Func U Func B Line No

  68. Func A Func U Func B Line No

  69. Func A Func U Func B Line No

  70. Func A Func U Func B Module 1 Module 2

  71. By Calls Line Functions Up • Measure the “orderliness”. •

    Keep them have the same direction. • May become module. • Try to line the classes and modules up by the imports?
  72. Face Bad Smell

  73. Don't get lost! Face Bad Smell • Comment: • For

    the pitfalls, the actual return type, the side effects, etc. • Use # FIXME: ... or # XXX: ... . • Seal it: • good = poor() • def good(): poor() • Stay focused!
  74. Use clues to boost maintainability!

  75. Photo Credits • “The Money“ https://commons.wikimedia.org/wiki/ File:Forex_Money_for_Exchange_in_Currency_Bank.jpg • “The Bricks”

    https://pixabay.com/zh/%E5%BB%BA%E8%AE%BE- %E6%92%AD%E6%94%BE-%E7%8E%A9%E8%80%8D- %E4%B9%90%E8%B6%A3-%E5%88%9B%E6%84%8F-1159776/ • Thanks!