3章 コードの品質管理
この章では、
- Notebookの利点と欠点
- コード品質とは何か
- コードを書く上で重要なこと
を説明します。
3.1. Notebookだけのデータサイエンティストからの卒業
Notebookの限界とPython Scriptへの入門
Jupyter NotebookをはじめとするNotebookはデータサイエンスの界隈では手軽でよく使われる開発環境であるが、ビジネスへの貢献が求められるにつれて、Notebookの限界が明らかになってきた。
具体的には以下のような課題がある。
- 実験的なコードと完全版コードの混在
- 構造化の難しさとコードの複雑化
- チーム開発やGit管理の難しさ
これらを解消するため、Python Scriptを用いていくのが良いだろう。「試行錯誤」の面ではNotebookが勝るが、「再現性」「コラボレーション」「構造化」の面ではPython Scriptに軍配が上がる。
Python Scriptを使いこなすためには次のようなポイントが重要になる。
- リファクタリングを行う
- デバッグ
- テストコードの作成
つまり、Notebookではコードを書き捨てにしがちだが、Python Scriptではコードの品質を意識する必要がある。
3.2. コード品質とは
コード品質の重要性
初学者や期限が短い場合は動けば良いコードを作成しがちになりやすい。
その結果、バグが多く含まれ、開発の効率が下がり、価値を提供することが難しくなる。そのため、コードが明確で検証しやすいことが重要になる。
また、他の人が読んだり修正したりする場合があるため、コードが理解しやすく、変更しやすいことも重要である。
コードの品質の高さとは
本書ではコード品質は主に可読性に重点を置きつつ、実際には以下の3つの要素を意識することを推奨している。
- 正確であること(Correct): 変数名や関数名、コメントの表現が正確
- 明確であること(Clear):コードの意図が伝わりやすい
- 簡潔であること(Concise):必要以上に複雑でなく簡潔である
エンジニアとデータサイエンティストで求められるコード品質には違いがある。
品質の高いコードとその実現方法
関数
関数の役割を大きく3つに分けて考える
- 再利用性
- 一度実装すれば他の場所でも再利用出来るため保守性が向上する
- 処理の名前づけと詳細の隠蔽
- 何を実行するのかが明確になり、認知負荷を減らせる
- テスタビリティ
- 入出力が明確なため、テストが容易になる
ベストプラクティスとして、下記の観点を意識する
- 参照透過性
- 同じ入力に対し、同じ出力を常に返す
- 副作用の排除
- 関数の外の状態を変更しない設計
- 関数の大きさ
- 簡潔に表現でき、入出力と関数名が自然に対応している
クラス
クラスは便利だが、単一のクラスに異なる機能や処理を詰め込みがち。
ベストプラクティスとして、下記の観点を意識する。
- カプセル化
- 関連するデータやロジックを1つのコンポーネントとしてまとめる
- 継承
- 親クラスの機能を受け継いだ子クラスを作る
- ポリモーフィズム
- 異なるクラスに対して、同じ名前のメソッドを実装する
命名
一般的に不適切なものとしては下記のようなものがある。
- 連番での命名
- 意味のない命名
- ローマ字の使用
- 一般的でない略語の使用
プログラミング言語ごとに定められている命名規則を参考にすると良い
| 種類 | 記法 | 例 |
|---|---|---|
| モジュール | snake_case | my_module.py |
| クラス | CamelCase | MyClass |
| 関数/メソッド | snake_case | my_function |
| 変数/インスタンス変数 | snake_case | my_variable |
| 定数 | UPPER_CASE | MY_CONSTANT |
また、型を明示するのも読み手に伝わりやすい命名規則である。
- Bool型:
is_,has_,can_,_exists - リスト型:
list_ - 辞書型:
<key>_map_<value>,dict_<key>_<value>
コメント
書かなくて良い情報
- コードと重複する内容
- 変数の説明
- 行っている処理
書くべき情報
- 実装の背景
- コードを見るだけではわからない情報
関数やクラスを使う場合はdocstringなども有効活用できる。
また、コメント記法として、特定のプレフィックス(ex: TODO, FIXME, HACK, NOTE)を使うことも有効である。
コーディング規約
PythonにはPEP8というコーディング規約が存在する。コードの一貫性を保つためにはこのような規約に従うことは読み易くするためには重要。
全ての規約を覚えるのは困難であるため、リンターとフォーマッターを活用するのが良い。
flask8
pylint
black
isort
ruff
型ヒント
変数や関数の引数や戻り値に対して型を注釈で追加できる仕組み。
typingモジュールを利用することで、戻り値の特殊ケースに対応することが可能。
def split_data(
data: list[float], size: float
) -> tuple[list[float], list[float]]:
split_index = int(len(data) * size)
return data[:split_index], data[split_index:]
テスト
テストコードは「バグの早期発見」「設計の振り返り機会」の役割を果たす。pythonでテストを行うためにはpytest使うことが一般的。
コードレビューによる品質管理
コードレビューの目的
コードレビューとは、プロジェクトで求める品質を担保するために作成したコードを作成者以外も確認し評価するプロセス。一般的にはGithubやGitLabなどのサービス上で行われる。
コードレビューをすることは下記の利点がある。
- 品質を担保できる
- 変更内容と意図を、他人や未来の自分に伝えることができる
- 個人の作業効率も上がる
レビュイー/レビュアーの心得
レビューを受ける側を「レビュイー」、レビューをする側を「レビュアー」という。
各役割において、それぞれ心掛けるべき点が存在する。
- レビュイー
- 自分のコードには自分が責任を持つ
- コードレビューに頼りすぎない
- コミットは小さく分ける
- 変更内容と理由を明確にする
- プレフィックスをつける
- 一目でわかるコミットメッセージ
- プルリクエストの粒度を意識する
- 役割は1つ
- レビュアーへの要望を明確にする
- 誰に、何を、どのように見て欲しいのか
- 作業途中のうちからプルリクエストを出す
- 作業の透明性を高める
- 自分のコードには自分が責任を持つ
- レビュアー
- コメントのプレフィックスに意図をかく
- 改善サイクルを促進する
- ポジティブなフィードバックもする
- レビューは賞賛の場でもある
- お互いにレビューをする
- 気づきや学びの場でもある
- レビュー以外の選択肢も持つ
- 輪読会やペアプロも有効
- コメントのプレフィックスに意図をかく
感想
私は個人で分析する機会が多いため、自分視点で綺麗なコードを書くことを意識してるものの、チームとして品質管理を意識をすることがあまりない。が、異動や転職が増えるにつれて引き継ぎされたコードを拝見する機会も増えたため、本章ではその重要性を再確認することができた。(私のみが意識しても意味がないため、レビューの文化や知見を共有する課題はのこるが...)
全体的に業務をしながらだと、本章の内容は短期的には効果が見えず、疎かになりがちである。分析のコードも1つの資産であり、積み上げることによってより、大きな利益をもたらすという意識が大事なのではないかと感じた。