Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Beyond the Style Guides


Published on

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


Published in: Software
  • D0WNL0AD FULL ▶ ▶ ▶ ▶ ◀ ◀ ◀ ◀
    Are you sure you want to  Yes  No
    Your message goes here

Beyond the Style Guides

  1. 1. Beyond 
 the Style Guides Mosky
  2. 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. 3. - Benjamin Franklin “Time is money.”
  4. 4. How to write faster? Good language, e.g., Python Powerful libraries Experience ∈ The things you can't change immediately.
  5. 5. Understandable codebase.
 i.e., codebase which has high maintainability. ∈ You can just learn from this share.
  6. 6. Style Guide? # It looks okay!
 count += 1
  7. 7. Not enough # But it was initialized as
 count = '1' # In JavaScript, 
 # there's even no an error.
  8. 8. You remain only 10k days in your life.
  9. 9. Spend time on writing exciting feature,
 not debugging.
  10. 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
  11. 11. Pinkoi

  12. 12. Pinkoi
  13. 13. Thanks!
  14. 14. Human Brain
  15. 15. A Computer Read the code line by line. Cover all of the code, usually. Just complain when it doesn't understand.
  16. 16. 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.
  17. 17. But, computer is always complaining. We jump to the failed line. Read back from the line. Finally, 
 we leave immediately after we fix it.
  18. 18. 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.
  19. 19. We read lines randomly.
  20. 20. Maintainability To understand a random line, 
 how many lines do you need to read back? Lesser → Higher maintainability
  21. 21. Name
  22. 22. Nothing But Have a good dictionary. Be exact to avoid ambiguity. Be consistent to avoid misleading. Hint, hint, and hint.
  23. 23. Be Exact “Apple” Which “Apple”? “Apple, the company.” apple_the_company
  24. 24. date_a-date_b Which dates? today-joined_date
  25. 25. user User’s what? user_name user_email
  26. 26. name Who’s name? user_name store_name
  27. 27. 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')
  28. 28. Too Long? The context helps. apple
  29. 29. 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
  30. 30. Make It Intuitive count should be numeric name string thing names many strings; may be a list
  31. 31. page page_no so should be numeric event event_key so should be string stuff
  32. 32. List or Set? requested_fields & allowed_fields ? set(requested_fileds) & allowed_field_set
  33. 33. List or Generator? large_rows large_rows[0] # ? large_row_gen # generator large_row_it # iterator
  34. 34. Object or Dict? user What is the type of user? user['name'] # ? # ? user_dict['name'] user_d['name']
  35. 35. Is it a bool? new_user A bool? A User instance? is_new_user A bool? A Function? new user_is_new
  36. 36. Is it a function? Use imperative, i.e., start with a verb.
  37. 37. .text .json A function? A string thing? .get_text .parse_from_json .text # string thing
  38. 38. def parse(x, return_dict=False): … ? def parse(x, to_return_dict=False): …
  39. 39. Explicit Unknown arg May be tuple, dict, or anything. arg_x
  40. 40. Avoid None d = None if failed else {}
 d['key'] = value
 value = d.get('key') It causes TypeError or AttributeError in Python, and extra effort in other language. Be consistent in type.
  41. 41. Some tips Raise exception. Use zero and infinite. Use constant. Filter the Nones out before return.
  42. 42. Content Type User Input The “Keys” URL JSON HTML SQL ∈ string thing
  43. 43. 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.
  44. 44. template.format(name) If template # -> "<a>{}</a>" name # -> "<script src=…></script>" !
  45. 45. template_html.format(escape(name)) Safe :) “Making Wrong Code Look Wrong “
  46. 46. Abstract Type it — iterator seq — sequence map — mapping
  47. 47. 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.)
  48. 48. Map users A dict? What are the key and the value?
  49. 49. uid_user_map
 uid_user_map['mosky'] # -> User('mosky')
  50. 50. # ok
 users = {
 'mosky': User('mosky'),
 } # even better
 uid_user_map = {
 'mosky': User('mosky'),
  51. 51. Tuple uid, name = uid_name_pair a, b, c = a_b_c_tuple
  52. 52. key_value_pairs = sql('select key, value') for key, value in key_value_pairs:
 … key_value_map = dict(key_value_pairs)
  53. 53. Composite If apply structure hint and type hint, It will be long. You may shorten. Keep long description in comment or doc.
  54. 54. Use common abbreviation Use acronym, e.g., rlname for really_long_name. Do comment if you use them.
  55. 55. # compromise between meaning and length
 # event key: e.g., 'monthers_day'
 # config_d: config dict
 # - start_date: …
 # …
 event_key_config_d_map = {
 'monthers_day': {…}
  56. 56. # focus on reducing length
 # ekey: event key
 # config: config dict
 # - start_date: …
 # …
 ekey_config_map = {
 'monthers_day': {…}
  57. 57. adj. new_user past participle joined_date present participle working_queue infinitive keys_to_remove another noun template_args
  58. 58. int n, m
 i, j, k
 twd_int int/range page_no
 birth_day tids_idx bool new, joined
  59. 59. 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
  60. 60. dict user_d, user_dict list uids, uid_list set uid_set mapping uid_user_map generator uid_gen
  61. 61. date start_date datetime joined_dt re email_re decimal total_dec currency total_currency, total_ccy
  62. 62. key → value uid_user_d_map (x, y) uid_user_pair [(x, y), …] uid_user_pairs (x, y, z) uid_nick_email_tuple
  63. 63. 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.)
  64. 64. .parse What we will get? .parse_to_tree
  65. 65. .allow_to_log_in Allow something to log in? .do_allow_to_log_in If return value is a bool, use yes–no question.
  66. 66. Performance Hint get_name # Memory op. parse_from_json # CPU op. query_html
 request_html # IO op. Let reader know the roughy cost.
  67. 67. 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.
  68. 68. Hints Type Hint Structure Hint Return Type Hint Performance Hint Private Hint
  69. 69. A random line now is more understandable.
  70. 70. Blank Line
  71. 71. Blank Line Use blank line to separate your code into: Paragraph Section Like lightweight markup language,
 e.g., Markdown, RST.
  72. 72. Paragraph Lines without any blank line. Group similar lines into a paragraph. Contains sub-paragraph. Use blank line to separate paragraphs.
  73. 73. try:
 html = read_html_from_cache(url)
 except IOError:
 html = request_html(url)
  74. 74. Section Paragraphs. Group similar paragraphs into a section. Avoid sub-section. Use two blank lines to separate sections.
  75. 75. <section A's paragraph 1>
 <section A's paragraph 2>
 <section B's paragraph 1>
  76. 76. Still don't understand?
 Try to read a paragraph, then a section.
  77. 77. The “Lines”
  78. 78. Dependency The F function calls the G function. F depends on G. F → G It's a “Line”.
  79. 79. 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.
  80. 80. At least, easier to trace.
  81. 81. Bad Smell
  82. 82. Reality Don't have time to refactor. They actually work well. Make you itch, but won't beat you. You may already understand.
  83. 83. 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.
  84. 84. Stay focused.
  85. 85. Recap
  86. 86. Recap We read lines randomly. Type hints and other hints Paragraph & section by blank line. Line your functions. Bad smell won't beat you.