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
自分たちのコードを Composer パッケージに分割して開発する
Search
Shohei Okada
May 29, 2021
Programming
0
220
自分たちのコードを Composer パッケージに分割して開発する
PHP カンファレンス沖縄 2021
Shohei Okada
May 29, 2021
Tweet
Share
More Decks by Shohei Okada
See All by Shohei Okada
たった 1 枚の PHP ファイルで実装する MCP サーバ / MCP Server with Vanilla PHP
okashoi
1
220
どうして手を動かすよりもチーム内のコードレビューを優先するべきなのか
okashoi
3
1.4k
パスワードのハッシュ、ソルトってなに? - What is hash and salt for password?
okashoi
3
210
設計の考え方 - インターフェースと腐敗防止層編 #phpconfuk / Interface and Anti Corruption Layer
okashoi
11
3.8k
"config" ってなんだ? / What is "config"?
okashoi
0
1.2k
ファイル先頭の use の意味、説明できますか? 〜PHP の namespace と autoloading の関係を正しく理解しよう〜 / namespace and autoloading in php
okashoi
4
1.6k
MySQL のインデックスの種類をおさらいしよう! / overviewing indexes in MySQL
okashoi
0
890
PHP における静的解析(あるいはそもそも静的解析とは) / #phpcondo_yasai static analysis for PHP
okashoi
1
610
【PHPカンファレンス沖縄 2023】素朴で考慮漏れのある PHP コードをテストコードとともに補強していく(ライブコーディング補足資料) / #phpcon_okinawa 2023 livecoding supplementary material
okashoi
3
1.9k
Other Decks in Programming
See All in Programming
技術同人誌をMCP Serverにしてみた
74th
1
510
なぜ「共通化」を考え、失敗を繰り返すのか
rinchoku
1
620
Is Xcode slowly dying out in 2025?
uetyo
1
240
Select API from Kotlin Coroutine
jmatsu
1
210
来たるべき 8.0 に備えて React 19 新機能と React Router 固有機能の取捨選択とすり合わせを考える
oukayuka
2
880
20250704_教育事業におけるアジャイルなデータ基盤構築
hanon52_
4
240
Google Agent Development Kit でLINE Botを作ってみた
ymd65536
2
210
AWS CDKの推しポイント 〜CloudFormationと比較してみた〜
akihisaikeda
3
320
WindowInsetsだってテストしたい
ryunen344
1
220
“いい感じ“な定量評価を求めて - Four Keysとアウトカムの間の探求 -
nealle
0
470
Result型で“失敗”を型にするPHPコードの書き方
kajitack
4
560
XP, Testing and ninja testing
m_seki
3
220
Featured
See All Featured
Automating Front-end Workflow
addyosmani
1370
200k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
15
1.5k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
17
950
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
26
2.9k
Optimising Largest Contentful Paint
csswizardry
37
3.3k
Designing for humans not robots
tammielis
253
25k
Unsuck your backbone
ammeep
671
58k
Raft: Consensus for Rubyists
vanstee
140
7k
Building Applications with DynamoDB
mza
95
6.5k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
29
9.5k
4 Signs Your Business is Dying
shpigford
184
22k
Code Review Best Practice
trishagee
69
18k
Transcript
自分たちのコードを Composer パッケージに 分割して開発する 2021/05/29 PHP カンファレンス沖縄 2021 @okashoi
岡田 正平/おかしょい Twitter: @okashoi GitHub: @okashoi 所属:株式会社ウィルゲート 登壇:
寄稿:
目次 • 導入(問題提起、提案) • ローカルのディレクトリを Composer パッケージとして扱う方法 • パッケージを分割する際の考え方 •
こぼれ話
目次 • 導入(問題提起、提案) • ローカルのディレクトリを Composer パッケージとして扱う方法 • パッケージを分割する際の考え方 •
こぼれ話
開発についてまわる問題 何も意識せずにフレームワークを使って開発していると 巨大なひとつの構造物となっていく 結果、次のような状態を引き起こしやすい • Controller に書き下される一連の詳細な処理 • 責任の境界が曖昧なクラス
• あちらこちらに出てくる同じような手順 • フレームワークの機能に過度に依存したコード → 可読性や再利用性の低下、バグの原因
ソフトウェア設計の領域において古くから存在する 「モジュール化」というアプローチ →しかし PHP は言語機能としてモジュールに相当するものを備えていない ※「モジュール」という語彙自体は「拡張モジュール」で使われるが別物 モジュール化
PHP における依存関係管理ツール 依存関係を「パッケージ(※)」単位で扱う ※Composer におけるパッケージとは composer.json が存在するディレクトリ
Composer
PHP における依存関係管理ツール 依存関係を「パッケージ(※)」単位で扱う ※Composer におけるパッケージとは composer.json が存在するディレクトリ
Composer 本発表で紹介する方法 Composer パッケージを「モジュール」に近い概念として扱う
目次 • 導入(問題提起、提案) • ローカルのディレクトリを Composer パッケージとして扱う方法 • パッケージを分割する際の考え方 •
こぼれ話
Packagist
Packagist からパッケージを持ってくることだけが選択肢ではない Composer には「リポジトリ」という概念があり、 GitHub のリポジトリやローカルに存在するディレクトリを composer install や
composer require の対象にできる Composer におけるリポジトリ
Packagist からパッケージを持ってくることだけが選択肢ではない Composer には「リポジトリ」という概念があり、 GitHub のリポジトリやローカルに存在するディレクトリを composer install や
composer require の対象にできる Composer におけるリポジトリ 今回はこっち
ローカルのディレクトリを Composer パッケージとして扱う ... ├── apps │ └── my-app │
└── composer.json ├── packages │ └── my-package │ └── composer.json ...
ローカルのディレクトリを Composer パッケージとして扱う ... ├── apps │ └── my-app │
└── composer.json ├── packages │ └── my-package │ └── composer.json ...
ローカルのディレクトリを Composer パッケージとして扱う ... ├── apps │ └── my-app │
└── composer.json ├── packages │ └── my-package │ └── composer.json ...
ローカルのディレクトリを Composer パッケージとして扱う { ... "repositories": [ { "type": "path",
"url": "../../packages/my-package" } ], ... } ... ├── apps │ └── my-app │ └── composer.json ├── packages │ └── my-package │ └── composer.json ...
ローカルのディレクトリを Composer パッケージとして扱う { ... "repositories": [ { "type": "path",
"url": "../../packages/my-package" } ], ... } ... ├── apps │ └── my-app │ └── composer.json ├── packages │ └── my-package │ └── composer.json ...
ローカルのディレクトリを Composer パッケージとして扱う ... ├── apps │ └── my-app │
└── composer.json ├── packages │ └── my-package │ └── composer.json ... $ composer require "my/package:*@dev"
ローカルのディレクトリを Composer パッケージとして扱う ... ├── apps │ └── my-app │
└── composer.json ├── packages │ └── my-package │ └── composer.json ... $ composer require "my/package:*@dev" "name": "my/package"
ローカルのディレクトリを Composer パッケージとして扱う ... ├── apps │ └── my-app │
└── composer.json ├── packages │ └── my-package │ └── composer.json ... apps/my-app/vendor/my/package から packages/my-package へとシンボリックリンクが張られる → Composer の autoload 機能を経由して my-app から my-package を利用できるようになる
Laravel におけるディレクトリ構造の例 ├── app │ ├── ... ... ├── composer.json
... ├── app │ ├── ... ... ├── packages │ └── my-package │ └── composer.json ... ├── composer.json ... ※ “my-package” はあくまで例なので、 適切な名前をつけてあげてください。
後藤知宏, “Laravel Package Development”, Laravel JP Conference 2019, https://speakerdeck.com/mikakane/laravel-package-development 参考資料
目次 • 導入(問題提起、提案) • ローカルのディレクトリを Composer パッケージとして扱う方法 • パッケージを分割する際の考え方 •
こぼれ話
パッケージに切り出す(モジュール化する)こと = インターフェースをデザインすること ポイントは • (特にフレームワークとの)依存関係 • 凝集度と結合度 どうやって分割していくか?
フレームワークに依存している状態 = 「フレームワークのその場所」から動かすのが困難な状態 • コードの再利用性が下がっている • フレームワークのバージョンアップに追従しにくくなる • 長期運用するアプリケーションではフレームワークを乗り換えることも
◦ 過度に依存しているとほぼ書き直しになる 「フレームワークに依存させないこと」の動機
Laravel の例を挙げれば • Illuminate に依存しない(use したり、完全修飾名で利用しない) ◦ extends、implements、引数、戻り値に出てこない • グローバルヘルパ関数や
Class Alias(\Log とか)を使わない これらを取り除いて残るのは、自ずと「自分たち」固有のコードになるはず ※ここでいう「自分たち」とはサービスやビジネス フレームワークに依存していない状態
自分たち固有のコードとは? • 見積もりの計算ロジックかもしれない • マッチングのアルゴリズムかもしれない • データのアクセス権限に関する条件式かもしれない • 税金の計算かもしれない
これら正しく抽出するには開発する対象領域への深い理解が必要 →この過程こそがモデリング 「自分たちのコード」
@77web, “そのコード、フレームワークの外でも動きますか?”, PHPerKaigi20201, https://speakerdeck.com/77web/sofalsekodo-huremuwakufalsewai-demodong-kimasuka 参考資料
モジュールの設計において古くから用いられている尺度 凝集度:責任範囲が明確でそこに集中しているかどうか。高い方が良い。 結合度:モジュール間でのデータの共有度合い。低いほうが良い。 凝集度と結合度
@sonatard, “オブジェクト指向その前に凝集度と結合度”, Object Oriented Conference 2020, https://speakerdeck.com/sonatard/coheision-coupling 参考資料
型情報の上でフレームワークに依存しなくなっても 「見えない依存関係」が存在しているケースがある • 型宣言がない箇所で、フレームワーク固有のクラスを想定している • 関数の呼び出しに暗黙の前提条件が存在している • 型は int や
string だが、その値の意味がフレームワークに特化している ◦ 例)フレームワークで使われるクラス名の文字列 このような実装は「結合度が高い」と言える →そのクラスや関数を使うのに、型から得られる情報以上の知識が 必要になってないかを意識する 見えない依存関係
パッケージに切り出す(モジュール化する)こと = インターフェースをデザインすること ポイントは • (特にフレームワークとの)依存関係 • 凝集度と結合度 どうやって分割していくか?(再掲)
パッケージに切り出す(モジュール化する)こと = インターフェースをデザインすること ポイントは • (特にフレームワークとの)依存関係 • 凝集度と結合度
→いきなり「自分たちのコード」を網羅的に切り出すのは難しい まず、1 つの関数だけでいいので切り出してみよう どうやって分割していくか?(再掲)
「自分たちのコード」を 依存の束縛から解き放とう
目次 • 導入(問題提起、提案) • ローカルのディレクトリを Composer パッケージとして扱う方法 • パッケージを分割する際の考え方 •
こぼれ話
「同一パッケージ内からのみアクセスできるクラス」は定義できない パッケージの詳細を(仕組みとして)隠蔽できないため、運用でカバーする必要があ る PHP のクラスは全て public
ルートパッケージの vendor ディレクトリ内に全ての依存関係が フラットに集約されるため、例えば次のような場合もエラーにならない 依存関係を厳密にチェックできるわけではない ルートパッケージ パッケージ A パッケージ B
ルートパッケージ パッケージ A パッケージ B ▪ composer.json に定義した依存関係 ▪本来依存していないパッケージにアクセスできてしまう パッケージ B からパッケージ A のコードを利用
私はやったことはないが、想定できるのは 🙆 分離することで CI のサイクルが早くなる 🙆 共通のコードを複数のプロジェクトから使える 🙅 運用やデプロイ(ローカル開発環境含む)が複雑になる 🙅
インターフェースの決定や変更について取り決めが必要になる 相当の規模の開発でないか、運用上のノウハウが無い限り デメリットの方が大きい気がする(経験・知見のある方の意見求ム) パッケージごとに Git リポジトリを別にすべきか?
「フレームワークにどこまで依存するのか?」は必ずどこかで線引きが必要 フレームワークに依存しないコードは • フレームワーク側から適切に呼び出すために、 フレームワークの一歩踏み込んだ理解が必要になる • コードの量が増える傾向にある あるいは
Carbon や Guzzle 等のライブラリへの依存も同様 最終的にどこまでやるかは「さじ加減」