
私が約1年前に書いた記事の続きを書くことにしたのは次の質問を受けたからです。
Q:PHP MVCフレームワークについて近況を教えてください。(2017/2/24)
A:PHPのフレームワークといえば、現時点ではLaravelとSymfonyに尽きます。これから新しいプロジェクトを始めるなら、わざわざCakePHP、Zend、CodeIgniter、Yiiなどを使う理由は見当たりません。これらのフレームワークを使い慣れているか開発経験のある開発者がいないのなら、使う理由はないでしょう。
実際に開発が始まったら、ツールやプラグインを集めたり、よくある問題への対処方法を調べたりする必要があります。LaravelとSymfonyはコミュニティーがあり、新「モジュール」や機能がどんどん開発されているので孤立していると感じることはありません。Laracastsだけでも(Laravelで開発していなかったとしても)、すばらしいものです。
iron.ioやほかのSaaSなどのサービス、さまざまなデータソースのサポート、Homesteadのようなローカル開発環境との統合を考えても、これらのフレームワークとサポートされているモジュールは大きく先行しています。
「手軽にAPIを開発できる」とLumenがコメントしているように、アプリケーションの高速開発とプロトタイピングの最新の手段として、Laravelはとても注目されています。大規模アプリケーションを開発するときは、少し制限があるかもしれません。
開発スタイルは一般的にコンテナ・ベースアーキテクチャーへ向かっており、MVCの役割は縮小しています。これからはマイクロサービス、オーケストレーション、アプリの「function」化 (例:AWS Lambdaのようなサービス)です。Node.jsやGo言語のスキルが求められる時代なのかもしれません。
この回答に不満はないものの何点か補足すると同時に、あらためて最新の状況を確認したいと思いました。
「Go言語」のような変わり種に飛びつく前に、一歩引いてPHP MVCフレームワークの世界のトレンドを下の図で、2017年の傾向を俯瞰してみます。
2017年も、これまでのトレンドが継続していることが分かります。Laravelが伸び続けている一方、残りはほとんど右肩下がりです。Symfonyの人気がわずかに上がっていますが、これは待望のSymfony 3がリリースされたためでしょう。「CakePHP 3」や「ZF2」のようにより対象を限定した検索もしてみましたが、統計的に有意なトレンドは見出せませんでした。
人気が明白なCodeIgniterも含めました。PHP MVCコミュニティーの中におけるCodeIgniterの立ち位置に関する質問をたくさん受けたからです。端的に言うと、真のMVCフレームワークでないCIはいまだに遅れをとっています。POPO(Plain Old PHP Object)をより集めたものとしか呼べません。
以下はCIのドキュメントから抜粋しました。
CodeIgniterではModelが必須でないので、MVCに厳密に沿おうとはしていません。分離する必要がなかったりモジュールのメンテナンスが複雑になるなら、無視して最小構成のアプリをControllerとViewで開発できます。
フレームワークの開発という観点からは、この方針には賛同できません。CodeIgniterの人気を考えると、これはまっとうなボイラープレートなのでしょうが、フレームワークが定めるなんらかの規則がないと、できあがるプロダクトはある種の「パターン」で味付けされたスパゲッティーコードのかたまりになってしまいます。
SymfonyはSymfony 3になって、開発のしやすさや依存項目の挿入、それ以外の多くの機能が十分使えるまでに改善しました。多くのPHPのフレームワークのようにマイクロフレームワークもあります。ZF3はPHP7のサポート(やっと)やマイクロフレームワークのような前進を見せたものの、ドキュメントにはまだ次のような記載があります。
Zend Framework 2 MVCユーザーにとって差はわずかです。
大きな差があるとドキュメントに書かれて、大幅なアーキテクチャーの改善や最新手法で開発するためのすばらしい新規モジュールがあるという期待は外れました。残念ながらZF3はほぼZF2のままです。
一言でいうと
2017年のPHPフレームワークの世界を私は次のように見ています。
- 必要に応じてSymfonyかLaravel
- それ以外
問題なくLaravelが場をさらっていきました。Laravelには情報量やLaracasts、世界の開発者層、シンプルなパターン実装、統合されたテストツール、Eloquent形式でのアクティブレコード実装、Lumen軽量バージョン、Homestead(Vagrant)を使ったローカル開発があり、初心者にとっても経験者にとっても群を抜いたすぐれたフレームワークです。
しかし、Eloquentモジュールは乱雑になったりサイズが大きくなったりしがちで、過剰なLaravelサービス(マイクロサービスではありません)が作成され、Laravelには関連しないRepositoryパターンの実装について考え始める人も出てきます。そこでモノリスが生まれました。
アクティブレコードパターンを好きになれずRepositoryの柔軟性を求めていたり、匿名関数の数が多すぎると感じていたりするなら、Symfony+Doctrineを使ってください。私はSymfonyがモノリシックなアプリケーションの入り口になるとは思いますが、Symfonyはもっとも優雅なものに位置づけられるでしょう。
全体として確かに昨年から劇的に変わっているとは思いませんが、より大きな視点で見る必要があります。適切にデザインされたアプリケーションは単なるMVCを超え、インフラ、デプロイパイプライン、デカップルドアーキテクチャーにおよびます。これらはすべてMVCスタックで実現できますが、モノリスを避けるよう細心の注意を払う必要があります。
マイクロサービスの登場
先ほど私はマイクロサービスの興隆に触れて、Go言語やNodeのスキルを磨くべきだと述べました。
実際のところPHP MVCに関する記事でも、マイクロサービス指向アーキテクチャー(MOA)へ向かう流れが否定しがたく、起きていることに触れない訳にはいかないでしょう。その流れは想像以上に勢いを増しています。
この2つのコンセプトは相反しませんが、交差はするものの異なる哲学から生まれてくるので、両者の類似点を探す意味はありません。
このように、MVCアプリとMySQLを別々のコンテナに入れてリンクすることは適切なMOAとはい言えません。とはいえ、MAMPやXAMPPなど、ローカルマシンでアプリケーションを動かすのに必要なものをインストールして環境を散らかすよりは、ずっとましなアプローチです。
加えて、異なるプラットホーム(開発者)やデプロイ戦略をい用いる場合のローカル環境負荷を軽減できるかもしれませんが、アプリのレイヤー/コンテナでのMVCモノリスは回避できません。
モノリスを破壊する
この「破壊」こそマイクロサービスが存在する意義です。
MVCは、関心を分離する堅固なアプローチを提供することでコードの構造と組織に働きかけるものの、このコンセプトはコンテナ/サービス/MOAにより拡張されます。
視点とモデルを分離する代わりに、各「かたまり」、すなわちアプリケーションの論理単位を、与えられた役割を適切に果たすようにデザインされた個別のサービスへと分離します。
たとえば、MVCアプリに「検索」コントローラー、実行、そして関連するモデルメソッドがあるなら、モノリシックアプリケーションができあがります。
それに対して、MOAアプローチでは次のように、1つ1つの処理単位に対してサービスを作ります。
- ルーターサービス(Router Service)
- リクエストサービス(Request Service)
- クエリサービス(Query Service)
- データソースサービス(DataSource Service)
- レスポンスサービス(Response Service)
ただし、これらの「サービス」がMVCスタックの一部にすぎないことに注意してください。これが積みあがってモノリスができます。
MOAならそれぞれのサービスが固有の環境で実行されるので、開発者として、さらにはアーキテクトとして、個別のニーズを解決するのに最適なアプローチを自由にデザインできます。
一例として、画像処理サービスをLaravel環境で書くとすると、画像処理の効率が低下するとしてもPHP-GD2 拡張機能のようなものを使うと思います。C++で書いた画像処理サービスのほうがはるかに高速でスケールアップに強いでしょう。さらに言うなら、画像処理サービスからの出力をデータストアサービスやクラウドストレージサービス、キューEmailサービスに送れます。
この問題をcron jobやもしかしたら個別のMVCアプリとカスタムスクリプトで解決していたのは過去(2年前)のことです。新しい解決方法を模索すべきです。
スケーラビリティ
問題はここで起こります(目的によってはここで終わります)。一方では、モノリスの規模拡大は難しく、同じMVCスタックにロジックをどんどん詰め込むと、きれいに構造化されているものの恐ろしく複雑なアプリができあがるでしょう。
他方では、多くの言語でたくさんのマイクロサービスを構築するなら、山のようなサービスをどのように管理するのでしょうか?
いろいろなコンテナ管理ツール(例:Kubernetes、Swarm、Mesos)や、コンテナ開発サービス(例:GKE、AWS ECS)がありますが、Dockerアーキテクチャーを上回るものはほとんどありません。Dockerなどのコンテナテクノロジー(例:GKE)を使わず開発を成功させた例は確かにあります。しかし、ほとんどはアーキテクト、開発者、DBA、エンジニアにリソースを費やす体力がある会社の事例です。しかし、適切に管理された美しいMOAをデプロイする方法については活発に議論されています。1つの方法がすべてに当てはまることはなく、この問題を解決する方法は複数あるはずです。
いずれにせよ、この問題に1人で取り組むことはなく(ここでこそDevOpsです!)、そもそもこの問題が生じるのは比較的巨大なスケールにまで拡大したときです。あれこれと策を講じるのは時期尚早かもしれません。
取りあえずの中間点、それほど複雑でないアプリやトラフィック要件が低いアプリの開発者にとっては、多くの典型的なサービスをサードパーティーに委ねることです。現在はほぼすべてがサービスとして提供されています。バックグラウンドジョブ、画像処理、認証、データ分析、ログ管理、email送信やキューシステムを、同じMVCスタック内に作りこむ必要はなく、アーキテクトとして月会費が安いSaaSシステム(例:Algoliaの検索)や、苛立たしい画像処理を扱うクラウドで稼働するカスタムビルドのdockerサービスに、なにを委託できるかを考えるべきでしょう。
大切なのは、はじめからアーキテクチャーを再構築するプロジェクトにしないことと、いまあるものすべてを捨て去ってdocker swarmを考えうるすべての場所にばらまかないことです。可能なものをデカップリングし、システムのボトルネックを学び、関心を分離する考え方をこの問題に適用させることで、少しずつ土台を改善できるでしょう。
最後に
2017年はコンテナベースとMOAに関する新しい話題と本番環境デプロイが見られるでしょう。この記事で私がDockerや、Go言語やNodeの使用についてたくさん書いたからと言って、PHPが廃れつつあるなどということはありません。開発者として最先端に立ち続けるべきで、もしマイクロサービスが最先端なら、Go言語を習得するのが良いと思います。Go言語はコンテナ化された小規模アプリの開発に最適(省メモリー、スピード、並列処理のため)です。NodeとGo言語は、小さいサービスを開発して、リンクし合うことで大きなサービスを形成するので、やろうと思えばDockerコンテナの巨大なswarmとしてリリースできるという、おもしろい技術です。
ただし、このようなすばらしい最先端のソリューションや言語があるからと言って、PHPが関係なかったり廃れた訳ではありません。MVCスタックやAPIエンドポイントの開発は当面の間は続くでしょう。
MOAで解決できていない問題の1つは、コンテナを活用すればバックエンドのモノリスを退治できるものの、フロントエンド、UI、ビューでは多くのアーキテクチャーの問題が残されていることです。
どのようなに堅牢なバックエンドアプリケーションを構築しても、最終的にはJSONで応答し、クライアントアプリケーションでレンダリングする必要があります。最終的なレスポンスオブジェクトがシンプルなPHPから送られるか、Lumenで動くエンドポイント(URL)から送られるか、メッセージインターフェイスから切り離された意思決定と処理のユニットのオーケストラから送られるかで、なにか変わるのでしょうか?実現したいこととアプリケーションの要件次第です。
今年はLaravelを学び、DockerとGo言語から目を離さず、もちろんデプロイパイプラインに注目するのが良いでしょう。特にMVCアプリを構築するときにはローカルからプロダクションにこれまでになくスムーズに移行できるようになるでしょう。
※この記事ははじめにZenOfCodingで公開され、著者の許可を得てここに再掲しました。
(原文:The State of PHP MVC Frameworks in 2017)
[翻訳:内藤夏樹/編集:Livit]
