グローバル状態管理:レビューで排除すべき共有変数の構造
はじめに
Pythonはモジュールスコープにおけるglobal変数の使用が許容される言語仕様を持ち、少人数のスクリプトでは気軽に共有状態が実装されがちです。
しかし、その「手軽さ」は構造的な不透明性・可視性の欠如・依存性の拡散を招き、コードの保守性を著しく損ないます。
本記事では、レビューアーの立場でグローバル変数の設計上の危険性をどう見抜き、どう指摘するかを、具体的なケースとともに解説します。
典型例:無防備なグローバル変数の使用
モジュールスコープでのグローバル定義
# config.py
DEBUG = True使用側(main.py)
from config import DEBUG
def process():
if DEBUG:
print("Debug mode on")レビュー指摘コメント
@Reviewer: `config.DEBUG`は変更可能なグローバル変数であり、どのタイミングで上書きされるか予測しにくくなります。
値を明示的に渡す構造、もしくはイミュータブルな設定定義への切り替えを検討すべきです。グローバル状態が引き起こす設計上の問題
1. 可視性の欠如
- 値の変更箇所が曖昧(副作用の影響範囲が追跡困難)
- IDE補完やLSP(Language Server Protocol)でも追えないケースが多い
2. テストの困難さ
- テストケースごとに状態をリセット・上書きする必要がある
- 並列実行に対して脆弱(pytestの
--forkedが必要になる場面も)
3. 再利用不能な設計
- グローバル変数に依存する関数は他モジュールへの再配置が難しい
- DI(依存性注入)や設定切り替えの妨げになる
グローバル変数による構造汚染
この構造では、DEBUG が明示的な依存関係として示されず、Processor の外部挙動に依存した状態となっており、設計上の密結合を引き起こします。
グローバルを使いたくなる誘惑:なぜ避けづらいか
- 小規模なプロジェクトで即座に動作する設計が求められる場合
- 設定ファイル(config)やログ設定など、「一元管理したい項目」が存在する場合
- 関数に引数で値を渡す設計が冗長に思える場合
しかし、そのコストの先送りが、後に修正不能な依存構造を生みます。
:::warningning グローバル変数使用時のレビュー観点
- 状態の初期値はどこで定義され、どこで変更され得るか?
- モジュールのインポート時に副作用が発生していないか?
- 関数・クラスの引数で受け取る設計に変更できないか?
- テスト時に状態を差し替える必要がある設計になっていないか? :::
状態管理の代替戦略
1. 明示的な依存注入
引数による構成
def process(debug: bool):
if debug:
print("Debug mode on")DI構造への改善提案
@Reviewer: `debug`状態を引数で渡す構造に変更することで、呼び出し元が状態を制御可能になります。
これは依存の明示化であり、テスト性と再利用性を高めます。2. 設定専用クラスによる状態保持
コンフィグクラスによる構造管理
class Config:
def __init__(self, debug=False):
self.debug = debug3. データクラスによるイミュータブル化
dataclass構造
from dataclasses import dataclass
@dataclass(frozen=True)
class Config:
debug: boolレビュー補足
@Reviewer: `@dataclass(frozen=True)`にすることで、設定値の変更を禁止し、
「状態が変わらないこと」が明示的な契約になります。テストコード観点からの副作用確認
テスト前後で状態を上書きしている例
import config
def test_debug_behavior(monkeypatch):
monkeypatch.setattr(config, "DEBUG", False)
...テスト観点レビュー
@Reviewer: グローバル変数の状態差し替えはテストの独立性を損なうため、依存注入構造への切り替えが望まれます。グローバル変数を避けるための設計チェックポイント
- 関数やクラスに、外部依存を明示的に注入できる構造か?
- 初期化と使用のタイミングが分離されているか?
- テスト時の再現性が確保されているか?
- シングルトンを使う場合、それは必要最小限か?
結論:レビューアーの責務は「構造の将来性」に目を向けること
グローバル変数は、短期的には開発効率に寄与するかもしれませんが、
長期的には設計崩壊の起点となり得る構造です。
レビューアーは以下の点を重視し、その構造が後々どう拡大し得るかまで視野に入れた上で設計の健全性を評価する必要があります。
- グローバル変数の存在自体が問題なのではなく、「変更可能かつ共有される状態」が問題
- 設定・状態の流れが外部から明示的に把握できる設計か
- テスト・拡張・リファクタリングの将来性が確保されているか
グローバル変数を「共有」ではなく、「設計によって渡す」構造へ置き換えていくこと。
それがレビューアーが果たすべき役割のひとつです。
