Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Perlにおける動的なモジュールロードのメリットとデメリット
Search
ybrliiu
November 03, 2019
Technology
0
660
Perlにおける動的なモジュールロードのメリットとデメリット
ybrliiu
November 03, 2019
Tweet
Share
More Decks by ybrliiu
See All by ybrliiu
これまでと、これからのPerlコミュニティ
ybrliiu
0
87
AstroNvim を使おう!
ybrliiu
0
2.7k
Perlでも関数の型をチェックしたい
ybrliiu
0
2k
Perl5.32の新機能
ybrliiu
0
110
Vue.jsで作ったサイトをバニラJSで書き直す悲しいお話
ybrliiu
1
840
黒魔術で独自定義のenum型制約を満たす値のリ ストを取得する話
ybrliiu
0
300
Perlにおけるクラスの実装パターン.pdf
ybrliiu
0
1.3k
Presentation.pdf
ybrliiu
0
230
ぼくがPerlで開発を行う時に工夫していること
ybrliiu
0
420
Other Decks in Technology
See All in Technology
君はApplication Composerというサービスを知っているか
tsukuboshi
1
510
二刀流でWinActorを活用してみた話
tamai_63
0
120
どうやってWebサービスのページ表示速度を1/3にしたか / how-to-reduce-display-speed
pinkumohikan
2
470
How to Build a Strong Engineering Culture
alperhankendi
0
120
スクラムガイドに載っていないスクラムのはじめかた - チームでスクラムをはじめるときに知っておきたい5個のコツ - / How to start Scrum that is not written in the Scrum Guide
takaking22
14
5.2k
Autonomous Database - Dedicated 技術詳細 / adb-d_technical_detail_jp
oracle4engineer
PRO
2
4.9k
理想の組織も自分たちで作ろう! ―LayerXの「全員採用」を支える文化 / How to create our own ideal team
ar_tama
6
2.1k
SSMエージェントはIAMロールの夢を見るか/ Do SSM Agents Dream Of IAM Roles?
yukihirochiba
0
1.4k
Automate your changelogs! Release Drafter
onenashev
PRO
2
410
『QAという人』が必要ではなく、『QAという技術』が必要
sadonosake
2
240
GitHub composite actions
hkusu
1
120
GitHub Actions Runner Controller
takesection
0
110
Featured
See All Featured
Typedesign – Prime Four
hannesfritz
36
2k
Ruby is Unlike a Banana
tanoku
95
10k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
34
8.8k
Creatively Recalculating Your Daily Design Routine
revolveconf
209
11k
Become a Pro
speakerdeck
PRO
8
4.2k
Principles of Awesome APIs and How to Build Them.
keavy
119
16k
The Illustrated Children's Guide to Kubernetes
chrisshort
28
46k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
24
2.2k
It's Worth the Effort
3n
180
27k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
4
1.4k
Gamification - CAS2011
davidbonilla
76
4.5k
The Power of CSS Pseudo Elements
geoffreycrofte
58
4.9k
Transcript
Perlにおける動的なモジュールロードの メリットとデメリット YAPC::Nagoya::Tiny @_ybrliiu
自己紹介 • id: mp0liiu / @_ybrliiu • 所属 : 株式会社モバイルファクトリー
• 新卒2年目(23歳) • Perl歴約7年 • 最近はソフトウェアアーキテクチャとか型に関心があります ◦ https://github.com/ybrliiu/p5-Types-TypedCodeRef
Perlの好きなところ • TMTOWTDI • 特にオブジェクト指向の実現方法がいろいろあるところ ◦ Any reference base class,
Inside-out class, いろんなクラスビ ルダー, etc... • 最近Perlコアにオブジェクト指向の構文を入れようという提案がでて いたりしていてテンションが上っています
よろしくお願いいたします!!!
なぜこの発表をしようと思ったのか • これまで趣味 + お仕事で動的なモジュールロードを行うコードをカ ジュアルに書いてきました • そのようなコードを運用していると、後から辛くなってくることが多かっ たので、なぜそうなっているのかを整理し、どうすれば改善できるのか を考えました
• http://mp0liiu.hatenablog.com/entry/2019/02/28/111424
次のようなコードがありました • とあるソーシャルゲームのコード • アイテムを使用すると、アイテムの種類に応じて効果が発動する • アイテムのデータはDBで管理されている
エンジニアA 「いちいちアイテム効果クラスを1つ1つuseしてアイテム の種類と対応させるコードを書くのめんどくさいなー」 エンジニアA 「せや!アイテムデータの種類を見て正規表現でいい感 じのアイテムクラス名を作ってそれをロードするようにするんや!」 エンジニアA 「よし!簡潔に書けていいな!」
数カ月後・・・
新しい効果をもつアイテムを追加することになりました
エンジニアB 「新しいアイテムのデータも追加したしアイテムの効果も 実装するか」 エンジニアB 「とりあえず他のアイテムのクラスを真似て作ろう」 エンジニアB 「クラス名はなんてすればいいんだ? grepしてもアイテム 効果クラスが使われている場所が見つからないぞ?」
None
今回の発表で伝えたいこと • 動的なモジュールロードは柔軟性がありすぎるので下手な使い方をす ると保守性が下がってしまう ◦ 静的なモジュールロードを行う方法でできないか検討しよう ◦ 動的なモジュールロードをする方が合理的なら保守性が下がらな いように工夫しよう
今日話すこと • 静的なモジュールロードと動的なモジュールロードについて • 動的なモジュールロードのメリット • 動的なモジュールロードのデメリット • 保守性を下げないようにするには
静的なモジュールロード • コンパイルフェーズで行うモジュールロードのこと • 通常は use でロード • ロードするタイミングやロードするモジュールに制約がかかる ◦
少なくともランタイムが開始する前にどんなモジュールがロードさ れるかが定まるようになっていないけない
動的なモジュールロード • ランタイムで行うモジュールロードのこと • ロードするタイミングやモジュールを好きなように決められる • 言語組み込みの機能で行うのなら require でのモジュールロード ◦
ロードするモジュールを動的に決めたいなら eval “require ...” • 通常は Module::Load, Class::Load などといったモジュールローダー を利用してロード
動的なモジュールロード • use する場合と挙動が違うところがあるので注意 ◦ import は自動的に呼ばれない ◦ CHECK, INITブロックに書かれたコードが実行されない
動的なモジュールロードを行うことによる メリット あるいはどのようなときに動的なモジュールロードを行いたくなるのか
コード量が少なくなる
for, while 文などでまとめてロードすればコード量が減る
Module::Find を利用すると、ある名前空間の下に属するモジュール をすべて読み込むことができる
Catalyst 風のモジュールローダーを利用する • useしなくてもモジュールを使える、use忘れがなくなる • パッケージ名を短く書ける
プラガブルなモジュールを簡単に作れる
モジュールに新たなメソッドを追加したりやモンキーパッチを当てれる ようにしたい場合 (Tengのようなケース)
None
与えられたものを読み取って何かするようなモジュールに、ルールを 追加していける構造にしたい (Perl::Critic のようなケース)
None
動的にディスパッチできる • 利用するモジュールを動的にディスパッチできる • プログラムの外部で管理されていたり、外部から受け付ける入力に応 じて処理を分岐させたい場合に非常に便利 ◦ 項目が多いマスタデータの種類に応じて ◦ HTTPリクエストの内容に応じて
動的にディスパッチできる
起動 / ロードにかかる時間の短縮 • モジュールをロードするタイミングをモジュール内のコードを実行する 直前にまで遅らせることで、アプリケーションの起動やモジュールの ロードにかかる時間を短くすることができる ◦ 当然その分実行時に短くした分の時間がかかる •
高速化を意識しているCPANモジュールや巨大なアプリケーションで よく見かける ◦ Moo, Type::Tiny, Class::Accessor::Lite, etc...
依存関係を動的に解決できる • 依存関係を動的に解決できる ◦ 条件に応じて依存モジュールを変更できる ◦ モジュールが相互に依存しても警告が発生しない • モジュールロードに失敗した場合の処理が書ける
動的なモジュールロードを行うことによる デメリット 開発体験にどのような悪影響がでるのか
可読性が下がる • 動的にロードするモジュール名を組み立てていると発生する問題 • 特に動的にモジュールロードされていることを知らない人がコードを 読むと、どこで何のモジュールが使われているのかがわかりにくい ◦ 特に正規表現でモジュール名を作ったりしていると非常に厳しい
可読性が下がる • 本質的には greppability の話 ◦ 調べたいコードが検索しにくい状態になってしまう ◦ 動的にシンボルを組み立てているとコードが検索しにくくて機械 も人間も辛い思いをする
◦ 静的解析を利用したツールの恩恵を授かれない恐れも
良くない設計の原因になる • どこでモジュールがロードがされるかわかりにくくなるので、注意しな いと混沌とした依存関係や構造ができあがる • モジュールの先頭で依存しているモジュールがまとめて use されて いる方が依存関係はわかりやすい •
依存関係が循環しているモジュールがあっても警告がでない
実際にロードされるまで動くかわからない • 依存しているモジュールがエラーなどで動かなくなっていても、実際 にコードが動くまでわからない • しっかりテストが書かれていたり、 Test::UseAllModules::all_use_ok みたいなテストが用意されてい るならそんなに問題にはならない •
またリッチな機能をもつエディタなら Syntax Error とかにも気づきや すい
つまり、むやみに動的なモジュールロード を行うと保守性が下がる
静的にモジュールロードする場合、柔軟性がない分 保守性が下がるような書き方をしにくい
なるべく静的にモジュールロードしたい
動的なモジュールロードを行うほうが合理的なときは、 なるべく保守性が下がらないようにしたい
どうするか
コード量を減らしたいとき
パッケージ名が長すぎる モジュールローダーの代わりに 定数や aliased でパッケージ名のエイリ アスを作る
use 忘れを防ぎたい • 現状代替案は知りません・・・ • いい方法を知っている方がいれば教えて下さい! • 理想を言えば他の言語みたいにエディタやIDEの機能でパッケージを 利用していたら自動でuseできるようになってほしい •
うたがわさんが便利そうなプラグインを作られていました ◦ 開発体験良くなりそうですね
まとめてロードしたい • 普通にuseする方法では不可能 • そもそもたくさんのモジュールをロードしたいケースは頻繁にあるの か? ◦ 拡張性を重視する構造でなければ、責務が大きくなりすぎている 可能性がある ◦
その場合はモジュールを分割すべき
まとめてロードしたい • 拡張性を重視していたり、useを延々と書き続けるのが現実的ではな い場合は動的にロードすべき • ただし保守性が低下しないように工夫する ◦ まとめすぎない (Module::Find::useall()) ◦
動的にパッケージ名を組み立てない ◦ Test::UseAllModules などを利用してコンパイルフェーズでエ ラーが起きないかをテストするようにする
プラグイン機構を実装したい時 • 手間がかかるが、プラグインオブジェクトを外でuseして作って渡すこ ともできる • フレームワークだったりプラガブルにしたい場合は動的にロードする のもよい • プロダクトのコード、特にビジネスロジックなどではプラガブルな構造 を用意するのはやり過ぎなケースが多い
◦ 基本的に保守性を重視して静的にロードする
モジュールに新たなメソッドを追加したりやモンキーパッチを当てれ るようにしたい場合 (Tengのようなケース)
None
動的にディスパッチしたい時 • 利用しうるモジュールは全て事前にロードしておき、外部からの値に 応じて利用するモジュールを分けるような対応表を書くことで対応で きる ◦ 数が多いなら対応表を自動生成する仕組みをつくるという手も • 工数、拡張性と保守性のトレードオフになるので状況に応じて判断 •
利用するパッケージ名を難しい正規表現とかで作っている場合は読 みにくくなるので対応表をちゃんと書くべき
動的にディスパッチしたい時
起動 / ロードにかかる時間の短縮 • 起動やロードにかかる時間を短縮したい場合は動的にロードするし かない • 保守性との引き換えになることを念頭に置いた上で、なるべく保守性 がおちないように工夫する ◦
良くない設計になってしまわないように注意を払う ◦ 動的にパッケージ名を組み立てない ◦ Test::UseAllModules などを利用してテストする
依存関係を動的に解決したい • 条件が実行する前に決まるなら if プラグマを利用したり、importや BEGIN句の中で頑張って静的にロードさせるようにすることができる • 依存関係が循環しているような場合は結合度が高く、設計としてよく ない状態になっているので設計を修正する
まとめ
まとめ • 動的なモジュールロードは下手な使い方をすると保守性が下がってし まう ◦ 静的なモジュールロードを行う方法でできないか検討しよう ◦ 動的なモジュールロードをする方が合理的なら保守性が下がらな いように工夫しよう
ご清聴ありがとうございました