ここ最近、開発系の業務に従事しているのでソフトウェア開発におけるノウハウを習得したく良い本がにないか模索していたところ下記の書籍がよいと推奨された。
まだ読んでいる途中だが、今回はこの書籍で最も伝えたいと思われる「関心の分離」について書いていく。今回は関心の分離とネームスペースについて書いていくがどちらもプログラムの保守性を向上するための概念となる。データサイエンティストもプログラムを書くことが多いため身に着けておいて損はないと思う。
関心の分離とは
関心の分離とは、ソフトウェア工学においては、プログラムを関心(責任・何をしたいのか)毎に分離された構成要素で構築することである(Wikipediaより引用)。ここでいう関心とは「プログラムそのものの目的」を指しており、プログラムや関数・クラスを作成する際に依存関係を疎にすること・処理内容に統一性をもたせようねという考え方となる。
関心の分離によるメリット
関心の分離を実施することで下記3点の利点を得ることができる。
- 理解しやすくなる:コードの処理内容が明確になり、プログラムを素早く理解できる。
- 変更:関心ごとに変更が限定されるため、変更や拡張が容易になる。
- 再利用:処理ごとに独立しているため、他のプログラムで再利用しやすくなる。
例として下記のサンプルコードを見てみる。
def main():
data = input()
# データの入出力
result = calculate(data)
# 処理
print(result)
# 出力
def calculate(data):
return int(data) * 2
データの入出力、処理、出力という3つの関心が1つの関数に混在していてコードを理解したり変更したりするのが難しくなる。上記は高々数行程度なのでさっと理解できるがこれが三桁、複数ファイルになると全体像の把握がに難しくなる。
def main():
data = input() # データの入出力
result = calculate(data) # 処理
print(result)
# 出力
def calculate(data):
return int(data) * 2
def input_data():
return input()
def output_result(result):
print(result)
main()
関数からcalculate()
関数の呼び出しを削除し、calculate()
関数の戻り値を直接使用するように変更。calculate()
関数を、データの入出力と計算を分離した2つの関数に分割。input_data()
関数でデータの入出力を実施。output_result()
関数で出力。
修正後のコードでは、データの入出力、処理、出力の3つの関心がそれぞれ独立した関数に分離されています。そのため、コードを理解したり変更したりするのがしやすくなりました。また、変更や拡張がしやすくなりました。例えば、データの入出力方法を変更する場合、input_data()
関数を変更するだけで済みます。あくまでサンプルなので関数化しなくてもよいのでは?と思うかもしれないが、複数人開発ではコードの可読性および変更を容易にすることは非常に重要なので関数名からどの処理を担っているのか判別しやすくなっている。
ネームスペース
名前空間とは、各要素に一意の異なる名前をつけなければ識別できない範囲のことであり、Pythonで使うすべての名前が何らかのネームスペースに所属している。一番わかりやすい機能だとimportが該当する
ネームスペースによるメリット
- コード作成が進んでいると複数の概念に類似あるいは同一の名前を付ける必要が生じるが、ネームスペースを活用することでこのような場合に「衝突」を回避できる
- コード量に比例して全体像の把握が困難になるためネームスペースを分離することで「どこに」「どのような」コードがあるか・ないかが明確になる。
- 新しいコードを追加する際に既存のネームスペースが新しいコードをどこに入れたらよいか、わかりやすくなる。
おわりに
jupyterを用いた開発だとセルごとに実行して結果を得ることできるので、自由度が高い代わりに後々に見返してみると再現性が担保できなかったりバリデーションチェック用のコードが残ったままとなっていてコードを素早く理解することが難しくなってしまう。処理したい内容は何か?常に意識してコードを書くことが大切であると感じた。最も重要なことは関心の分離には絶対の正解はなく「類似の処理をまとめ,類似していないものはわける」ことが大目的となる。細かな点の議論に執着してしまわずにこの目的が達しているか否かという観点で見ていきたい。
コメント