goo blog サービス終了のお知らせ 

N2 ToolBox(跡地)

跡地です。引っ越しました。http://d.hatena.ne.jp/nosen

LiQのドキュメント:36.8kg

2008-03-19 08:27:10 | LiQ
1.0のリリースに向けてLiQ Containerのドキュメントを改善しようと、思案中です。

が、わかりやすいドキュメントにするのは、なかなか難しいですね。
LiQ Containerはよくも悪くも汎用的で抽象的なフレームワークなので、
効果的な使い方を、よくありそうなサンプルをあげて説明するのは困難です。

いっそのこと、LiQ ContainerのAPIの使い勝手を検証するためにつくった
データアクセスとかWebアプリケーションとかのフレームワークをサンプルとして
公開した方が早いのかもしれません。

性能対決! LiQ vs Guice:63.8kg

2008-03-12 06:54:44 | LiQ
そもそも設計思想が違うし、私は性能測定は素人だし、
使われる状況によっても結果はかわるしで、どこまでリアルなものかわかりませんが、LiQ Containerと Google Guice の性能を比較してみました。

テストケースは極めて単純で、Guiceのユーザガイドにのってる単純なインスタンス生成のコードを、LiQ とGuiceそれぞれで10万回繰り返す時間を測定する、というもの。

結果は下記の通り。

----
Guice Singleton:258ms
Guice PerLookup:289ms
LiQ PerLookup(Object Factory):213ms
LiQ PerLookup(Mapping):386ms
LiQ Singleton:213ms
----

JDK はMac OS X上の1.5.0_06, マシンはCore 2 Duo 1.83GHzのMacBookです。

Object Factoryとか、Mappingてのはなんじゃい、と思う方もおられると思いますが、とりあえずは設定方法の違いだと思ってください。

少なくとも単純なケースにおいては、Guiceに遜色ないパフォーマンスを出すことも可能だとわかって少し安心しました。

ただし、実はLiQは性能よりも柔軟性を重視して設計されているので、
設定が複雑になればなるほどLiQは性能的には不利だと思います。
でも、設定の手間は圧倒的に少ないはず。
LiQの世界ではいちいちModuleとかを書かなくても自動的にInjectできるケースが
ほとんどなのです。アピールしたいのは実は性能じゃないんですよね。
私としては、LiQがボトルネックになるような状況はそんなにはないよ、
ということがいえれば十分満足です。

それにしてもGuiceもLiQも毎回インスタンス生成するのと、
Singletonであまり性能が違わないんですねぇ。

あとは、同時実行性能も気になるところです。

いちおう今回のテストコード全文を貼付けておきます。
----
package jp.liq.vs.guice;

import jp.liq.container.Container;
import jp.liq.container.ContainerVocabulary;
import jp.liq.container.vocabulary.Factory;

import org.junit.Before;
import org.junit.Test;

import com.google.inject.Binder;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.Scope;
import com.google.inject.Scopes;

public class GuiceTest implements ContainerVocabulary {
	public static interface Service {
		
	}
	
	public static class ServiceImpl implements Service {
		
	}
	
	public static class Client {
		@Inject
		public Client(Service service) {
			
		}
	}
	
	public class SingletonModule implements Module {

		public void configure(Binder binder) {
			binder.bind(Service.class)
				.to(ServiceImpl.class)
				.in(Scopes.SINGLETON);
		}
		
	}

	public class PerLookupModule implements Module {

		public void configure(Binder binder) {
			binder.bind(Service.class)
				.to(ServiceImpl.class);
		}
		
	}
	
	@Before
	public void warmUpGuice() {
		Injector injector = Guice.createInjector(new PerLookupModule());
		for(int i = 0; i < 100000; i++) {
			Client client = injector.getInstance(Client.class);
		}
	}
	
	@Before
	public void warmUpLiQ() {
		Container container = new Container();
		components.configure(container)
			.define(component.instance(Service.class, new ServiceImpl()));
		sentinel.configure(container);


		for(int i = 0; i < 100000; i++) {
			Client client = container.get(Client.class);
		}
	}

	@Test
	public void testGuiceSingleton() {
		Injector injector = Guice.createInjector(new SingletonModule());
		long start = System.currentTimeMillis();
		for(int i = 0; i < 100000; i++) {
			Client client = injector.getInstance(Client.class);
		}
		long end = System.currentTimeMillis();
		System.out.println("Guice Singleton:" + (end - start));
	}

	@Test
	public void testGuicePerLookup() {
		Injector injector = Guice.createInjector(new PerLookupModule());
		long start = System.currentTimeMillis();
		for(int i = 0; i < 100000; i++) {
			Client client = injector.getInstance(Client.class);
		}
		long end = System.currentTimeMillis();
		System.out.println("Guice PerLookup:" + (end - start));
	}


	
	public class ServiceFactory {
		@Factory
		public Service createService() {
			return new ServiceImpl();
		}
	}
	
