$30 off During Our Annual Pro Sale. View Details »

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
Tweet

More Decks by Mosky Liu

Other Decks in Programming

Transcript

  1. Beyond 

    the Style Guides
    Mosky

    View Slide

  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

    View Slide

  3. - Benjamin Franklin
    “Time is money.”

    View Slide

  4. How to write faster?
    Good language, e.g., Python
    Powerful libraries
    Experience
    ∈ The things you can't change immediately.

    View Slide

  5. Understandable codebase.

    i.e., codebase which has high maintainability.
    ∈ You can just learn from this share.

    View Slide

  6. Style Guide?
    # It looks okay!

    count += 1

    View Slide

  7. Not enough
    # But it was initialized as

    count = '1'
    # In JavaScript, 

    # there's even no an error.

    View Slide

  8. You remain only 10k days in your life.

    View Slide

  9. Spend time on writing exciting feature,

    not debugging.

    View Slide

  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

    View Slide

  11. View Slide

  12. View Slide

  13. Pinkoi

    㫎窓磧य़戔懯珶ߝ搳ᇔ翕ᒊ

    View Slide

  14. Pinkoi

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

    View Slide

  15. View Slide

  16. View Slide

  17. Thanks!

    View Slide

  18. Human Brain

    View Slide

  19. A Computer
    Read the code line by line.
    Cover all of the code, usually.
    Just complain when it doesn't understand.

    View Slide

  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.

    View Slide

  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.

    View Slide

  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.

    View Slide

  23. We read lines randomly.

    View Slide

  24. Maintainability
    To understand a random line, 

    how many lines do you need to read back?
    Lesser → Higher maintainability

    View Slide

  25. Name

    View Slide

  26. Nothing But
    Have a good dictionary.
    Be exact to avoid ambiguity.
    Be consistent to avoid misleading.
    Hint, hint, and hint.

    View Slide

  27. Be Exact
    “Apple”
    Which “Apple”?
    “Apple, the company.”
    apple_the_company

    View Slide

  28. date_a-date_b
    Which dates?
    today-joined_date

    View Slide

  29. user
    User’s what?
    user_name
    user_email

    View Slide

  30. name
    Who’s name?
    user_name
    store_name

    View Slide

  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')

    View Slide

  32. Too Long?
    The context helps.
    fruit.py
    apple

    View Slide

  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

    View Slide

  34. Make It Intuitive
    count
    should be numeric
    name
    string thing
    names
    many strings; may be a list

    View Slide

  35. page
    page_no
    so should be numeric
    event
    event_key
    so should be string stuff

    View Slide

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

    View Slide

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

    View Slide

  38. Object or Dict?
    user
    What is the type of user?
    user['name'] # ?
    user.name # ?
    user_dict['name']
    user_d['name']

    View Slide

  39. Is it a bool?
    new_user
    A bool? A User instance?
    is_new_user
    A bool? A Function?
    new
    user_is_new

    View Slide

  40. Is it a function?
    Use imperative, i.e., start with a verb.

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  44. 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.

    View Slide

  45. Some tips
    Raise exception.
    Use zero and infinite.
    Use constant.
    Filter the Nones out before return.

    View Slide

  46. Content Type
    User Input
    The “Keys”
    URL
    JSON
    HTML
    SQL
    ∈ string thing

    View Slide

  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.

    View Slide

  48. template.format(name)
    If
    template # -> "{}"
    name # -> ""
    !

    View Slide

  49. template_html.format(escape(name))
    Safe :)
    “Making Wrong Code Look Wrong “

    View Slide

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

    View Slide

  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.)

    View Slide

  52. Map
    users
    A dict? What are the key and the value?

    View Slide

  53. uid_user_map

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

    View Slide

  54. # ok

    users = {

    'mosky': User('mosky'),

    …

    }
    # even better

    uid_user_map = {

    'mosky': User('mosky'),

    …

    }

    View Slide

  55. Tuple
    uid, name = uid_name_pair
    a, b, c = a_b_c_tuple

    View Slide

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


    key_value_map = dict(key_value_pairs)

    View Slide

  57. Composite
    If apply structure hint and type hint,
    It will be long.
    You may shorten.
    Keep long description in comment or doc.

    View Slide

  58. Use common abbreviation
    http://abbreviations.com/
    Use acronym, e.g., rlname for really_long_name.
    Do comment if you use them.

    View Slide

  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': {…}

    }

    View Slide

  60. # focus on reducing length

    #

    # ekey: event key

    # config: config dict

    #

    # - start_date: …

    # …

    #

    ekey_config_map = {

    'monthers_day': {…}

    }

    View Slide

  61. adj. new_user
    past participle joined_date
    present participle working_queue
    infinitive keys_to_remove
    another noun template_args

    View Slide

  62. int
    n, m

    i, j, k

    twd_int
    int/range
    page_no

    birth_month

    birth_day
    tids_idx
    bool
    new, joined

    user_is_new

    new_or_not

    new_bool

    View Slide

  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

    View Slide

  64. dict user_d, user_dict
    list uids, uid_list
    set uid_set
    mapping uid_user_map
    generator uid_gen

    View Slide

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

    total_twd

    View Slide

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

    View Slide

  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.)

    View Slide

  68. .parse
    What we will get?
    .parse_to_tree

    View Slide

  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.

    View Slide

  70. Performance Hint
    get_name # Memory op.
    parse_from_json # CPU op.
    query_html

    request_html # IO op.
    Let reader know the roughy cost.

    View Slide

  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.

    View Slide

  72. Hints
    Type Hint
    Structure Hint
    Return Type Hint
    Performance Hint
    Private Hint

    View Slide

  73. A random line now is more understandable.

    View Slide

  74. Blank Line

    View Slide

  75. Blank Line
    Use blank line to separate your code into:
    Paragraph
    Section
    Like lightweight markup language,

    e.g., Markdown, RST.

    View Slide

  76. Paragraph
    Lines without any blank line.
    Group similar lines into a paragraph.
    Contains sub-paragraph.
    Use blank line to separate paragraphs.

    View Slide

  77. try:

    html = read_html_from_cache(url)

    except IOError:

    html = request_html(url)

    View Slide

  78. Section
    Paragraphs.
    Group similar paragraphs into a section.
    Avoid sub-section.
    Use two blank lines to separate sections.

    View Slide









  79. View Slide

  80. Still don't understand?

    Try to read a paragraph, then a section.

    View Slide

  81. The “Lines”

    View Slide

  82. Dependency
    The F function calls the G function.
    F depends on G.
    F → G
    It's a “Line”.

    View Slide

  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.

    View Slide

  84. At least, easier to trace.

    View Slide

  85. Bad Smell

    View Slide

  86. Reality
    Don't have time to refactor.
    They actually work well.
    Make you itch, but won't beat you.
    You may already understand.

    View Slide

  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.

    View Slide

  88. Stay focused.

    View Slide

  89. Recap

    View Slide

  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

    View Slide