第136回 実務で使えるPython基礎:関数設計とモジュール化で作る再利用可能でテストしやすいデータ処理コンポーネント

はじめに — つまずきに寄り添って

現場で「とりあえず動く」スクリプトを書いた経験は多いはずです。しかし時間が経つと、同じ処理が別の場所でコピペされ、テストがなく、変更がこわくなります。本記事では第135回(CSVクリーニング)から自然につながる実践的な手順で、そうした“一発スクリプト”を再利用可能でテストしやすいコンポーネントに変える方法を示します。

設計原則(短く実務視点で)

単一責務(Single Responsibility)

関数は一つの目的だけを持ちます。読み込み・変換・書き出しは別々にし、組み合わせは上位の関数で行います。

純粋関数と副作用の分離

データ変換は入力を受け取り出力を返す純粋関数にし、ファイルやログなどの副作用は別モジュールにまとめます。こうするとユニットテストが容易になります。

依存注入

外部リソース(ファイルパス、DB接続、設定)は引数で渡すか、IOアダプターを介して渡します。テスト時はモックやスタブに差し替えます。

パターン実例:CSVクリーナーのリファクタ(before / after)

まず典型的な一発スクリプト(before)です。

実装メモ: コード例は環境に合わせて調整してください。例: # before: csv_cleaner.py

問題点:読み込み・変換・書き出しが混在。テストが難しい。

リファクタ後は3つの責務に分けます:pure functions(transform)、io_adapter(読み書きラップ)、cli(エントリポイント)。

実装メモ: コード例は環境に合わせて調整してください。例: # package layout (例)

この構成の利点:transformは純粋関数なのでユニットテストが容易。io_adapterをモックすれば統合テストもしやすい。

ディレクトリとパッケージ構成(推奨)

小規模プロジェクトの最低限の構成例:

実装メモ: コード例は環境に合わせて調整してください。例: mycsv/

__init__.pyで外部に公開する関数を明記し、内部実装は隠すと保守性が高まります。

テスト設計:pytestでの例

pure functionは通常のユニットテスト、IOはtmp_pathやモックで扱います。例:

実装メモ: コード例は環境に合わせて調整してください。例: # tests/test_transform.py

実行コマンド例:

  • pip install -e .[dev]
  • pytest -q

CIと品質ゲート(最低ライン)

テスト・型チェック・lintを最低限組み込みます。簡単なGitHub Actionsジョブ例:

実装メモ: コード例は環境に合わせて調整してください。例: # .github/workflows/ci.yml

pyproject.toml の最低例:

実装メモ: コード例は環境に合わせて調整してください。例: [project]

実務的チェックリスト

チェック項目 説明 判定基準
関数の責務は明確か 一つの関数が複数のことをしていないかを確認 変換はpure、I/Oは別モジュール
グローバル状態はないか モジュールレベルの可変変数が無いか 無ければOK
I/Oは分離されているか ファイルやDBアクセスが専用アダプターにあるか モック可能であればOK
テストカバレッジの最低ライン 重要な変換ロジックに対するユニットテストの有無 変換ロジックは100%を目指す(現実的最低は80%)
後方互換性の扱い API変更時の互換性維持方針があるか 破壊的変更はバージョニングで管理

段階的リファクタ計画と落とし穴

段階的に置き換える手順:

  • 1) transformをpure関数として切り出し、既存スクリプトから呼び出せるようにする
  • 2) io_adapterを作成して既存I/Oを置換する(動作確認は並列運用で)
  • 3) testsを追加、CIで確認してからマージ

注意点:

  • 過度な抽象化は避け、複雑化してしまう場合はスコープを縮小する
  • 既存運用中のスクリプトはブランチ戦略で段階的に切り替える(トグル可能にする)
  • 大規模CSVはメモリに全ロードせずチャンク処理を使う。transformは行単位に保つと組み合わせやすい

まとめと次の実践課題

本稿のポイントは次の通りです。

  • 関数は単一責務にし、変換ロジックは純粋関数にする
  • 副作用(I/O)は別モジュールにまとめ、依存注入やモックでテストしやすくする
  • パッケージ構成と最低限のテスト・CIを整えることで運用コストを下げる

手を動かす練習(3ステップ)

  1. リポジトリを作り、上記構成で最小限のファイルを作る(cli.py, transform.py, io_adapter.py)。
  2. transformのユニットテストを書いてpytestで実行する(pytest -q)。
  3. 簡単なGitHub Actionsワークフローを追加してPushでテストが回ることを確認する。

次回はこの基盤を使って、AIを組み合わせた自動データ正規化パイプラインに進みます。小さく始めて、確実に保守できる形にすることを優先してください。