日曜日, 8月 02, 2009

【Google App Engine】 RESTfulアプリのCRUDサンプル -Modeling編- このエントリーを含むはてなブックマーク


 前回に引き続き、RESTfulアプリの解説をおこなう。今回はModeling編。本当は最初に説明すべきところ。

Entity設計

 外部設計において基本となるのはBCEモデル。3分で分かる設計の話 にもあるように、Entity設計とは項目の整理をすること。項目の抽出は画面設計を行ってからじゃないとできないので、実際には、Boundary=>Entity=>Controlの順番で設計を進めていくことになる。Entityの設計では、基本的には名前と型と多重度の定義を行うだけでよいのだが、もう少しがんばって、具体的にXMLのインスタンス(項目とデータを含むもの)まで作成するとよいと思う。ちなみに、請求書アプリのXMLインスタンスはこんな感じになった=>XML

 ReflexではModel設計のことを敢えてEntity設計と言うようにしている。Modelは型で、Entityはその型から作ったインスタンスであるから、Entityは金太郎飴の一粒のようなもの。Reflexでは、Entityのインスタンスイメージの方が具体的で好都合なので、なるべくそう呼ぶようにしているが、設計フェーズを意識しないときは、Model設計とEntity設計はよく同じ意味で使ったりもするので、実際にはそれほどこだわっているわけでもない。ただ、Modelを強調してしまうと、「Model=抽象的な器+ロジック」のロジック部分が強調されることになって、データ構造を中心に考えるReflexの設計に合わなくなってしまうので、やっぱりEntity設計と呼ぶのがいいような気がしている。
 
Modelの設計とサービス化
 
 Entityの設計ができたら内部設計をすすめてModelを設計していく。Modelには、データ構造を表現する部分と、ロジック(ビジネスロジック、または、ドメインロジック)を表現する部分から成るが、Reflexではこれを2つに分離させることを推奨している。具体的には、データ構造を表現したModelに実際のデータの管理をまかせてCRUDのAPIを持たせることが一つと、ドメインロジックには、専らビジネスロジックの実行処理をまかせるのが二つ目。ビジネスロジックの実行では、例えば、Entityから別のEntityへの変換や、HTMLやPDFなどへの変換、メール送信などが考えられる。前者はDatastoreへの登録があるから不揮発性なのに対し、後者は揮発性であるのが特徴である。ドメインロジック内で許されるのは参照のみで、登録や更新は絶対に許されないとものする。ただし、Datastoreからの参照は可能であり、必ずしもWebサービス経由で参照する必要はない。
 また、Modelのこれら2つの機能をREST化したものをサービスと呼んでいる。例えば、EntityをCRUDで操作するデータ管理用のサービスと、PDF変換などのロジック実行用のサービスなどがある。これらはModelの2つの性質をサービス化したものと考えることができる。

