## とりあげた本
Tomasz Lelek、Jon Skeet『ソフトウェア設計のトレードオフと誤り ―プログラミングの際により良い選択をするには』オライリー・ジャパン、2023年
## mixi2
https://mixi.social/communities/513e0bc9-582b-4962-a9c1-c5c076175e08/about
## ShowNote
https://gennei.notion.site/EP241-PART2-40cc645d4911811690aeda5e79fb99d3
感想
まだ感想はありません。最初の1件を書きましょう!
サマリー
第4章「柔軟性と複雑性のバランス」をもとに、拡張性を高める設計が複雑性や保守コストを増やすトレードオフを話します。フックAPIとリスナーAPIを取り上げ、関心の分離、ライフサイクルへの差し込み、AOPやDI、オブザーバーパターンの利点を、PHPやCakePHP、Laravelなどの実例とともに振り返ります。イベントやリスナーは疎結合を実現する一方、例外処理やトレーサビリティ、意図しない副作用に注意が必要です。後半ではイミュータビリティやサービスロケーター、ファクトリーなどにも触れ、何にどの程度柔軟性を持たせるかは経験とチームでの判断が重要だとまとめます。
柔軟性と複雑性のトレードオフ
平氏テーマのが4章。柔軟性と複雑性のバランス。
ここはどんなことが書いてあるかっていうと、ここでも結構幅広めですよね、トピックが。
うん、広いっすね。
柔軟性と拡張性、バーサスメンテナンスコストと複雑性みたいな話とか。
柔軟性と拡張性を手に入れようとすると、いろんなものを抽象化したりとか、いろんなところに拡張ポイントみたいなのを作っていくと、
だんだんそれを色々知らないと使えないってなった時に、別にそもそも拡張とか柔軟性とかそんなに必要だったんだっけ?
見たことになると、そこってそんなに頑張る必要あったかな?見たことが起きたりとかするんで、この辺は結構トレードオフになりやすいっていうのはありますね。
柔軟にしすぎるとね、要するに何でもやっていい理想になってるから、何も言ってないに等しくないみたいになって。
そうそうそう。
ルート権限で動くエンドポイント作りましたみたいに。あとは好きなものインジェクションしてくださいみたいになりますからね。
まあ垂直に柔軟なんですけどね、それが。
君はフレームワークを作ってたのかい?みたいな感じになっていくんですよね。
フックAPIとライフサイクルへの差し込み
この中で結構自分が読んでいいなと思ったのが、フックのAPIの話とリスナーAPIの話があって、この辺とかの考え方ってすごいいいなと思いながら、これ結構意識してるなっていうのはありましたね。
ここで言ってるAPIはあれですね、全然WebAPIとかじゃなくて、ライブラリとかの公開メソッドって感じですね。
で、フックはあれですかね、ミドルウェアみたいなイメージをしてもらうといいって感じですかね。
ミドルウェアっていうと色々あるからまた。
APIとかミドルウェアとか。
WebのAPIとかで、このルーティングに来た時に、バリデーションなんかチェックしたりとか認可処理だったりとか、認証認可だったりとかを挟んでおくとかってやるときのミドルウェアみたいなところの、
イメージですかね。
そうですね、フック経由でAPIに拡張性与えるって書いてあるんで、これは本体に手を入れないで外から処理を挟み込むことをやりたいときにどうするっていう話ですよね。
そうですね、そうですね。
例えばこのメソッドが呼ばれたらロギングしたいとかいう時とかも、フックのところがあるとそこに差し込むだけで実際の処理を変えなくても、フックを付け外しするだけでロギングできたりしていいよねみたいなのがあ
って、
これってAOPってやつで見たことあるなと思って、そういう考え方で色々差し込みができると拡張性があっていいなって思ったことが過去結構ありましたね。
君はフレームワークを作ってるのかいって話じゃないですか。
フレームワークがそういうことを用意してくれていて、そういう風にフックできるのがやりたかったんだな俺はみたいなことを思って、結局関心の分離ができるとすごいソースコードが読みやすくなっていいなっていうのは
あって、
この辺が結構ベアサンデーのレイディーアイとかがAOPを持ってたりとかして、結構便利って思いながらアノテーションを書くとそのアノテーションをヒントにしながらフックを仕込んでくれるみたいなことやってくれた
りとかしてて、いいなと思ったりとかしましたね。
レイディーアイはあれなんですよね、ドキュメントとか見ると書いてありますけど、
10年以上か、10年以上確かメジャーバージョン上がってないはずで。
そうそうそう。
いわゆる広報互換性をずっと維持してるんですよね。これこそが本当に拡張性を維持してる表れだなぁみたいな気もするし。
メンテナンスしてないわけじゃなくて、ちゃんとメンテして新しいPHPの機能にも対応してっていう中でやってるわけですからね。互換性維持して。かっこいいよなぁ。
これぐらい考え込んで作れたら、すごい楽しいだろうなって思いながら、思った通り狙った通りに生き延びているっていうのがすごくいいなぁって思いますね。
あとロゴがめちゃくちゃ好きなんですよ。
いいっすね。
かわいい。ロゴの話とかさすがに脇道すぎるんですけど。
だからあれですよね、ライフサイクルの中でフック生やしてそこに噛ませられるようにしようぜみたいなやつですよね。
そうすると利用者側とか諸々から、なんかその主要なタイミングで必要な処理をコアに手を入れずに挟み込めるよみたいな。
そうなんですよ。この辺とかをなんか自分は、なんかPHPだけ書いてた時あんまり意識してなかったんですけど、
やっぱView.jsとか、あとiOSのSwiftを書いた時のViewControllerとか、あの辺とかに結構こういう順番でメソッドが順番に呼び出されるんで、
例えば画面の初期化時に何かしたい時はここに差し込んでねとか、画面の読み込みが終わった時にはこういうことをやりたいってなったらここに差し込んでねみたいなのを理解して、
あ、そうか、そういうライフサイクルってものがあるのかみたいなことを見た時に結構、なんていうか、目の前が明るくなったというか、
すごい、あ、視界が開けたみたいな感覚があって、なんかこのフックの考え方すごい好きだなって思ったりをちょっと読んでしてましたね。
僕、いつだろうな、やっぱりケーク使い始めてそのbeforeフィルターとかafterフィルターっていうのがあるよっていう話で知ってはいたって感じが、
そのフックとかそのコントローラーのアクションに入る前のbeforeの処理でコンポーネントをロードしてみたいな、
ケーク2とかそういう使い方だったんで、少し特殊なことしようとすると。
なんかそこらへんとか、あとはテストはあるか、PHPユニット使い始めて、なんかbeforeというかセットアップとかbeforeのアノテーションとか使ったりとか、
あとは、Defenseはあんまり使ってないんですけど。
あとあれなんですよね、ケーク3のアプリケーションフレームワーク側がコントローラーの処理に入る前にさっき言ってたコンポーネントとかをアクティベートするとき読み込むみたいなところに、
テスト側からフックで仕込むことができて、なんかそこでコンポーネントをスパイとかダミーに置き換えるみたいなフックが入ってたんですよね。
公式にドキュメンテーションされてたかわかんないか、なんかインターナルな使い方想定してたかもしれないですけど、
なんかよく見たらこういうフック履いてて使ってるテスト書いてるなーみたいなのあって、めっちゃ便利パクローみたいなのがあって、そういうのは使ってたな。
多分聞いたの、記事僕が書いたのが、十何年前に出てくると思うんですけど。
フレームワークって要するにテンプレートメソッドパターンだよねみたいなことをおっしゃってるPHP会話の図書がいて、それ見かけたときはあんまりピンときてなかったんですけど、
なんかあるときそれがどうかそういうことかみたいな気がして、非常に今もそう思ってるって感じです。
この辺でなんか物の見方を獲得できるとすごいね、こうなんだこんなことかってある種なってくるから、
それを獲得するまでってある種プログラムって上から下に順次実行されていって、全部呼び出さないといけないんじゃないかとか、呼び出したくないときは分岐しないといけないんじゃないかとか、いろいろ思っちゃったり
するんだけども、
実は本当に真っさらから書いたらそうなんだけど、いろんなフレームワークだったりとかいろんなものの上に乗っかっていく上では、
各フレームワークだったりライブラリだったりいろんなものが拡張性ってものをどう考えてるかっていうところを手に入れると、
なるほどここに差し込めばいいのねみたいなことが見えてくると、なんだそんなに頑張っていろんなことやらなくてもいいじゃないかとか、
DIを覚えれば、なるほどこうやってテストを簡単に書けるようにすればいいのかとかっていうふうになってくるから、この辺の柔軟性とかって引き出しとして持っておくといいなっていうのはすごい思いますね。
リスナーとイベントによる関心の分離
この本でいうと引き出しのもう一つっていうか対抗馬としてリスナーっていうのもあるよねって話をしてますね。
フックバーサスリスナーの話をしてて。
リスナーと聞いたらイベントリスナーっていうのを思い出すんだ。
ウェブのフロントエンドやってるとなんかすごい昔いっぱいアドイベントリスナーとかいろいろやったなっていうのをちょっと今思い出しましたね。
クリックをすごく使ってたな。
っていうのをやったりとか、通知系とかこれを変更したときにアップデートかけたらいろんな通知を飛ばしたいとかいうときとかに結構リスナー使ったりしますね。
あとはあれじゃないですかPHPユーザー的にはやっぱり標準クラスでオブザーバーパターンを実装できるっていうクラスがあるから
SPLオブザーバーっていうクラスがありますからね。
もう一回も使ったことないよ。
使ったことないですね。
SPLオブザーバーインターフェースをSPLサブジェクトとともに使うとオブザーバーパターンを実装することができますっていうクラスがですね組み込みであるんでね。
それ使うことあるかなみたいなこういう気持ちになりながら。
流行ってたんでしょうねこれ書いた人の中で。
オブザーバーパターン自体は多分使うことはあるんだろうけど。
それはめちゃくちゃ使いますけどね。
けどなかなかねなかなかSPLのオブザーバーを使うことはないですね。
デスクトップアプリとかオブザーバーパターンがあるおかげで何かこれを値を更新したら何かその更新を自分でイベント発火しなくていいんだみたいなのを自社アップ書いてたときに思ってこれすごいと思ってましたね。
そうなんか全然関係ないっていうか本筋じゃないサイド処理をやっぱり書きたくないですもんね。
なんか通知だけ抜けて誰か必要な人を受け取ってくださいみたいなのをやっときた。
本当そうなんですよ。
そうするとやっぱりすごい拡張性に開かれてる。
要は疎結合に作れるから見通しもいいし、あとはそこがちゃんと呼び出されてるかだけ気にしとけばいいってなるとだいぶ気は楽になりますね。
見通しも観点によりません?
どこでリスされてるんだみたいなとか。
リスナーこれに反応しそうなリスナーは誰かなはコードをグレープというかIDでバッて出せるんですけど、
アタッチされてるリスナーは違うみたいな状態になってくるのっていいじゃないですか。
自分はわりとそういうのは設定ファイル的な感じで集約されてて欲しいなって思うから、統一されてここに書いておいてっていうのは思ったりしますね。
ちょっと今想定してるケースによって全然違ったりしますけど。
そうそうそう、ケーキの話またなっちゃいますけど、今も残ってるのかな、ケーキPHPでイベントシステムっていうドキュメントのページがあって、
それこそリスナーとかイベントのリスパッチとかっていう話をしてるんですけど、
なんかそのドキュメントの中に偉大な力には偉大な責任が伴うことを心に留めておいてくださいって書いてあって、
これ好きなんですよね。
まあやろうと思えばすごいピタゴラスイッチみたいなの作ろうと思えば作れちゃうからな。
そうそうそう、イベントはあなたのアプリケーション内の関心事を分離させる偉大な方法であり、
これは格言言いたいがために偉大な方法って言い出したなみたいな気がして。
そうですね。
毎回これ思い出します。
そういうのを気にしておかないと、さっきの例外勝利の話だけど、イベントリスナーのその先で何が起きるかとか、
知らないままノンキー使ってて、じゃあ例外ハンドリングどうしますかっていうとか、
何も考えてなかったりするとちょっと危なかったりするっていうのもあるんで、
そういうのは結構即結合な部分はいいけど、ある種ちゃんとイベント発火したんだっけとか、
どこから呼び出されたかとか、いろんなところをちゃんと追いかけますかみたいなところはやっぱり、
後で不具合が起きたときに調べられるようにしようがないといけないとか、いろいろありますからね。
そうなんですよね、トレーサビリティみたいな話が出てくるのかな。
ララベルでもイベントあるからそれを使ってリスしてとかっていうのは使ってはいますけど、
うっかりいろんな、本当はこの時に設定したくないんだよねとかいうのがあったりすると困るんで、
その辺はちょっとやっぱり気をつけないと、そうなった時にはそもそも設計がおかしいのではとか、
いろいろ前提を疑ったりとかしますけど。
前提を疑えるかどうかはやっぱり経験値ですからね。
いやー、これなー、イベントケーキとかララベルとかにちゃんとそういうのがあっていいなと思いながら、
昔オレオレフレームワークをメンテしてた時はそういうのないから、
頑張って普通に書類を呼び出すしかできなくて、
イベント自体を作るのかみたいな気持ちになりながら厳しいっていう気持ちになってたりもしたので、
拡張性ってありがたいなってすごい思います。
自分で実装したくないなって思いながら。
そうなんだよな。
柔軟性の安全性とトレーサビリティ
あとはイミュータブルの話とかがあったりして、
拡張される側として本当に安全なのかとか、
注入する側として、
お任せした先で変な副作用を持って帰ってこないよねみたいな話を意識しておかないと、
その柔軟性っていうのに振り回されすぎるよねっていう話でイミュータビリティとか出てきてますからね。
さっき言った、リスナーの話とかでも、
インジェクションされた処理の中で例外吐かれたら君はどうするみたいなことが書いてあったり、
じゃあ全部安全にしてからイミュータブルにしようぜって言ってると、
なんかメモリ馬鹿食いしたりするけど大丈夫かいとか、
そもそも算数をされた先の書き換えはなんか拒否できないみたいな、
ザブにせよPHPにせよJSのコンストにせよあると思うんで、
そこら辺の意味で本当の意味でのイミュータブルへの履き違いでと言いたい意味もいるよねとか。
いろいろありますね。
コンストラクターが1回しか読めないって思っていたらそうじゃない言語もありますからね。
よう見つけてきたなって思いましたね本当に。
この辺はね、いくらでも喋れそうだなやっぱり。
まとめとか見ると複雑性はコードとメンテナンスだけではなく、
システムのその他の部分にも発生しますっていうのが、
さっき言ってたね、結局外に押し付けてるだけとか目の届かないところに追いやってるだけかもしれないんで、
みたいなところまで意識してそのトレードオフっていうのを決定していかなくちゃいけんよねっていうのがちょっと思うところですかね。
ただ多くの場合においては拡張性がなくて辛いなっていうコードの方がよく見る気がするんで。
多少ちょっとやりすぎなくらい拡張性をやってみて、そこから良いところに落とすところに持ってってくれる方がいいかなって思うことが多いなって個人的な感覚としてはありますね。
サービスロケーターと柔軟性の設計判断
そこら辺は本当に学んでいくというかチームでコツを合わせていくしかないですもんね。
最初は多分ニューなんとかなんとかサービスとかで書かれて、そこは少なくともちょっとリアにしましょうよとかいうところから始まっていきみたいな。
ここどこをどうやってする?
じゃあわかりました、このリアコンテナのインスタンスをどこからでも取り出せるようにします。
ララベルで言うとアップメイクって書いてそこにクラス名を書けばなんと引数も渡せるんですみたいな配列で引数を渡してコンストラクターに渡せるんですかって言われて、
いや違うそうじゃないんだよなみたいなことを読みながらサービスロケーター。
サービスロケーター召喚師みたいになっちゃうんだよね。
っていうのをだんだん疎結合にしながら、じゃあ全部ガチャガチャガチャっとどっかで、
いや全部ファクトリーメソッド一気に出してやるんで、ファクトリーの先見たらいろんなものはガチャガチャガチャって入れられて、
結局これ何が出来上がるんですかね、びっくりメカが出来上がりますみたいなことになるとそれはそれでやっぱ大変だし。
ニューをインスタンスニューしてコンストラクトしてるとかサービスロケーターを使ってるから悪いっていうんじゃなくて、
オブジェクトの性質とか性格っていうのに沿っていろいろ組み合わせようねみたいな話ですからね。
ニューが悪いですって言われて、じゃあ全部スタティックにしますって言われたらそれはそれは困るわけだし。
すごい便利。
どこから読み出して便利ってなるけど、例えばロガーみたいなものはもしかしたらスタティックに読み出したいパターンもあるかもしれないし、
ファサード経由だったりすることはララベルだったらあるかもしれないけど、スタティックと同等に扱いたいみたいなケースもあったりすると思うんで、
ある種単純なコンストだったら別にスタティックに読んでもいいだろうしとか、
なのでやっぱり何をどこに柔軟性を持たせる必要があるかとかどういう問題を解きたいかということを考えながら、
ここは変更が入りそうだから拡張性を持たせておこうとかいうようなことを経験しながらどんどん手札を増やしていくみたいなことができるといいですよね。
そうですね。ここら辺は本当に経験積みましょう、要はバランスレスになってはしまう。
そうですね。いろんなものを経験しましょうということしか言えないからな。
じゃあそんな感じでまた次のトピック行きますか。
行きますか。
俺最初にここら辺を触れようかって言ってたのにあれ。
コメント
スクロール