Perl Hackers Hub

第60回 動的なモジュールロードとの付き合い方(3)

この記事を読むのに必要な時間:およそ 3 分

(1)こちら⁠2)こちらから。

動的なモジュールロードで発生する問題とその対策

さて,⁠2)までは動的にモジュールロードをすることで実現できることを見てきましたが,動的なモジュールロードを行っていると良いことばかりあるわけではありません。注意して利用しなければ保守性が下がります。

(3)では動的にモジュールロードをすることで発生する問題と,その対策について解説していきます。

可読性が低くなる─⁠─動的にモジュール名を作らない

モジュールロードをする際に文字列連結や正規表現などで動的にロードするモジュール名を作っていると,ロードするモジュールの名前は処理を追わないとわからなくなるので,可読性が低くなります。

また,機械的にもコードを調べにくくなるため,コードが検索しにくくなったり,静的解析を利用したツールの恩恵にあずかれなくなる可能性があります。

可読性が低くならないようにするため,動的にモジュールロードする際はなるべくモジュール名を動的に作らないようにしましょう。動的に作る必要がある場合もなるべく単純なルールにします。複雑な正規表現やロジックでモジュール名を作るのは,特別な理由がない限り避けたほうがよいでしょう。

例外として,WAFのルーティングの記述など,宣言的にディスパッチルールを記述したい場合は,暗黙的な知識が増えることと引き換えに実装の簡単さと視認性が得られるので,複雑なロジックで動的なモジュール名の作る合理性があります。しかし,暗黙的な知識が増えるとその分開発者が覚えなければならないことが増えるため,文書化やチームへの知識の共有が必要ですし,それが本当に必要なのかもよく検討するべきでしょう。

循環する依存関係が作られる─⁠─依存関係をチェックする

循環するモジュールの依存関係があると,依存関係のあるモジュールのどこかが壊れたり変更があったりした場合に,依存関係のあるモジュールすべてに影響が及ぶ可能性があります。ですので,なるべくモジュールの依存関係は単方向にしたいです。

しかし,動的にモジュールロードを行っている箇所が多いと,モジュールの依存関係が混沌としていつの間にか循環する依存関係を作ってしまいがちです。

そうならないように,できるだけモジュールの依存関係が単方向になるようチェックするしくみを導入するべきでしょう。

静的にモジュールロードしている場合

静的にモジュールロードしている場合は,次の理由により依存関係のチェックがしやすいため,循環する依存関係は作られにくいです。

  • 循環している依存関係があればサブルーチン再定義の警告が出る
  • モジュールロードするコードはファイル上部にまとめて書かれていることが多いので,どのモジュールに依存しているかが視認しやすい
  • Perl::PrereqScannerなど静的解析を利用したツールによって依存しているモジュールの検出がしやすいため,依存関係のチェックがしやすい
動的にモジュールロードしている場合

しかし,動的にモジュールロードしている場合は,次の理由により循環する依存関係が作られがちです。

  • 動的に依存関係を解決するため,循環する依存関係があってもサブルーチン再定義の警告が出ない
  • あらゆる箇所から自由に別モジュールの処理を呼べるため,どのモジュールがどのモジュールに依存しているかが視認しにくくなり,混沌とした依存関係になる
  • 静的解析を利用したツールによって依存しているモジュールの検出ができないか,できたとしても独自に静的解析する処理を書かないと依存しているモジュールの検出ができないため,精度の高い依存関係のチェックがしにくい
循環する依存関係を作らないようにするには

循環する依存関係を作らないようにするには,どうにかして依存関係が単方向になっているかをチェックする必要があります。どのモジュールがロードされるか静的解析でわかる場合は,自分で静的解析する処理を書いて依存関係をチェックできます。静的解析でわからない場合は,完璧な依存関係のチェックは諦め,独自のモジュールローダを作りcallerで呼び出しもとを調べて記録,循環する依存があれば警告を出すしくみなどを用意するとよいでしょう。

しかし,上記のような依存関係をチェックするしくみを用意し運用するのはかなり大変です。依存関係をチェックするしくみが用意できないようなら,できるだけ静的にモジュールロードしたほうがよいでしょう。

実行までモジュールロードできるかわからない─⁠─すべてのモジュールがロード可能かテストする

依存しているモジュールが文法エラーなどでモジュールロードに失敗する状態になっていても,実際にコードが実行されるまでモジュールロード可能かわからなくなります。ですので,テストが書かれていない箇所が本番環境で急に使えなくなる,などといった現象が起きる可能性があります。

最近ではIDEIntegrated Development Environment統合開発環境)やエディタが高機能になっており,開発中に文法エラーをチェックして気付けるのであまり大きな問題にはなりませんが,それでもすべてのモジュールがロード可能なのかの保証がなく不安です。

すべてのモジュールがロード可能であることを保証するには,すべてのモジュールがロード可能かをチェックするモジュールを使ってテストをするとよいでしょう。Test::UseAllModulesはそういった機能を提供するモジュールの1つで,デフォルトではall_use_ok関数でlib以下のすべてのモジュールがロード可能かをテストします。

著者プロフィール

楠田来安(くすだらいあん)

学生時代からPerlを使いCGIゲームの開発運営などを行う。2018年に株式会社モバイルファクトリーに新卒入社し,現在はソーシャルゲームの開発に携わりつつ,Perlコミュニティなどで活動している。

GitHub:https://github.com/ybrliiu