サービスにおけるEntityの扱い方と具体例

 RESTfulな新3層アーキテクチャでも説明しているとおり、すべての操作はパラメータにentityを与えることにより実行する、というポリシーで設計する。こうすることで、entityという一貫したI/Fが扱えるようになり、その結果、外部設計の目的が明確になる。外部設計とは、つまり、entity設計を意味することになる。


 entity = create(entity);
 entity = retrieve(entity);
 entity = update(entity);
 entity = delete(entity);


 請求書アプリで具体的に説明してみよう。まず、create(entity)に対応するのは、invoiceのXMLをPOSTメソッドで実行する部分である。Servlet内部では、reflexgaeライブラリを使ってXMLをrequestオブジェクトから取り出してinvoiceオブジェクトに変換、それを直接datastoreに挿入している。非常にシンプルな実装である。<参考>RESTfulアプリのCRUDサンプル -Servlet編-


 Invoice invoice = (Invoice) getEntity(req, MODEL_PACKAGE);
 jdoUtils.insert(invoice);


 retrieve(entity)に対応するのは、以下の部分で、requestオブジェクトのクエリパラメータの内容を、一旦、Invoice paramに詰めて、それを条件にjdoUtils.getEntriesByParam()で検索を実行している。


 Invoice param = new Invoice();
 (new RequestMapper()).setValue(req, param);
 ・・
 jdoUtils.getEntriesByParam(param, pagesize, nextid);


 update(entity)も基本的に同様であり、PUTされてきたXMLをInvoiceに変換して、jdoUtils.update(invoice)を実行するだけである。delete(entity)も同様である。


 Invoice invoice = (Invoice) getEntity(req, MODEL_PACKAGE);
 JdoUtils jdoUtils = new JdoUtils();
 jdoUtils.update(invoice);


 jdoUtilsの内部では、reflexgaeの FieldMapperを使って、targetのinvoice(persistant)に対して、sourceのinvoiceの更新があるプロパティだけをセットするようにしている。つまり、sourceのinvoiceのプロパティのうち、nullでなく、かつ、targetと異なる内容のものを、setterを介してセットするという処理をfieldMapper内で行っている。わざわざsetterを介すのは、JDOに更新であることを認識させるためである。(フィールドを直接書き換えると更新されないので注意)
 また、invoiceのように、1:nの子要素を持つ場合でも、この操作1回ですべての子要素を更新することができる。ただし、子要素のKeyはしっかりsourceの方にセットしておく必要がある。(私が試したのは2階層までであり、3階層の孫要素も更新されるかどうかはわからないので注意。)


fieldMapper.setValue(invoice,target);


 

Control

 Controlは、簡単に言うとサービスを呼ぶ機能のことである。他のサービスを呼びつつ、一連のフローを実行して、別の新たな結果を返すような機能、といった感じだろうか。いわゆる、マッシュアップがそうだし、先日公開した、Google Spread SheetからPDF生成するBookmarkletもControlの一種である。ドメインロジックをサービス化したものはControlになることができるが、すべてがControlと呼べるかというとそうではない。

Boundary

 いわゆる画面のことである。本当はこれを最初に説明すべきところだが最後になってしまった。ここでいいたいのは一つだけ。レンダリングのために必要な処理はBoundary内に記述すべきということ。EntityをサービスからXMLやJSONで受け取ってレンダリングしたり、あるいは、GEARなどに一時的に保存したり、サービスに登録内容を送信したりする処理は、Boundaryとして実装すべきであり、決してControlなどに押し付けてはいけない。画面内に閉じることで疎結合のメリットを最大限に享受できるようになるからだ。

まとめ

 ここまで、主に外部設計の話とBCEモデルについて説明してきたが、あらためて強調したいのは、Entity設計をクローズアップするということ。つまり、Entityの設計をしっかりやって、それを一貫したI/Fとして扱うべし、ということにつきる。サービスについても、EntityをパラメータとしたCRUDや、Entityを与えてEntityを返すという単純なものにすべきである。そう考えていくと、Entityさえできれば、それをもとに自動的にscaffoldを作成するなんてことは簡単にできる。ちなみに、Reflexでは、reflexentityeditorというものを用意しており、Reflex表現からEntityを自動作成するツールも用意している。将来的には、CRUDができるServletや、HTMLページなどを生成するscaffold生成機能も用意したいと考えている。しかし、今現時点では、まだ他に優先してやるべきことがたくさんあるので取り掛かることはまだしない。

 最近知ったのだが、これに非常によく似たものに、Simple Modelerというものがある。モデル駆動開発を掲げ、Scalaで作成したメタデータを元にモデルを自動生成できる。

 Reflexは割と古くて2005年ぐらいから存在しているが、そのコンセプトは黙殺されてきた感がある。(別に流行らなくても結構なのだが)
 最近、同じようなことを考えている方が世の中にもいるということで、ちょっと安心した感もある。だが、Simple Modelerが大流行りして、Reflexが真似しているといわれないようにしないといけないなあとは思う。

0 件のコメント:

 
© 2006-2015 Virtual Technology
当サイトではGoogle Analyticsを使ってウェブサイトのトラフィック情報を収集しています。詳しくは、プライバシーポリシーを参照してください。