Rookieに良くする話

tell-k
BPStudy #150 (2020.02.28)

おまえ誰よ?

https://pbs.twimg.com/profile_images/1045138776224231425/3GD8eWeG_200x200.jpg

目的/動機

自走プログラマー

https://images-na.ssl-images-amazon.com/images/I/410FSLNj5lL._SX396_BO1,204,203,200_.jpg

対象者

Rookiesとは?

経験が浅い人とは?

Rookiesとは?

早く成長するためには?

_images/good_elements.png

最良にフォーカス

_images/sairyo.png

学習することを絞る

_images/gakusyu.png

1人前を目指す

どんな感じのことやるの?

Python Professional Programing

https://images-fe.ssl-images-amazon.com/images/I/419ZPrd-cVL.jpg

課題のリポジトリ

こんな感じのリポジトリを cloneするところからスタート

_images/python_challenge.png

課題はどんなの?

_images/pychallenge001.png

レビューで良く指摘されるポイント

ガード節/早期リターン

ガード節/早期リターン

# Bad ---

def something_func(reply, user_result, permission_result):

    if user_result == STATUS_SUCCESS:
        if permission_result != STATUS_SUCCESS:
            reply.write_errors("error reading permissions")
            reply.done()
            return
        reply.write_errors("")
    else:
        reply.write_errors(user_result)

    reply.done()

ガード節/早期リターン

# Bad ---

def something_func(reply, user_result, permission_result):

    if user_result != STATUS_SUCCESS:
        reply.write_errors(user_result)
        reply.done()
        return # <- 必要なくなったら処理を抜ける

    if permission_result != STATUS_SUCCESS:
        reply.write_errors("error reading permissions")
        reply.done()
        return

    # ここからが正常な処理
    reply.write_errors("")
    reply.done()

処理効率の悪い探索

for bank_id, amount in aggregates.items():

    # Bad ---
    bank_name = ""
    for bank in banks:
        if bank_id  == bank.id:
            bank_name = bank.name

    print(f"{bank_name} への振込金額は {amount}円です")

処理効率の悪い探索

# 予めた探索しやすいようなデータを作っておく
bank_dict = {b.id: b for b in banks}

for bank_id, amount in aggregates.items():

      # Good
      bank_name = bank_dict[bank_id].name
      print(f"{bank_name} への振込金額は {amount}円です")

処理効率の悪い探索

for bank in banks:
    if bank_id == bank.id:
        bank_name = bank.name
        break  # <- ここで breakすればループはそこで止まる

境界値の扱い

# Bad  ---
from datetime import datetime

target = datetime(2020, 1, 2, 23, 59, 59, 1) # 2020/01/02 ではあるが絞り込みからは漏れてしまう

start = datetime(2020, 1, 1)
end = datetime(2020, 1, 2, 23, 59, 59)

print(start <= target <= end) # => False
# Good  ---
start = datetime(2020, 1, 1)
end = datetime(2020, 1, 3)  # 確実に漏れが発生しない条件を指定する

print(start <= target < end) # => True

lint と code formatter

変数の命名規則

_single_leading_underscore ... 先頭にアンダースコア。
                               クラスやモジュールの内部だけで使うことを意味する

single_trailing_underscore_ ... 末尾にアンダースコア。
                                Pythonのキーワードと被る時に利用する

// PEP8 には書いてないが多値を返すような関数の場合
// 使わない値は "アンダースコアのみ" の変数に格納したりします。

for var, _ in get_hoge_list():
    # ... varしかつかない処理

標準のライブラリや良く見る処理の実装

# Bad ---

summary = {}
for name, amount in products.items():
    category = get_category_by_name(name)

    # いきなり金額を加算代入できないので、最初はキーを初期化する
    if name not in summary:
       summary[category] = amount
    else:
       summary[category] += amount

標準のライブラリや良く見る処理の実装

# Good ---

from collections import defaultdict

summary = defaultdict(int)
for name, amount in products.items():
    category = get_category_by_name(name)

    # 存在しないキーの場合は int(=0)で初期化される
    summary[category] += amount

その他

レビュー観点

レビュー観点

レビューする/される時に意識してもらいたこと

対応のレベルのイメージ

MUST

SHOULD

MAY

以下のURLも参考になります。

参考: コードレビューの基本

まとめ

謝辞

ご静聴ありがとうありがとうございました

Use the left and right arrow keys or click the left and right edges of the page to navigate between slides.
(Press 'H' or navigate to hide this message.)