Perlにおける動的なモジュールロードのメリットとデメリット
by
ybrliiu
Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
Perlにおける動的なモジュールロードの メリットとデメリット YAPC::Nagoya::Tiny @_ybrliiu
Slide 2
Slide 2 text
自己紹介 ● id: mp0liiu / @_ybrliiu ● 所属 : 株式会社モバイルファクトリー ● 新卒2年目(23歳) ● Perl歴約7年 ● 最近はソフトウェアアーキテクチャとか型に関心があります ○ https://github.com/ybrliiu/p5-Types-TypedCodeRef
Slide 3
Slide 3 text
Perlの好きなところ ● TMTOWTDI ● 特にオブジェクト指向の実現方法がいろいろあるところ ○ Any reference base class, Inside-out class, いろんなクラスビ ルダー, etc... ● 最近Perlコアにオブジェクト指向の構文を入れようという提案がでて いたりしていてテンションが上っています
Slide 4
Slide 4 text
よろしくお願いいたします!!!
Slide 5
Slide 5 text
なぜこの発表をしようと思ったのか ● これまで趣味 + お仕事で動的なモジュールロードを行うコードをカ ジュアルに書いてきました ● そのようなコードを運用していると、後から辛くなってくることが多かっ たので、なぜそうなっているのかを整理し、どうすれば改善できるのか を考えました ● http://mp0liiu.hatenablog.com/entry/2019/02/28/111424
Slide 6
Slide 6 text
次のようなコードがありました ● とあるソーシャルゲームのコード ● アイテムを使用すると、アイテムの種類に応じて効果が発動する ● アイテムのデータはDBで管理されている
Slide 7
Slide 7 text
エンジニアA 「いちいちアイテム効果クラスを1つ1つuseしてアイテム の種類と対応させるコードを書くのめんどくさいなー」 エンジニアA 「せや!アイテムデータの種類を見て正規表現でいい感 じのアイテムクラス名を作ってそれをロードするようにするんや!」 エンジニアA 「よし!簡潔に書けていいな!」
Slide 8
Slide 8 text
数カ月後・・・
Slide 9
Slide 9 text
新しい効果をもつアイテムを追加することになりました
Slide 10
Slide 10 text
エンジニアB 「新しいアイテムのデータも追加したしアイテムの効果も 実装するか」 エンジニアB 「とりあえず他のアイテムのクラスを真似て作ろう」 エンジニアB 「クラス名はなんてすればいいんだ? grepしてもアイテム 効果クラスが使われている場所が見つからないぞ?」
Slide 11
Slide 11 text
No content
Slide 12
Slide 12 text
今回の発表で伝えたいこと ● 動的なモジュールロードは柔軟性がありすぎるので下手な使い方をす ると保守性が下がってしまう ○ 静的なモジュールロードを行う方法でできないか検討しよう ○ 動的なモジュールロードをする方が合理的なら保守性が下がらな いように工夫しよう
Slide 13
Slide 13 text
今日話すこと ● 静的なモジュールロードと動的なモジュールロードについて ● 動的なモジュールロードのメリット ● 動的なモジュールロードのデメリット ● 保守性を下げないようにするには
Slide 14
Slide 14 text
静的なモジュールロード ● コンパイルフェーズで行うモジュールロードのこと ● 通常は use でロード ● ロードするタイミングやロードするモジュールに制約がかかる ○ 少なくともランタイムが開始する前にどんなモジュールがロードさ れるかが定まるようになっていないけない
Slide 15
Slide 15 text
動的なモジュールロード ● ランタイムで行うモジュールロードのこと ● ロードするタイミングやモジュールを好きなように決められる ● 言語組み込みの機能で行うのなら require でのモジュールロード ○ ロードするモジュールを動的に決めたいなら eval “require ...” ● 通常は Module::Load, Class::Load などといったモジュールローダー を利用してロード
Slide 16
Slide 16 text
動的なモジュールロード ● use する場合と挙動が違うところがあるので注意 ○ import は自動的に呼ばれない ○ CHECK, INITブロックに書かれたコードが実行されない
Slide 17
Slide 17 text
動的なモジュールロードを行うことによる メリット あるいはどのようなときに動的なモジュールロードを行いたくなるのか
Slide 18
Slide 18 text
コード量が少なくなる
Slide 19
Slide 19 text
for, while 文などでまとめてロードすればコード量が減る
Slide 20
Slide 20 text
Module::Find を利用すると、ある名前空間の下に属するモジュール をすべて読み込むことができる
Slide 21
Slide 21 text
Catalyst 風のモジュールローダーを利用する ● useしなくてもモジュールを使える、use忘れがなくなる ● パッケージ名を短く書ける
Slide 22
Slide 22 text
プラガブルなモジュールを簡単に作れる
Slide 23
Slide 23 text
モジュールに新たなメソッドを追加したりやモンキーパッチを当てれる ようにしたい場合 (Tengのようなケース)
Slide 24
Slide 24 text
No content
Slide 25
Slide 25 text
与えられたものを読み取って何かするようなモジュールに、ルールを 追加していける構造にしたい (Perl::Critic のようなケース)
Slide 26
Slide 26 text
No content
Slide 27
Slide 27 text
動的にディスパッチできる ● 利用するモジュールを動的にディスパッチできる ● プログラムの外部で管理されていたり、外部から受け付ける入力に応 じて処理を分岐させたい場合に非常に便利 ○ 項目が多いマスタデータの種類に応じて ○ HTTPリクエストの内容に応じて
Slide 28
Slide 28 text
動的にディスパッチできる
Slide 29
Slide 29 text
起動 / ロードにかかる時間の短縮 ● モジュールをロードするタイミングをモジュール内のコードを実行する 直前にまで遅らせることで、アプリケーションの起動やモジュールの ロードにかかる時間を短くすることができる ○ 当然その分実行時に短くした分の時間がかかる ● 高速化を意識しているCPANモジュールや巨大なアプリケーションで よく見かける ○ Moo, Type::Tiny, Class::Accessor::Lite, etc...
Slide 30
Slide 30 text
依存関係を動的に解決できる ● 依存関係を動的に解決できる ○ 条件に応じて依存モジュールを変更できる ○ モジュールが相互に依存しても警告が発生しない ● モジュールロードに失敗した場合の処理が書ける
Slide 31
Slide 31 text
動的なモジュールロードを行うことによる デメリット 開発体験にどのような悪影響がでるのか
Slide 32
Slide 32 text
可読性が下がる ● 動的にロードするモジュール名を組み立てていると発生する問題 ● 特に動的にモジュールロードされていることを知らない人がコードを 読むと、どこで何のモジュールが使われているのかがわかりにくい ○ 特に正規表現でモジュール名を作ったりしていると非常に厳しい
Slide 33
Slide 33 text
可読性が下がる ● 本質的には greppability の話 ○ 調べたいコードが検索しにくい状態になってしまう ○ 動的にシンボルを組み立てているとコードが検索しにくくて機械 も人間も辛い思いをする ○ 静的解析を利用したツールの恩恵を授かれない恐れも
Slide 34
Slide 34 text
良くない設計の原因になる ● どこでモジュールがロードがされるかわかりにくくなるので、注意しな いと混沌とした依存関係や構造ができあがる ● モジュールの先頭で依存しているモジュールがまとめて use されて いる方が依存関係はわかりやすい ● 依存関係が循環しているモジュールがあっても警告がでない
Slide 35
Slide 35 text
実際にロードされるまで動くかわからない ● 依存しているモジュールがエラーなどで動かなくなっていても、実際 にコードが動くまでわからない ● しっかりテストが書かれていたり、 Test::UseAllModules::all_use_ok みたいなテストが用意されてい るならそんなに問題にはならない ● またリッチな機能をもつエディタなら Syntax Error とかにも気づきや すい
Slide 36
Slide 36 text
つまり、むやみに動的なモジュールロード を行うと保守性が下がる
Slide 37
Slide 37 text
静的にモジュールロードする場合、柔軟性がない分 保守性が下がるような書き方をしにくい
Slide 38
Slide 38 text
なるべく静的にモジュールロードしたい
Slide 39
Slide 39 text
動的なモジュールロードを行うほうが合理的なときは、 なるべく保守性が下がらないようにしたい
Slide 40
Slide 40 text
どうするか
Slide 41
Slide 41 text
コード量を減らしたいとき
Slide 42
Slide 42 text
パッケージ名が長すぎる モジュールローダーの代わりに 定数や aliased でパッケージ名のエイリ アスを作る
Slide 43
Slide 43 text
use 忘れを防ぎたい ● 現状代替案は知りません・・・ ● いい方法を知っている方がいれば教えて下さい! ● 理想を言えば他の言語みたいにエディタやIDEの機能でパッケージを 利用していたら自動でuseできるようになってほしい ● うたがわさんが便利そうなプラグインを作られていました ○ 開発体験良くなりそうですね
Slide 44
Slide 44 text
まとめてロードしたい ● 普通にuseする方法では不可能 ● そもそもたくさんのモジュールをロードしたいケースは頻繁にあるの か? ○ 拡張性を重視する構造でなければ、責務が大きくなりすぎている 可能性がある ○ その場合はモジュールを分割すべき
Slide 45
Slide 45 text
まとめてロードしたい ● 拡張性を重視していたり、useを延々と書き続けるのが現実的ではな い場合は動的にロードすべき ● ただし保守性が低下しないように工夫する ○ まとめすぎない (Module::Find::useall()) ○ 動的にパッケージ名を組み立てない ○ Test::UseAllModules などを利用してコンパイルフェーズでエ ラーが起きないかをテストするようにする
Slide 46
Slide 46 text
プラグイン機構を実装したい時 ● 手間がかかるが、プラグインオブジェクトを外でuseして作って渡すこ ともできる ● フレームワークだったりプラガブルにしたい場合は動的にロードする のもよい ● プロダクトのコード、特にビジネスロジックなどではプラガブルな構造 を用意するのはやり過ぎなケースが多い ○ 基本的に保守性を重視して静的にロードする
Slide 47
Slide 47 text
モジュールに新たなメソッドを追加したりやモンキーパッチを当てれ るようにしたい場合 (Tengのようなケース)
Slide 48
Slide 48 text
No content
Slide 49
Slide 49 text
動的にディスパッチしたい時 ● 利用しうるモジュールは全て事前にロードしておき、外部からの値に 応じて利用するモジュールを分けるような対応表を書くことで対応で きる ○ 数が多いなら対応表を自動生成する仕組みをつくるという手も ● 工数、拡張性と保守性のトレードオフになるので状況に応じて判断 ● 利用するパッケージ名を難しい正規表現とかで作っている場合は読 みにくくなるので対応表をちゃんと書くべき
Slide 50
Slide 50 text
動的にディスパッチしたい時
Slide 51
Slide 51 text
起動 / ロードにかかる時間の短縮 ● 起動やロードにかかる時間を短縮したい場合は動的にロードするし かない ● 保守性との引き換えになることを念頭に置いた上で、なるべく保守性 がおちないように工夫する ○ 良くない設計になってしまわないように注意を払う ○ 動的にパッケージ名を組み立てない ○ Test::UseAllModules などを利用してテストする
Slide 52
Slide 52 text
依存関係を動的に解決したい ● 条件が実行する前に決まるなら if プラグマを利用したり、importや BEGIN句の中で頑張って静的にロードさせるようにすることができる ● 依存関係が循環しているような場合は結合度が高く、設計としてよく ない状態になっているので設計を修正する
Slide 53
Slide 53 text
まとめ
Slide 54
Slide 54 text
まとめ ● 動的なモジュールロードは下手な使い方をすると保守性が下がってし まう ○ 静的なモジュールロードを行う方法でできないか検討しよう ○ 動的なモジュールロードをする方が合理的なら保守性が下がらな いように工夫しよう
Slide 55
Slide 55 text
ご清聴ありがとうございました