	@Test
	public void testLiQObjectFactory() {
		Container container = new Container();
		components.configure(container)
			.define(component.instance(Service.class, new ServiceImpl()));
		sentinel.configure(container);

		long start = System.currentTimeMillis();

		for(int i = 0; i < 100000; i++) {
			Client client = container.get(Client.class);
		}
		long end = System.currentTimeMillis();
		System.out.println("LiQ PerLookup(Object Factory):" + (end - start));
	}

	@Test
	public void testLiQMapping() {
		Container container = new Container();
		components.configure(container)
			.define(component.mapping(Service.class, ServiceImpl.class));
		sentinel.configure(container);

		long start = System.currentTimeMillis();

		for(int i = 0; i < 100000; i++) {
			Client client = container.get(Client.class);
		}
		long end = System.currentTimeMillis();
		System.out.println("LiQ PerLookup(Mapping):" + (end - start));
	}

	@Test
	public void testLiQSingleton() {
		Container container = new Container();
		components.configure(container)
			.define(component.instance(Service.class, new ServiceImpl()));
		sentinel.configure(container);

		long start = System.currentTimeMillis();

		for(int i = 0; i < 100000; i++) {
			Client client = container.get(Client.class);
		}
		long end = System.currentTimeMillis();
		System.out.println("LiQ Singleton:" + (end - start));
	}


}



続:Webフレームワーク作りたい病

2008-03-03 06:22:41 | LiQ
土日は何かに取り憑かれたかのようにコードを書いていました。
LiQ Container の検証のために書いているWebフレームワークです。
URLをクラスにマッピングするところと、結果をHTMLにして出力するところは
大体できました。あとは、軽くValidationの仕組みを作ってみたいと
思っています。Validationはプロジェクトによって、全然要件が変わってくるので、
共通のフレームワークにするのは意外に難しいんですけど。

出来ばえが良さそうだったら公開します。

LiQ Containerの方は大きな問題はそれほどなく、
予定どおり小規模な修正のみで済んでいます。

仕事の方も山場を迎えていて、やらなきゃいけないこと/やりたいこと
が山積しています(いつものことですが)。

内部での1日が外界での1年に相当するという、あの部屋にはいりたい。

Iterable好き:ClassDiscoverer編

2008-02-28 08:00:37 | LiQ
以下のようなクラスを作ってみました。

例えば、META-INF/classes.lstというファイルに、
以下のようにクラス名をリストアップ
しておきます。
----
jp.liq.sample.AImpl1
jp.liq.sample.AImpl2
java.lang.String
----
以下のようなコードで上記のクラスが取得できます。
----
ClassDiscoverer discover = new ClassDiscoverer();

discover.addClassList("META-INF/classes.lst");

int cnt = 0;
for(Class c: discover.classes().isA(A.class)) {
    assertTrue(A.class.isAssignableFrom(c));
    cnt++;
}
assertEquals(2, cnt);
----
ここではインタフェース「A」のサブクラスのみを取得しています。
仕掛け自体は非常に単純なのですが、
これで、Jarファイルをクラスパスに通すだけで、そのJarのMETA-INF/classes.lst
に書いてあるクラスを取得できるようになります。
LiQ Containerと組み合わせるとプラグインぽい仕組みを簡単に作ることが
できて便利そうなので、LiQ Container本体にこっそり入れるかどうか
考え中です。

Webフレームワーク作りたい病

2008-02-26 07:57:58 | LiQ
最近、そういう病気が再発してしまったようです。

すでに似たようなものがあるのに、自分で新しく作りたくなってしまうという
病気。

LiQ Containerの使い勝手の最終確認をかねて、最近ちまちまコード書いてます。

Iterable好き

2008-02-20 07:54:12 | LiQ
もし、JDKのインタフェースで一番好きなのはどれ、と問われたら、
私はおそらく「Iterable」と即答するでしょう。

最近いろいろなものをIterableにするのに凝っています。
LiQ Container にも、Iterableを利用してオブジェクトのメソッドや
フィールドを簡単に取得できる仕組みを組み込んでおります。

例えば
----
for(MethodWrapper m : methods.of("hoge")) {
    System.out.println(m.name());
}
----
で"hoge"というStringの持つ public メソッドが全部とれるといった具合。
java.reflect.Methodそのものでなくて、Wrapperを返しているのは、
主にリフレクションAPIが返す煩雑なチェック対象例外を
LiQ Container の RuntimeExceptionでラップするためです。

以下のように書くと、"get"で始まるメソッドのみを返すことも出来ます。
----
for(MethodWrapper m : methods.of("hoge").withPrefix("get")) {
    System.out.println(m.name());
}
----
同様にwithAnnoationというメソッドを使うと特定のアノテーションを
持つメンバのみを取得できます。

実際使ってみると便利です、これ。

LiQ Container 1.0-rc1 リリース

2008-02-15 07:29:55 | LiQ
しました。ダウンロードはこちらから
APIが beta1 から相当変わってますので、ユーザガイドも完全に
書き直しました。

今回の出来栄えは、自己満足度 100% 。
Guice とかとも違う、一風変わった世界を作り出せたのではないかと思っております。
アピールしたいところは、

