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

Beyond the Style Guides

Beyond the Style Guides

It's a talk about how to write understandable code from understanding human brain at Taipei.py [1] and PyCon HK 2015 [2].

[1]: http://www.meetup.com/Taipei-py/events/222174472/
[2]: http://2015.pycon.hk/

Mosky Liu

May 28, 2015

More Decks by Mosky Liu

Other Decks in Programming


  1. Beyond 
 the Style Guides Mosky

  2. It's all about time. I can write a 4x faster

    program than you! But the hardware is super powerful now,
 it may be just 0.0001 ms vs. 0.0004 ms. I can write 4x faster. And human brain haven't changed a lot,
 so it may be even 1 week vs. 1 month. Human Time ⋙ Computer Time
  3. - Benjamin Franklin “Time is money.”

  4. How to write faster? Good language, e.g., Python Powerful libraries

    Experience ∈ The things you can't change immediately.
  5. Understandable codebase.
 i.e., codebase which has high maintainability. ∈ You

    can just learn from this share.
  6. Style Guide? # It looks okay!
 count += 1

  7. Not enough # But it was initialized as
 count =

    '1' # In JavaScript, 
 # there's even no an error.
  8. You remain only 10k days in your life.

  9. Spend time on writing exciting feature,
 not debugging.

  10. Mosky Python Charmer at Pinkoi The author of the Python

    packages MoSQL, Clime, … The speaker of the conferences, PyCon TW/JP/SG, … Also teaching Python mosky.tw
  11. None
  12. None
  13. Pinkoi

  14. Pinkoi
 a.k.a. 揮因ᇔጱঅ瑿ො

  15. None
  16. None
  17. Thanks!

  18. Human Brain

  19. A Computer Read the code line by line. Cover all

    of the code, usually. Just complain when it doesn't understand.
  20. A Human Brain We can't read code like a computer.

    CPU is super slow, and even can't focus. RAM is tiny, programmer especially. Disk is losing bytes all the time. Nobody to complain. So we prefer to leave code alone.
  21. But, computer is always complaining. We jump to the failed

    line. Read back from the line. Finally, 
 we leave immediately after we fix it.
  22. Or, new requirement comes. We still jump to the related

    line. Read back from the line. Finally, 
 we also leave immediately after we finish it.
  23. We read lines randomly.

  24. Maintainability To understand a random line, 
 how many lines

    do you need to read back? Lesser → Higher maintainability
  25. Name

  26. Nothing But Have a good dictionary. Be exact to avoid

    ambiguity. Be consistent to avoid misleading. Hint, hint, and hint.
  27. Be Exact “Apple” Which “Apple”? “Apple, the company.” apple_the_company

  28. date_a-date_b Which dates? today-joined_date

  29. user User’s what? user_name user_email

  30. name Who’s name? user_name store_name

  31. Be Consistent Saw this in somewhere: apple = Company('apple') Now

    you read: apple Then you will guess it is a company. So don't: apple = Fruit('apple')
  32. Too Long? The context helps. fruit.py apple

  33. Type Hint We operate variables. count += 1 parse(input_json) If

    we know how to operate it at first glance,
 it saves time from tracing or running. Not the “Type Hint” in PEP 0484
  34. Make It Intuitive count should be numeric name string thing

    names many strings; may be a list
  35. page page_no so should be numeric event event_key so should

    be string stuff
  36. List or Set? requested_fields & allowed_fields ? set(requested_fileds) & allowed_field_set

  37. List or Generator? large_rows large_rows[0] # ? large_row_gen # generator

    large_row_it # iterator
  38. Object or Dict? user What is the type of user?

    user['name'] # ? user.name # ? user_dict['name'] user_d['name']
  39. Is it a bool? new_user A bool? A User instance?

    is_new_user A bool? A Function? new user_is_new
  40. Is it a function? Use imperative, i.e., start with a

  41. .text .json A function? A string thing? .get_text .parse_from_json .text

    # string thing
  42. def parse(x, return_dict=False): … ? def parse(x, to_return_dict=False): …

  43. Explicit Unknown arg May be tuple, dict, or anything. arg_x

  44. Avoid None d = None if failed else {}

    = value
 value = d.get('key') It causes TypeError or AttributeError in Python, and extra effort in other language. Be consistent in type.
  45. Some tips Raise exception. Use zero and infinite. Use constant.

    Filter the Nones out before return.
  46. Content Type User Input The “Keys” URL JSON HTML SQL

    ∈ string thing
  47. json['keyword'] # ? Actually the json is a dict-like. JSON:

    JavaScript Object Notation → a string arg_dict = json.loads(arg_json) Transformation You can see the domain and codomain.
  48. template.format(name) If template # -> "<a>{}</a>" name # -> "<script

    src=…></script>" !
  49. template_html.format(escape(name)) Safe :) “Making Wrong Code Look Wrong “

  50. Abstract Type it — iterator seq — sequence map —

  51. Structure Hint We operate the variables. If we know how

    to operate it at first glance,
 it saves time from tracing or running. (Yeah, I copied it from the type hint.)
  52. Map users A dict? What are the key and the

  53. uid_user_map
 uid_user_map['mosky'] # -> User('mosky')

  54. # ok
 users = {
 'mosky': User('mosky'),
 } #

    even better
 uid_user_map = {
 'mosky': User('mosky'),
  55. Tuple uid, name = uid_name_pair a, b, c = a_b_c_tuple

  56. key_value_pairs = sql('select key, value') for key, value in key_value_pairs:

    … key_value_map = dict(key_value_pairs)
  57. Composite If apply structure hint and type hint, It will

    be long. You may shorten. Keep long description in comment or doc.
  58. Use common abbreviation http://abbreviations.com/ Use acronym, e.g., rlname for really_long_name.

    Do comment if you use them.
  59. # compromise between meaning and length
 # event key:

    e.g., 'monthers_day'
 # config_d: config dict
 # - start_date: …
 # …
 event_key_config_d_map = {
 'monthers_day': {…}
  60. # focus on reducing length
 # ekey: event key

    # config: config dict
 # - start_date: …
 # …
 ekey_config_map = {
 'monthers_day': {…}
  61. adj. new_user past participle joined_date present participle working_queue infinitive keys_to_remove

    another noun template_args
  62. int n, m
 i, j, k
 twd_int int/range page_no

    birth_day tids_idx bool new, joined
  63. str name, month_str str/key event_key str/url next_url str / json

    user_json str/html page_html str/sql to_update_sql
  64. dict user_d, user_dict list uids, uid_list set uid_set mapping uid_user_map

    generator uid_gen
  65. date start_date datetime joined_dt re email_re decimal total_dec currency total_currency,

  66. key → value uid_user_d_map (x, y) uid_user_pair [(x, y), …]

    uid_user_pairs (x, y, z) uid_nick_email_tuple
  67. Return Type Hint We operate the variables. If we know

    how to operate it at first glance,
 it saves time from tracing or running. (Yeah, I copied it from type hint, again.)
  68. .parse What we will get? .parse_to_tree

  69. .allow_to_log_in Allow something to log in? .do_allow_to_log_in If return value

    is a bool, use yes–no question.
  70. Performance Hint get_name # Memory op. parse_from_json # CPU op.

 request_html # IO op. Let reader know the roughy cost.
  71. Private Hint “Don't touch me hint” A simple underscore prefix

    (_) Don't use me out of the module or file. Non-privates are just public APIs.
  72. Hints Type Hint Structure Hint Return Type Hint Performance Hint

    Private Hint
  73. A random line now is more understandable.

  74. Blank Line

  75. Blank Line Use blank line to separate your code into:

    Paragraph Section Like lightweight markup language,
 e.g., Markdown, RST.
  76. Paragraph Lines without any blank line. Group similar lines into

    a paragraph. Contains sub-paragraph. Use blank line to separate paragraphs.
  77. try:
 html = read_html_from_cache(url)
 except IOError:
 html = request_html(url)

  78. Section Paragraphs. Group similar paragraphs into a section. Avoid sub-section.

    Use two blank lines to separate sections.
  79. <section A's paragraph 1>
 <section A's paragraph 2>

 <section B's paragraph 1>
  80. Still don't understand?
 Try to read a paragraph, then a

  81. The “Lines”

  82. Dependency The F function calls the G function. F depends

    on G. F → G It's a “Line”.
  83. How messy? Are the directions are all same? Usually ↑

    in a file and files. Order your code. Are they point to limited sections or a files? Lesser is better. Section or modularize them.
  84. At least, easier to trace.

  85. Bad Smell

  86. Reality Don't have time to refactor. They actually work well.

    Make you itch, but won't beat you. You may already understand.
  87. So Just Seal It Off Comment the pitfalls. Use #TODO

    rather than really refactor. Assign return value to a better named variable. Wrap them. Just write new code.
  88. Stay focused.

  89. Recap

  90. Recap We read lines randomly. Type hints and other hints

    Paragraph & section by blank line. Line your functions. Bad smell won't beat you. http://mosky.tw