Boost Maintainability

D16bc1f94b17ddc794c2dfb48ef59456?s=47 Mosky
June 03, 2016

Boost Maintainability

In your code base, 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 practicing 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 • Python Charmer at

    Pinkoi. • Has spoken at • PyCons in TW, KR, JP, SG, HK,
 COSCUPs, and TEDx, etc. • Countless hours 
 on teaching Python. • Own Python packages: • ZIPCodeTW, 
 MoSQL, Clime, etc. • http://mosky.tw/
  14. Android & Backend
 Engineers We're looking for

  15. Boost Maintainability • “Maintainability” • Lines need to read back.

    • Making It Zero • Progressive From Zero
  16. Making It Zero

  17. A 
 Dominant Rule

  18. Be exact & consistent. ” “

  19. result = ... result = ...

  20. resp = ... parsed_dict = ... ✓

  21. user = User(user_id) buyer = user_id

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

  23. Get a dictionary, please.

  24. Ops Hint

  25. page = ... △

  26. page_no = ... page_html = ... ✓

  27. requested_fields
 &
 allowed_fields ?

  28. set(requested_fields)
 &
 allowed_field_set ✓

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

  30. user = User(...) user_d = {} ✓

  31. resp = requests.get(...)

  32. resp.text resp.json ?

  33. resp.text resp.json() !

  34. resp.text resp.parse_as_json() ✓

  35. Req.is_secure()

  36. is_secure = True

  37. secure = True with_tls = True ✓

  38. using_tls = True
 req_is_secure = True ✓

  39. The General Rules Ops Hint • Hints which 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.
  40. For Callable Ops Hint • <verb>_ = imperative sentence. •

    <yes-no question> → boolean. • to_<thing> → thing.
  41. For Boolean Ops Hint • Normal objects take <noun>. •

    Callables take <verb>_ and <yes-no question>. • So use: • <adj> • <prep>_ • <participle>_ • <simple sentence> • <to-infinitive>
  42. For Return Value Ops Hint • Use on the return

    value: • get_page_no → numeric >= 1. • query_user → user object. • parse_to_tree → tree object.
  43. Explicit Unknown Ops Hint • _x: anything. • Rather than

    an ambiguous name. • You won't forget to determine the ops it supports. • Use hasattr or isinstance later.
  44. Avoid None and Null Ops Hint • 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.
  45. tmpl = '<p>{}</p>'
 tmpl.format(name)

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

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

  48. arg = parse(arg) ?

  49. arg_d = parse(arg_json) ✓

  50. str/x Ops Hint • _key: key (of a dict). •

    'lowercase_n_underscore' • Or just k. • _url: URL. • Percent-encode. • _json: JSON. • JSON is a string, actually. • _html: HTML. • Avoid XSS. • _sql: SQL. • Avoid SQL injection.
  51. numeric/x Ops Hint • _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.
  52. Structure Hint

  53. users ?

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

  55. uid_email_map = {
 'mosky': 'mosky.tw@gmail.com', ...
 }

  56. uid_email_map ✓

  57. uid_email_pairs = ... uid_email_map = dict(↖) ✓

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

  59. For Dict & Tuple Structure Hint • <key>_<value>_map • For

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

  61. “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 Hint
  62. “Should I cache it?” Performance Hint • get_: memory op.

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

  64. Too long? Use proper abbreviation.

  65. Define in Comment

  66. receiver_address_dict

  67. # rad: receiver addr dict rad = ...

  68. Paragraph 
 & Section

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

    content) return content
  70. # Check Arguments ...
 ... # Query from Tables ...


    ... ...
 ... # Transform ...
  71. With Blank Line and Comment Paragraph & Section • Like

    writing reStructuredText or Markdown. • Paragraph: • A paragraph contains no blank line. • A blank line separates paragraphs. • Section: • A section contains paragraphs. • A “title comment” separates sections. • A semi-function.
  72. Line Functions Up

  73. Func A Func U Func B Line No

  74. Func A Func U Func B Line No

  75. Func A Func U Func B Line No

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

  77. By Calls Line Functions Up • Measure the “disorderedness”. •

    In a file, • Keep the lines has same direction. • Layer functions, and may become modules. • In a project, • Apply it to modules.
  78. Face 
 Bad Smell

  79. Don't lost! Face Bad Smell • Comment: • Pitfalls, the

    actual return type, side effects, etc. • # TODO: • Seal it with better name or stabler wrapper. • good = poor() • def good(): poor() • Stay focused!
  80. Use hints to 
 boost maintainability!

  81. 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!