1. 超軽量
2. 拡張が容易
3. 設定の仕方が変

の3点です。

1. の軽量であることには自信があって、メインになる Container というクラスなんて
インスタンス変数に ArrayList 1個もってるだけなのです。
コンテナ生成のコストが低いので、リクエストごとにコンテナ作ったりとかしても全然問題ないと
思います。

2. の拡張が容易、については、ドキュメントにまだ書ききれていないので、よくわからない
かもしれません。でもソース読めば分かるはずです。

3.の設定の仕方については、ユーザガイドに書いたので、そちらを参照願います。
基本的には Fluent Interface ぽい感じなのですが、何かが変です。

仕事の方では立場上マネジメントに手一杯でコードを書く機会に恵まれない昨今ではありますが、
せっかく好きこのんでIT業界に転職したんだから、ひとかどのプログラマになりたい、
という気持ちは、まだ捨てていません。

LiQ はそんな気持ちのはけ口になっていて、beta1からrc1にいたるまでの長い間、
好きなだけ時間をかけて、心から楽しんで作りました。
そんな思い入れのあるソースコードをいろいろな人に読んでもらって、批評して
もらえたら、それ以上うれしいことはありません。

なので、今回はJXRのレポートを生成して、公開しています。
ぜひ、さまざまなご意見を下さいませ。

今回のリリースでようやくAPIはFIXして、あとはバグフィックスとドキュメントを手直しして、
1.0をリリースしたいと考えています。

時間がとれたら性能なんかも測ってみたいなぁ。


旅路の果て

2008-01-28 23:50:08 | LiQ
長い長い、いつ果てるともしれないリファクタリングの旅の果てに、
LiQ Containerの 1.0 リリースの時期がようやく近づいて来ました。

現在、本体のソースコードは ほぼ Fix の状態で、あとドキュメントの
書き直しが終わった段階で 1.0-rc1としてリリース、特に問題なければ、
あまり期間をあけずに1.0 を正式リリースしたいと考えています。

今回は、実戦配備からのフィードバックを受けて、概念的に分かりづらかった
部分を簡単に使えるように配慮したほか、設定の書き方も大幅に変更しています。

約1年半前に、最初に自分でDIコンテナを作り始めようと思い立ったきっかけは、
単にXMLで設定を書くのが嫌で、Javaで書いた方がいいんじゃないか、
ということだったのですが、最近では、もはやJavaで書けますとかは半分
どうでも良くなってきています。

むしろ、長い旅路の果てにたどり着いた、DI の新しい地平、
シンプルさと柔軟性が高度に同居する世界をアピールしたいのです。

使い勝手改良中

2007-10-25 00:35:36 | LiQ
現在、お仕事のプロジェクトのフレームワークをLiQ Container ベースで作ってるのですが、半年もの間 練り上げた API が実際使ってみると以外に
使いにくい部分もあって、それなりにショックです。

しかし、嘆いていても始まらないので、地道に改良作業を続けています。

その結果、例えば以下のようにModuleの記述を改善することができました。
(改良前)
register(Components.createdBy(
        methodsOf(ObjectMethodModule.class)
            .withAnnotation(FactoryMethod.class), this));

(改良後)
component(created.by(
        methods.of(this)
            .withAnnotation(FactoryMethod.class)));


この改良は見た目以上にインパクトが大きいものです。
なぜなら、改良前のmethodsOfというメソッドは、
実はReflectorというクラスのstaticメソッドをstaticインポート
したものでした。

一番の問題は、
Eclipseがstaticインポートをうまく補完できない(嘘でした。すみません。下のkoichikさんのコメントを参照してください)

ことで、いちいちstaticインポート文を書くのが耐えがたいほどめんどくさい
ものになってしまっていました。

暫く悩んだ後、たどり着いた解決策が改良後のコードです。
同じことがmethodsというstaticフィールドのofメソッドを呼び出すことで
実現されてます。

こういう風にすると、いちいち面倒なimport 文を書かなくてもきれいに
補完がきくようになる、という訳です。

嘘でした。すみません。下のkoichikさんのコメントを参照してください

LiQの今後の予定

2007-10-23 00:32:08 | LiQ
今日、ひさびさに仕事でマジ切れしました。

通常、歳をとるに従い、人間が大きくなっていくものですが、
私の場合は、どんどん人間が小さくなっていく気がします。

それはさておき、なぜここに来てLiQ Containerのリリースを急いだのかというと、
今取り組んでいるプロジェクトはひさしぶりに言語がJavaなので、
うやむやのうちにうまいことLiQ を突っ込んでしまおう、と企んでいるからです。

実際のプロジェクトでLiQ を使って作ったフレームワークを構築してみて、
プロジェクトを跨って切り出せそうな部分があれば、
そのアイデアを生かしてLiQ と組み合わせる部品として公開していきたい、
と考えています。


一発でいいモノができるわけないから、
部品として切り出すときにはどうせソースは1から書き直すことになるので、
特に問題はないかな、と思ってます。