Slide 1

Slide 1 text

Boost Maintainability

Slide 2

Slide 2 text

File "api.py", line 101, in generate_response next_page = page + 1 TypeError: must be str, not int

Slide 3

Slide 3 text

page + 1 ?

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

We read lines randomly. ” “

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

page_html + 1 !

Slide 8

Slide 8 text

— Joel on Software Making wrong code look wrong ” “

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

Maintainability

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

Time is just

Slide 13

Slide 13 text

❤ Python & Open Source Mosky • Backend Lead at Pinkoi. • Has spoken at: • PyCons in TW, JP, SG, HK, KR, MY, COSCUPs, and TEDx, etc. • Countless hours on teaching Python. • Own Python packages: • ZIPCodeTW, MoSQL, Clime, etc. • http://mosky.tw/

Slide 14

Slide 14 text

Boost Maintainability • “Maintainability” • Lines need to read back. • Making It Zero • Progressive From Zero

Slide 15

Slide 15 text

Making It Zero

Slide 16

Slide 16 text

The Dominant Rule

Slide 17

Slide 17 text

Be consistent & exact. ” “

Slide 18

Slide 18 text

user = User(user_id) buyer = user_id

Slide 19

Slide 19 text

buyer = User(user_id) buyer_id = user_id ✓

Slide 20

Slide 20 text

result = ... result = ...

Slide 21

Slide 21 text

resp = ... parsed_dict = ... ✓

Slide 22

Slide 22 text

Get a dictionary, please.

Slide 23

Slide 23 text

Ops Clues

Slide 24

Slide 24 text

page = ... △

Slide 25

Slide 25 text

page_no = ... page_html = ... ✓

Slide 26

Slide 26 text

requested_fields & allowed_fields ?

Slide 27

Slide 27 text

set(requested_fields) & allowed_field_set ✓

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

resp = requests.get(...)

Slide 31

Slide 31 text

resp.text resp.json ?

Slide 32

Slide 32 text

resp.text resp.json() !

Slide 33

Slide 33 text

resp.text resp.parse_as_json() ✓

Slide 34

Slide 34 text

Req.is_secure()

Slide 35

Slide 35 text

is_secure = True

Slide 36

Slide 36 text

with_tls = True req_is_secure = True ✓

Slide 37

Slide 37 text

to_use_tls = True secure = True ✓

Slide 38

Slide 38 text

The General Rules Ops Clues • Clue the ops you should use. • _no: numeric. • : sequence, usually is mutable sequence (list). • _: if no intuitive way. • _: • _seq: for sequence. • _gen: for generator. • More: collections.abc – Python Docs.

Slide 39

Slide 39 text

For Callable Ops Clues • _ = imperative sentence. • → boolean. • to_ → thing. • from_ ← thing.

Slide 40

Slide 40 text

For Boolean Ops Clues • The normal objects took the nouns. • The callables took _ and . • We have: • _ • • to__ •

Slide 41

Slide 41 text

For Return Value Ops Clues • Clue the return value: • get_page_no → numeric which >= 1. • query_user → user object. • parse_to_tree → tree object.

Slide 42

Slide 42 text

Avoid None and Null Ops Clues • 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.

Slide 43

Slide 43 text

tmpl = '

{}

' tmpl.format(name)

Slide 44

Slide 44 text

name = '...' !

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

arg = parse(arg) ?

Slide 47

Slide 47 text

arg_dict = parse(arg_json) ✓

Slide 48

Slide 48 text

str/x Ops Clues • _key: str/key (of a dict). • 'lowercase_n_underscore' • _json: str/json. • JSON is a string, not dict. • _url: str/url. • Clue percent-encoding; avoid URL injection. • _html: str/html. • Avoid XSS. • _sql: str/sql. • Avoid SQL injection.

Slide 49

Slide 49 text

numeric/x Ops Clues • _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.

Slide 50

Slide 50 text

Structure Clues

Slide 51

Slide 51 text

users ?

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

uid_email_dict ✓

Slide 55

Slide 55 text

uid_email_pairs = ... uid_email_dict = dict(↖) ✓

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

For Dict & Tuple Structure Clues • __dict • For tuples: • _pair: 2-tuple. • _pairs: 2-tuples. • <1st>_<2nd>_<3rd>_tuple: n-tuple.

Slide 58

Slide 58 text

Others

Slide 59

Slide 59 text

“Don't use me!” • _ • Don't use when out of: • A module. • A class. • Don't guarantee the behavior. • Make it easier to trace and refactor. Private Clues

Slide 60

Slide 60 text

“Should I cache it?” Performance Clues • get_ / set_: memory op. • parse_ / calc_ : CPU-bound op. • query_: IO-bound op. • query_or_get_: IO-bound op with cache.

Slide 61

Slide 61 text

Progressive From Zero

Slide 62

Slide 62 text

Paragraph & Section

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

# check arguments ... ... # query from tables ... ... ... ... # transform ...

Slide 65

Slide 65 text

With Blank Line and Comment Paragraph & Section • Like writing in Markdown. • Paragraph: • A paragraph contains no blank line. • A blank line separates paragraphs. • Section: • A section contains paragraphs. • A comment with blank line separates sections.

Slide 66

Slide 66 text

Line Units Up

Slide 67

Slide 67 text

Func A Func U Func B Line No

Slide 68

Slide 68 text

Func A Func U Func B Line No

Slide 69

Slide 69 text

Func A Func U Func B Line No

Slide 70

Slide 70 text

Func A Func U Func B Module 1 Module 2

Slide 71

Slide 71 text

By Calls Line Functions Up • Measure the “orderliness”. • Keep them have the same direction. • May become module. • Try to line the classes and modules up by the imports?

Slide 72

Slide 72 text

Face Bad Smell

Slide 73

Slide 73 text

Don't get lost! Face Bad Smell • Comment: • For the pitfalls, the actual return type, the side effects, etc. • Use # FIXME: ... or # XXX: ... . • Seal it: • good = poor() • def good(): poor() • Stay focused!

Slide 74

Slide 74 text

Use clues to boost maintainability!

Slide 75

Slide 75 text

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!