プログラムでやろうとしていることを、 仕様 と言います。仕様が正しいかは、要件通りに動くかどうかで決まります。
実際のプログラムでやっていることが、実装です。
プログラムは思った通りに動かない。書いたとおりに動きます。
プログラムを書く際には 「仕様」 がとても大切です。
特に以下に注目して仕様を理解しましょう。
・どんなデータが存在するのか
・どんなデータを作るべきなのか
・どんな処理が必要なのか
・このようにプログラムの「データと入出力と処理」を常に意識しましょう。
・これは大規模なシステムでも小規模なプログラムでも、何かプログラムを書くときには大切になります。
仕様を元に処理の「まとまり」をイメージしよう
例
①売上生データと商品マスターデータを読み込む
②売上生データの「商品ID」から「商品名」と「商品価格」を取得し、含める
③売上データとして出力する
④必要になりそうな処理の「まとまり」をイメージしてください。
対象の年月の売上生データを読み込む処理の「まとまり」
商品マスターデータを読み込む処理の「まとまり」
商品IDから商品(商品名、商品価格)を取得する処理の「まとまり」
売上データを作成する処理の「まとまり」
売上データを書き出す処理の「まとまり」
これが「設計」に必要なことです。
何かを書き始める前に、役割やまとまり、データに注目してプログラムの構成をイメージすることです。
良いプログラムって?
元のプログラムは、下記のように、プログラマーから見て「ソースコードの品質が低い」と言えます。
①どこで何をしているのか読みにくい == 可読性が低い
②修正がしにくい。1箇所修正すると色々な場所で動かなくなる == 保守性が低い
③過剰にファイルを開いて閉じている
コラム: 同じ処理があれば全て関数にまとめたほうが良い?
いいえ。単純に「同じ処理だから」という理由だけで共通の関数にするのはオススメしません。
今回の場合、処理が共通なだけでなく「CSVファイルの読み込み」という一般的な処理をするため、関数に置き換えています。
このように関数に分離する場合はその「関数の役割」に注目することが大切です。
役割: CSV形式のファイルを読み込む
入力: ファイル f と、カラムの順序 columns
出力: 関数の返り値としてファイル各行を1つの辞書としたリストを返す
このような役割と入出力を明確に説明できる場合は関数に分離すると良いでしょう。
端的に表現できない場合は無理に関数にすると余計に読みにくくなる場合が多いです。
解説
以下のように関数をそれぞれのPythonファイルに移動しました。
item.py: read_items 関数と関連する定数
sales.py: read_sales_raw 、 write_sales 関数と関連する定数
「商品マスターデータ」と「売上」に関数をまとめています。
Pythonファイルに分割する勘所は、意味はそれぞれのPythonファイルに分離したことで main.py の役割も明確になります。main.py の処理は商品マスターデータと売上生データから売上データを作成するプログラムです。
この文中の「商品マスターデータ」という役割は main.py に直接は関係しません。
「商品マスターデータ」という「モノ」として意識しています(中身がCSVだろうが何だろうとも、 main.py からすればどうでも良い話です)。
その商品に関する役割を item.py にまとめることで、 main.py の直接の関心事から分離しています。
このように「モノ」や「役割」、「関心事」に注目して関数や定数を別々のPythonファイルに分離できます。
特に、仕様の中にあるデータや「モノ」に注目すると良いでしょう。
今回は「商品」や「売上」というモノが仕様から読み取れますので、それぞれのPythonファイルに分離しました。
Pythonファイルに分割する機会はいくつかあります。
ビジネス(お仕事)上の「データ」や「モノ」、「役割」ごとにまとめる場合
汎用的な処理をひとまとめにする場合
フレームワークやライブラリーが決めている場合
今回の item.py や sales.py は 1 の観点で分離しています。
Pythonファイルにプログラムを分離する場合は、このようにモノや役割を考えて分離すれば分かりやすくできるでしょう。