本記事はJavaEEのアーキテクチャを再興する。(まとめページ)の一部です。
Javaには歴史があり、Webアプリケーションを作る上でもいろいろな作り方があります。
古くはXMLに大量の設定情報を記述してごちゃごちゃするものから、Webアプリケーションであることを意識せずに作れるもの、いろいろあります。
最近のアーキテクチャを使用すると、スッキリとした構成のWebアプリケーションができます。
本書では、スッキリとした構成のWebアプリケーションのレイヤリングと、そこで使用する技術、ライブラリのマッピングをご紹介します。
Modern Java Web Architectureのレイヤリング
場所 | レイヤ | 説明 |
---|---|---|
Browser | Base Page | 本アプリケーションはSingle Page Single Page Application(SPA)として作成します。これは画面の部品化によりアプリケーションの統一感を保ちながら保守性を担保するためです。 また、SPAとして作成することは重複するデータの通信を削減する効果があるため、サーバの保守代金の低減に寄与します。 |
Template Page | 各ページ中の入れ替わる部分の画面をベース部分とは分けて作成します。Template Pageは一つのBase Pageに対して複数あります。 | |
Helper Plugin | 画面を作成するための部品です。複雑な画面を作る際にはその複雑さを内包し、アプリケーション全体はシンプルな構成に保つために利用します。 | |
View Framework | アプリケーションはいろいろなプラットフォームのBrowserに対応する必要があります。プラットフォームとは、スマートフォンやタブレット、パソコンのことです。このような様々な大きさの画面に対応するためにフレームワークを導入します。 | |
Controller | ユーザが最適にアプリケーションを使うためにはBrowser上でのインタラクションが必要です。Controllerは画面のインタラクションをコントロールし、BrowserとServerの橋渡しを行います。 | |
Network | JSON or Parameter | BrowserからServerへのデータ通信フォーマットはJSONかParameterを用います。Httpのメソッド、POST・PUTではJSONを、 GET・DELETEではParameterを用います。 |
Static Datas or JSON | ServerからBrowserへのデータ通信フォーマットはStatic Datas(静的情報)かJSONを用います。Serverでは画面の作成は一切行いません。画面の生成はクライアントサイドで行うことで、レイヤ間の責務を明確に分割します。動的データを送りたい場合はJSON形式で送ることにより、画面とデータを分割します。このことにより画面を作成する要員がサーバサイドの要素を意識することなく画面を作成することが可能になります。例えばデザイナと開発者の共同作業の役に立ちます。またレイヤの責務を分割することによりアプリケーションの保守性を担保することに役立ちます。 | |
Server | Parameter | ServerはBrowserからParameter形式のデータを受け取りバリデーションを行います。 |
JSON Reader | ServerはBrowserからJSON形式のデータを受け取ります。JSON ReaderはJSONの解析とオブジェクト化、バリデーションを行います。 | |
Static Datas | Serverは画面をStatic Datas(静的情報)として返却します。画面を動的に生成することはありません。これは画面の処理はBlowserに任せるためです。このことで画面を作成する要員はサーバサイドの技術を意識することなく画面を作成することが可能になります。 | |
JSON Writer | Serverからの動的情報はJSONとしてBrowserに返却します。Serverが画面の生成を行うことはありません。 | |
Action | BrowserからServerへのデータの入力を加工しServiceに渡す責務と、ServiceからBrowserのデータをクライアントに送信する形式に整える責務を持ちます。 | |
Service | ServiceはServerで行う主要な処理を行う責務を持ちます。主要な処理とは、ユーザが目的とする処理のことです。 Serviceの観念は「窓口」に例えられることがあります。郵便局をアプリケーションに置き換えて例に出すと、郵便局というアプリケーションには、「預貯金」「送付」「保険」という窓口、Serviceがあります。「預貯金」Serviceには「お金を預ける」機能や「お金を引き出す」機能、「振込」機能があります。Serviceはクラス単位で、機能はメソッドとして実装されます。 |
|
Entity | アプリケーションが解決しようとする世界観(ドメイン)の登場人物です。Entityはデータ構造を定義し、アプリケーションが行う処理のうち、Entityに固有の処理を行う責務を持ちます。 | |
Dto | Entityにはならないデータ構成を取り扱うために用います。 アプリケーションでは時にEntityを複雑に組み合わせたデータが必要になる時があります。 Serviceが複数のEntityを操作することで複雑なデータを組み立てることが可能ですが、多くの場合においてこの処理はアプリケーションの処理性能の劣化につながります。その際にDtoを用いて、データの取得操作を一括で行うことにより、処理性能を最適化します。 アプリケーションはできる限りこのレイヤのDtoを用いず、Entityで処理を行うことを検討しなければなりません。これはこのレイヤのDtoを用いるとデータの変更に対するアプリケーションの保守性に悪い影響をあたえることが多いためです。 |
|
Accessor | 他システムや他ノードへのアクセス処理を行う責務を持ちます。Accessorが処理を内包することでServiceは他システムへのアクセス手順を知ることなく責務を行うことが可能になります。 | |
Test | Integration Test | ソフトウェアの全レイヤを結合した自動テストを作成します。ユーザが実際に行う操作をエミュレートします。自動テストの作成には時に大きなコストが必要になります。アプリケーションのメンテナンス、拡張に必要十分なレベルを勘案して自動テストを作成してください。 |
Unit Test | Serviceはアプリケーションの処理の肝です。処理が正しいことを確認します。 Integration Testと分けてテストを実施する目的は一般的にはIntegration Testはユーザの操作であり、大まかなユーザストーリーをテストするのに適しているのに対し、Unit TestはAPIのテストであり、より細かなテストが可能になるためです。 |
Modern Java Web Architectureの各レイヤで用いるライブラリ・フレームワーク
各レイヤで用いるライブラリ・フレームワークを示します。
ライブラリ・フレームワークを用いることで各レイヤのアプリケーションの構成を均質化することができます。
ライブラリ・フレームワークを選定する場合は、できるだけ流行っているものを利用するようにします。流行っているものであれば、情報を取得しやすく、学習効率が高いことが多いためです。また、流行っているものであれば、別プロジェクトでも知識を流用できる可能性が高くなります。
場所 | レイヤ | 説明 |
---|---|---|
Browser | Base Page | Browser上のアプリケーションはAngularJSを用いて作成します。AngularJSを用いることで、HTMLの実装形式を保ちつつ、インタラクションをもつ画面を作成可能です。 サーバサイドでHTMLを動的に生成するべきではありません。サーバサイドでHTMLを出力する場合の多くは、HTMLに独自の形式を埋め込んだ技術を使う必要があります。独自形式をHTMLに埋め込むことは画面作成に複雑さを招き、余計な学習コストが必要になる場合があります。クライアントサイドフレームワークを用いて、HTMLの形式に沿った実装で動的な画面を作るべきです。 |
Template Page | AngularJS Routeを用いてindex.htmlの内容を書き換えるHTMLを作成します。画面の内容を書き換えるのに、JavaScriptのDOMを使うのは避けるべきです。HTMLの表現形式を守り、デザイナでも理解可能な形式を保つため、また、HTMLとJavaScriptの2つの方式にまたがり画面を作成する、という複雑さを回避するためです。 | |
Helper Plugin | AngularJSのモジュールを利用・作成することで、複雑な画面処理を内包します。 | |
View Framework | Twitter Bootstrapを用いることで統一化されたUXの画面を作ることが可能です。また、Grid Systemを用いて、マルチデバイス対応が可能です。 | |
Controller | AngularJSのコントローラをTemplate Pageに1対1でControllerを作成します。 | |
Server | Parameter | Jerseyを用いてServerのAPIを作成します。Jerseyを用いるのはJSR 339 JAX-RSの参照実装であるからです。BrowserとServerはParameterか、JSON形式でデータをやりとりします。ブラウザの技術との親和性が良いからです。 XMLに機能別の処理設定(ServletのURLへのマッピングなど)を書くことや、アプリケーションに唯一のrouteファイルにルーティング設定を書くことなどは避けてください。チームで開発する際に、一機能の追加がアプリケーション全体の挙動に影響をあたえる可能性を低減するためです。 |
JSON Reader | JAX-RSのMessageBodyReaderを用い、JSONをJavaのオブジェクトにマッピングします。マッピングとともにJSR 303 Bean Validationを利用して入力データのバリデーションを行います。JSR 303 の実装にはHibernate Validatorを利用します。Hibernate Validatorを用いるのはJSR 303の参照実装であるからです。 | |
Static Datas | Serverからは静的ファイル、HTML、CSS、JavaScriptのみを返却すべきです。出来る限りにおいて、サーバサイドで静的ファイルを動的に生成することは避けてください。特に、静的ファイルに別の拡張した言語を入れるべきではありません。拡張した言語とは、JSPやJava Server Faces、PHPのスクリプトレットや、Rubyのファイルのことです。何故ならば不要な複雑性を画面作成の実装に混入させることになるためです。 | |
JSON Writer | JAX-RSのMessageBodyWriterを利用してオブジェクトをJSONに変換します。 | |
Action | JAX-RSのURLマッピングを利用して、JSONを返すAPIを作成します。 | |
Service | POJOでServiceを作成します。 JSR 338 JPAを用いてEntityをDBとやりとりする処理を記述します。 性能的な必要性がある場合、JPQLやSQLとDtoでDBに複雑なクエリを発行します。 保守性に寄与するように、できるだけUnit Testしやすいように作成します。 |
|
Entity | JSR 338 JPAによりDBに保存されます。 Entity独自の処理を保つ場合はメソッドとして実装します。 |
|
Dto | POJOで、SQLによるクエリ結果をマッピングするオブジェクトを作成します。 | |
Accessor | 他クラスにアクセスするためのクラスです。POJOとして作成し、Serviceのテストによりテストしやすいようにします。必要があれば他システムのダブルを作成します。 | |
Test | Integration Test | JUnitから起動する、Seleniumでブラウザを操作する自動テストを作成します。テストの再現性を担保するためにテストデータをDBUnitを使って投入します。TomcatのEmbed機能を使ってJUnitからアプリケーションサーバの起動、停止を行うことで、テストのポータビリティーを高めます。 再現性を担保し、適時テストを追加していくことによりアプリケーションの機能性確認が洗練、成長していくことを目指します。 |
Unit Test | JUnitから起動するテストを作成します。DBUnitを用いて、テストの再現性を担保します。Integrationテストよりも、より細かな試験を行います。 |
Modern Javaで堅牢性と生産性を両立するアプリケーションを作りましょう。
Javaの「硬さ」はサーバサイドのロジックを堅牢に作るのに非常に優れます。それとAngularJSの生産性を組み合わせることでとても良いWebアプリケーションを作ることができます。ご考慮ください。