80
Boost Maintainability

Boost Maintainability

Embed Size (px)

Citation preview

Page 1: Boost Maintainability

Boost Maintainability

Page 2: Boost Maintainability

File "api.py", line 101, in generate_response page + next_page TypeError: Can't convert 'int' object to str implicitly

Page 3: Boost Maintainability

page +

next_page

?

Page 4: Boost Maintainability

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

!

Page 5: Boost Maintainability

We read lines randomly.

Page 6: Boost Maintainability

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

Page 7: Boost Maintainability

page_html +

next_page_no

!

Page 8: Boost Maintainability

— Joel on Software

Making wrong code look wrong

Page 9: Boost Maintainability

—Joel on Sof tware

Making Wrong Code Look Wrong

• “Making Wrong Code Look Wrong”

• http://bit.ly/joel-wrong

• 「讓錯的程式看得出錯」

• http://bit.ly/joel-wrong-cht

• This talk will be more systemic than it.

• but exception is good, IMO.

Page 10: Boost Maintainability

Maintainability

Page 11: Boost Maintainability

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

Page 12: Boost Maintainability

💰💰💰Time is just

Page 13: Boost Maintainability

❤ Python & open source

Mosky

• Python Charmer at Pinkoi

• has spoken at

• PyCons in TW, KR, JP, SG, HK

• COSCUPs & TEDx, etc.

• countless hr on teaching Python

• has serval Python packages

• ZIPCodeTW, MoSQL, Clime, etc.

• http://mosky.tw/

Page 14: Boost Maintainability

Android & Backend Engineers

We're looking for

Page 15: Boost Maintainability

Boost Maintainability

• Define our “Maintainability”

• lines need to read back

• Making It Zero

• Progressive From Zero

Page 16: Boost Maintainability

Making It Zero

Page 17: Boost Maintainability

A Dominant Rule

Page 18: Boost Maintainability

Be exact & consistent.

Page 19: Boost Maintainability

result = ... result = ...

𝖷

Page 20: Boost Maintainability

resp = ... parsed_dict = ...

Page 21: Boost Maintainability

user = User(user_id) buyer = user_id

𝖷

Page 22: Boost Maintainability

buyer = User(user_id) buyer_id = user_id

Page 23: Boost Maintainability

Get a dictionary, please.

Page 24: Boost Maintainability

Ops Hint

Page 25: Boost Maintainability

page = ...

Page 26: Boost Maintainability

page_no = ... page_html = ...

Page 27: Boost Maintainability

requested_fields &

allowed_fields

?

Page 28: Boost Maintainability

set(requested_fields) &

allowed_field_set

Page 29: Boost Maintainability

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

?

Page 30: Boost Maintainability

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

Page 31: Boost Maintainability

resp = requests.get(...)

Page 32: Boost Maintainability

resp.text resp.json

?

Page 33: Boost Maintainability

resp.text resp.json()

!

Page 34: Boost Maintainability

resp.text resp.parse_as_json()

Page 35: Boost Maintainability

Req.is_secure()

Page 36: Boost Maintainability

is_secure = True

𝖷

Page 37: Boost Maintainability

secure = True with_tls = True

Page 38: Boost Maintainability

req_is_secure = True to_use_tls = True

Page 39: Boost Maintainability

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

Page 40: Boost Maintainability

for Callable

Ops Hint

• <verb>_, = imperative sentence

• <yes-no question> → boolean

• to_<thing> → thing

Page 41: Boost Maintainability

for Boolean

Ops Hint

• Normal objects take <noun>

• Callables take <verb>_ and <yes-no question>

• so use

• <adj>

• <prep>_

• <simple sentence>

• <to-infinitive>

Page 42: Boost Maintainability

for Return Value

Ops Hint

• Use on the return value,

• get_page_no → numeric >= 1

• query_user → user object

• parse_to_tree → tree object

Page 43: Boost Maintainability

Explici t 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.

Page 44: Boost Maintainability

So, 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.

Page 45: Boost Maintainability

tmpl = '<p>{}</p>' tmpl.format(name)

Page 46: Boost Maintainability

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

!

Page 47: Boost Maintainability

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

Page 48: Boost Maintainability

arg = parse(arg)

?

Page 49: Boost Maintainability

arg_d = parse(arg_json)

Page 50: Boost Maintainability

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

Page 51: Boost Maintainability

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

Page 52: Boost Maintainability

Structure Hint

Page 53: Boost Maintainability

users

?

Page 54: Boost Maintainability

users = { 'mosky': '[email protected]', ... }

Page 55: Boost Maintainability

uid_email_map = { 'mosky': '[email protected]', ... }

Page 56: Boost Maintainability

uid_email_map

Page 57: Boost Maintainability

uid_email_pairs = ... uid_email_map = dict(↖)

Page 58: Boost Maintainability

# select uid, email

for uid, email in uid_email_pairs: ...

Page 59: Boost Maintainability

for dict & tuple

Structure Hint

• <key>_<value>_map

• tuple

• _pair: 2-tuple

• _pairs: 2-tuples

• <1st>_<2nd>_<3rd>_tuple: n-tuple

Page 60: Boost Maintainability

Others

Page 61: Boost Maintainability

“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

Page 62: Boost Maintainability

“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

Page 63: Boost Maintainability

Progressive From Zero

Page 64: Boost Maintainability

Too long? Use proper abbreviation.

Page 65: Boost Maintainability

Define in Comment

Page 66: Boost Maintainability

receiver_address_dict

Page 67: Boost Maintainability

# rad: receiver addr dict rad = ...

Page 68: Boost Maintainability

Paragraph & Section

Page 69: Boost Maintainability

def request_or_get(url):

if has_cache(url): return get_cache(url)

content = request(url) set_cache(url, content)

return content

Page 70: Boost Maintainability

# Check Arguments

...

...

# Query from Tables

...

...

...

...

# Transform

...

Page 71: Boost Maintainability

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.

• is a semi-function.

Page 72: Boost Maintainability

Line Functions Up

Page 73: Boost Maintainability

Func A

Func U

Func B

Line No

Page 74: Boost Maintainability

Func A

Func U

Func B

Line No

Page 75: Boost Maintainability

Func A

Func U

Func B

Line No

Page 76: Boost Maintainability

Func A

Func U

Func B

Module 1

Module 2

Page 77: Boost Maintainability

by Calls

Line Functions Up

• Measure the “disorderedness”.

• In a file,

• keep the lines has same direction

• layer functions, and may → modules

• In a project,

• apply it to modules

Page 78: Boost Maintainability

Face Bad Smell

Page 79: Boost Maintainability

Don't lost!

Face Bad Smell

• Comment

• pitfalls: the actual return type, side effects

• # TODO:

• Seal it with better name or stabler wrapper

• good = poor()

• def good(): poor()

• Stay focused!

Page 80: Boost Maintainability

Use hints to boost maintainability!

🚀