Typemock: その過去・現在・未来
Eli Lopian氏率いるTypemock社の過去・現在・未来について、インタビュー形式にて記します。

作者 Shay Banon, 翻訳者 編集部 投稿日 2007年10月10日 午前8時9分
多くのアプリケーションでは、ドメインエンティティを検索するか調べるというユーザ要件があります。これは、アプリケーションに対するエントリーポイントとして、またはフォームに必要事項を記入するメカニズムとして必要とされています。通常これは、ナビゲーション(ドメインを階層的に表し、ユーザがアイテムの場所を見つけて選択できるようになっている)、または検索フォーム(検索をかけられるフィールドが多数入ったフォームをユーザに示す)のいずれかによって解決できます。
現実では、使いやすさの点から両方のアプローチは次善最適だといえます。エンティティの数が多い場合、ナビゲーション方式はすぐに遅くなり、面倒になります。またユーザは通常どのエンティティを探しているか厳密にわかっているのに、それを見つけるためにわざわざ階層を行き来しなければなりません。検索フォーム方式も、検索をかけられるフィールドの数に限定されてしまいます。検索をかけられるフィールドが十分あることと、検索フォーム自体が複雑になることは二律背反の関係なのです。
使いやすさから見たこの問題に対する答えは、検索しているエンティティの任意のフィールドに合致する条件をユーザが入力でき、それらの条件に合致する結果を提示してくれる単一のGoogle式検索ボックスを提供することです。これはオートコンプリートでGoogleサジェスト形式の入力フィールドがフォームに収まったものか、表形式の結果が得られる通常の検索のいずれかになりますが、この解決策の本質は、UIが単純で、ユーザがどのような条件を入力してもよく、大変な仕事は検索機能がすべてやってくれるという点です。ここでの唯一の疑問は、この検索機能をどのように実装するかということなのです。
従来の複数フィールドの検索フォームを実装するという課題に直面した際、大部分のアプリケーションはSQLに頼ります。検索フィールドは通常、SQLクエリがLIKE句で使うカラムと合致します。しかしあまりに多くのフィールドと合致する必要があるSQLの複雑さが原因で、またおそらくこれらのフィールドのテキストサイズも原因で、この実装のパフォーマンスは通常かなり落ちます。2つ目の問題は、検索結果のランキングが存在せず、ヒットが返されるのは、それが検索クエリにとってどの程度関連しているかではなく、クエリに合致するかしないかによるという点です。3つ目に、検索結果で合致した条件を強調表示するサポートはありません。
ここで必要なのは検索エンジンだということを、大部分のアプリケーションはすぐに認識します。エンティティのすべてのフィールドはあたかも1つのドキュメントであるかのようにインデックス作成され、次に通常のテキスト検索を行い合致するエンティティを検索できます。世に出回っている有名なオープンソース検索エンジンの1つにLucene(サイト・英語)があります。Luceneは多くのアプリケーションがうまく活用している優れた検索エンジンです。低レベルの検索エンジンAPIを提供し、Luceneデータ構造(「Document」、「Field」)を使ったデータのインデックス作成と、クエリAPIまたは検索エンジンクエリを使っての検索が可能です。Java、C#、C++など多数の言語で利用可能です。
典型的なWebアプリケーションを分析すると、通常は非常に似通った構造と特徴を備えているものです。普通、アプリケーションはバックエンドのリレーショナルデータベースと連動しています。システム内の主要なエンティティを表わすドメインモデルを持ち、ORMフレームワークを使ってドメインモデルをデータベースにマップします。大部分はサービス層フレームワークを使ってトランザクション、コーディネーション、時にはビジネスロジック、そしてWebフレームワークを管理します。ここで出てくる疑問は、Luceneをどのようにこのようなアプリケーションに統合するかということです。
まずは最初の急増をうまくやり過ごすという比較的ささいな困難を乗り越え、Luceneをアプリケーションに統合しようとする際、すぐに多くの課題に直面します。最初の問題は、アプリケーションデータのインデックス作成です。すぐにかなりたくさんのボイラープレートコードがアプリケーションドメインモデルをLuceneデータ構造にマップさせ、再び取り出すことに費やされます。Luceneの主要なデータ構造であるLucene Documentは平坦なMap状のデータ構造で、ストリングしか含んでいません。したがってかなりの量のコードがドメインオブジェクトをマーシャル、アンマーシャルして出し入れするために費やされます。もう1つの問題は、Luceneではトランザクションのサポートが欠けており、ドメインモデルのデータベースと検索エンジンへの保存が問題となる点です。その他にも、サーチャーのキャッシュ・無効化、Google式検索をサポートするための集約された「all」プロパティの作成、適切な更新セマンティクスのための識別可能なDocumentを持つなど、Luceneを使う際に実施すべきよく知られた慣行・パターンがあります。
Compass(サイト・英語)の目的は、検索機能のアプリケーションへの統合を簡素化することです。Compassは、明確な検索エンジンの抽象化を使い、Lucene上に構築されます。Compassでは中核のLuceneが拡張され、データベース内にインデックスを格納する能力と合わせて、トランザクションサポートと迅速な更新が加わります。また何よりも、Luceneの機能が隠れてしまうことがありません。つまりLuceneの持つ全機能がCompassを通じて利用できるのです。
Compassは単純でなじみやすいAPIを提供します。このAPIは、Compassの学習曲線を下げるために(適用可能なところで)現行のORMツールAPIを模倣しているためなじみやすいのです。Compass APIはいくつかの主要なインターフェースを中心に展開されています。
APIを使った単純な例を以下に示します。
// Compass is configured and created on an application scope
CompassConfiguration conf =
new CompassConfiguration().setConnection("/tmp/index").addClass(Author.class);
Compass compass = conf.buildCompass();
// A request scope operation
CompassSession session = compass.openSession();
CompassTransaction tx = null;
try {
tx = session.beginTransaction();
...
session.save(author);
CompassHits hits = session.find("jack london");
Author a = (Author) hits.data(0);
Resource r = hits.resource(0);
...
tx.commit();
} catch (CompassException ce) {
if (tx != null) tx.rollback();
} finally {
session.close();
}
トランザクション管理コードを簡素化するため、Compassはいくつかのオプションを提供しています。1つ目がCompassTemplateを使うもので、これはトランザクション管理コードを抽象化して取り出すために一般的なテンプレート設計パターンを用います。2つ目のオプションは、CompassがJTAおよびSpringトランザクションのようなトランザクションマネージャと統合されていて、すでに実行中のトランザクション内で動作するという、トランザクション管理環境で作業する際に適用します。このような場合、Session操作が実行される際に自動的にトランザクションを結合するプロキシを使うことでCompassSessionを利用できます。プロキシはプログラミングで生成するか、Spring Ioc(Spring 2での@CompassContext注入サポート)を使って生成することができます。
Compassはアトミックトランザクション操作をサポートし、ローカルトランザクション管理、JTA統合のためのJTA SyncとXA、Spring同期統合など、様々なトランザクション管理戦略と統合します。
Compassの構成は主要な値設定に基づいています。Compassは、プログラミングによる構成、xml DTDベースの構成(マッピングと設定を定義)、そして表現形式のxmlスキーマに基づいた構成を使って構成可能です。xmlスキーマに基づいた構成は、Spring 2の新しいスキーマに基づいた構成サポートと合わせて使うことも可能です。
Compassの主な機能の1つに、アプリケーションモデルの中から検索エンジンへの宣言型マッピングが可能であるということがあります。Compass検索エンジンのドメインモデルは、Resource(1つのLucene Document)とProperty(1つのLucene Field)で構成されています。これは検索可能なコンテンツのインデックスを作成するために使われる抽象型データオブジェクトです。
最初のマッピングはRSEM(Resource/Search Engine Mapping)です。これはCompass ResourceおよびProperty検索エンジンの抽象化(Lucene DocumentとFieldへのマップ)から検索エンジンまでの低レベルのマッピングです。Authorリソース向けのRSEM定義の例を以下に示します。
<resource alias="author">
<resource-id name="id"/>
<resource-property name="firstName"/>
<resource-property name="lastName" store="yes" index="tokenized"/>
<resource-property name="birthdate" converter="mydate"/>
</resource>
ここでは、Authorエイリアスに対してマップされたResourceを定義します。Resourceマッピングは、リソースに関連付けられたIDと、いくつかの追加プロパティを持ちます。プロパティの定義は、ある特性をコンバータに関連付けられるなど、様々なプロパティの特性を宣言的に制御できますが、あくまで任意です。Authorリソースをデータで埋め、インデックスを作成するコードを以下に示します。
Resource r = session.createResource("author");
r.addProperty("id", "1")
.addProperty("firstName", "jack")
.addProperty("lastName", "london")
.addProperty("birthdate", new Date());
session.save(r);
Compassの一部の機能が上記のコード断片に現れています。1つ目は、Resourceが識別可能だという事実のおかげでCompassはResourceがインデックスにすでに存在していればそれを更新します。2つ目の機能は、多くのCompass内蔵コンバータを使えることと合わせて、コンバータをプロパティに宣言的に割り当てられる機能です。以上のコードに関するCompass構成を次に示します(mydateコンバータ構成を含む)。
<compass-core-config xmlns="http://www.opensymphony.com/compass/schema/core-config"
xsi:schemaLocation="http://www.opensymphony.com/compass/schema/core-config
http://www.opensymphony.com/compass/schema/compass-core-config.xsd">
<compass name="default">
<connection>
<file path="index" />
</connection>
<converters>
<converter name="mydate" type="org.compass.core.converter.basic.DateConverter">
<setting name="format" value="yyyy-MM-dd" />
</converter>
</converters>
<mappings>
<resource location="sample/author.cpm.xml" />
</mappings>
</compass>
</compass-core-config>
サポートされている2つ目のマッピングはOSEM(Object/Search Engine Mapping)です。アプリケーションオブジェクトドメインモデルを検索エンジンにマップすることができます。アノテーションを使ったOSEM定義で、Authorクラスの例を次に示します。
@Searchable
public class Author {
@SearchableId
private Long id;
@SearchableComponent
private String Name;
@SearchableReference
private Listbooks;
@SearchableProperty(format = "yyyy-MM-dd")
private Date birthdate;
}
// ...
@Searchable
public class Name {
@SearchableProperty
private String firstName;
@SearchableProperty
private String lastName;
}
OSEMは、Resourceに対するオブジェクト階層のマーシャル、アンマーシャルをサポートします。Authorオブジェクトを保存する際、Authorを表す同じResourceにNameクラスがマーシャルされ(コンポーネントマッピングのおかげで)、本の著者リスト(他のResourceに格納されている)にある各本を参考にして、CompassはResourceにオブジェクトをマーシャルします。結果として生じるリソースは次に検索エンジンに保存され、インデックスが作成されます。
Compassはドメインモデルを検索エンジンにマッピングする非常に柔軟なメカニズムを提供します。上記のサンプルはあくまで単純な例にすぎません。OSEMにより、カスタムコンバーター、クラスプロパティごとの複数のメタデータ(Resourceプロパティへのマップ)、アナライザー、「all」フィールドの関与など、多くのことを指定できます。
Authorクラスがどのように使われるかの例をここに示します。
// ...
Author author = new Author(1, new Name("jack", "london"), new Date());
session.save(author);
// ...
author = (Author) session.load(Author.class, 1);
Compassでサポートされている最後の検索エンジンマッピングはXSEM(Xml/Search Engine Mapping)です。このマッピングにより、xmlマッピング定義に基づいてxmlデータ構造を直接検索エンジンにマップすることができます(xpath駆動型)。XSEMプロセスは、Resource間で同じマーシャル、アンマーシャルプロセスを経ます。Compassは、xpath表現式評価も行える様々な実装を持つ(dom4j、W3C Document)XmlObjectというxmlラッパーオブジェクトを導入します。次のようなxmlデータ構造を見てみましょう。
<xml-fragment>
<author id="1">
<firstName>Jack</firstName>
<lastName>London</lastName>
</author>
</xml-fragment>
そして考えられるXSEM定義は次のとおりです。
<compass-core-mapping>
<xml-object alias="author" xpath="/xml-fragment/author">
<xml-id name="id" xpath="@id" />
<xml-property xpath="firstName" />
<xml-property xpath="lastName" />
<xml-content name="content" />
</xml-object>
</compass-core-mapping>
このマッピングは、xpath表現式を使ったxmlデータ構造から検索エンジンにマップします。xmlコンテンツのマッピングにより、検索エンジン内にあるようにxml構造を格納し、データの読み込み、検索時に使うことができます。Compassは、JSE 5、dom4j(SAXとXPP)などいくつかのxml domライブラリをサポートしており、カスタム実装が容易に可能です。どのように使えるかの例を次に示します。
Reader reader = // construct an xml reader over raw xml content
AliasedXmlObject xmlObj = RawAliasedXmlObject("author", reader);
session.save(xmlObj);
// ...
Resource resource = session.loadResource("author", 1);
// since we have xml-content, we can do the following as well
XmlObject xmlObj = session.load("author", 1);
Compass GpsはCompass内の1つのモジュールで、Compassを様々なデータソースに統合することを目的としています。最も一般的なデータソース統合は、Compassを様々なORMツールと統合させる事例です。CompassはJPA、Hibernate、OJB、JDO、iBatisをサポートしています。
Hibernateを例に取ると、Compassはインデックス作成とミラーリングという2つの主要な操作を展開します。インデックス作成では、HibernateマッピングとCompassマッピングの両方を使ってデータベースコンテンツのインデックスを自動で作成することができます。両方のマッピングを持つオブジェクトは、Hibernateを使ってデータベースから自動でフェッチされ、検索エンジンに保存されます。ミラーリングの場合、イベントリスナーをHibernateに登録することでHibernate APIを使って検索エンジンミラー操作を自動で行えます。これにより、データベースへのあらゆる変更はHibernate APIを介して行い、インデックスを常に最新の状態に保てます。Compass GpsのHibernate統合をどのように使うかを次に示します。
SessionFactory sessionFactory = // Hibernate Session Factory
Compass compass = // set up a Compass instance
CompassGps gps = new SingleCompassGps(compass);
CompassGpsDevice device = new Hibernate3GpsDevice("hibernate", sessionFactory);
gps.addDevice(device);
// start the gps, mirroring any changes made through Hibernate API
// to be mirrored to the search engine
gps.start();
// ....
// this will cause the database to be indexed
gps.index();
// this will cause Hibernate to store the author in the database
// and also index the author object through Compass
hibernateSess.save(new Author(1, new Name("jack", "london"), new Date()));
本記事では、Compassとその特色を簡単に紹介しましたが、Compassの使い方についての基本事項だけを取り上げています(とりわけ、CompassはSpringとの広範囲な統合モジュールを持っています)。Compassは、検索エンジンを使う際の日常的な細かいニュアンスを多く取り上げており、大規模な構成サポートを有しています。冒頭で述べたとおり、Compassの主要な目標は、あらゆる種類のアプリケーションへの検索機能の統合を簡素化することにあり、今回の簡潔な記事は、どのようにそれが実施できるかの基本事項について取り上げています。
Shayは、検索機能をあらゆるアプリケーションモデルに組み込める独自のソリューションであるCompass(サイト・英語)のオープンソースプロジェクトの創業者です。ShayはミッションクリティカルなリアルタイムのC、C++システムへの取り組みからスタートし、後にJavaへと移行しました(二度と過去をふり返りませんでした)。Javaの世界においてShayは、分散ルールエンジン(RETE)サーバーの妥当な実装、典型的なJavaベースのWebプロジェクト、金融業界内のメッセージングをベースとしたプロジェクトに取り組んできました。現在Shayは、GigSpaces(サイト・英語)でシステムアーキテクトを務めています。
原文はこちらです:http://www.infoq.com/articles/compass-search-tutorial
(このArticleは2006年11月29日にリリースされました)
この論文では、仮想化やクラウドサービスの複雑なメリットと実世界における応用を検討します。さらに重要なこととして、Contegixが複雑な問題の解決に仮想化を実装している方法や、仮想化を使うべきではないケースについて詳細を提供します。
Fiberはユーザに試練を課すことなくこの考えを実装する有益な並行性ツールとして、ライブラリが2つあります。まさにこのためのソリューションとしてあるのがNeverBlockライブラリです。私たちはNeverBlockプロジェクトのMohammad A. Ali氏とRevactorライブラリのTony Arcier氏に話を聞きました。
システムの保守容易性や拡張性を確保するためのベスト・プラクティスに関する記事は数多くありますが、この記事では避けた方がいい、いくつかの悪習慣(ワースト・プラクティス)を強調します。
この記事では、私達がどのようにして大規模(240人月、10万行強)でインドとオランダの開発者も参加したスクラム・プロジェクトを成功させたのかを示しています。
Agileカンファレンスに「参加者としてだけでなく、発表者として参加しよう」を掲げたチームgoyattomは、サブミッションを提出し、7つのセッションが日本から選択されました。参加者はカンファレンスで各々の発表や、各セッションへの参加、諸外国のエンジニアとの出会い、ステージ上で DearXPを熱演などの様々な思い出を抱えて、無事日本に戻ってきました。
マイクロソフトのRobert Bellが、SilverlightとJavaを使用したインターオペラビリティのシナリオを紹介し、サンプルコードを例にとってアーキテクチャの手引きを提供します。
No comments
返信