ラクス リーダブルコード LT会 - vol.2
2021/07/07🎋 nikkie
みなさん、ふだんどの言語を書いてますか?
インタラクティブにやってみるので、LT中の Zoomチャット大歓迎 です!
Love Python!
Love anime!!(🎺🎷🔥 🌲🌳🐲 📽🎞🎥🎬🧡 🍎🍋🥝🍇🧺)
PyCon JP 2021 座長🇨🇭
可読性の高いコードやリファクタリングについてLTでアウトプットしましょう!
『リーダブルコード――より良いコードを書くためのシンプルで実践的なテクニック』🎼
💬 読んだ方?🙋♂️ 聞いたことはある方?🙋♀️
新卒1年目のとき、会社でおすすめされて読んだ
「他の人が最短時間で理解できるように」(1章)👉 読みやすさ
命名 が特に印象的(他にも早期リターンなど)
もっと「カラフル」な単語を探す(2章)
情報が伝わる
目的に適した明確な名前
気取った言い回しよりも明確で正確なほうがいい。(2章)
実践してきた命名だけではなさそう
『リーダブルコード』には 外側 がある!
気づきの中から、値オブジェクト を共有します
💬 知ってる方?🙋♂️ 聞いたことはある方?🙋♀️
バリューオブジェクトとも
1章「小さくまとめてわかりやすくする」で値オブジェクトを紹介
値を扱うための専用クラスを作る
基本データ型を 属性 として1つか2つ
コンストラクタで値の範囲の検証(完全コンストラクタ)
不変(値オブジェクトを使った計算では、新しい値オブジェクトを返す)
Money
(金額を扱うクラス)
@dataclass(frozen=True)
class Money:
value: int # 基本データ型を属性として1つ
def __init__(self, value: int) -> None:
if value < 0: # 完全コンストラクタ(金額は0円以上)
raise ValueError("不正: 0未満")
object.__setattr__(self, "value", value)
Money
(金額を扱うクラス)続き
def multiply(self, number: int) -> Money:
"""Moneyを整数倍した、新しいMoneyを作って返す(不変)
>>> Money(500).multiply(3)
Money(value=1500)
"""
return Money(self.value * number)
Quantity
(数量を扱うクラス)
@dataclass(frozen=True)
class Quantity:
value: int # 基本データ型の属性
def __init__(self, value: int) -> None:
if value < 0: # 完全コンストラクタ
raise ValueError("不正: 0未満")
object.__setattr__(self, "value", value)
『現場で役立つシステム設計の原則』から読みやすいと思った例
注:Pythonの型ヒントが絡みます
変数や関数の仮引数・返り値の型を表す ラベル (コメントに近い)
実行時に型をチェックするわけでは ない
詳しくは 過去の登壇資料 をどうぞ
引数の順番、分かりづらくないですか?(型ヒントがともに int
。第1引数は金額?個数?)
def amount(unit_price: int, quantity: int) -> int:
"""総額計算"""
return unit_price * quantity
def amount(unit_price: Money, quantity: Quantity) -> Money:
# quantity.as_int()で Quantity型からint型に変換
return unit_price.multiply(quantity.as_int())
読みやすい !
型ヒントを手がかりに、理解にかかる時間が短くなっている印象
値オブジェクトで、どんな値を処理しているか が明確に
例えば、unit_price
が Money
(金額)であることは、命名の工夫ではここまで短くできないのでは?
引数に何をどんな順番で渡せばいいかが明確!(VSCodeでの例)
値オブジェクトによる 不変性
静的型チェック(例: Money
を渡していないと気づける)
副次的に読みやすく
デメリット: 小さいクラスたくさん になるので、実装量は増える
デメリットを軽減する方法を見つけるべく、プライベートで書くスクリプトでやっていき💪
『現場で役立つシステム設計の原則』で値オブジェクトを知った
値オブジェクトと型ヒントで、関数が読みやすくなる!
『リーダブルコード』の外側(設計で読みやすく する)に気づいた
📣 PyCon JP 2021は 7/10(土) までトークのプロポーザル募集中!🙏
関連アウトプット、Appendix、いただいたコメントへの返答が続きます(よろしければどうぞ!)
「object活用ことはじめ 〜dataclassと特殊メソッド〜」というLTをしました
NewType
https://docs.python.org/ja/3/library/typing.html#newtype
静的型検査器は新しい型を元々の型のサブクラスのように扱います。
>>> from typing import NewType
>>> Money = NewType("Money", int)
>>> money = Money(1000)
NewType
値オブジェクトと比較すると、不変でない
>>> Money(1000) + Money(500) # return int
1500
完全コンストラクタも実装されていません
PyDantic 導入?
本文では標準ライブラリの dataclasses モジュールを使った実装を紹介
PyDantic は dataclasses + 実行時の型チェック
たくさんのコメントありがとうございました!
勉強会の盛り上がりを感じました
いろいろな言語が挙がりました(サーバサイド〜フロントエンド)
Python使いの方もちらほら
読んだ方が多め
会社の「おすすめ技術本で殿堂入り」
(ここは飛ばしすぎてコメントする余裕が作れなかったかもしれません)
2本目のしげ丸さんの Primitive Obsession の話にも通じますね
不変オブジェクトは考えることが減って安心して使えて嬉しいです。
ドメインに処理を持たせるの良いですよね!
nikkieはソフトウェアエンジニアリングを極めたい!志向なので恩恵はあると思います
ただPythonを適用する分野によっては使っても恩恵は得られにくいかと思います(例:機械学習)
PythonでDDDの例:https://github.com/iktakahiro/dddpy
動的型付け言語ではありますが、例えば静的型チェッカー mypy
をエディタでファイル保存時に走らせて、実行する前に書き間違えに気づけるようにもできます
nikkieはVSCodeしか使っていない(比較していない)ので、偏った回答になります
他のPython使いにも聞いていただくといろいろな意見が集まって参考にしやすいと思います
💬 「書く量が増えるかわりに読むスピードはあがる」
トータルコストで考える視点はありませんでした。コメントありがとうございます
ちょっと複雑なメソッドの命名で動詞+目的(処理対象)+補語ってする宗派と、動詞+補語+目的ってする宗派があると思うけどみんなどっちが好きなんでしょう?
— IKEDA@ホモ・リディクラス (@masaike1221) July 7, 2021
例えば退職中のユーザーを取得するメソッドをgetUserRetiredとするかgetRetiredUserが好きかみたいな。#readablelt
getよりはfetchでしょうか(まず目が行きました)
語順は後者にすると思います(getRetiredUser
「retired userを取得」と読めるので)
前者だと SVC文型 で、user を retired にするとも読めちゃうかもしれません
状況によっては getUser(status.Retired)
のようなメソッドにするかも