技術
BEAR.Sundayの特徴的な技術と機能を以下の章に分けて解説します。
アーキテクチャと設計原則
リソース指向アーキテクチャ (ROA)
BEAR.Sunday のROAは、Web アプリケーション内でRESTful APIを実現するアーキテクチャです。これはBEAR.Sundayの設計原則の核となるものであり、ハイパーメディアフレームワークであると同時にサービスとしてのオブジェクト(Object as a service)として扱います。Webと同様に、全てのデータや機能をリソースとみなし、GET、POST、PUT、DELETEなどの標準化されたインターフェースを通じて操作します。
URI
URI(Uniform Resource Identifier)はWebの成功の鍵となる要素であり、BEAR.SundayのROAの中核でもあります。アプリケーションが扱うすべてのリソースにURIを割り当てることで、リソースを識別し、アクセスしやすくなります。 URIは、リソースの識別子として機能するだけでなく、リソース間のリンクを表現するためにも使用されます。
ユニフォームインターフェース
リソースへのアクセスはHTTPのメソッド(GET, POST, PUT, DELETE)を用いて行われます。これらのメソッドはリソースに対して実行できる操作を規定しており、リソースの種類に関わらず共通のインターフェースを提供します。
ハイパーメディア
BEAR.Sunday のリソース指向アーキテクチャ (ROA) では、各リソースがハイパーリンクを通じてアフォーダンス(クライアントが利用可能な操作や機能)を提供します。これらのリンクは、クライアントが利用できる操作を表し、アプリケーション内をナビゲートする方法を指示します。
状態と表現の分離
BEAR.SundayのROAでは、リソースの状態とそのリソース表現が明確に分離されています。リソースの状態はリソースクラスで管理され、リソースにインジェクトされたレンダラーが様々な形式(JSON, HTMLなど)でリソースの状態をリソース状態表現で変換します。ドメインロジックとプレゼンテーションロジックは疎結合で、同じコードでもコンテキストによって状態表現の束縛を変更すると表現も変わります。
MVCとの相違点
BEAR.SundayのROA(リソース指向アーキテクチャ)は、従来のMVCアーキテクチャとは異なるアプローチを採用しています。 MVCはモデル、ビュー、コントローラーの3つのコンポーネントでアプリケーションを構成し、コントローラーはリクエストオブジェクトを受け取り、一連の処理を制御してレスポンスを返します。一方、リソースはリクエストメソッドにおいて、単一責任原則(SRP)に従い、リソースの状態の指定のみを行い、表現には関与しません。
MVCではコントローラーとモデルの関係に制約はありませんが、リソースはハイパーリンクとURIを使用した他のリソースを含める明示的な制約があります。これにより、呼び出されるリソースの情報隠蔽を維持しながら、宣言的な方法でコンテンツの内包関係とツリー構造を定義できます。
MVCのコントローラーはリクエストオブジェクトから手動で値を取得しますが、リソースは必要な変数をリクエストメソッドの引数として宣言的に定義します。そのため、入力バリデーションもJsonSchemaを使用して宣言的に実行され、引数とその制約がドキュメント化されます。
依存性の注入 (DI)
依存性の注入 (Dependency Injection, DI) は、オブジェクト指向プログラミングにおけるアプリケーションの設計と構造を強化するための重要な手法です。DIの中心的な目的は、アプリケーションの機能を複数の独立したドメインまたは役割を持つコンポーネントに分割し、それらの間の依存関係を管理することです。
DIは、1つの機能(関心事、責務)を複数の機能に水平分割するのに役立ちます。分割された機能は「依存」として各部分を独立して開発、テストができるようになります。単一責任原則に基づき明確な責任と役割を持つそれらの依存を外部から注入することで、オブジェクトの再利用性とテスト性を向上させます。また依存は他の依存へと垂直でも分割され、依存関係のツリーを形成します。
BEAR.SundayのDIはRay.Diという独立したパッケージを使用しており、Google社製のDIフレームワークであるGuiceの設計思想を取り入れ、ほぼすべての機能をカバーしています。
その他に以下の特徴があります。
- コンテキストにより束縛を変え、テスト時に異なる実装を注入することができます。
- アトリビュートによる設定でコードの自己記述性が高まります。
- Ray.Diはコンパイル時に依存性の解決を行うため、ランタイム時のパフォーマンスが向上します。これは、ランタイム時に依存性を解決する他のDIコンテナとは異なる点です。
- オブジェクトの依存関係をグラフで可視化できます。例)ルートオブジェクト
アスペクト指向プログラミング (AOP)
アスペクト指向プログラミング(AOP)は、ビジネスロジックなどの本質的な関心と、ログやキャッシュなどの横断的関心を分離することで、柔軟なアプリケーションを実現するパターンです。横断的関心とは、複数のモジュールやレイヤーにまたがって存在する機能や処理のことを指します。探索条件に基づいた横断的処理の束縛が可能で、コンテキストに基づいた柔軟な構成が可能です。
BEAR.SundayのAOPはRay.Aopという独立したパッケージを使用しており、PHPのアトリビュートをクラスやメソッドに付与して、横断的処理を宣言的に束縛します。Ray.Aopは、JavaのAOP Allianceに準拠しています。
AOPは「既存の秩序を壊す強い力」と誤解されがちな技術です。その存在意義は制約を超えた力の行使などではなく、マッチャーを使った探索的な機能の割り当てや横断的処理の分離などオブジェクト指向が不得意とする分野の補完にあります。AOPはアプリケーションの横断的な制約を作ることのできる、つまりアプリケーションフレームワークとして機能するパラダイムです。
パフォーマンスとスケーラビリティ
モダンCDNとの統合によるROAベースのイベントドリブンコンテンツ戦略
BEAR.Sundayは、リソース指向アーキテクチャ(ROA)を中核として、Fastlyなどのインスタントパージ可能なCDNと統合することで、高度なイベントドリブンキャッシュ戦略を実現しています。この戦略では、従来のTTL(Time to Live)によるキャッシュの無効化ではなく、リソースの状態変更イベントに応じてCDNとサーバーサイドのキャッシュ、およびETag(エンティティタグ)を即座に無効化します。
このようにCDNに揮発性のない永続的なコンテンツを作るというアプローチにより、SPOF(Single Point of Failure)を回避し、高い可用性と耐障害性を実現するだけでなく、ユーザー体験とコスト効率を最大化させ、ダイナミックコンテンツでもスタティックコンテンツと同じWeb本来の分散キャッシングを実現します。Webが1990年代から持っていたスケーラブルでネットワークコストも削減する分散キャッシュという原則を、現代的な技術で再実現しているのです。
セマンティックメソッドと依存によるキャッシュ無効化
BEAR.SundayのROAでは、各リソース操作にセマンティック(意味的な役割)が与えられています。例えば、GET メソッドはリソースを取得し、PUT メソッドはリソースを更新します。これらのメソッドがイベントドリブン方式で連携し、関連するキャッシュを効率的に無効化します。たとえば、特定のリソースが更新された際には、そのリソースを必要とするリソースのキャッシュが無効化されます。これにより、データの一貫性と新鮮さが保たれ、ユーザーに最新の情報が提供されます。
ETagによる同一性確認と高速な応答
システムがブートする前にETagを設定することで、コンテンツの同一性を迅速に確認し、変更がなければ304 Not Modified応答を返しネットワークの負荷を最小化します。
ドーナッツキャッシュとESIによる部分的な更新
BEAR.Sundayでは、ドーナッツキャッシュ戦略を採用しており、ESI(Edge Side Includes)を使用してCDNエッジで部分的なコンテンツ更新を可能にしています。この技術により、ページ全体を再キャッシュすることなく、必要な部分だけを動的に更新しキャッシュ効率を向上させます。
このように、BEAR.SundayとFastlyの統合によるROAベースのキャッシュ戦略は、高度な分散キャッシングの実現とともに、アプリケーションのパフォーマンス向上と耐障害性の強化を実現しています。
起動の高速化
DIの本来の世界では、ユーザーは可能な限りインジェクター(DIコンテナ)を直接扱いません。その代わり、アプリケーションのエントリーポイントで1つのルートオブジェクトを生成してアプリケーションを起動します。BEAR.SundayのDIでは、設定時でもDIコンテナの操作が実質存在しません。ルートオブジェクトは巨大ですが1つの変数なのでリクエストを超えて再利用され極限まで最適化したブートストラップを実現します。
開発者エクスペリエンス
テストの容易性
BEAR.Sundayは、以下の設計上の特徴により、テストが容易で効果的に行えます。
- 各リソースは独立していて、RESTのステートレスリクエストの性質によりテストは容易です。 リソースの状態と表現が明確に分離されているため、HTML表現の時でもリソースの状態をテストすることが可能です。
- ハイパーメディアのリンクをたどりながらAPIのテストを行え、PHPとHTTPの同一コードでテストできます。
- コンテキストによる束縛により、テスト時に異なる実装を束縛します。
APIドキュメント生成
コードからAPIドキュメントを自動生成します。コードとドキュメントの整合性を保ち、保守性を高めます。
視覚化とデバッグ
リソースが自身でレンダリングする技術的特徴を生かし、開発時にHTML上でリソースの範囲を示し、リソース状態をモニターする事や、PHPコードやHTMLテンプレートをオンラインエディターで編集し、リアルタイムに反映することもできます。
拡張性と統合
PHPインターフェイスとSQL実行の統合
BEAR.SundayではPHPのインターフェイスを通じて、データベースとのやり取りを行うSQL文の実行を簡単に管理できます。クラスを実装することなく、PHPインターフェイスに直接SQLの実行オブジェクトを束縛することが可能です。ドメインとインフラストラクチャーの境界をPHPインターフェイスで繋ぎます。
その際引数には型も指定でき、不足している分はDIが依存解決を行い文字列として利用されます。SQL実行に現在時刻が必要な時でも渡す必要はなく、自動束縛されます。クライアントが全ての引数を渡す責任がなく、コードの簡潔さを保つのに役立ちます。
またSQLの直接管理は、エラー発生時のデバッグを容易にします。SQLクエリの動作を直接観察し、問題の特定と修正を迅速に行うことができます。
他システムとの統合
コンソールアプリケーションと統合し、ソースコードを変えずにWebとコマンドライン双方からアクセス可能にします。また 同一PHPランタイム内で異なるBEAR.Sundayアプリケーションを並行実行できることでマイクロサービスを構築する事なく独立した複数のアプリケーションを連携させることができます。
ストリーム出力
リソースのボディにファイルのポインタなどのストリームをアサインすることで、メモリ上では扱えない大規模なコンテンツを出力できます。その際、ストリームは通常の実変数と混在させることも可能で大規模なレスポンスを柔軟に出力できます。
他のシステムからの段階的移行
BEAR.Sundayは段階的な移行パスを提供し、LaravelやSymfonyなどの他のフレームワークやシステムとのシームレスな統合を可能にします。このフレームワークは、Composerパッケージとして実装できるため、開発者は既存のコードベースにBEAR.Sundayの機能を段階的に導入できます。
技術移行の柔軟性
BEAR.Sunday は、将来の技術的変化や要件の進化に備えて投資を保護します。このフレームワークから別のフレームワークや言語に移行する必要がある場合でも、構築したリソースは無駄になりません。 PHP環境では、BEAR.SundayアプリケーションをComposerパッケージとして統合して継続的に利用できますし、BEAR.Thriftを使用すると、他の言語からBEAR.Sundayリソースに効率的にアクセスできます。Thriftを使用しない時でもHTTPでアクセスが可能です。またSQLコードの再利用も容易です。
たとえ使用しているライブラリが特定のPHPバージョンに強く依存している場合でもBEAR.Thriftを使って異なるバージョンのPHPを共存することができます。
設計思想と品質
標準技術の採用と独自規格の排除
BEAR.Sunday は、可能な限り標準技術を採用し、フレームワーク独自の規格やルールを排除するという設計思想を持っています。 例えば、デフォルトでJSON形式とwwwフォーム形式のHTTPリクエストのコンテントネゴシエーションではサポートし、エラーレスポンスにはvnd.error+jsonメディアタイプ形式を使用します。リソース間のリンクにはHAL(Hypertext Application Language)を採用し、バリデーションにはJsonSchemaを用いるなど、標準的な技術や仕様を積極的に取り入れています。
一方で、独自のバリデーションルールや、フレームワーク特有の規格・ルールは可能な限り排除しています。
オブジェクト指向原則
BEAR.Sundayはアプリケーションを長期的にメンテナンス可能すとするためのオブジェクト指向原則を重視しています。
継承より合成
継承クラスよりコンポジションを推奨します。一般に子クラスから親クラスのメソッドを直接呼び出すことは、クラス間の結合度を高くする可能性があります。設計上ランタイムで継承が必要な抽象クラスはリソースクラスのBEAR\Resource\ResourceObject
のみですが、これもResourceObjectのメソッドは他のクラスが利用するためだけに存在します。ユーザーが継承したフレームワークの親クラスのメソッドをランタイムに呼び出すことはBEAR.Sundayではどのクラスにもありません。
全てがインジェクション
フレームワークのクラスが「設定ファイル」や「デバッグ定数」を実行中に参照して振る舞いを決定する事はありません。振る舞いに応じた依存が注入されます。これにより、アプリケーションの振る舞いを変更するためには、コードを変更する必要がなく、インターフェイスに対する依存性の実装の束縛を変更するだけで済みます。APP_DEBUGやAPP_MODE定数は存在しません。ソフトウエアが起動した後に現在どのモードで動いているか知る方法はありませんし、知る必要もありません。
後方互換性の永続的確保
BEAR.Sundayは、ソフトウェアの進化において後方互換性の維持を重視して設計されており、リリース以来、後方互換性を破壊することなく進化を続けています。現代のソフトウェア開発では、頻繁な後方互換性の破壊と、それに伴う改修やテストの負担が課題となっていますが、BEAR.Sundayはこの問題を回避してきました。
BEAR.Sunday では、セマンティックバージョニングを採用するだけでなく破壊を伴うメジャーバージョンアップを行いません。新しい機能の追加や既存機能の変更が既存のコードに影響を与えることを防いでいます。古くなって使われなくなったコードは「deprecated」の属性が与えられますが、削除されることはなく、既存のコードの動作にも影響を与えません。代わりに、新しい機能が追加され、進化が続けられます。
非環式依存原則
非環式依存原則(ADP)とは、依存関係が一方向であり、循環していないことを意味します。BEAR.Sundayフレームワークはこの原則に基づき、一連のパッケージで構成されており、大きなフレームワークパッケージが小さなフレームワークパッケージに依存する階層構造をしています。各レベルはそれを包含する他のレベルの存在自体を知る必要はなく、依存関係は一方向のみで循環しません。例えば、Ray.AopはRay.Diの存在すら知りませんし、Ray.DiはBEAR.Sundayの存在を知りません。
後方互換性が保持されているため、各パッケージは独立して更新が可能です。また、他のフレームワークで見られるような全体をロックするバージョン番号は存在せず、オブジェクト間を横断する依存関係を持つオブジェクトプロキシーの機構もありません。
この非環式依存原則はDI(依存性注入)の原則と調和していて、BEAR.Sundayが起動する際に生成されるルートオブジェクトも、この非環式依存原則の構造に従って構築されています。
ランタイムも同様です。リソースにアクセスが行われる際、まずメソッドに結びつけられたAOPアスペクトの横断的な処理が行われ、その後でメソッドがリソースの状態を決定しますが、この時点でメソッドは結びつけられたアスペクトの存在を認識していません。リソースの状態に埋め込まれたリソースも同じです。それらは外側の層や要素の知識を持っていません。 関心の分離が明確にされています。
コード品質
高いコード品質のアプリケーションを提供するためにBEAR.Sundayフレームワークも高い水準でコード品質を維持するよう努めています。
- フレームワークのコードは静的解析ツールのPsalmとPHPStan双方で最も厳しいレベルで適用しています。
- テストカバレッジ100%を保っていて、タイプカバレッジもほぼ100%です。
- 原則的にイミュータブルなシステムであり、テストでも毎回初期化が不要なほどクリーンです。SwooleのようなPHPの非同期通信エンジンの力を引き出します。
BEAR.Sundayのもたらす価値
開発者にとっての価値
- 生産性の向上:堅牢な設計パターンと原則に基づき時間が経っても変わらない制約で、開発者はコアなビジネスロジックに集中できます。
- チームでの協業:開発チームに一貫性のあるガイドラインと構造を提供することで、異なるエンジニアたちのコードを疎結合のまま統一的に保ち、コードの可読性とメンテナンス性を向上します。
- 柔軟性と拡張性:BEAR.Sundayのライブラリを含まない方針は、開発者にコンポーネントの選択における柔軟性と自由をもたらします。
- テスト容易性:BEAR.Sunday の DI(依存性の注入)と ROA(リソース指向アーキテクチャ)がテスト容易性を高めます。
ユーザーにとっての価値
- 高いパフォーマンス:BEAR.Sundayの最適化された高速起動とCDNを中心としたキャッシュ戦略はユーザーに高速で応答性の高いエクスペリエンスをもたらします。
- 信頼性と可用性:BEAR.SundayのCDNを中心としたキャッシュ戦略は、単一障害点(SPOF)を最小化し、ユーザーは安定したサービスを享受できます。
- 使いやすさ:BEAR.Sundayの優れた接続性は他の言語やシステムと協調することを容易にします。
ビジネスにとっての価値
- 開発コストの削減:BEAR.Sundayが提供する一貫性のあるガイドラインと構造は、持続的で効率的な開発プロセスを促進し開発コストを削減します。
- 維持コストの削減:BEAR.Sundayの後方互換性を維持するアプローチは、技術的継続性を高め、変更対応の時間とコストを最小限に抑えます。
- 高い拡張性:BEAR.Sunday のコードの変更を最小限に抑えつつ振る舞いを変えるDI(依存性の注入)やAOP(アスペクト指向プログラミング)といった技術で、ビジネスの成長や変化に合わせながらアプリケーションを容易に拡張できます。
- 優れたユーザーエクスペリエンス(UX):BEAR.Sunday は高いパフォーマンスと高い可用性を提供することで、ユーザーの満足度を高め、顧客ロイヤリティの向上、顧客基盤の拡大、ビジネスの成功に貢献します。
優れた制約は変わりません。BEAR.Sundayがもたらす制約は、開発者、ユーザー、ビジネスのそれぞれに具体的な価値を提供します。
BEAR.Sundayは、Webの原則と精神に基づいて設計されたフレームワークであり、開発者に明確な制約を提供することで、柔軟で堅牢なアプリケーションを構築する力を与えます。