tag:blogger.com,1999:blog-238648772024-03-14T00:24:42.182+09:00A Life in Shinjuku.Unknownnoreply@blogger.comBlogger182125tag:blogger.com,1999:blog-23864877.post-20601118381674296342011-11-08T16:26:00.001+09:002011-11-08T16:45:30.508+09:00WindowsでLeiningen behind a proxy<br />
<div style="overflow-x: hidden; overflow-y: hidden;">
JavaEE勉強会でProgramming Clojureを読んではいるものの、途中不参加だった時期もあり、いまいち身についている感がない。このまま終わってしまうのもアレなので、Webアプリでも作ってもう少し慣れようなどと思い立つ。仕事で時間ができた時に少しずつさわることを想定して、Windows上で環境構築をはじめることにした。</div>
<div style="overflow-x: hidden; overflow-y: hidden;">
<br /></div>
<div style="overflow-x: hidden; overflow-y: hidden;">
<span class="Apple-style-span" style="font-size: large;">まずはNoirフレームワークで</span></div>
<div style="overflow-x: hidden; overflow-y: hidden;">
Webで調べてみたところ、Clojure用フレームワークとしてはCompojureが有名っぽい。そういえば、JavaEE勉強会の角田さんによる発表で、Heroku+CompojureでWebアプリを作っていたような気がする。しかし、社内からはProxyの問題でHerokuが使えないことは確認済み。同じ構成だとHerokuに上げたくなって悔しくなりそう。違うフレームワークを探してみたところ、Noirというものを見つけた。シンプルなWebフレームワークらしいので、まずはNoir向けに環境を作って動かしてみよう。</div>
<div style="overflow-x: hidden; overflow-y: hidden;">
# と思ったら、NoirはCompojure+Ring上に構築されてるらしいです<br />
<br /></div>
<div style="overflow-x: hidden; overflow-y: hidden;">
<span class="Apple-style-span" style="font-size: large;">Leiningenインストール</span></div>
<div style="overflow-x: hidden; overflow-y: hidden;">
lein-noirというプラグインを使えばNoir関連の依存ライブラリをインストールしてくれるらしいので、Leiningenからインストールする。現在の最新バージョンは1.6.1.1。<a href="https://github.com/technomancy/leiningen#readme">LeiningenのGithub</a>からlein.batをダウンロードし、Pathの通った場所に置いてから</div>
<blockquote class="tr_bq">
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
lein self-install</div>
</blockquote>
<div style="overflow-x: hidden; overflow-y: hidden;">
すればOK。ただし、Path上にWget.exeがない場合は leiningen-x.x.x.x-standalone.jar がダウンロードできずに怒られるので注意。この辺りは親切にも、lein self-install のエラーメッセージにダウンロード先を含めて書いてあるので問題ないとは思う。</div>
<div style="overflow-x: hidden; overflow-y: hidden;">
Proxy環境の人なら、環境変数にhttp_proxyを設定すればOK。認証ありでも同じく環境変数を設定すれば問題なし。</div>
<div style="overflow-x: hidden; overflow-y: hidden;">
<br /></div>
<div style="overflow-x: hidden; overflow-y: hidden;">
<span class="Apple-style-span" style="font-size: large;">lein-noirインストール</span></div>
<div style="overflow-x: hidden; overflow-y: hidden;">
最新のバージョンは1.2.1。以下のコマンドでOK…のはずだった。</div>
<blockquote class="tr_bq">
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
lein plugin install lein-noir 1.2.1</div>
</blockquote>
<div style="overflow-x: hidden; overflow-y: hidden;">
しかし、あえなくエラー発生。リポジトリ上にlein-noir-1.2.1.jarが見つからないらしい。ブラウザからclojars.org/repo に行って確認したところ、JARはきちんと存在している。</div>
<blockquote>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
D:\>lein plugin install lein-noir 1.2.1</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Exception in thread "main" org.apache.maven.artifact.resolver.ArtifactNotFoundEx</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
ception: Unable to download the artifact from any repository</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Try downloading the file manually from the project website.</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Then, install it using the command:</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
mvn install:install-file -DgroupId=lein-noir -DartifactId=lein-noir -Dversio</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
n=1.2.1 -Dpackaging=jar -Dfile=/path/to/file</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Alternatively, if you host your own repository you can deploy the file there:</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
mvn deploy:deploy-file -DgroupId=lein-noir -DartifactId=lein-noir -Dversion=</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
1.2.1 -Dpackaging=jar -Dfile=/path/to/file -Durl=[url] -DrepositoryId=[id]</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
<br /></div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
lein-noir:lein-noir:jar:1.2.1</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
from the specified remote repositories:</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
clojars (http://clojars.org/repo/),</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
central (http://repo1.maven.org/maven2)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
(NO_SOURCE_FILE:0)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at clojure.lang.Compiler.eval(Compiler.java:5440)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at clojure.lang.Compiler.eval(Compiler.java:5391)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at clojure.core$eval.invoke(core.clj:2382)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at clojure.main$eval_opt.invoke(main.clj:235)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at clojure.main$initialize.invoke(main.clj:254)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at clojure.main$script_opt.invoke(main.clj:270)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at clojure.main$main.doInvoke(main.clj:354)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at clojure.lang.RestFn.invoke(RestFn.java:551)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at clojure.lang.Var.invoke(Var.java:390)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at clojure.lang.AFn.applyToHelper(AFn.java:193)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at clojure.lang.Var.applyTo(Var.java:482)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at clojure.main.main(main.java:37)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Caused by: org.apache.maven.artifact.resolver.ArtifactNotFoundException: Unable</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
to download the artifact from any repository</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Try downloading the file manually from the project website.</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Then, install it using the command:</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
mvn install:install-file -DgroupId=lein-noir -DartifactId=lein-noir -Dversio</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
n=1.2.1 -Dpackaging=jar -Dfile=/path/to/file</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Alternatively, if you host your own repository you can deploy the file there:</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
mvn deploy:deploy-file -DgroupId=lein-noir -DartifactId=lein-noir -Dversion=</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
1.2.1 -Dpackaging=jar -Dfile=/path/to/file -Durl=[url] -DrepositoryId=[id]</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
<br /></div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
lein-noir:lein-noir:jar:1.2.1</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
from the specified remote repositories:</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
clojars (http://clojars.org/repo/),</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
central (http://repo1.maven.org/maven2)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
<br /></div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at org.apache.maven.artifact.resolver.DefaultArtifactResolver.resolve(De</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
faultArtifactResolver.java:212)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at org.apache.maven.artifact.resolver.DefaultArtifactResolver.resolveAlw</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
ays(DefaultArtifactResolver.java:80)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at java.lang.reflect.Method.invoke(Unknown Source)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:90)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at clojure.lang.Reflector.invokeInstanceMethod(Reflector.java:28)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at leiningen.install$standalone_download.invoke(install.clj:39)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at leiningen.install$install.invoke(install.clj:62)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at leiningen.plugin$install.invoke(plugin.clj:32)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at leiningen.plugin$plugin.invoke(plugin.clj:75)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at clojure.lang.Var.invoke(Var.java:373)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at clojure.lang.AFn.applyToHelper(AFn.java:167)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at clojure.lang.Var.applyTo(Var.java:482)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at clojure.core$apply.invoke(core.clj:540)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at leiningen.core$apply_task.invoke(core.clj:229)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at leiningen.core$_main.doInvoke(core.clj:294)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at clojure.lang.RestFn.applyTo(RestFn.java:139)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at clojure.core$apply.invoke(core.clj:542)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at leiningen.core$_main.invoke(core.clj:297)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at user$eval42.invoke(NO_SOURCE_FILE:1)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at clojure.lang.Compiler.eval(Compiler.java:5424)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
... 11 more</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Caused by: org.apache.maven.wagon.ResourceDoesNotExistException: Unable to downl</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
oad the artifact from any repository</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at org.apache.maven.artifact.manager.DefaultWagonManager.getArtifact(Def</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
aultWagonManager.java:332)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
at org.apache.maven.artifact.resolver.DefaultArtifactResolver.resolve(De</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
faultArtifactResolver.java:200)</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
... 33 more</div>
</blockquote>
<div style="overflow-x: hidden; overflow-y: hidden;">
どうやら内部的にはMavenを使っているようなので、 ~/.m2/settings.xmlにproxy設定を追加してみたが状況は変わらず。ちなみに、プロキシがローカルホストなのは、NTLM認証が面倒なのでローカルプロキシを入れているため。</div>
<div style="overflow-x: hidden; overflow-y: hidden;">
<br /></div>
<pre><settings>
<proxies>
<proxy>
<active>true</active>
<protocol>http</protocol>
<host>localhost</host>
<port>9090</port>
</proxy>
</proxies>
</settings>
</pre>
<div style="overflow-x: hidden; overflow-y: hidden;">
<br /></div>
<div style="overflow-x: hidden; overflow-y: hidden;">
切り分けのためにMaven3をインストールし、切り分け用のpom.xmlを作って depenencies に lein-noir 1.2.1 を追加。リポジトリにも clojars を追加してから mvn compile を叩くと、正常にダウンロードが完了した。この後再び lein plugin install lein-noir 1.2.1 と叩くと、無事にインストールが完了したらしい。謎。</div>
<blockquote class="tr_bq">
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
lein plugin install lein-noir 1.2.1</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Copying 1 file to C:\DOCUME~1\....~1\LOCALS~1\Temp\lein-c7edc836-8953-4a2b-b0e</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
0-830eeeaa1ad0\lib</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Including lein-noir-1.2.1.jar</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Including clojure-1.2.1.jar</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Created lein-noir-1.2.1.jar</div>
</blockquote>
<div style="overflow-x: hidden; overflow-y: hidden;">
<span class="Apple-style-span" style="font-size: large;">Noirプロジェクト作成</span></div>
<div style="overflow-x: hidden; overflow-y: hidden;">
LeiningenでNoirプロジェクトを作成。</div>
<blockquote class="tr_bq">
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
lein noir new samplenoir</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Creating noir project: samplenoir</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Creating new dirs at: D:\...\projects\clojure\samplenoir</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Adding files...</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Project created!</div>
</blockquote>
<div style="overflow-x: hidden; overflow-y: hidden;">
プロジェクトディレクトリに移動してlein runでサーバが起動してデフォルトアプリケーションが利用可能になる。</div>
<blockquote class="tr_bq">
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
lein run</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Downloading: org/clojure/clojure/1.3.0/clojure-1.3.0.pom from central</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Downloading: org/sonatype/oss/oss-parent/5/oss-parent-5.pom from central</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Downloading: noir/noir/1.2.1/noir-1.2.1.pom from central</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Downloading: noir/noir/1.2.1/noir-1.2.1.pom from clojars</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
- 中略 -</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Downloading: org/mindrot/jbcrypt/0.3m/jbcrypt-0.3m.jar from clojars</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Downloading: org/mindrot/jbcrypt/0.3m/jbcrypt-0.3m.jar from central</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Copying 31 files to D:\watanabeknt\projects\clojure\samplenoir\lib</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Starting server...</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
2011-11-08 15:00:00.098:INFO::Logging to STDERR via org.mortbay.log.StdErrLog</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
2011-11-08 15:00:00.098:INFO::jetty-6.1.25</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
2011-11-08 15:00:00.238:INFO::Started SocketConnector@0.0.0.0:8080</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
Server started on port [8080].</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
You can view the site at http://localhost:8080</div>
<div style="font-family: Arial, Helvetica, 'Microsoft Yahei', sans-serif; font-size: 0.8em; overflow-x: hidden; overflow-y: hidden;">
#<Server Server@1f02b85><server server@1f02b85=""></server></div>
</blockquote>
<div style="overflow-x: hidden; overflow-y: hidden;">
普通に依存ライブラリをダウンロードできているっぽいんですけど、さっきは何がダメだったのだろう?</div>
<div style="overflow-x: hidden; overflow-y: hidden;">
<br /></div>
<div style="overflow-x: hidden; overflow-y: hidden;">
<span class="Apple-style-span" style="font-size: large;">Noirアプリケーションにアクセス</span></div>
<div style="overflow-x: hidden; overflow-y: hidden;">
コンソールに表示されているとおり、localhost:8080にアクセスすればデフォルトページが表示される。ここには、簡単なサンプルとともに、チュートリアルへのリンクが表示されている。</div>
<div style="overflow-x: hidden; overflow-y: hidden;">
<br /></div>
<div style="overflow-x: hidden; overflow-y: hidden;">
<span class="Apple-style-span" style="background-color: #474949; color: #d1d9e1; font-family: Monaco, Consolas, 'Courier New'; font-size: 16px; line-height: 24px; white-space: pre;">(defpage "/my-page" []
(html
[:h1 "This is my first page!"]))</span></div>
<div style="overflow-x: hidden; overflow-y: hidden;">
<br /></div>
<div style="overflow-x: hidden; overflow-y: hidden;">
あれ?なんかあんま好きじゃない感じの記法なんですけど…。なんか昔Javaでこんないけてないライブラリがあったようななかったような。</div>
<div style="overflow-x: hidden; overflow-y: hidden;">
一区切りついて気に入らなかったら、結局Compojureに行ってしまうかもしれない…。</div>
<div style="overflow-x: hidden; overflow-y: hidden;">
<br /></div>
<div style="overflow-x: hidden; overflow-y: hidden;">
<span class="Apple-style-span" style="font-size: large;">次</span></div>
<div style="overflow-x: hidden; overflow-y: hidden;">
次は、Noirのチュートリアルと、エディタの整備をやりたい。エディタは、CounterclockwiseかClojureboxどちらかの予定。Emacsとは仲良くなれなかったのでCounterclockwiseが有力。</div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-23864877.post-84490827467950680312011-04-20T16:35:00.004+09:002011-04-20T17:16:16.816+09:00QCon Tokyo 2011 アーキテクチャパネルディスカッション+DDD雑多ネタアーキテクチャパネルディスカッションとラウンジ・ビアパーティでの雑談から、主にDDDに関して興味深かった話をいくつか。聞き取り能力は低いので抜けている部分もあると思いますがご容赦を。<br /><div><br /></div><div><span class="Apple-style-span" style="font-size: large;"><b>ビジネス的な有用性はどこにあるのか</b></span></div><b>Evans氏発言要旨</b><br /><div>経営層など意思決定を行う人たちに対して、ドメイン駆動設計の有用性をどう訴えかけるのか?という問いに対して、Evans氏は主にコアドメインへの注力によって競争上の優位、市場優位につなげる部分を強調。ここから一段階細かいレベルとして、ビジネスパーソンにとって理解できるソフトウェアへと進んでいくとのこと。ただし、常に労力に見合う価値が得られるわけではないことも忘れずに付加。</div><div><br /></div><div><b>雑感</b></div><div>この質問はなかなか難しく、聴衆の反応も微妙なものだったように思う。これは、DDDをオブジェクト指向設計方法論として受け取っている人が多く、こうした部分の有用性についての回答を期待していたものの、Evans氏は主にPartⅣの戦略的設計(Strategic Design)の有用性について語ったために、ギャップが生じたためだと思う。</div><div>DDDは一読するとオブジェクト指向分析・設計方法論に関する本のようにも見えるが、実際はOOに直接結びついているわけではない。ドメインを中心に設計をする上で都合の良いパラダイムが現状ではオブジェクトパラダイムであるために、実現方法を記した部分(PartⅡ、PartⅢ)がオブジェクト指向設計に沿った形で書かれているにすぎない。DDDにとって根本的に重要なのはOOではなく、その名が示すとおり「ドメイン」へのフォーカスだ。この点を踏まえたなら、コアドメインへの注力はシステム/ソフトウェア全体をドメインの観点から区分するという意味で、まさに大きな意思決定を行うレベルでのドメイン駆動設計そのものだということが理解できると思う。<br />OO話がなかったのは…残念でした。</div><div><br /></div><div><span class="Apple-style-span" style="font-size: large;"><b>ドメインエキスパートをどうやって巻き込むのか</b></span></div><div><b>Evans氏発言要旨</b></div><div>ドメインエキスパートとの最初のミーティングで、「あなたが最も難しく、面倒だと感じるのはどういった部分なのか?」「安眠を妨げるような問題はないか?」とたずねて、具体的なシナリオをあげてもらう。細かい問題は後で決めれば良い。画面項目の最大長や色などを聞くのはナンセンスで、ただでさえ忙しいドメインエキスパートの貴重な時間を浪費することになる。そんなことをしてはいけない。本当に難しい、重要な問題にフォーカスしてシナリオを描き、シナリオを解決できるモデルをホワイトボードに描き出して共有する。</div><div>仮にドメインエキスパートが示す問題がドメインにとってはさほど重要な問題ではなく、彼にとって重要・面倒であるだけであっても大きな問題ではない。彼と信頼関係を構築するのが重要。このセッションがうまくいけば、ドメインエキスパートはセッションを楽しみに待ってくれるようになることもある。これは実際にEvans氏が経験した話。</div><div><br /></div><div><b>雑感</b></div><div>画面項目の最大長…といったくだりは刺さった。多くのプロジェクトでは、まさにこうしてドメインエキスパートの時間を無駄にしている。ここでも、ドメインにフォーカスし、重要な部分にリソースを投入する、というドメイン駆動の原則が生きている。リソースというのは、開発者のリソースだけではなく、ドメインエキスパートのリソースも同じなのだ。モデリングセッションの進め方は<a href="http://domainlanguage.com/ddd/whirlpool/">Whirlpool</a>に沿ったものだが、ここに至って、繰り返し型・反復型開発の重要性も浮き彫りになってくる。ウォーターフォール型の開発プロセスで、横並びに設計を進めるのなら、こうしたアプローチを取るのは難しくなるだろう。しかし、重要な部分を先に進めることを合意できているなら(RUPくらいなら顧客合意も難しくないだろう)、ドメインエキスパートにとって重要な問題にフォーカスすることで注意を引きつけ、それを知的に解決するさまを共有することでモデリングセッションを軌道にのせる姿も現実的なものとして見えてくるのではないだろうか。</div><div><br /></div><div><span class="Apple-style-span" style="font-size: large;"><b>一般的・形式的な概念体系をどう扱うか</b></span></div><div><b>問題要旨</b></div><div>書籍Domain Specific Languageでは、ドメインエキスパートとのコミュニケーションを促進するためにDSLを構築し、DSLの背後にある概念体型としてセマンティックモデル(Semantic Model)を導入する。このセマンティックモデルの一形態として代替計算モデル(Alternative Computational Model)が挙げられており、よりうまく問題領域にフィットする場合に有効である旨が記述されている。代替計算モデルとして挙げられているステートマシン(State Machine)、依存ネットワーク(Dependency Network)、決定表(Decision Table)などは言わば確立された形式的な概念体系であるのだが、こうした体系とDDDのモデルはどういった関係にあるのか。</div><div><br /></div><div><b>Evans氏発言要旨</b></div><div>確立された概念体系自体は非常に有用であるものの、これは汎用的なものであって、ドメインの重要な概念を直接的に表すものではない。重要なのはむしろ、モデルからこうした概念体系を分離した後に残るものであり、それこそがドメインの概念をより良く表すものとなり得る。</div><div><br /></div><div><b>雑感</b></div><div>これは、15章「蒸留(Distillation)」に属するパターンの1つである、凝集されたメカニズム(Cohesive Mechanisms)を念頭に置いた回答ではないかと思う。DDDの書籍では、組織内の関係を表すモデルからグラフ構造をCohesive Mechanismsとして取り出す例があげられており、こうすることで組織のモデルからグラフ構造にまつわる概念群(ノード、アークなど)を消し去って、残されたモデルをより本質的なものにしている。また、貨物輸送の例でも配送ルートを決定する際にグラフ構造が使われており、Itineraryを実装した際に混入したであろうグラフにまつわる概念群を引き剥がすことに成功している。これはDDD Sampleでも確認できる。</div><div>DSLの代替計算モデル相当をDDDに組み込む場合、最も素直なアプローチはCohesive Mechanismsとして利用することだと考えている。貨物輸送の例であれば、うまくすればエンドユーザーが書いたDSLスクリプトを解釈実行することで、直接配送ルートを表すグラフ構造を構築でき、このモデルを使って最適経路を計算できるだろう。</div><div><br />ただ、この回答については少し疑問が残っていて、実際は「確立された概念体系」と「ドメインの本質を表す概念群」との境界はそんなにはっきりしたものではないのではないかと思っている。例えば、8章「ブレークスルー」などで登場するシェアパイ(SharePie)は、代数的構造の1つである「群」の概念に沿ったもので、確立された概念体系、もしくはそれに限りなく近いものだが、DDD書籍ではドメインエキスパートがこの概念を操り、ユビキタス言語の一部にもなっている。このように、純粋にメカニズム的な意味を持った概念体系は確かにモデルの本質を表しはしないのであろうが、確立された概念体系自体がドメインの本質を表す場合もあるのではないかと思う。</div><div><br /></div><div># この話、酔っ払った状態でEvans氏に話そうとしたけどstuckしてしまった…無念すぎる。酔っ払ってなくてもダメだったかもしれないことは置いておこう…。</div><div><br /><b>関連:</b><br /><ul><li><a href="http://hibituredure.blogspot.com/2010/09/fowler-dsl.html">Fowler DSLのエッセンス</a></li><li><span class="Apple-style-span" style="color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 14px; line-height: 18px;"><a href="http://hibituredure.blogspot.com/2011/04/code-generation-language-workbenchesdsl.html">Code Generation & Language Workbenches@DSL読書会</a></span></li></ul><br /><span class="Apple-style-span" style="font-size: large; "><b>英語以外の言語ではどう実践すべきか</b></span></div><div><b>問題要旨</b></div><div>英語以外の言語を用いる場合、ほとんどの実装言語が英語に沿ったものであるため、ドメイン概念をそのままソフトウェアとして実装できないことが問題になる。仮にここで、実装言語にあわせて英語を混在させた場合、ユビキタス言語が歪められてしまう。</div><div><br /></div><div><b>Evans氏発言要旨</b></div><div>ソースコードでも日本語を使え。以上。</div><div><br /></div><div><b>雑感</b></div><div>実際にはこれほど乱暴な話になったわけではない。Evans氏も英語以外の言語での実践経験はなく、他の言語圏でどうやって対処しているのかは不思議に思っていた様子。ただ、Javaのコードを見ながら話をした際にクラス名に対して日本語でコメントがつけられているのを見て、これではダメだと感じたようだった。「ドメインエキスパートがこの言葉(日本語コメントで書かれたクラス名)を使っているのなら、なぜクラス名にこれを使わない?」とのこと。「日本語でJava等を書くと、Java慣習にかたっぱしから違反してしまうので問題なんだ、コードも読みづらいし」と反論(?)してみたものの、「重要なのはドメインの概念であって、技術的な問題はそれに比べれば瑣末なものだろう?」と言われてしまい、もう納得するしかなかった。実際のところ、主語・動詞・目的語・修飾語等の位置が異なるため、英語に比べるとかなり違和感のあるコードが出来上がってしまうのだが、DDDがこれまで述べてきた「ドメイン重視、技術要素は二の次」という姿勢が貫かれていることを知ってすっきりした。これでDDDerは、日本語でコードを書いてみなくちゃならなくなった!実践した人は、Evans氏にフィードバックしてあげましょう。</div><div><br /><iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm-jp.amazon.co.jp/e/cm?t=lifeinshin-22&o=9&p=8&l=as1&asins=4798121967&ref=qf_sp_asin_til&fc1=000000&IS2=1&lt1=_blank&m=amazon&lc1=0000FF&bc1=000000&bg1=FFFFFF&f=ifr" style="height: 240px; width: 120px;"></iframe><iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm-jp.amazon.co.jp/e/cm?t=lifeinshin-22&o=9&p=8&l=as1&asins=0321712943&ref=qf_sp_asin_til&fc1=000000&IS2=1&lt1=_blank&m=amazon&lc1=0000FF&bc1=000000&bg1=FFFFFF&f=ifr" style="height: 240px; width: 120px;"></iframe></div><div><br /></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-23864877.post-13635727371511680432011-04-18T10:41:00.001+09:002011-04-18T23:39:23.145+09:00QCon Tokyo 2011QCon Tokyo 2011に、DDD読書会(JavaEE勉強会)のコミュニティ枠として参加させていただきました。初回開催となる2009以来2年ぶりの参加になります。<br />
<br />
今回の<a href="http://qcontokyo.com/program.html">セッションプログラム</a>はビアパーティまであわせると総数が21で、以下の6つに分類されています。総プログラム数からすると多彩な内容ですね。<br />
<ul><li>クラウド</li>
<li>Design & Patterns</li>
<li>技術</li>
<li>クオリティ & テスト</li>
<li>アーキテクチャ</li>
<li>ケーススタディ</li>
</ul>しかし、なんといっても今回の目玉は、DDDの創始者Eric Evans氏の来日でしょう。基調講演に通常プログラム、パネルディスカッションと盛りだくさんの内容でした。僕はこのDDDと、クラウド関連のセッションに的を絞って出席してきました。具体的には、以下の7つ+ビアパーティに参加、という形です。<br />
<ul><li>ドメイン駆動設計:複雑な問題群に対する有用なモデルたち</li>
<li>Webアプリケーションエンジニアが見てきたこの10年</li>
<li>クラウドのデータアーキテクチャー設計の原則</li>
<li>Understanding IA: The Extension of Man 2011</li>
<li>クラウドコンピューティングの未来:10年後の情報システムを考える</li>
<li>ドメイン駆動設計においてレガシーシステムを扱うための戦略</li>
<li>アーキテクチャパネルディスカッション</li>
</ul><div><br />
</div><span class="Apple-style-span" style="font-size: large;">セッションの感想</span><br />
QCon2009風に感想を分類すると、こんな感じでした。<br />
<br />
[面白かった!]<br />
<ul><li>クラウドのデータアーキテクチャー設計の原則</li>
<li>クラウドコンピューティングの未来:10年後の情報システムを考える</li>
<li>ドメイン駆動設計においてレガシーシステムを扱うための戦略</li>
<li>アーキテクチャパネルディスカッション</li>
</ul><div>[ふつう]</div><ul><li>ドメイン駆動設計:複雑な問題群に対する有用なモデルたち</li>
</ul><br />
[いまいち]<br />
<ul><li>Webアプリケーションエンジニアが見てきたこの10年</li>
<li>Understanding IA: The Extension of Man 2011</li>
</ul><br />
<div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><span class="Apple-style-span" style="font-size: large;">雑感</span></div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">今回のQConでは、2年前に比べると統一的な方向性のようなものを見出すことはできませんでした。色々な人が色々なことをやっていて、その成果を個々に見ているような感じです。これは、僕が主に出席したクラウド系のセッションとDDD関係のセッションの方向性がかなり異なっているのが大きな理由かもしれません。</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><b>クラウド系</b></div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">クラウド系で特に面白かったのは、佐藤一郎氏の「クラウドコンピューティングの未来:10年後の情報システムを考える」でした。この講演では、クラウドコンピューティングをソフトウェア技術中心の他のセッションとは異なった視点から捉えており、クラウドコンピューティングと物流業態との類似性や他の業態を模した異なる形態でのクラウドコンピューティングの可能性、アプリケーションとの関係、アプリケーションのビジネス化のヒントが散りばめられていて、非常に新鮮なものでした。</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><b>DDD系</b></div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">DDDのセッションで面白かったのは、Eric Evans氏の「アーキテクチャパネルディスカッション」でした。ここでの収穫はなんといっても、Evans氏自らドメインエキスパートとのモデリングセッションについて、具体例を交えて生き生きと語ってくれたことでした。ドメインエキスパートとのモデリングセッション自体はDDD書籍にもいくつか例示されているのですが、どのようにしてドメインエキスパートとのモデリングに入っていくのか、的を絞ったモデリングセッションを続けるにはどうすればいいのか、どの程度の頻度でモデリングを行うのか、など実際に実行する上で不明な部分が多く、果たして現実的に可能なのだろうか、と疑問に思った人は多数いたように思います。今回は氏自らセッションへの入り方、雰囲気作り、関係の保ち方、焦点の絞り方といった部分を語ってくれたことで、こうした部分を現実感を持って理解することができました。こうした方法は、<a href="http://domainlanguage.com/ddd/whirlpool/Domain_Language_Model_Exploration_Whirlpool_v2010-06-19.pdf">Model Exploration Whirlpool</a>というミニプロセスとして形式的にまとめられており、DDDの前進を感じることができました。</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"># 面白かったものについては、備忘録的に個別にエントリを書こうかと思います。</div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-23864877.post-42031166524732804452011-04-14T01:52:00.000+09:002011-04-14T01:52:15.980+09:00ブレイクスルー体験記@DevLove Beautiful DevelopmentDevLoveさんのイベント「DevLove Beautiful Development ソフトウェアの核心にある複雑さに立ち向かう」にて発表させていただきました。<br />
僕のITスキルが低い&緊張のために、画面が小さいことに気づかずにそのまま進めてしまいました。見えにくかった方、申し訳ありませんでしたorz<br />
イベント全体の情報は、<a href="http://www.devlove.org/past-beneficiaries/devlove_ddd2">オフィシャルサイト</a>にて非常にわかりやすく整理されています。ぜひそちらへ。<br />
<div id="__ss_7571308" style="width: 425px;"><strong style="display: block; margin: 12px 0 4px;"><a href="http://www.slideshare.net/kentaro714/beautiful-development" title="Beautiful Development ブレイクスルー体験記">Beautiful Development ブレイクスルー体験記</a></strong> <iframe frameborder="0" height="355" marginheight="0" marginwidth="0" scrolling="no" src="http://www.slideshare.net/slideshow/embed_code/7571308" width="425"></iframe> <br />
<div style="padding: 5px 0 12px;">View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/kentaro714">kentaro watanabe</a></div></div>実は、スライドの最後には僕の大好きな漫画である日本橋ヨヲコ先生の「G戦場ヘヴンズドア」の1シーンを入れてました。すさまじい才能を持ちながら、漫画編集者の父との確執からストーリーが作れなくなった鉄男と、漫画家の父との確執から歪んだ形で小説家を目指す町蔵が心を通わせ、ともに戦場に歩み出そうとするシーンです。<br />
<br />
町蔵「バカかお前…何こんな中途半端なモン世に出そうとしてんだよ!!オレは本気が見てえんだよ!!人の顔色うかがって描いてんじゃねえよ!!」<br />
鉄男「作れないんだ、ストーリーが。もう言いたいことがないんだ、オレは、からっぽだから堺田君にひかれたんだよ。」<br />
町蔵(……ああ、こいつもか。)<br />
町蔵(誰にも、)<br />
町蔵(期待してないんだな。)<br />
町蔵「お前は天才かもしれねえ。けどそれだけだ。才能だとか画力だとか、プロはもうそんなとこで生きてねえ。」<br />
町蔵「万人受け狙えば通用するような甘い世界でもねえ。」<br />
町蔵<span class="Apple-style-span" style="font-size: large;">「いいか、オレと組むなら手加減すんな。」</span><br />
町蔵<span class="Apple-style-span" style="font-size: large;">「…もしお前がもう一度…」</span><br />
町蔵<span class="Apple-style-span" style="font-size: large;">「オレを震えさせてくれるなら、」</span><br />
町蔵<span class="Apple-style-span" style="font-size: x-large;">「この世界で、一緒に汚れてやる。」</span><br />
<br />
ヘタレだから出せなかったよ。でももう何も言うことはないよ。<br />
<br />
<iframe src="http://rcm-jp.amazon.co.jp/e/cm?t=lifeinshin-22&o=9&p=8&l=as1&asins=409188301X&ref=qf_sp_asin_til&fc1=000000&IS2=1<1=_blank&m=amazon&lc1=0000FF&bc1=000000&bg1=FFFFFF&f=ifr" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe><iframe src="http://rcm-jp.amazon.co.jp/e/cm?t=lifeinshin-22&o=9&p=8&l=as1&asins=4798121967&ref=qf_sp_asin_til&fc1=000000&IS2=1<1=_blank&m=amazon&lc1=0000FF&bc1=000000&bg1=FFFFFF&f=ifr" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-23864877.post-25462475525924022492011-04-13T23:17:00.004+09:002011-04-14T01:55:57.561+09:00Code Generation & Language Workbenches@DSL読書会少し前になりますが、DSL読書会@JavaEE勉強会でCode GenerationとLanguage Workbenchesのまとめを発表したので、ここにも載せておきます。<br /><br /><iframe frameborder="0" height="342" src="https://docs.google.com/present/embed?id=dg472vvr_462dm9qmw2j" width="410"></iframe><br /><br />Google Docsで作ってみたのですが、Slide Shareと勝手が違っていて、埋め込んだ状態でうまく閲覧できそうにないです。まともに見たい人は、最大化ボタンをクリックするのが良いかと思います。<br /><br />僕の担当分はDSL本の最後の部分で、この資料はそれまでの部分のまとめが他の人から発表されている前提で作っています。これだけ見てもあまりわからないかもしれませんので、字だけになりますが少しだけ補足しておきます(<a href="http://hibituredure.blogspot.com/2010/09/fowler-dsl.html">Fowler DSLのエッセンス</a>にさらっと目を通しておかれると、少しは分かり良いかもしれません)。<br /><br /><span class="Apple-style-span" style="font-size: large;">DSL Overview</span><br />DSL概念全体の中でCode Generationがどのような位置づけにあるかを俯瞰するために、Fowler DSLの全体像を示しています。<br /><br />DSLスクリプトを言語処理層(Language Processing Layer、パーサー/ビルダーなど)が処理することでセマンティックモデルが構築され、セマンティックモデルをアプリケーションから直接実行したり、他の環境向けにコードを生成してから実行することで望みの計算を行います。セマンティックモデルはFowler DSLのキーとなるもので、Fowler DSLを他のDSLアプローチと隔てている最も大きな要因の一つです。<br /><br />DSLは、DSLスクリプトと言語処理層の形態によって内部DSLと外部DSLに分類されます。内部DSLはDSLスクリプト、言語処理層、セマンティックモデルを同じプログラミング言語上に構築するもので、外部DSLはDSLスクリプトを独立した言語で記述するものです。<br /><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">言語処理層を構成するパターン群を総称して、構文解析戦略(Syntactic Analysis Strategy)と呼び、特に内部DSLを構築するテクニックが豊富に語られています。</div><br />セマンティックモデルから望みの結果を得るためのパターン群を総称して、出力生成戦略(Output Production Strategy)と呼びます。Code Generationはこのうちの1部分という位置づけです。<br /><br />ちなみに、ハートマークはFowler自身がセマンティックモデルを直接実行するスタイルを好んでいる印としてつけています。本命はセマンティックモデルの直接実行であり、コードジェネレーションは仕方なくやっている、という匂いが文章の端々から感じられるためです。<br /><br /><span class="Apple-style-span" style="font-size: large;">Code Generation Patterns (What to produce)</span><br />コード生成のためのパターンのうち、「何を(どのようなスタイルのコードを)生成するか」についてのパターンを示したスライドです。<br /><br />Model Ignorant Generationは、その名の通りモデルらしきものがまったく存在しないコードを生成するパターンです。モデルが持つ振る舞いはすべて、コードの中に手続きの形で平坦化されて埋めこまれます。これは、ターゲット環境がサポートする言語に抽象化能力が乏しく、モデルが構成できない場合や、モデルを実体化できるほどメモリリソースに余裕がない場合にある意味仕方なく取られるパターンです。もちろんFowlerはあまり好んではいません。<br /><br />Model Aware Generationは、ターゲット環境上にも(限られた形態かもしれないものの)モデルを構築し、モデルを操作する形のコードを生成するパターンです。Fowlerお気にです。<br /><br /><span class="Apple-style-span" style="font-size: large;">Code Generation Patterns (How to produce)</span><br />続いて、「どうコードを生成するか」についてのパターンを示したスライドです。「どう作るか」は「何を作るか」に強く依存することに注意が必要です。<br /><br />Templated Generationは、テンプレートエンジンを使ってコード出力するパターンです。生成対象となるコードで静的に決定される部分が多い場合に有効です。Model Ignorant Generationを使う場合、平坦化されたコードが一定のパターンで繰り返されることが多いため、このパターンが向いています。通常テンプレートエンジンは複雑な制御機構を持っていないため、分岐や選択が入り組んだ複雑な生成には向きません。<br /><br />Transformer Generationは、モデルを変換するコードをカスタムで作るパターンであり、要はTemplated Generation以外の場合を指しています。複雑な制御が必要であったり、コードに動的に決定される部分が多い場合に向いています。Model Aware Generationを使う場合、コードの記述は最小限となり、繰り返しも少なく静的に決定される部分も小さいため、このアプローチが向いています。<br /><br /><span class="Apple-style-span" style="font-size: large;">Language Workbenches</span><br />言語ワークベンチは、「独自のカスタムDSLを容易に構築できるようにしてくれる環境」です。さらに次のスライドで、言語ワークベンチに共通する要素を紹介しています。FowlerのDSL概念と似た形はとっていますが、異なる部分もいくつかあります。<br /><br />最も大きな違いは、セマンティックモデルが振る舞いを持つことはほとんどなく、必要な振る舞いはコードジェネレーションのプロセスでテンプレートエンジンによって埋め込まれる点です。<br />セマンティックモデルが振る舞いを持たないのは、言語ワークベンチが汎用的・統一的に個々のセマンティックモデルを扱えるようにするために「メタモデル」を用意した(せざるを得なかった)のが主な原因のようです。あまり詳しくはないのですが、メタモデルに汎用的な振る舞いの表現を埋め込むのは確かに難しそうです。<br /><br />もう一つは、セマンティックモデルを様々な方法で視覚化したり、編集したりできる編集環境が用意されている点です。自分が見たツールでは、メタモデルと関連づけながら独自エディタを生成するための開発環境が用意されていました。<br /><br /><span class="Apple-style-span" style="font-size: large;">MOFとの関係</span><br />最後のMOFとの関連はおまけみたいなもんです。とりあえずMOFは忘れてよし!<br /><br />手抜きで字だらけなのであまり分かりやすくはないと思いますが…<br /><br /><iframe src="http://rcm-jp.amazon.co.jp/e/cm?t=lifeinshin-22&o=9&p=8&l=as1&asins=0321712943&ref=qf_sp_asin_til&fc1=000000&IS2=1<1=_blank&m=amazon&lc1=0000FF&bc1=000000&bg1=FFFFFF&f=ifr" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-23864877.post-9711078656013524362010-09-19T15:17:00.003+09:002011-04-14T01:57:34.809+09:00外部DSL実装のためのAntlrチュートリアル昨日、JavaEE勉強会で外部DSL実装に向けたAntlrのチュートリアルをやってきた。<br /><div id="__ss_5221932" style="width: 425px;"><strong style="display: block; margin: 12px 0 4px;"><a href="http://www.slideshare.net/kentaro714/antlrworks-for-dsl" title="AntlrWorks for DSL">AntlrWorks for DSL</a></strong><object height="355" id="__sse5221932" width="425"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=antlrworks-100917080049-phpapp01&stripped_title=antlrworks-for-dsl&userName=kentaro714" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse5221932" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=antlrworks-100917080049-phpapp01&stripped_title=antlrworks-for-dsl&userName=kentaro714" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><br /><div style="padding: 5px 0 12px;">View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/kentaro714">kentaro watanabe</a>.</div></div>JavaEE勉強会では今Fowler DSL本の読書会をやっており、導入、内部DSLを終え、外部DSLもほぼ終わったあたり(全体だと2/3くらい?)まで来ている。過去内部DSLが終わった際には、理解を深めるために各自で内部DSLを実装して発表するハンズオンを開催している。外部DSLでも同様のハンズオンが開かれる予定で、このチュートリアルはそのための準備という位置づけ。<br /><br />実際やってみると、以下のようなファイルの保存先パスに日本語が入っているとNGになるケースがあった模様。<br /><ul><li>AntlrWorksのJAR保存先 </li><li>文法ファイル(*.g)の保存先</li></ul><div>また、文法ファイル名と文法名(文法ファイルの先頭に定義された「grammer」に続く定義)が不一致なため、デバッグ時の自動コンパイルで失敗している人もいた。注意注意。</div><br /><iframe src="http://rcm-jp.amazon.co.jp/e/cm?t=lifeinshin-22&o=9&p=8&l=as1&asins=0978739256&ref=qf_sp_asin_til&fc1=000000&IS2=1<1=_blank&m=amazon&lc1=0000FF&bc1=000000&bg1=FFFFFF&f=ifr" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe><iframe src="http://rcm-jp.amazon.co.jp/e/cm?t=lifeinshin-22&o=9&p=8&l=as1&asins=0321712943&ref=qf_sp_asin_til&fc1=000000&IS2=1<1=_blank&m=amazon&lc1=0000FF&bc1=000000&bg1=FFFFFF&f=ifr" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-23864877.post-35704392089333216772010-09-19T15:00:00.001+09:002011-04-14T01:59:57.916+09:00Fowler DSLのエッセンスとあることからFowler DSLのエッセンスを考える機会があり、昔内輪向けに作った資料を引っ張りだして眺めてみたが、わりと良い線いってると思う。<br /><br /><div id="__ss_3299075" style="width: 425px;"><strong style="display: block; margin: 12px 0 4px;"><a href="http://www.slideshare.net/kentaro714/dsl-3299075" title="HEAD FIRST DSL">HEAD FIRST DSL</a></strong><object height="355" id="__sse3299075" width="425"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=dsl-100228074316-phpapp01&stripped_title=dsl-3299075&userName=kentaro714"><param name="allowFullScreen" value="true"><param name="allowScriptAccess" value="always"><embed name="__sse3299075" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=dsl-100228074316-phpapp01&stripped_title=dsl-3299075&userName=kentaro714" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><br /><div style="padding: 5px 0 12px;">View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/kentaro714">kentaro watanabe</a>.</div></div>FowlerのDSL本が提示する価値は、おおまかに以下の3点にある。上記のスライドでは1と2にフォーカスしている。<br /><ol><li>モデルを中心に据えた思想の提示</li><li>実装スタイルの分類</li><li>実装テクニック集</li></ol>これは、紙幅の大半が3に割かれており、書いた時点では実装テクニックを全て把握していなかったことや、そもそも3はまとめがほぼ不可能、ということもあった。<br /><br /><span class="Apple-style-span" style="font-size: x-large;">モデルを中心に据えた思想の提示</span><br />従来のDSLでは、スクリプトによるモデルの組み立て、という考えが必ずしも明示的に意識されておらず、DSLがもたらす価値の源泉はDSL自身にある、と考える傾向が強かった。<br />FowlerのDSL本では、<u>DSLによってモデルを組み立てる</u>という点が非常に重視されている。DSLでモデルを構築する場合、今まではDSLによってもたらされている、と思われていた価値の多くは、実際はDSLによってではなくモデルによってもたらされている、ということがわかってくる。<br />DSLの価値は、モデルによってもたらされる価値を高めることにある。<br /><br /><span class="Apple-style-span" style="font-size: x-large;">実装スタイルの分類</span><br />これは、最近DSLについて書かれた文章ではほぼ常に述べられている内容で、実装スタイルを以下の2つに分類する、というもの。<br /><ul><li>内部DSL</li><li>外部DSL</li></ul>スライドだと言語ワークベンチを第3の実装スタイルにしていたが、言語ワークベンチは外部DSLの実装をサポートするためのツールという位置づけかと思う。<br /><br /><span class="Apple-style-span" style="font-size: x-large;">実装テクニック集</span><br />内部DSL向け、外部DSL向け、共通トピック数多くのパターンが記述されており、DSL実装のためのパタンランゲージが構成されている。少なくとも、普段の仕事でこれらの語彙が使えるようになると非常に助かる。<br /><br /><br /><br />本の大半を読み終えてみて、1, 2について付け足したいことがあるとすれば、以下の概念同士の関係の補足だろうか。<br /><ul><li>意味論モデル</li><li>(ドメインモデルを含む従来の)モデル</li><li>アクティブモデル</li><li>代替計算モデル</li></ul><div><br /></div><div><span class="Apple-style-span" style="font-size: x-large;">意味論モデル</span></div><div>意味論モデルは、一般のモデルをDSLの観点から構築対象として見た時の名称/概念。</div><div><ul><li>意味論モデルは、従来のモデルである。</li><li>意味論モデルは、アクティブモデルである場合がある。</li><li>意味論モデルは、代替計算モデルを表す場合がある。この場合、意味論モデルはアクティブモデルである。</li></ul></div><div><br /></div><div><span class="Apple-style-span" style="font-size: x-large;">従来のモデル</span></div><div>最も一般的/汎用的なモデル概念。</div><div><ul><li>従来のモデルは、意味論モデルである場合がある。</li><li>従来のモデルは、アクティブモデルである場合がある。</li><li>従来のモデルは、代替計算モデルを表す場合がある。</li></ul></div><div><br /></div><div><span class="Apple-style-span" style="font-size: x-large;">アクティブモデル</span></div><div>アクティブモデルは、従来のモデルであるが、インスタンス間の関係が変わるとモデル全体の振る舞いがきわめて大きく変更されるモデルのこと。この性質によって、個々のモデル要素の変更なしに、モデル構成を変更するだけで様々な計算を行うことができる。</div><div>語源はOOの「アクティブオブジェクトモデル」だが、オブジェクトパラダイムである必要はないため、アクティブモデルとした。</div><div><ul><li>アクティブモデルは、従来のモデルである。</li><li>アクティブモデルは、意味論モデルである場合がある。</li><li>アクティブモデルは、代替計算モデルを表す場合がある。</li></ul></div><div><br /></div><div><span class="Apple-style-span" style="font-size: x-large;">代替計算モデル</span></div><div>命令型計算モデル以外の計算モデル。計算モデルとは、ざっくり言えば計算を表す方法を指す。</div><div>命令型計算モデルは、個々の計算ステップを逐次/選択/繰り返しといった制御フローを使って並べることで計算を表すモデル。これ以外の計算モデルとして、「デシジョンテーブル」「ステートマシン」「プロダクションルールシステム」などがあげられている。</div><div><ul><li>代替計算モデルは、アクティブモデルで表現される場合がある。</li></ul><div>20110414追記:ドラフト版では「アクティブモデル」と「アダプティブモデル」の間で揺れていた用語は、出版版では「アダプティブモデル」に統一されています。</div></div><br /><iframe src="http://rcm-jp.amazon.co.jp/e/cm?t=lifeinshin-22&o=9&p=8&l=as1&asins=0978739256&ref=qf_sp_asin_til&fc1=000000&IS2=1&lt1=_blank&m=amazon&lc1=0000FF&bc1=000000&bg1=FFFFFF&f=ifr" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe><iframe src="http://rcm-jp.amazon.co.jp/e/cm?t=lifeinshin-22&o=9&p=8&l=as1&asins=0321712943&ref=qf_sp_asin_til&fc1=000000&IS2=1&lt1=_blank&m=amazon&lc1=0000FF&bc1=000000&bg1=FFFFFF&f=ifr" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe><script src="http://b.scorecardresearch.com/beacon.js?c1=7&c2=7400849&c3=1&c4=&c5=&c6="></script><script src="http://b.scorecardresearch.com/beacon.js?c1=7&c2=7400849&c3=1&c4=&c5=&c6="></script>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-23864877.post-34239189435868887382010-02-21T01:55:00.000+09:002010-02-21T01:55:47.752+09:00デブサミ2010 - 出張!DDD難民救済キャンプで話してきましたDDD読書会@JavaEE勉強会代表として、「DDD難民に捧ぐ」の佐藤さん、読書会主催syの角田さん、思想系プログラマの和智さん、モデレータのt-wadaさんと一緒にパネルをさせていただきました。<br />
推進派の佐藤さん、懐疑派の角田さん、受託開発現場の立場から自分、言葉を重視する立場から和智さんと、短い時間ながら立場を明確にしたパネルができたと思っています。<br />
<br />
<div id="__ss_3222312" style="text-align: left; width: 425px;"><a href="http://www.slideshare.net/kentaro714/19b5ddd-3222312" style="display: block; font: 14px Helvetica,Arial,Sans-serif; margin: 12px 0 3px 0; text-decoration: underline;" title="【19-B-5】出張!DDD難民救済キャンプ">【19-B-5】出張!DDD難民救済キャンプ</a><object height="355" style="margin: 0px;" width="425"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=random-100218234036-phpapp02&stripped_title=19b5ddd-3222312" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=random-100218234036-phpapp02&stripped_title=19b5ddd-3222312" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><br />
<div style="font-family: tahoma,arial; font-size: 11px; height: 26px; padding-top: 2px;">View more <a href="http://www.slideshare.net/" style="text-decoration: underline;">presentations</a> from <a href="http://www.slideshare.net/kentaro714" style="text-decoration: underline;">kentaro714</a>.</div></div><br />
パネルの内容自体に関しては、SlideShareをながめながらtsudaってくれた方のTweet(#devsumi2010ハッシュタグ)を眺めれば、おおよその話は見えてくると思います。特に@yattom さんがとても詳細にtsudaってくださっています。<br />
# yattomさんありがとうございます!<br />
というわけで、ここでは内容について書くかわりに、パネルができる過程で起きた「ZENに導かれたブレイクスルー」とでもいうべき転換点について書き残しておきます。<br />
<br />
<span class="Apple-style-span" style="font-size: x-large;"><b>ZENに導かれたブレイクスルー</b></span><br />
当日パネルでお話した内容のほかにも、DDDについて話したいことは山ほどありまして、打ち合わせの段階ではThe bookについてのより体系的な紹介や、最近のDDDコミュニティの広がり、実装レベルの具体的な話、BDDやTDD、DSL、PoEAA、アナリシスパターンなど他のアプローチとの関係などなど多くのトピックが候補としてあげられていました。<br />
# 機会があればこれらも何かしらの形でまとめられれば、と思いますが<br />
<div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">パネルのタイトルは「出張!DDD難民救済キャンプ」なので、当初はパネルを聞いた人ができる限りDDDの内容を持って帰れることを目指して進めていました。が、これらの内容を50分で、しかもパネルの形式で伝えきるのは明らかに無理があります。やればやるほどパネル形式を取る意味がわからなくなってきて、一度行き詰まりました。</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">スライドを見ればわかるとおり、僕らはプレゼンテーションZEN廚状態でした。<br />
<span class="Apple-style-span" style="font-size: x-large;">「PCから離れよう」</span><br />
このZENの教えに従い、僕らは一度PCを閉じ、これまでの方針を忘れて一から考え直すことにしました。<br />
<br />
今回のパネルでは、ZENの言う<span class="Apple-style-span" style="font-size: x-large;">主要なメッセージ</span>は一体何になるのか?つまり、来てくれた人が会場を出るときに持っていて欲しいものは一体何なのか?複数人が議論する「パネル」という形式でも主要なメッセージというのは可能なのか?パネリストがそれぞれ違う意見を持っているのではないか?それぞれが伝えたいことは何なのか?考えの違いを超えて伝えたいことはあるのか?<br />
<br />
こうして考えた結果、The bookの内容紹介やDDDの近況については思い切って省略し、かわりにDDDに対する自分たちのポジションを明確に打ち出す方向に転換しました。その上で、個々のメッセージを超えて、会場に来てくれた人に「ちょっとDDDについて調べてみようか」と思ってもらえるようにしたい。これが僕らのメッセージであり、このことに気づいたこの出来事が僕たちにとっての<span class="Apple-style-span" style="font-size: x-large;">ブレイクスルー</span>だった、ということになっています。この思いが暴走した結果、「1、2、3、ディーーー!」みたいな事故が起きたわけですがw<br />
<br />
<span class="Apple-style-span" style="font-size: x-large;"><b>DDDをはじめてみよう!</b></span><br />
実際のところ、どうだったんでしょう?メッセージ、伝わったんでしょうか?僕らはただの痛い人になってしまったんでしょうか?痛い人なのは全然かまわないんですが、少しでもDDDに興味を持ってくれる人がいたなら幸甚です。</div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-23864877.post-48497413939136905602010-02-17T13:04:00.000+09:002010-02-17T13:04:35.616+09:00共訳させていただいた「実用Git」が発売になります<div class="separator" style="clear: both; text-align: center;"><a href="http://www.amazon.co.jp/gp/product/4873114403?ie=UTF8&tag=lifeinshin-22&linkCode=as2&camp=247&creative=7399&creativeASIN=4873114403" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="http://www.oreilly.co.jp/books/images/picture978-4-87311-440-8.gif" /></a><img alt="" border="0" height="1" src="http://www.assoc-amazon.jp/e/ir?t=lifeinshin-22&l=as2&o=9&a=4873114403" style="border: none !important; margin: 0px !important;" width="1" /></div><br />
このたび発売になる「実用Git」を、<a href="http://d.hatena.ne.jp/hiratara/">hirataraさん</a>、<a href="http://d.hatena.ne.jp/kaiseh/">kaisehさん</a>と共訳させていただきました。きょう配本だそうなので、ぼちぼち書店に並ぶのではないかと思います。<br />
<br />
この本は、前から順番に読みつつ出てくるコマンドを叩いていくことで、自然とGitが内部構造も含めてわかるようになっていることが特徴です。Gitを理解するには内部構造を知ることが近道なのですが、概念的な話だけでは頭に入ってきません。この本では、実際にリポジトリを用意し、コマンドを順に試していくことで、日常の作業と内部構造がつながりをもって理解できるように構成されています。<br />
コマンド出力も丁寧に載せられているので、Git環境が手元にない場合でも、実際にGitを使っているように学ぶことができます。<br />
<br />
自分自身、この翻訳をはじめた時は特にGitに詳しいわけではありませんでした。しかし、翻訳をすすめてGitを理解するにつれて、バージョン管理システムをもっとうまく使うことで、今の開発をよりよくできることに気づきました。いま開発でCSV/Subversionをなんとなく使っている人も、この本を読むことで開発をよりよくする道が見えるのではないかと思います。カオスなソースコード管理に悩んでいる人にもおすすめできる本です。興味がわきましたら、ぜひ読んでみてください。<br />
<br />
ちなみに、本には直接関係ありませんが、この本の翻訳もGitを使って進められました。<br />
<ul><li>翻訳者3人による編集</li>
<li>監訳者吉藤さんによる監訳</li>
<li>オライリー・ジャパンの宮川さんによる編集</li>
</ul><div>こうした分散作業をGitで行っています。もしこういう仕事の進め方に興味がわいたなら、日本語版で追加された、瀧内元気さんによる「GitHub入門」や、hirataraさんによる「Gitにおける日本語の利用」が役に立つかもしれません。</div>Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-23864877.post-76889154091948112642009-12-19T18:00:00.012+09:002009-12-25T11:50:10.070+09:00モデル上に明示されたトランザクションとしてのAggregate<div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">最初に読んだ時には今ひとつ理解できなかったAggregate。社内のDDD読書会で読み返してみて感じたのは、「Aggregateは、従来の手続き的な一貫性維持に関する情報(トランザクションスコープ含む)をモデル上に明示したものである」と捉えることで理解しやすくなる、ということ。以下もう少し詳しくみていく。<br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><b><span style="font-size: x-large;">Aggregateの定義と位置づけ</span></b><br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">DDDのGlossaryを見るとAggregateは、<br />
</div><blockquote>A cluster of associated objects that are treated as a unit for the purpose of data changes. External references are restricted to one member of the AGGREGATE, designated as the root. A set of consistency rules applies within the AGGREGATE'S boundaries.<br />
</blockquote><blockquote><i>データ変更を行う上で1単位として扱う必要があるような、相互に関連するオブジェクト群。外部からのAGGREGATEへの参照は、ルートとして識別されたものだけに制限される。一貫性を保つためのルールの集合は、AGGREGATE境界の内部に対して適用される。</i><br />
</blockquote><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
このように説明されており、データの一貫性を保つ単位であることが強調されている。しかし、本を流し読みしただけでは、Repositoryと同レベルのビルディングブロックとして扱うほどの重要性は感じない。冒頭に述べたとおり、Aggregateの位置づけやその重要性は、従来のトランザクション設計と対比させることでわかりやすくなるのではないかと思う。<br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
<br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><b><span style="font-size: x-large;">手続き型トランザクション</span></b><br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">まず最初に、従来の手続き型アプリケーションでのトランザクション設計を考えてみたい。従来自分が行っていた典型的なトランザクション設計は、手続きの範囲を指定することでトランザクションスコープを設定し、その内部で主にデータモデルに対して楽観・悲観の同時実行制御を行う、というものだった。DDDの構成要素で言えば、アプリケーション層のService(のメソッド)をトランザクション境界として設計し、SQLやストアドプロシージャでロックをかけることが多い。<br />
<br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">DDDのAggregateで紹介されている、注文(PurchaseOrder)、注文明細(PurchaseOrderLineItem)、商品(Product)の例を使った例を考えてみる。<br />
<br />
[単純な注文のモデル]<br />
<div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="http://yuml.me/diagram/scruffy/class/%5BPurchaseOrder%5D1-1..*%3C%3E%5BPurchaseOrderLineItem%5D,%20%5BPurchaseOrderLineItem%5D*-%3E1%5BProduct%5D" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="37" src="http://yuml.me/diagram/scruffy/class/%5BPurchaseOrder%5D1-1..*%3C%3E%5BPurchaseOrderLineItem%5D,%20%5BPurchaseOrderLineItem%5D*-%3E1%5BProduct%5D" width="400" /></a><br />
</div><br />
<br />
(残念ながら自分が)よく見るコードはこんな感じだろうか。<br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
[AddPurchaseOrderLineItemService]<br />
</div><pre class="prettyprint">public class AddPurchaseOrderLineItemService {
@Transactional
public void addNewItem(Command cmd) {
...
// PurchaseOrderとPOLineItemを結合したオブジェクトのList
List<PurchaseOrderResult> porList = poDao.findForUpdate(criteria);
...
PurchaseOrderLineItem newItem = new PurchaseOrderLineItem(poList.get(0).getId(), ...);
...
// 内部ではinsert
if (porList.get(0).getLimit() >= (totalPrice(porList) + newItem.getPrice())) {
poLineItemDao.insert(newItem);
}
...
}
}</pre><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">上記のコードでは、一貫性維持に関する知識は…<br />
</div><ul><li>一貫性維持の範囲</li>
<ul><li>=> ApplicationService上の@Transactionalアノテーション</li>
</ul>
<li>一貫性維持範囲内で守るべき不変式</li>
<ul><li>=> if文の条件式</li>
</ul>
<li>同時実行制御戦略</li>
<ul><li>=> DAOのメソッドによるロック</li>
</ul>
</ul><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">これらの中に分散して存在し、モデル(データモデルorオブジェクトモデル)上ではまったく表現されていない。<br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">さらに、ApplicationServiceはユーザーイベント単位に作成されることが多いため、同じモデル(ここではPurchaseOrder)の一貫性に関する情報であるにも関わらず、ユーザーイベントごとにも散逸してしまうことになる。<br />
<br />
<br />
<b><span style="font-weight: normal;"><b><span style="font-size: x-large;">一貫性の知識を手続きからモデルへ</span></b></span></b><br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">DDDでは、ドメイン知識はドメイン層のモデルとして表現するのが原則であり、重要な知識であればモデル上で明示的に表現することを強く推奨している。この方針に沿って上記の問題を解決しようとすれば、自然とモデル上への一貫性を表現する単位の導入に辿り着く。具体的には…<br />
<ul><li>一貫性維持の範囲</li>
<ul><li>=> 維持範囲のモデル表現としてAggregateを導入する</li>
</ul>
<li>一貫性維持範囲内で守るべき不変式</li>
<ul><li>=> Aggregateルートの変更操作内に移動</li>
<li>=> グローバルなルールや、ユビキタス言語に登場すべきルールであれば、Rule/Specificationの導入を検討</li>
</ul>
<li>同時実行制御戦略</li>
<ul><li>=> モデル側で表現</li>
<li>=> ドメイン知識ではないので、外部に追い出す</li>
</ul>
</ul>以下、具体的に見ていく。<br />
<br />
<b>一貫性維持の範囲を明示</b><br />
最終的にはService上で手続きに対する一貫性制約を明示することにはなると思うが、まずはモデルに対して一貫性の維持範囲を設定し、必要に応じてそれらをServiceで調整する、という方針に転換する。今回の例で用いた言語(Java5 or later)ではAggregateを明示的に扱うことができないため、設計上の決めごとに加え、対応するRepositoryを作ることで間接的にAggregateを表現する。<br />
<br />
今回の例での一貫性維持単位、つまりAggregateを構成する要素は、PurchaseOrderとPurchaseOrderLineItemとする。ルートは当然PurchaseOrderになる。<br />
<br />
<div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">現状のDAOでは、Aggregateの子であるPurchaseOrderLineItemを直接取得・変更するようになっているので、AggregateルートであるPurchaseOrderを取得するように変更し、名称もPurchaseOrderRepositoryに変更する。<br />
</div></div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
[AddPurchaseOrderLineItemService]<br />
</div><pre class="prettyprint">public class AddPurchaseOrderLineItemService {
@Transactional
public void addNewItem(Command cmd) {
...
PurchaseOrder po = poRepository.findForUpdate(cmd.id);
...
PurchaseOrderLineItem newItem = new PurchaseOrderLineItem(po.getId(), ...);
...
if (po.getLimit() >= po.getTotal() + newItem.getPrice())) {
po.add(newItem);
poRepository.save();
}
...
}
}</pre>また、最低限一貫性を持たせねばならない範囲はPurchaseOrderのAggregateであるため、トランザクションスコープはPurchaseOrderの状態変更メソッドであるaddItemに設定する。トランザクション設定値としては、このAggregateが必要とする値を設定する。<br />
# 今回はデフォルト値のまま<br />
<br />
[PurchaseOrder]<br />
<pre class="prettyprint">public class PurchaseOrder {
List items = Lists.newArrayList();
@Transactional
public void addItem(PurchaseOrderLineItem item) {
if (limitOver(item.getPrice())) {
throw new ...
}
items.add(item);
}
private boolean limitOver(int price) {
return (price + total) > limit;
}
}</pre>これで、呼び出し側がトランザクションを開始していなくても、PuchaseOrderが必要なトランザクションを設定できる。<br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><b>不変式をモデル内に移動</b><br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">if文内の条件式をAggregateルートの変更操作内に(不変式として)移動させる。これで、ドメイン層のモデル上で表現された。<br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
[PurchaseOrder]<br />
</div><pre class="prettyprint">public class PurchaseOrder {
List items = Lists.newArrayList();
public void addItem(PurchaseOrderLineItem item) {
if (limitOver(item.getPrice())) {
throw new ...
}
items.add(item);
}
private boolean limitOver(int price) {
return (price + total) > limit;
}
}</pre><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
移動後のサービスには、重要な知識は何も残っていない。<br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
[AddPurchaseOrderLineItemService]<br />
</div><pre class="prettyprint">public class AddPurchaseOrderLineItemService {
@Transactional
public void addNewItem(Command cmd) {
...
PurchaseOrder po = poRepository.findForUpdate(cmd.id);
...
PurchaseOrderLineItem newItem = new PurchaseOrderLineItem(po.getId(), ...);
...
poRepository.save();
...
}
}</pre><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
<b>同時実行制御戦略の場所を移動</b><br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">同時実行制御戦略を、取得操作側ではなくEntity側に設定する。また、具体的な制御戦略はドメイン知識ではないので、モデルから追い出すのが良い。<br />
<br />
[PurchaseOrder]<br />
</div><pre class="prettyprint">@Entity
@org.hibernate.annotations.Entity(
optimistcLock = OptimisticLockType.VERSION
)
public class PurchaseOrder {
List items = Lists.newArrayList();
public void addItem(PurchaseOrderLineItem item) {
if (limitOver(item.getPrice())) {
throw new ...
}
items.add(item);
}
private boolean limitOver(int price) {
return (price + total) > limit;
}
}</pre><br />
# TODO:とはいえ、ここの記述はイメージで、この設定でPurchaseOrderLineItemを追加した場合にPurchaseOrderのVERSIONが更新されるようにできるかは未確認…Hibernate詳しくない^^;<br />
<br />
Repositoryのインタフェースからは、同時実行制御戦略を消す。<br />
<br />
[AddPurchaseOrderLineItemService]<br />
<pre class="prettyprint">public class AddPurchaseOrderLineItemService {
@Transactional
public void addNewItem(Command cmd) {
...
PurchaseOrder po = poRepository.find(cmd.id);
...
}
}</pre><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><b>維持範囲の変更/調整</b><br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">DDD本書では、一貫性の維持範囲内にProductを含めるかどうかという議論が出ており、以下のような論点から組み入れるのは好ましくない、という結論になっている。<br />
<ul><li>個々の注文を編集するためにProductまで同時実行制御の対象となってしまい、編集エラーが多発する</li>
<ul><li>Productは、PurchaseOrder/PurchaseOrderLineItemに比べてHigh-Contention</li>
</ul>
<li>Productのpriceが変更になった場合、過去のPurchaseOrderの金額に影響を与えたくない</li>
</ul>これらはいずれもドメイン知識(もしくはそこから得られる洞察)であるため、ドメインモデルに反映したい。Aggregateを明示的に示し、PurchaseOrderAggregateからProductを除外しておくことで、こうした設計判断をモデル上で示すことができる。<br />
いずれにせよ、ProductをPurchaseOrderAggregateの子にすると、Productの変更をPurchaseOrder経由で行うことになり、これは明らかにおかしいので、ソフトウェア設計の視点からも当然の判断だと思う。<br />
</div><br />
<div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><b><span style="font-size: x-large;">手続き+データのパラダイムでは</span></b><br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">一貫性を保たねばならない範囲をモデル上に表現すべき、というのはオブジェクトモデルに限った話ではなく、データモデル上で明示するのも良いプラクティスだろう。DAOやストアドプロシージャなどデータモデルにアクセスする各処理は、こうしたモデルに関する情報に基づいて適宜一貫性を保つようにすることで、一貫性上の問題を起きづらくできる。<br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
</div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-23864877.post-58728361318317851602009-12-12T00:50:00.007+09:002010-01-23T01:31:37.774+09:00KPT2009というわけで、<a href="http://hibituredure.blogspot.com/2008/12/kpt2008.html">2008のKPT</a>および<a href="http://hibituredure.blogspot.com/2009/12/kpt2008.html">2009年のTRY評価</a>を踏まえた上での2009年の振り返り。<br />
<div><br />
</div><div><span style="font-size: large;"><b>■ KEEP</b></span><br />
</div><div>* 英語<br />
</div><div><ul><li>日常の情報ソースを含めた多聴・多読</li>
<li>定期的な実務翻訳</li>
</ul></div><div>* 体系的な学習<br />
</div><div><ul><li>コンピュータ科学の不足部分学習</li>
<li>「モデル」とその扱いの学習</li>
<li>数学とそこそこ仲良くする、関わり続ける</li>
<li>DDDの学習</li>
</ul></div><div>* 交流<br />
</div><div><ul><li>内外の勉強会への参加</li>
<li>社内勉強会の開催</li>
</ul></div><div>* 現場の改善<br />
</div><div><ul><li>現場での設計プラクティスの改善</li>
<li>現場の洗脳(自分がやりたいことをやるための土壌作り)</li>
<li>コードの適正化への働きかけ</li>
</ul></div><div>* 趣味<br />
</div><div><ul><li>楽器を定期的にさわって楽しむ</li>
</ul></div><div><br />
</div><div><span style="font-size: large;"><b>■ PROBLEM</b></span><br />
</div><div><ul><li>数学の基礎知識が圧倒的に不足。数学系の勉強会に出続けるのはつらい。技術士の一次にも不足。</li>
<li>精読とリスニングの力があまりあがっていない。基礎からやらねば。</li>
<li>満足いくようなソフトウェアを作れていない。何か1つ作りたい。</li>
<li>相変わらず趣味と料理が…orz。好きなことを学ぶのが趣味みたいなもんだが…。</li>
<li>会いたい人に会いにいけてない。躊躇してもしょうがない。</li>
</ul></div><div><br />
</div><div><span style="font-size: large;"><b>■ TRY</b></span><br />
</div><div>* 英語<br />
</div><div><ul><li>来年こそTOEICで900点!</li>
<li>精読の力を身につける。</li>
<li>リスニングの力をつけるために、シャドウイングをもっと実践する。</li>
</ul><div>* 実務<br />
</div><div><ul><li>自信を持って内外に紹介できるシステムを作る。</li>
<li>DDDのアイディアを使って、現場の開発を改善する。コードの可読性も向上させる。</li>
<li>ESBをうまく使ってみる。</li>
<li>機会があればDSLをうまく使ってみる。</li>
</ul></div><div>* その他学習<br />
</div><div><ul><li>より利用者側にフォーカスしたアーキテクチャの学習。The Timeless Way of Buildingのシステム版のようなもの。いかにシステムと人間が同居するのかを探求。</li>
<li>数学。まずは技術士試験用に基本的なところから。</li>
<li>OOの原典。どうも、原典を読まないと話が空転する場合があるようだ。</li>
<li>コンピュータ科学。どのあたりに行くかは未定…</li>
</ul><div>* 社交/発信<br />
</div><div><ul><li>社外での勉強会開催。一度くらいやってみたい。</li>
<li>何か役に立つソフトウェアを1つ作って公開。</li>
<li>会うべき人に会いにいく。</li>
</ul><div>* 趣味<br />
</div><div><ul><li>今年こそバンド。無理か?</li>
<li>年賀状を自作の絵で。無理か?</li>
</ul><div><br />
</div><div>思いつく限りではこんなところ。あまり面白くない!てか地味なんだよ!<br />
</div></div></div></div></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-23864877.post-34478787177440117572009-12-12T00:01:00.008+09:002009-12-12T01:22:49.449+09:002009年TRYの評価<div>明日のJavaEE勉強会のポジペネタでもあるので、この機会に整理。まずは、<a href="http://hibituredure.blogspot.com/2008/12/kpt2008.html">KPT2008</a>のTRY(つまり2009年のTRY)の評価から。今年のTRYはこんなんでした。</div><div><br /></div><div><div>■TRY</div><div> * 英語により慣れる</div><div><ul><li>今年はTOEIC 900点を目指したい</li><li> オリジナルが英語の情報は全部英語で読む</li></ul></div><div> * 交流をより増やす</div><div><ul><li>OSSプロジェクトに参加する or 書籍出版に関わる</li><li>何という無理くささ</li></ul></div><div> * 体系的な勉強</div><div><ul><li>ドメイン工学系(GenarativeProgramming => Multiparadigm Design)</li><li>ビジネスモデリング系(Ericsson-Penker => Analysis Patterns => Data Moedl Patterns)</li><li>DSL系(Fowler DSL Books WIP => Meta Programming System)</li><li>ビジネス系(会計~中小企業診断士を趣味的に)</li></ul></div><div> * 趣味</div><div><ul><li>ベース楽しく弾く</li><li>できればアマ志向でバンド組んでスタジオで騒ぐ</li><li>かっくいいのかいてpixivとかに投稿してみたい</li><li>もっかい将棋はじめてもいいかなぁ</li></ul></div><div> * 料理</div><div><ul><li>とりあえずペペロンチーノで乳化あたりから</li></ul></div></div><div><br /></div><div><span class="Apple-style-span" style="font-size:large;"><b>英語に慣れる</b></span></div><div>TOEICは900点には届かず。相変わらず、リスニングでの取りこぼしと、文法まわりのミスが目立つ。反面、リーディング部分はほぼ満点で、高速でざっくり流し読みする、というのは非常に得意になった。ここ数年、インプットとしての英語情報の量に圧倒されていたため、多少の精度は犠牲にしてとにかく高速で流し読みするスキルを鍛えてきた。このスキルをどうやら取得できたのは歓迎すべきことだ。長文の英語を読む前の、あの「ヤだなー」という感じや、読んでいるとすぐに疲れてくる感じはほとんどなくなり、日本語を読むのと近い感覚で読み進められるようになってきた。</div><div><br /></div><div>しかしながら、文法を含めた精読のスキルはあまり向上しておらず、特に実務翻訳を行う場合に苦労した。わかりづらい英文に対して、論理的に英語の意味を確定していく、という作業の精度が、流し読みのレベルに比べると低いのだ。</div><div>今後はリスニングとあわせて、精読のスキルを重点的に鍛えていきたい。</div><div><br /></div><div><span class="Apple-style-span" style="font-size:large;"><b>交流をより増やす</b></span></div><div>交流…増えたのかなぁ。層・圏・トポスや檜山さんのセミナーである程度増えたんだけど、最近予定が合わずにあまり行けてないからなぁ…。</div><div>交流する人数が劇的に増えているわけではないと思う。そもそもそういうタイプの人間でもないし。今交流がある人とのつきあいを大事にしつつ、機会をみつけてちょこちょこ手を伸ばしていく感じにしたい。</div><div>書籍の出版に関しては、層・圏・トポスのご縁からお手伝いさせてもらえることに。色々ご迷惑をおかけします。お世話になってます。</div><div><br /></div><div><span class="Apple-style-span" style="font-size:large;"><b>体系的な勉強</b></span></div><div>今年やった勉強は、こんなところ。</div><div><ul><li>圏(基礎およびモナドまわり)</li><li>ラムダ計算(初等テキスト)</li><li>コンパイラ基礎(ふつパイラで)</li><li>DDD(書籍勉強会開催+現場でいくつか実践)</li><li>DSL(JavaEE勉強会でFowlerのDSL本輪講中)</li><li>微積分(技術士向けに勉強はじめた程度)</li></ul></div><div>ドメイン工学系やビジネスモデリング系はあまり進んでいない。去年力を入れていた、「システム全体」や「人間系+コンピュータ系の複合システム全体」をうまく捉えるための、より広範・抽象的で多分に曖昧さを含む方向にはあまり手を伸ばさず、詳細・厳密な方向へ行っている印象。コンピュータ科学の専門教育受けてないので、専門知識や土台の不足を実感したのが主な要因か。来年はもう1度そっち方面に向かうかもしれない。</div><div>ビジネス系にまったく手を出せていないのは、自分には基礎的な技術の勉強とビジネス系の勉強を同時に進めるほどの器用さがないと悟ったから。仕事での必要性を考えると、基礎技術を固めるのが重要だと考えて、ビジネス系は優先順位を下げている。来年もそうなりそう。</div><div><br /></div><div><span class="Apple-style-span" style="font-size:large;"><b>趣味</b></span></div><div>ベースはちょこちょこさわっているけど、継続してやっている感じではないなぁ。面白い曲を見つけたら耳コピして演奏、楽しんで満足している程度。バンドを組むにはほど遠い。環境だけは整えたんだけど。</div><div><br /></div><div>絵については、好きな漫画をパクってイラスト描いてみたり、会議中に色々描いて(^^;)描くことに慣れるようにしているんだけど、あまりうまくなった感なし。描き散らしているだけで、きちんとした作品にするまで頑張れていないんだよなぁ。基本的なスキルも身に付いてない印象。絶対的に量が足りてない。とりあえず形から入る意味で、ペンタブでも買ってみようかと画策中。来年の年賀状(メール)は、手書きの絵を送りたいものだ。</div><div><br /></div><div><span class="Apple-style-span" style="font-size:large;"><b>料理</b></span></div><div>orz…iPhoneにクックパッド入れたよ!</div><div><br /></div><div>全体的に見ると、趣味系がいまいち、あとはそこそこ頑張っているが満点では決してない、という感じか。トータル65点くらいかな。KPT2009に続きます。</div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-23864877.post-28778859824990599962009-10-02T16:26:00.008+09:002009-10-08T23:50:01.763+09:00ユビキタス言語と日本語数ヶ月前から社内でDDD勉強会を実施していて、最近「ユビキタス言語(Ubiquitous Language)」まで来たんだけど、ここでやっぱり「日本語を使ったら1つの言語、モデルになるのか?」という疑問が出てきた。JavaEE勉強会でも同様の意見が(確かhirataraさんから)出てきていたものの、残りの部分に答えが書いてある可能性もあったので、その時点では「まぁ、用語の一覧みたいなのを作ってなんとかすればいいんじゃないの?」と流したものの、あらためて同じ問題に直面してみると、なかなかやっかいな問題だ。先に進む前に、この時点での自分なりの結論を書いておく。<div><br /></div><div><span class="Apple-style-span" style="font-size:large;"><b>DDDの世界観</b></span></div><div>まずは、DDDにおけるユビキタス言語やモデルの扱いについて簡単にまとめておく。</div><div># 断るまでもないと思うけど、もちろん個人的な理解。</div><div><br /></div><div>ユビキタス言語はドメインモデルに基づく言語であり、ドメイン専門家と開発者の双方が作り、双方が使う。これら2つは一体となっており、片方が変更されればもう一方も変更される。</div><div><br /></div><div>ユビキタス言語が構成する世界−−言い換えれば、言語によって制限された物の見方−−がモデルであり、モデルは第一義的には概念上の存在である。わかりやすく言い換えると、モデルのマスターは頭の中に存在している、ってこと。これを文章やダイヤグラム、コードで表現することもできるけど、そうして表現されたものはすべてモデルの死体のようなもので、作った瞬間から古くなっていく。</div><div><br /></div><div>モデルが頭の中にしかないのであればユビキタス言語も同様で、会話の中にあらわれるものこそが第一義的な「ユビキタス言語」になる。</div><div><br /></div><div>僕たちはソフトウェアを開発したいので、モデルが頭の中にしかないってのはあまりうれしくない。最低でも(モデル表現としての)コードは必要になってくるけど、DDDではモデルを複数作らないのが原則だ。となると、コードの構造は頭の中のモデルを投影したものになり、コードはユビキタス言語で表現されることになる。</div><div><br /></div><div>DDDの世界観は、こんな感じ。</div><div><br /></div><div><span class="Apple-style-span" style="font-size:large;"><b>で、問題は何よ</b></span></div><div><div>日本で開発する場合、顧客と開発者の会話はふつう日本語で行われる。よって、ユビキタス言語は日本語として構築されることになる。</div><div>一方、プログラミング言語は通常英語(というよりは英数字)がベースだ。日本語プログラミング言語も存在しているが、少なくとも業務システムではほとんど使われていない。最近の言語はたいていUnicodeをサポートしているので、識別子として日本語を使えばいいじゃん、と思うかもしれないが、言語が持つ標準的なコーディングスタイルから著しく逸脱するので、信じられないほど可読性が低下する。</div><div># 一度Javaでやってみたことがあるが、正直2度と読みたくない。</div></div><div><br /></div><div><span class="Apple-style-span" style="font-size:large;"><b>どうするべき?</b></span></div><div>ここで取るべき道は2つ。</div><div><ol><li>コードは英語、その他は日本語</li><li>コードはローマ字による日本語表現、その他も日本語</li></ol></div><div>ここで、僕のような西洋かぶれは1番目の方法を選びたがるわけだけど、これはおそらく大きな誤りだ。</div><div><div>英語と日本語は、単に文法や単語が違うだけではなく、世界の見方自体が異なっているので、どうやってもうまく対応させられない部分が出てくる。それがわかっていればまだ良い方で、うまく対応させたと思っているものの、実際は完全に間違えていることだって少なくない。そうした無理な変換によって、実質的にはモデルが2つできてしまいかねない。</div><div>そもそも母国語だけ使っていても、単一のモデルを(言語、文章、コードにわたって)維持するのは非常に困難なので、基本的な道具立てに撹乱要因が入るのはできればご遠慮願いたい。</div></div><div><br /></div><div>2番目は、おそらく現場で一般的に取られている方法だろう。コードを見ると頭が痛くなるような識別子が並ぶことになるのだが、無理に英語を使って混乱するよりはまだマシだろう。</div><div><br /></div><div><span class="Apple-style-span" style="font-size:large;"><b>言語学との関連</b></span></div><div>実際のところ、一番興味深いと感じたのは、Evansのユビキタス言語に関する考え方が、最近読んだ言語学の本での言語に対する態度とかなり近いという点。言語として会話を重視する、といった態度のことね。考えてみれば当たり前なんだけど、言語の中には文字がないものだって存在するし、何より頻繁に変わっていく(設計のためのユビキタス言語のような)言語に追随するには、話されている生きた言語を捕える必要がある。</div><div>にもかかわらず、自分も含めて、言語を「紙に書かれた文字や文章」や「文法書」、「辞書」である、と考える人が異常に多いということに気づいて愕然としてしまった。</div><div><br /></div><div><span class="Apple-style-span" style="font-size: large;"><b>2009/10/8追記:</b></span></div><div>勉強会でさらに話し、名詞の厳格な扱いのおかげで概念をより厳密な言語(プログラム言語)に落とし込みやすい英語と比べ、日本語では概念を明確にしづらい…といった話が。結局、ユビキタス言語は混成言語(ピジン語)のようなものにせざるを得ないのかもしれない。ただし、文法の混成はかなり限定的になりそうだけど。</div>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-23864877.post-85290613415717543172009-10-01T13:48:00.008+09:002009-10-07T15:27:34.521+09:00コンテキストあれこれ<div>知り合いのu1hoshinoががんばってAP設計のノウハウをまとめはじめたようです。手始めは<a href="http://u1hoshino.wordpress.com/2009/09/21/%E3%82%B3%E3%83%B3%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88/">コンテキスト</a>ですが、前半の概念を導入している部分でいろいろ消化不良感があったのでコメントに書こうと思ったのですが、長くなりそうだったのでこっちに書きます。脳内ダンプ的なものなので、特に結論はないです。</div><div><br /></div><div><span class="Apple-style-span" style="font-size:large;"><b>コンテキストって何</b></span></div><div><div>計算機の話に限定すれば、「コンテキスト」は「特定の計算における環境」だと言えます。ここで言う「環境」としては、広義には言語やランタイムを表すこともありますが、今回は(元記事の想定に基づいて)「変数と値のセット」に限定します。</div><div><br /></div><div>特定の計算を構成する命令(ステートメント)を、何かしらの形(関数、プロシージャ、クラス…)でモジュール化することを考えた場合、計算に必要な入力値すべてを引数や戻り値で渡せば、環境は不要になります。実際、純粋関数型言語ではこのようにして計算を組み立てます。しかし、モジュール(の複数の命令)をまたがって同じ情報を繰り返し参照するなら、その情報はパラメータで渡すのではなく、環境として設定してどこからでも参照できるようにすることで、モジュール間の結びつきが煩雑化するのをある程度抑えられます。これが、コンテキストを利用する比較的大きな理由だと思います。</div><div><br /></div><div># 他方で、抽象化された「環境」を引数や戻り値として受け渡していくことで、副作用を排除しつつモジュールの煩雑化を防ぐ、モナドのようなアプローチもあります。</div><div><br /></div><div><span class="Apple-style-span" style="font-size:large;"><b>何故Webでコンテキストを作るのか?</b></span></div><div>Javaで標準的なWebインフラ(Servlet)には、組み込みでリクエスト・セッション・アプリケーションなどのコンテキストオブジェクトが存在しており、自由に利用できます。</div><div>これらのコンテキストにはServlet内から自由にアクセスできるため、まさに「特定のリクエスト実行における環境」になっており、Servlet内部に命令を書いている限り、これらがまさにコンテキストとして機能したはずです。</div><div>しかし現状では、レイヤパターンの適用によってリクエスト処理を複数モジュールに分割し、Webレイヤ以外では上記のコンテキストは使えないように設計するのが一般的になりました。これによって、ビジネスロジックと呼ばれる命令群が特定インフラへ依存することは少なくなったものの、コンテキストの喪失によって最初に設定した問題が発生することになりました。これを解決するために、Web非依存の独自コンテキストを再設計している、というのが元記事で言うところの「コンテキスト」が誕生した経緯です。</div></div><div><br /></div><div><span class="Apple-style-span" style="font-size:large;"><b>コンテキスト情報として何を設定する?</b></span></div><div>これは、計算の性質や、どのようにモジュール分割するかによって変わりそうです。また、リクエスト処理のコンテキスト設定がアプリケーションプログラム側で許可されていないケースも多く、基盤や(APじゃない)アーキテクチャが把握できる範囲となると、相当広範囲で共通的に使われるものに限られるケースが多くなります。結果的に、元記事でも書いてあるような</div><div><ul><li>ユーザー情報</li><li>日付</li></ul><div>などが多くなるわけですね。</div><div>また、コンテキスト情報として設定するものの中で、レイヤ指針に反するような内容を設定した場合、不適切な依存関係が発生する可能性があるので注意する必要があります。ビジネスロジックをインフラから切り離すためのレイヤ化だったのに、コンテキストに端末IDやIPアドレスが設定されていると、ロジックがこれらに依存する可能性があります。単なるデータとして扱っているうちは良いですが、不用意にインフラに特化した「型」に依存してしまうと、物理モジュールの管理が面倒になるので、注意が必要です。</div><div><br /></div><div><span class="Apple-style-span" style="font-size:large;"><b>結局</b></span></div><div>結局、「コンテキスト」が何で、どうして必要なのかを自分の中でもう少し整理しておきたかったというわけでした。書いてみると当たり前というか、しょーもない話ですね。</div></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-23864877.post-82866754061980150532009-06-29T13:34:00.005+09:002009-06-29T13:44:31.701+09:00第4回「層・圏・トポス」読書会にいってきためでたく読書会が開催されるようになってから、めっきり自分で勉強しなくなってしまったんだけど、もともと数学的な知識や素養があるわけでもないので毎回結構辛い ^^; その辛い感じが結構楽しいんだけども。<br /><br />というわけで、今回から(iPhone3GSを買ったこともあり!)黒板を写真に撮ってきて、Descriptionつけながら復習することにした。Picasaにあげようかと思ったけど、iPhotoがFlickrに対応していてアップロードが楽だったので、Flickrにあげた。<br /><br /><a href="http://www.flickr.com/photos/33201663@N07/sets/72157620683685222/">Flickr : 第4回 層・圏・トポス読書会</a><br /><br />まだ半分くらいしかDescription書いていないけど、思い出しながら地道に埋めていく予定。ちなみに、読書会はGoogle Groupsも出来ました。<br /><br /><a href="http://groups.google.co.jp/group/sheaf-category-and-topos">Google Groups : 『層・圏・トポス』読者の会</a><br /><br />謎の合宿(水着のおねえちゃん目当て?)も企画されているようなので、興味があれば是非。Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-23864877.post-2984431335012579822009-05-15T21:13:00.008+09:002009-05-15T22:07:00.479+09:00Poken[Rockstar]が来た。<span style="font-weight: bold;font-size:130%;" >Poken 到着〜ユーザー登録</span><br />QCon Tokyo 2009 のアンケートで当たったPokenが来た。こんなの。この子はどうも、<a href="http://www.amazon.co.jp/gp/product/B0026DOI0C?ie=UTF8&tag=lifeinshin-22&linkCode=as2&camp=247&creative=7399&creativeASIN=B0026DOI0C">Rockstar</a><img src="http://www.assoc-amazon.jp/e/ir?t=lifeinshin-22&l=as2&o=9&a=B0026DOI0C" alt="" style="border: medium none ! important; margin: 0px ! important;" border="0" height="1" width="1" />っていうらしい。まぁまぁかわいい…よね?<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_Sde1cTDCAXc/Sg1dgDOpfWI/AAAAAAAAA_k/V5wcyoMTIBs/s1600-h/DSCF1148.JPG"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_Sde1cTDCAXc/Sg1dgDOpfWI/AAAAAAAAA_k/V5wcyoMTIBs/s320/DSCF1148.JPG" alt="" id="BLOGGER_PHOTO_ID_5336023938707848546" border="0" /></a>思ったよりずいぶん小さい。大きめの消しゴムくらいの大きさ。箱から出すと…<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_Sde1cTDCAXc/Sg1dxs3eNVI/AAAAAAAAA_s/GknwQo-_Oc4/s1600-h/DSCF1149.JPG"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://4.bp.blogspot.com/_Sde1cTDCAXc/Sg1dxs3eNVI/AAAAAAAAA_s/GknwQo-_Oc4/s320/DSCF1149.JPG" alt="" id="BLOGGER_PHOTO_ID_5336024241942705490" border="0" /></a>こんな。コレ以外何も入っていない。<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_Sde1cTDCAXc/Sg1d7ppfqII/AAAAAAAAA_0/-M3hgEd06p0/s1600-h/DSCF1150.JPG"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_Sde1cTDCAXc/Sg1d7ppfqII/AAAAAAAAA_0/-M3hgEd06p0/s320/DSCF1150.JPG" alt="" id="BLOGGER_PHOTO_ID_5336024412877465730" border="0" /></a><br />キャップ(Rockster氏)を取ると、USB端子が。これをUSBポートに差し込むと、autorun が有効になっている(危険な)PCでは、Poken の登録サイトが表示される。<br />autorun が無効になっている場合は、マスストレージになっているので、中に入って"Start_Poken.html"をブラウザで表示すればOK。<br /># ちなみに、Chrome では正常に表示できない模様(友人談)。<br /><br />あとは、表示された Poken サイトで Poken 専用アカウントを作成し、個人情報をポチポチ入れていけば完了。<br /><br /><span style="font-weight: bold;font-size:130%;" >Pokenの仕組み</span><br />"Start_Poken.html"の中を見てみると…<br /><pre class="prettyprint"><META http-equiv="Refresh" content="1; URL=http://p.poken.ch/u/なんかデバイス固有のトークンっぽいもの-+の大量繰り返し"><br /></pre><br />てな感じになっている。http-equiv="Refresh" で自動的にサイトに接続される仕掛けのようだ。肝心の URL は、デバイストークンと-+の繰り返し。-+ の繰り返し部分にはおそらく、交換した名刺の情報が入るのだろう。Poken で情報を交換するたびに、Poken デバイスがこの URL を書き換えているのだと思われる。<br /># このファイルは当然、ユーザーからは書き換え不能。<br /><br /><span style="font-weight: bold;font-size:130%;" >Poken on Mac</span><br />初回接続(新規ユーザー登録)時には Poken サイト上に表示されているPoken デバイス接続状態を示すアイコンが正常に表示されておらず、もしかして Win + IE でしか使えないデバイス認識プラグインとか使ってるのか!? と思ったが、2回目は正常に認識された。どうやら、デバイストークンが送付されていれば接続状態だと認識しているようだ。デバイスが接続されていても、トップページから普通に("Start_Poken.html"を使わず)ログインすると、デバイスは認識されていなかった。<br />というわけで、ネイティブ環境にアクセスできるプラグインを使っているわけでもなさそうだ。Mac ユーザーも安心。<br /><br /><span style="font-weight: bold;font-size:130%;" >セキュリティ</span><br /><a href="http://d.hatena.ne.jp/okdt/20090418/1240011375">Poken/セキュリティ上のご注意 - オートログインはoff、でね。</a><br /><br />仕組みのところで見たけど、接続先の scheme は https ではなくhttp になっている。上記のサイトではこれが問題視されてるんだけど、なんでだろう?情報は全部 URL で送っているんだから(それはそれで問題なわけだが)、SSL だろうがなんだろうが関係ない気がするけど。Poken サイト自体は SSL に対応しているし。昔は対応してなかったのかなぁ。セキュリティはあんま詳しくないからわからないんだけども。<br /><br />デバイストークンや交換した名刺の情報がURL経由で漏洩する可能性については、どうにもならないから割り切ってあきらめるしかなさそうだ。信頼できないネットワーク環境(Proxy含む)では使わないように心がけよう。<br /><br />さーて、誰か交換できる人見つかるかな。<br /><br /><iframe src="http://rcm-jp.amazon.co.jp/e/cm?t=lifeinshin-22&o=9&p=8&l=as1&asins=B0026DOI0C&md=1X69VDGQCMF7Z30FM082&fc1=000000&IS2=1&lt1=_top&m=amazon&lc1=0000FF&bc1=FFFFFF&bg1=FFFFFF&f=ifr&nou=1" style="width: 120px; height: 240px;" marginwidth="0" marginheight="0" frameborder="0" scrolling="no"></iframe>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-23864877.post-28088367270770953352009-05-06T15:57:00.006+09:002009-05-07T08:24:52.973+09:00DDD Sample Application version1.1.0: ユースケーススライスから見たアプリケーション構造の確認(2)前回は、シンプルな参照の機能が、サンプル上でどのように構成されているかを確認した。今回は、積荷の一覧・詳細表示で参照機能の構成を確認しつつ、積荷の新規登録・状態更新まで確認してみたい。<br /><ul><li><s>配送状況の詳細表示</s></li><li><span style="font-weight: bold;">積荷の一覧・詳細表示</span><br /></li><li style="font-weight: bold;">積荷の新規登録</li><li style="font-weight: bold;">積荷の状態更新</li><li>配送ルート候補検索</li><li>積荷への配送ルート設定</li><li>配送状況の更新</li><li>配送状況の更新(バッチ)</li></ul><br /><span style="font-weight: bold;font-size:130%;" >積荷一覧・詳細表示の概要</span><br />これは、商品発送側が現在管理対象になっている積荷の情報を確認するためのもの。おなじみの一覧・詳細表示アプリだ。アプリケーション内では、Booking と呼ばれている。Booking (Trackingもそうだが)はコンテキストなのだろうか?<br />この機能は、一見すると配送状況の詳細表示と同じように思えるが、内部的には異なった作りになっており、Web層の Controller からリモートサービスとして構成された BookingServiceFacade を呼び出す形になっている。<br /><br /><img src="http://yuml.me/diagram/class/%5BCargoAdminController%5D-%3E%5BBookingServiceFacade%5D,%5BBookingServiceFacade%5D-%3E%5BBookingService%5D,%5BBookingServiceFacade%5D-%3E%5BLocationRepository%5D,%5BBookingServiceFacade%5D-%3E%5BCargoRepository%5D,%5BBookingServiceFacade%5D-%3E%5BVoyageRepository%5D,%5BBookingService%5D-%3E%5BCargoRepository%5D,%5BBookingService%5D-%3E%5BLocationRepository%5D,%5BBookingService%5D-%3E%5BRoutingService%5D" width="100%" /><br /><br />BookingServiceFacadeの先も、前回のように単純にRepositoryを呼ぶだけではなく Application層(BookingService)を経由しているため、多少複雑な構成になっている。<br /><br /><span style="font-weight: bold;font-size:130%;" >積荷の一覧・詳細表示</span><br />よくあるエンティティの一覧・詳細表示。検索の種類が違うだけで、アプリケーションの構成はどちらもほとんど同じ。なので、ここでは一覧検索だけを見ていくこととする。<br /><br /><span style="font-weight: bold;">INTERFACES</span><br />エントリポイントは、上記の図でわかるとおり interafaces パッケージの CargoAdminController。<br /><br />[CargoAdminController]<pre class="prettyprint">public final class CargoAdminController extends MultiActionController {<br /></pre><br />このクラスは Spring WebMVC のMultiActionController を継承しているが、これは複数のリクエストを1つのController で処理するためのクラス。デフォルトでは、リクエストURIのスラッシュで区切られた末尾部分と同じ名前のメソッドを呼び出す。その他は SimpleFormController と大差ない。<br /><br />一覧表示は index.jsp から「/admin/list」で呼び出されているが、「/admin」は web.xml で BookingDispatcherServlet に割り当てられており、booking-servlet.xml 経由で上述のCargoAdminControllerに割り振られ、最終的に list メソッドが呼び出されている。<br /><br />[CargoAdminController#list]<pre class="prettyprint"> public Map list(HttpServletRequest request, HttpServletResponse response) throws Exception {<br /> Map<string,> map = new HashMap<string,>();<br /> List<cargoroutingdto> cargoList = bookingServiceFacade.listAllCargos();<br /><br /> map.put("cargoList", cargoList);<br /> return map;<br /> }<br /></pre><br />BookingServiceFacade#listAllCargos() を呼び直しているだけだ。<br /><br />[BookingServiceFacadeImpl#listAllCargos]<pre class="prettyprint"> public List<cargoroutingdto> listAllCargos() {<br /> final List<cargo> cargoList = cargoRepository.findAll();<br /> final List<cargoroutingdto> dtoList = new ArrayList<cargoroutingdto>(cargoList.size());<br /> final CargoRoutingDTOAssembler assembler = new CargoRoutingDTOAssembler();<br /> for (Cargo cargo : cargoList) {<br /> dtoList.add(assembler.toDTO(cargo));<br /> }<br /> return dtoList;<br /> }<br /></pre><br />Repository で Cargo の一覧を取得している。ただし BookingFacadeService はリモートサービスなので、呼び出し元に結果を返却するために DTO を作っている。DTO には Cargo の情報だけでなく、関連する配送ルートの情報まで展開した上で返却している。<br /><br />[CargoRoutingDTOAssembler#toDTO]<pre class="prettyprint"> public CargoRoutingDTO toDTO(final Cargo cargo) {<br /> final CargoRoutingDTO dto = new CargoRoutingDTO(<br /> cargo.trackingId().idString(),<br /> cargo.origin().unLocode().idString(),<br /> cargo.routeSpecification().destination().unLocode().idString(),<br /> cargo.routeSpecification().arrivalDeadline(),<br /> cargo.delivery().routingStatus().sameValueAs(RoutingStatus.MISROUTED));<br /> for (Leg leg : cargo.itinerary().legs()) {<br /> dto.addLeg(<br /> leg.voyage().voyageNumber().idString(),<br /> leg.loadLocation().unLocode().idString(),<br /> leg.unloadLocation().unLocode().idString(),<br /> leg.loadTime(),<br /> leg.unloadTime());<br /> }<br /> return dto;<br /> }<br /></pre><br />ちなみに、CargoAdminController から BookingServiceFacade へのリモート呼び出しは RmiProxyFactoryBean でうまく隠蔽されている。<br /><br />[booking-servlet.xml]<pre class="prettyprint"> <bean id="remoteBookingService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean"><br /> <property name="serviceUrl" value="rmi://localhost:1099/BookingService"/><br /> <property name="serviceInterface" value="se.citerus.dddsample.interfaces.booking.facade.BookingServiceFacade"/><br /> </bean><br /><br /> <bean name="/*" class="se.citerus.dddsample.interfaces.booking.web.CargoAdminController"><br /> <property name="bookingServiceFacade" ref="remoteBookingService"/><br /> </bean><br /></pre><br />ここまでがINTERFACES。というか、ここまででほとんど終わりだ。<br /><br /><span style="font-weight: bold;font-size:100%;" >APPLICATION</span><br />今回はアプリケーションサービスとして BookingService が存在するが、このシナリオでは使われていない。<br /><br /><span style="font-weight: bold;">INFRASTRUCTURE</span><br />Tracking との目立った違いはない。<br /><br /><span style="font-weight: bold;font-size:130%;" >積荷の新規登録</span><br />エンティティの新規登録。新規登録画面の初期化・表示と、入力された積荷情報の登録の2ステップにわかれている。<br />新規登録画面の初期化時は、出発地・到着地を選択するためのドロップダウンメニューに設定する情報を取得しているのみであるため、ここでは積荷情報の登録を見ていく。<br /><br /><span style="font-weight: bold;">INTERFACES</span><br />エントリポイントは、CargoAdminController の register メソッド。<br /><br />[CargoAdminController#register]<pre class="prettyprint"> public void register(HttpServletRequest request, HttpServletResponse response,<br /> RegistrationCommand command) throws Exception {<br /> Date arrivalDeadline = new SimpleDateFormat("M/dd/yyyy").parse(command.getArrivalDeadline());<br /> String trackingId = bookingServiceFacade.bookNewCargo(<br /> command.getOriginUnlocode(), command.getDestinationUnlocode(), arrivalDeadline<br /> );<br /> response.sendRedirect("show.html?trackingId=" + trackingId);<br /> }<br /></pre><br />BookingServiceFacade に丸投げ。<br /><br />[BookingServiceFacadeImpl#bookNewCargo]<pre class="prettyprint"> public String bookNewCargo(String origin, String destination, Date arrivalDeadline) {<br /> TrackingId trackingId = bookingService.bookNewCargo(<br /> new UnLocode(origin),<br /> new UnLocode(destination),<br /> arrivalDeadline<br /> );<br /> return trackingId.idString();<br /> }<br /></pre><br />さらにアプリケーションレイヤに丸投げ。<br /><br /><span style="font-weight: bold;">APPLICATION</span><br />ついにアプリケーションサービスが登場。<br /><br />[BookingServiceImpl#bookNewCargo]<pre class="prettyprint"> @Override<br /> @Transactional<br /> public TrackingId bookNewCargo(final UnLocode originUnLocode,<br /> final UnLocode destinationUnLocode,<br /> final Date arrivalDeadline) {<br /> // TODO modeling this as a cargo factory might be suitable<br /> final TrackingId trackingId = cargoRepository.nextTrackingId();<br /> final Location origin = locationRepository.find(originUnLocode);<br /> final Location destination = locationRepository.find(destinationUnLocode);<br /> final RouteSpecification routeSpecification = new RouteSpecification(origin, destination, arrivalDeadline);<br /><br /> final Cargo cargo = new Cargo(trackingId, routeSpecification);<br /><br /> cargoRepository.store(cargo);<br /> logger.info("Booked new cargo with tracking id " + cargo.trackingId().idString());<br /><br /> return cargo.trackingId();<br /> }</pre><br />処理の流れとしては、Command から取得したコードをもとに ENTITIES や VALUE OBJECTS を復元して新規 Cargo に設定し、最後に Repository で保存している。ごくごく基本的な流れではあるが、設定項目が多すぎて少しぎこちなくなっているため、将来的には CargoFactory を作ってそこに移すのが良いと考えているようだ。<br />この時点で既にトラッキングIDが発行されていることから、ビジネス的には配送ルートが設定されていなくても、正当な積荷らしい。また、Cargo が状態を持っている様子もない。<br />@Transaction でこのメソッドをトランザクション境界に設定している点にも注意。<br /><br /><span style="font-weight: bold;">INFRASTRUCTURE</span><br />一件検索系はもういいので無視して、トラッキングIDの新規発行を担っている CargoRepository#nextTrackingId を確認したい。<br /><br />[CargoRepositoryHibernate#nextTrackingId]<pre class="prettyprint"> public TrackingId nextTrackingId() {<br /> // TODO use an actual DB sequence here, UUID is for in-mem<br /> final String random = UUID.randomUUID().toString().toUpperCase();<br /> return new TrackingId(<br /> random.substring(0, random.indexOf("-"))<br /> );<br /> }</pre><br />あぁ…TODO とかついちゃってるよ…。現段階では UUID が使われているが、本来はDBシーケンスを使う、とのこと。もうバージョン1.1.0なんですけど :-D<br /><br /><span style="font-weight: bold;font-size:130%;" >積荷情報(到着地点)の更新</span><br />基本的な流れは積荷の新規登録と同じなので省略する。<br /><br /><span style="font-weight: bold;font-size:130%;" >まとめ</span><br />リモートファサードを使う場合の実装方針がわかった、ってところだろうか。あえてドメインの構造には立ち入っていないが、このユースケースではドメイン層に入る余地もなさそう。おそらく、配送ルートの検索あたりでないとロジックらしいロジックは出てこないだろうな。<br /><br />目次:<br /><a href="http://hibituredure.blogspot.com/2009/05/ddd-sample-application-version110.html">DDD Sample Application version1.1.0を確認する</a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-23864877.post-1188058502230584922009-05-06T12:06:00.010+09:002009-05-07T08:24:52.973+09:00DDD Sample Application version1.1.0: ユースケーススライスから見たアプリケーション構造の確認(1)前回まででユースケース、アプリの全体構造までを確認したところで、今回はユースケースごと(ユーザーイベントごと)のアプリケーション構造を追っていく。ユーザーイベントを再掲する。<br /><ul><li style="font-weight: bold;">配送状況の詳細表示</li><li>積荷の一覧・詳細表示<br /></li><li>積荷の新規登録</li><li>積荷の状態更新</li><li>配送ルート候補検索</li><li>積荷への配送ルート設定</li><li>配送状況の更新</li><li>配送状況の更新(バッチ)</li></ul>まとめてやろうかと思っていたが、思った以上に長くなったので1イベント per 1エントリで進めることにした。今回は一番上、配送状況の詳細表示。<br /><span style="font-weight: bold;"><br /><span style="font-size:130%;">配送状況詳細表示の概要</span></span><br />主に、顧客が発注商品の配送状況を確認するために使う機能。アプリケーション内では、Tracking という言葉で呼ばれている。<br />Web インタフェースから情報を参照するだけの機能なので、Spring WebMVCのコントローラから Repository 経由でデータを取得して表示するだけのシンプルな作りになっている。アプリケーション層のクラスは存在しない。<br /><img src="http://yuml.me/diagram/class/%5BCargoTrackingController%5D-%3E%5BCargoRepository%5D,%20%5BCargoTrackingController%5D-%3E%5BHandlingEventRepository%5D" width="100%" /><br /><br /><span style="font-weight: bold;font-size:130%;" >INTERFACES</span><br />se.citerus.dddsample.interfaces.tracking の CargoTrackingController がエントリポイントになっている。このクラスは、Spring WebMVC のSimpleFormController を拡張している。<br /><br /><span style="font-weight: bold;">補足:Spring WebMVC の仕組み</span><br />中身に行く前に、これから何度も出てくるであろう Spring WebMVC の仕組みを確認しておく。SimpleFormController は Form のサブミットをハンドリングするために用意されたクラスだ。onSubmit メソッドを決められたメソッドシグネチャで作成しておくと、Form が送信された際に自動的に呼び出される。メソッド引数は、HttpServletRequest, HttpServletResponse[, AnyObject as Command] [, AnyExceptionClass] のようになっているらしい。<br />リクエストが送信された際には、CommandClass プロパティに設定されたクラスがインスタンス化され、リクエストパラメータが設定されて onSubmit の引数として渡されてくることになる。<br /><br />[CargoTrackingController.java]<pre class="prettyprint">public final class CargoTrackingController extends SimpleFormController {<br /><br /> private CargoRepository cargoRepository;<br /> private HandlingEventRepository handlingEventRepository;<br /><br /> public CargoTrackingController() {<br /> setCommandClass(TrackCommand.class);<br /> }<br /><br /> @Override<br /> protected ModelAndView onSubmit(final HttpServletRequest request, final HttpServletResponse response,<br /> final Object command, final BindException errors) throws Exception {<br /><br /> final TrackCommand trackCommand = (TrackCommand) command;<br /> final String trackingIdString = trackCommand.getTrackingId();<br /><br /> final TrackingId trackingId = new TrackingId(trackingIdString);<br /> final Cargo cargo = cargoRepository.find(trackingId);<br /><br /> final Map<string,> model = new HashMap<string,>();<br /> if (cargo != null) {<br /> final MessageSource messageSource = getApplicationContext();<br /> final Locale locale = RequestContextUtils.getLocale(request);<br /> final List<handlingevent> handlingEvents = handlingEventRepository.lookupHandlingHistoryOfCargo(trackingId).distinctEventsByCompletionTime();<br /> model.put("cargo", new CargoTrackingViewAdapter(cargo, messageSource, locale, handlingEvents));<br /> } else {<br /> errors.rejectValue("trackingId", "cargo.unknown_id", new Object[]{trackCommand.getTrackingId()}, "Unknown tracking id");<br /> }<br /> return showForm(request, response, errors, model);<br /> }<br /><br /> public void setCargoRepository(CargoRepository cargoRepository) {<br /> this.cargoRepository = cargoRepository;<br /> }<br /><br /> public void setHandlingEventRepository(HandlingEventRepository handlingEventRepository) {<br /> this.handlingEventRepository = handlingEventRepository;<br /> }<br /><br />}</pre>設定可能なプロパティには以下のようなものがある。<br /><ul><li>sessionForm<ul><li>Commandオブジェクトをセッションに保存するかどうか</li></ul></li><li>commandName<ul><li>CommandオブジェクトをRequest/Sessionにバインドする際の名前</li></ul></li><li>formView<ul><li>初回アクセスまたはバリデーションエラー時に表示するビュー名</li></ul></li><li>successView<ul><li>onSubmitが成功した場合に表示するビュー名</li></ul></li><li>validator<br /><ul><li>Commandのバリデータ</li></ul></li></ul>これらは、Bean定義ファイルを用いて以下のように設定されている。<br /><br />[tracking-servlet.xml]<pre class="prettyprint"><beans xmlns="http://www.springframework.org/schema/beans"<br /> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br /> xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"><br /><br /> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"><br /> <property name="interceptors"><br /> <list><br /> <ref bean="openSessionInViewInterceptor"/><br /> </list><br /> </property><br /> </bean><br /><br /> <bean name="/track" class="se.citerus.dddsample.interfaces.tracking.CargoTrackingController"><br /> <property name="sessionForm" value="true"/><br /> <property name="commandName" value="trackCommand"/><br /> <property name="formView" value="track"/><br /> <property name="successView" value="start"/><br /> <property name="validator" ref="trackCommandValidator"/><br /> <property name="cargoRepository" ref="cargoRepository"/><br /> <property name="handlingEventRepository" ref="handlingEventRepository"/><br /> </bean><br /><br /> <bean id="trackCommandValidator" class="se.citerus.dddsample.interfaces.tracking.TrackCommandValidator"/><br /><br /></beans></pre><br /><span style="font-weight: bold;">onSubmitの処理内容</span><br />onSubmit では、コマンドオブジェクトから取り出したトラッキングID を使って CargoRepository から Cargo オブジェクトを、HandlingEventRepository から HandlingEvent のリストを取得してビューに返しているだけだ。ただし、ビューにはドメインオブジェクトをそのまま返すのではなく、アダプタを作って返している。この点は後述する。<br />TrackingCommand は trackingId しか持っておらず、TrackingCommand のバリデーターは、trackingId が空でないことを確認しているだけだ。<br /><br /><span style="font-weight: bold;">プレゼンテーションモデルの選択</span><br />DDD では、プレゼンテーション層のモデルとしてどのようなものを採用するかがよく議論になっている。一般的なものとしては、以下のような候補がある。<br /><ul><li>DomainObject をそのまま返す</li><li>DomainObject のアダプタを作り、View にはアダプタインタフェースを返す</li><li>専用のプレゼンテーションモデルを作り、DomainObject のデータをコピーした上で返す<br /></li></ul>今回は2番目の、アダプタを作ってビューに返す方法を取っている。<br /><br /><span style="font-weight: bold;">OpenSessionInView の採用</span><br />Hibernate の Lazy 用として、openSessionInViewInterceptor がインターセプタとして設定されているのが面白い。Seasar コミュニティでは Dxo の導入が一般的になっていた気がするけど、こちらは OpenSessionInView パターンを使っているのか。OpenSessionInView は嫌われているようだけど、自分は別に嫌いではない。常に Dxo 層導入するの面倒くさいし。<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">APPLICATION</span></span><br />存在しない。<br /><br /><span style="font-weight: bold;font-size:130%;" >INFRASTRUCTURE</span><br />ここで出てくるのは、(上記で説明したSrpring WebMVCを除けば)Repository のHibernate 実装の部分だ。中を見てみると実際はあまり大したことをしておらず、ほとんどの処理を Hibernate に丸投げしている。ORM 万歳。<br /><br />[CargoRepositoryHibernate.java]<pre class="prettyprint">@Repository<br />public class CargoRepositoryHibernate extends HibernateRepository implements CargoRepository {<br /><br /> public Cargo find(TrackingId tid) {<br /> return (Cargo) getSession().<br /> createQuery("from Cargo where trackingId = :tid").<br /> setParameter("tid", tid).<br /> uniqueResult();<br /> }<br /><br /> public void store(Cargo cargo) {<br /> getSession().saveOrUpdate(cargo);<br /> // Delete-orphan does not seem to work correctly when the parent is a component<br /> getSession().createSQLQuery("delete from Leg where cargo_id = null").executeUpdate();<br /> }<br /><br /> public TrackingId nextTrackingId() {<br /> // TODO use an actual DB sequence here, UUID is for in-mem<br /> final String random = UUID.randomUUID().toString().toUpperCase();<br /> return new TrackingId(<br /> random.substring(0, random.indexOf("-"))<br /> );<br /> }<br /><br /> public List<cargo> findAll() {<br /> return getSession().createQuery("from Cargo").list();<br /> }<br /><br />}<br /></pre><br />今回は、find メソッドしか使っていない。これは、単に JPQL を使って一件検索しているだけだ。すべての XxxxRepositoryHibernate は HibernateRepository を継承しているが、HibernateRepository はサブクラスからの getSession 呼び出しに応じて Session を提供しているだけだ。<br /><br />[HibernateRepository.java]<pre class="prettyprint">public abstract class HibernateRepository {<br /><br /> private SessionFactory sessionFactory;<br /><br /> @Required<br /> public void setSessionFactory(final SessionFactory sessionFactory) {<br /> this.sessionFactory = sessionFactory;<br /> }<br /><br /> protected Session getSession() {<br /> return sessionFactory.getCurrentSession();<br /> }<br /><br />}<br /></pre><br />HandlingEventRepository はさらにシンプルで、メソッドは1つしかない。こちらも、JPQL で一覧検索しているだけ。<br /><br />[HandlingEventRepository.java]<pre class="prettyprint">@Repository<br />public class HandlingEventRepositoryHibernate extends HibernateRepository implements HandlingEventRepository {<br /><br /> @Override<br /> public void store(final HandlingEvent event) {<br /> getSession().save(event);<br /> }<br /><br /> @Override<br /> public HandlingHistory lookupHandlingHistoryOfCargo(final TrackingId trackingId) {<br /> return new HandlingHistory(getSession().createQuery(<br /> "from HandlingEvent where cargo.trackingId = :tid").<br /> setParameter("tid", trackingId).<br /> list()<br /> );<br /> }<br /><br />}</pre><br /><span style="font-weight: bold;"><span style="font-size:130%;">まとめ</span></span><br />シンプルな検索は、(アプリケーションレイヤをスキップして)Web-FWから直接 Repository を呼び出すことで実現している。プレゼンテーションモデルとしては、Adapter アプローチを取っている。<br /><br />もともとシンプルなユースケースであることも手伝って、なんだか依存テクノロジの説明がほとんどになってしまった。次回からはこういった説明は少なくなるはずなので、もっとさくさく進むはず!<br /><br />目次:<br /><a href="http://hibituredure.blogspot.com/2009/05/ddd-sample-application-version110.html">DDD Sample Application version1.1.0を確認する</a>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-23864877.post-51873830859094880682009-05-06T03:33:00.009+09:002009-05-07T08:24:52.974+09:00DDD Sample Application version1.1.0: アプリケーション全体構造の確認続いては、アプリケーション全体構造の確認。ここからようやく、ソースコードレベルでの確認に入っていく。単にソースを見るだけなら<a href="http://dddsample.sourceforge.net/download.html">ダウンロードページ</a>からダウンロードすればいいが、効率よく読んでいくためには Eclipse 等 IDE のサポートが必要だろう。Maven を使っているので多少面倒くさいが、<a aiotarget="false" aiotitle="ダウンロードページ" href="http://dddsample.sourceforge.net/download.html">ダウンロードページ</a>には IDE で使うための情報も書かれているので、(特に Eclipse ユーザーは)参考にすると良い。<br /><br /><span style="font-weight: bold;font-size:130%;" >インフラストラクチャが依存するテクノロジ</span><br />実際のアプリケーションに入る前に、まずはインフラが依存する基本的なテクノロジ(ライブラリやフレームワーク)を確認しておく。採用するテクノロジは列挙にとどめる。<br /><ul><li>IoC (DI)コンテナ<ul><li>Spring 2.5.6</li></ul></li><li>Webフレームワーク<ul><li>Spring WebMVC 2.5.6</li></ul></li><li>ORM<ul><li>Hibernate 3.3.1</li></ul></li><li>ロギング<ul><li>log4j 1.2.14</li></ul></li></ul><br /><span style="font-weight: bold;font-size:130%;" ><span style="font-weight: bold;">パッケージ</span>の概要</span><br />アプリケーションは、大きく以下の3つのパッケージに分割されている。<br /><ul><li>com.pathfinder</li><li>com.aggregator</li><li>se.citerus.dddsample</li></ul>com.pathfinder は配送ルート候補を計算するために使われているのだが、これは一般的なグラフ構造を扱うパッケージになっており、Distillation の観点から見ると COHESIVE MECHANISMS(一般的な問題を解決するためのメカニズムを表す部分) になっている。もしかすると、GENERIC SUBDOMAINS(ドメインの観点から見て重要性が低い部分)とみなしても良いのかもしれない。<br /><br />aggregator は 配送状況を一括更新するための Java-XML マッピングと Webサービスを扱っているパッケージだが、この部分を interfaces に含めず独立したパッケージとして扱っている理由がよくわからない。Webインタフェース用の Servlet や Spring WebMVC の Controller が interfaces パッケージに含まれることを考えると、Webサービス用だけが独立しているのは理解しづらい。<br /><br />se.citerus.dddsample は、CORE DOMAIN(ドメインの観点から重要度の最も高い部分)、またはCORE DOMAINを含むパッケージとなっているはずで、主要な機能はすべてここにおさめられている。<br /><br /><span style="font-weight: bold;font-size:130%;" >レイヤの確認</span><br />se.citerus.dddsample パッケージはさらに、以下の4つのパッケージで構成されている。<br /><ul><li>interfaces</li><li>infrastructure</li><li>application</li><li>domain</li></ul>このうち、interfaces を除く3つは、the book で基本的なレイヤとして紹介されているもので、それがそのままパッケージ構造に反映されている。これらレイヤの概要は、<a href="http://dddsample.sourceforge.net/architecture.html">Architectureと題されたページ</a>に書かれている。<br /># なお、テストパッケージにはこれらに加えて「scenario」が存在し、シナリオテストが収められている。<br /><br /><span style="font-weight: bold;font-size:130%;" >INTERFACES</span><br />今回から新たに導入されたレイヤ。Webブラウザ等のヒューマンインタフェースを含む、外部システムとのインタフェースすべてが配置される。入力データの解釈、検証、変換や、出力データのシリアライズはこのレイヤが担う。DTO も含まれる。<br /># だったらなおさら、なんで aggregator が独立パッケージなのかわからないが<br /><br />このパッケージは、さらに以下の3つのパッケージで構成されている。<br /><ul><li>tracking</li><li>booking</li><li>handling</li></ul>これは、ビデオで紹介されている主要なインタフェースに対応…つまり、 tracking が Customer による配送状況の確認に、booking が配送手配者による積荷の管理に、handling が配送業者による配送状況の更新に対応している。<br /><br />これらのパッケージは、それぞれがさらにテクノロジ依存のサブパッケージ(web, file, wsなど)を持っているが、この部分の詳細は次回以降で確認する。<br /><br /><span style="font-weight: bold;font-size:130%;" >APPLICATION</span><br />積荷の新規登録(Booking)と配送状況更新(Handling)に関するアプリケーションサービスとその実装、それに ApplicationEvent というイベント通知用のインタフェースから構成されている。アプリケーションサービスに配送状況確認(Tracking)がないのは、おそらくシンプルすぎてサービスが必要ないからだと思われる。Tracking は参照のみなので、Repository のメソッドを呼ぶだけですんでしまう。次回参照するが、この処理は interfaces パッケージ内の Controller に直接記述されている。<br />ApplicationEvent はいわゆるイベントオブジェクトではなく、ステートレスなイベント通知インタフェースで、ほぼサービスと考えても良いくらいのものだ。ApplicationEvent の実装はメッセージングを使うようになっており、そのインフラ色の強さからか infrastructure パッケージに配置されている。<br /><br />テストやサンプルデータ生成用のユーティリティも配置されているが、これらは本来ならテストソースフォルダなりリソースフォルダなりに移すべきものだろう。<br /><br /><span style="font-weight: bold;font-size:130%;" >INFRASTRUCTURE</span><br />infrastructure パッケージは、以下の3つのパッケージで構成されている。<br /><ul><li>persistence.hibernate</li><li>messaging.jms</li><li>routing<br /></li></ul> persistence.hibernate パッケージには、何度も the book で述べられているとおり(ドメイン層にインタフェースだけ存在する) Repository の Hibernate 実装が配置されている。<br /><br />messaging.jms にはその名のとおり JMS 関連のコードが配置されており、infrastructure の観点では特に興味深い点はないが、ApplicationEvent のような application レイヤの実装も含まれている点は面白い。Sample Application 1.0 にはinfrastructure パッケージが存在せず、すべて application につっこまれていたことから、application は infrastructure-aware で良いのかと思っていたが、application もきちんとインフラから分離するようだ。<br /><br />routing パッケージに唯一存在する ExternalRoutingSerivice は、なんとドメインサービスの実装だ。ドメインサービスの実装が infrastructure に配置されるなんて構成は考えたこともなかった。このサービスは、COHESIVE MECHANISMS として紹介した pathfinder へのリモート接続を含むため、infrastructure に配置されているようだ。接続先の pathfinder サービスは javax.rmi.Remote を実装しているため、RemoteException をスローする。<br /><br /><span style="font-weight: bold;font-size:130%;" >DOMAIN</span><br />すべての中心となる部分。パッケージは以下のように分割されている。<br /><ul><li>model</li><li>service</li><li>shared</li></ul>model には、ENTITIES, VALUE OBJECTS, DOMAIN EVENTS, REPOSITORIES, FACTORIES といったDDDのビルディングブロックが含まれている。また、各種 Exception も含まれている。あまり説明はいらないだろう。<br /><br />service には、ドメインサービスが含まれている。今回は、先ほど infrastructure で説明した RoutingService しか配置されていない。<br /><br />shared には、DDDビルディングブロックを表す各種インタフェースや、Specification 関連の基本クラスなど、まさにドメインレイヤの基盤になるクラスたちが配置されている。<br /><br /><span style="font-weight: bold;font-size:130%;" >まとめ</span><br />まずは主要な部分である se.citerus.dddsample と補助的な部分である com.aggregator/com.pathfinder とは明確に分離できる。主要なドメインである dddsample は、(interfacesが追加されているものの)基本的には the book に忠実に分割されていることがわかる。<br /><br />目次:<br /><a href="http://hibituredure.blogspot.com/2009/05/ddd-sample-application-version110.html">DDD Sample Application version1.1.0を確認する</a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-23864877.post-34683170998412189092009-05-06T02:15:00.017+09:002009-05-07T08:24:52.974+09:00DDD Sample Application version1.1.0: ユースケースの確認さて、まずは Sample Applicatin のユースケースを確認する。これには、実際に動かしてみるのが一番だが、そこまでするのが面倒な人のために、丁寧にもビデオが用意されている。なので、確認はこのビデオに沿って進めていきたい。<br /><br /><span style="font-weight: bold;font-size:130%;" >概要</span><br />細かい説明に入る前に断っておきたいのだが、このアプリケーションは the book(Evans の DDD本)で何度も例としてあげられている、積荷の出荷とトラッキングを扱ったアプリケーションがもとになっている。イメージとしては、DELL やら Amazon やらで商品を買った際に通知されてくる、配送状況確認ページを思い浮かべてもらうとわかりやすいと思う。<br />このアプリケーションではさらに、上記のような商品を買った側(Customer)からの配達状況の確認だけでなく、商品提供側(DELL や Amazon)による配送の手配や、配送業者による配達状況の更新までできるようになっている。最初にこれくらいのイメージを持っているとわかりやすい。<br />というわけで、ビデオはこれ。とりあえずは、ざっと画面のイメージだけ確認できればOK。細かい内容はこの後にも書いてます。逆に、ビデオの内容が完璧にわかれば、この後はほとんど読む必要ないです ^^;<br /><br /><object height="340" width="560"><param name="movie" value="http://www.youtube.com/v/eA8xgdtqqs8&hl=ja&fs=1"><param name="allowFullScreen" value="true"><param name="allowscriptaccess" value="always"><embed src="http://www.youtube.com/v/eA8xgdtqqs8&hl=ja&fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" height="340" width="560"></embed></object><br /><br />このアプリケーションには、以下のような3つのインタフェースがある。<br /><ul><li>積荷(Cargo)のトラッキングインタフェース</li><li>配送予約とルートの管理用インタフェース</li><li>配送状況の更新インタフェース</li></ul>最初の2つは Web、3つ目には Swing によるリッチクライアントアプリケーションと、ファイルトリガのバッチアプリケーションの2種類が用意されている。<br /><br /><span style="font-weight: bold;font-size:130%;" >積荷のトラッキング</span><br />これは、顧客(Customer)が注文した積荷の配送状況を確認するためのもので、トラッキングIDを入力できるだけのシンプルなインタフェースになっている。ここにトラッキングIDを入力して送信すると、以下の情報が表示される。<br /><ul><li>積荷の到着予定時刻<br /></li><li>現在の積荷の場所</li><li>次に積荷が向かう場所</li><li>積荷の配送履歴</li></ul>積荷が間違って(予定とは異なるルートで)配送されてしまった場合には、画面上に「Cargo is misdirected」とエラーメッセージが表示され、次に積荷が向かう場所は表示されず、積荷の到着予定時刻は不明と表示される。また、配送履歴のうちミスがあった部分に「×」がつく。<br /># 実際、顧客に直接こんな情報表示するんかいなという感じがするが…。<br />後で出てくるのだが「配送状況の更新インタフェース」にて誤った情報を送信した場合にこのように表示されることになる。<br /><br /><span style="font-weight: bold;font-size:130%;" >配送予約とルートの管理</span><br />商品の配送者(DELLとかAmazonとか)が、積荷の新規登録や配送ルートの選択を行うインタフェース。以下のようなことが可能。<br /><ul><li>積荷の状況確認</li><li>積荷情報の更新<br /></li><li>積荷の新規登録(配送予約)</li><li>積荷の配送ルート候補の検索および確定</li></ul>積荷の状況確認機能では、積荷情報の一覧表示、詳細表示ができる。詳細画面では積荷情報の更新に進むことができ、配送先のみが変更できる。「モノ」を管理するための典型的なインタフェース構成で、業務システムを作ったことがある人なら見飽きているだろう。<br />積荷の新規登録では、一度にすべての情報を入力しきるのではなく、まずは出発地点と到着地点、そして到着デッドラインのみを登録する。この時点でトラッキングIDが払い出されるが、配送ルートはまだ決まっていない。配送ルートは、配送ルート候補の検索および確定機能で別途確定させる。<br /><br />配送ルートの検索と確定は、このシステムで一番面白いところだろう。入力された情報をもとに、配送ルートの候補がいくつか表示される。管理者はこの候補を確認し、好ましいルートを選択して配送ルートを確定させる。<br /><br />なお、ビデオでは到着地点の更新は実行されていないが、既に配送ルートが選択された状態で到着地点を変更しても、エラーになることもなく警告メッセージのようなものも表示されない。かなり寛容な作りなようだ。<br /><br />個人的には、こんなことに興味がある。後で確認してみたい。<br /><ul><li>Cargoに別々の状態を持たせているのかどうか</li><li>トラッキングIDをどのように払い出しているのか</li><li>配送ルート候補の検索で使われる、ルート選択ポリシーの種類とその扱い</li></ul><br /><span style="font-weight: bold;font-size:130%;" >配送状況の更新</span><br />配送業者(クロネコとか佐川とか)が、配送状況を随時更新するためのインタフェース。このアプリケーションはシンプルで、1画面しかない。ここに、以下のような情報を入力する。<br /><ul><li>更新時刻</li><li>トラッキングID</li><li>便(Voyage)</li><li>イベント発生場所のコード</li><li>イベントタイプ<br /></li></ul>便は必須項目ではないらしく、イベントタイプによっては必要ないようだ。例えば、工場から積荷を受け取るイベントが発生した場合、この時点では便は関係ないので入力は不要だ。<br /><br />項目名に「イベント」とあるように、これは DDDのビルディングブロックの1つである「DomainEvent」を発生させるためのインタフェースであるらしい。これだけがリッチクライアントとして作られているのは、配送の現地(倉庫や船)から更新することを考えるとバーコードなどの専用端末からの更新が現実的なためで、Swingは端末を簡易にエミュレートしているのだろう。<br /><br />個人的には、このあたりに興味がある。<br /><ul><li>バリデーションが存在しないのは、DomainEventパターンの適用によるものなのか、端末エミュレートによるものなのか</li></ul><br /><span style="font-weight: bold;font-size:130%;" >配送状況の更新(バッチ)</span><br />Swingアプリケーションとは別に、配送状況を一括更新するインタフェースも存在する。これは、タブ区切りのテキストデータが指定のフォルダに置かれると、そのデータをもとに自動的に配送状況が一括更新されるというものだ。一括更新であること以外の機能は Swingアプリケーションと同じで、テキストデータの1行として記述する項目も、Swing アプリケーションと同じ。ビデオでは、配送状況の更新インタフェースの一部として扱われている。<br /><br /><span style="font-weight: bold;font-size:130%;" >まとめ</span><br />というわけで、ビデオを見るとだいたい何をやっているかはつかめると思う。一応、次回以降で確認するイベントをあげておく。<br /><ul><li>配送状況の詳細表示</li><li>積荷の一覧・詳細表示<br /></li><li>積荷の新規登録</li><li>積荷の状態更新</li><li>配送ルート候補検索</li><li>積荷への配送ルート設定</li><li>配送状況の更新</li><li>配送状況の更新(バッチ)<br /></li></ul>次回は、これらイベントの個別のハンドリング方法を確認する前段階として、アプリケーションの全体構造を確認する。<br /><br />目次:<br /><a href="http://hibituredure.blogspot.com/2009/05/ddd-sample-application-version110.html">DDD Sample Application version1.1.0を確認する</a>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-23864877.post-5674249161732375872009-05-06T01:04:00.008+09:002009-05-07T08:24:52.975+09:00DDD Sample Application version1.1.0 を確認するようやく Evans の DDD本(the book)をすべて読み終わった(長かった!)ので、オフィシャルに提供されているサンプルアプリケーションである <a href="http://dddsample.sourceforge.net/">DDD Sample Application</a> を確認し、具体的な実装方法やビルディングブロックの実例を見つつ理解を深めておきたい。昨年リリースされたバージョン1.0は軽く確認したのだが、3月25日にリリースされたバージョン1.1.0はまた結構変わっているようなので、あらためて最新のDDDアプリケーション構造を確認していく。<br />とりあえずは、こんな感じで進めていく予定。<br /><ol><li>ユースケースの確認</li><li>アプリケーション全体構造の確認<br /></li><li>ユースケーススライスから見たアプリケーション構造の確認<br /></li><li>ドメイン構造の確認</li></ol><br /><span style="font-weight: bold;font-size:130%;" >ユースケースの確認</span><br />このアプリケーションが何を目的として作られ、どんな機能を提供するのかをユーザー視点で確認する。<br /><br /><br /><span style="font-weight: bold;font-size:130%;" >アプリケーション全体構造の確認</span><br />細かいコードの確認に入る前に、アプリケーション全体の構造がどのようになっているのかを確認する。主に、Distillation や Large-Scale Structure の観点からアプリケーション全体構造の特徴を把握する。<br /><br /><span style="font-size:130%;"><br /></span><span style="font-weight: bold;font-size:130%;" >ユースケーススライスから見たアプリケーション構造の確認</span><br />機能的な観点から見たアプリケーションの構造を確認する。各ユーザーイベントに対してどのようなソフトウェア要素が対応し、どのようにドメインレイヤにつなげていくのかを把握する。主にプレゼンテーション層(interfacesパッケージ)、サービス・アプリケーション層(applicationパッケージ)、インフラ層(infrastructureパッケージ)を確認する。<br /><br /><br /><span style="font-weight: bold;font-size:130%;" >ドメイン構造の確認</span><br />ドメイン層がどのように構成されているのかを確認する。メインの部分。<br /><br /><br />最後までできるかな…てか予定どおりいくかな…。<br /><br />コンテンツ一覧:<br /><ol><li><a href="http://hibituredure.blogspot.com/2009/05/ddd-sample-application-version110_06.html">DDD Sample Application version1.1.0: ユースケースの確認</a></li><li><a href="http://hibituredure.blogspot.com/2009/05/ddd-sample-application-version110_9820.html">DDD Sample Application version1.1.0: アプリケーション全体構造の確認</a></li></ol>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-23864877.post-74761560092737418272009-05-02T01:14:00.011+09:002009-05-05T17:58:24.001+09:00DSM(DomainSpecificModeling) + DDDDDDオフィシャルサイトに掲載されている、DSM(Domain Specific Modeling)に関するインタビューを起こしてみた。オリジナルのビデオは<a href="http://www.domaindrivendesign.org/library/bell_gitlevich_2009">ここ</a>。どうでもいいと思ったところや一部よくわからなかったところは飛ばしてるし、間違っているところもあると思います ^^;<br /><br /><span style="font-weight: bold;font-size:130%;" >はじめに<br /></span>Interviewer(以下"I"):<br />Peter Bellが来てくれた。自己紹介してくれる?<br /><br />Peter Bell(以下"P"):<br />カンファレンスなど、色んな場面でこのトピックについて話している。DSMやコードジェネレーションについて話すのにベストな人間だと思う。<br /><br /><span style="font-weight: bold;font-size:130%;" >DSMとは</span><br />I: 今日はDSMについて話したいが、まずはDSMが何か教えてもらえるだろうか?<br /><br />P: 役に立つ良い定義としては「開発プロセスのスピードアップ、アプリケーションの一部または全体の生成、コードベースのメンテナンスなどのためにDSLを使うこと」のように言えると思う。<br /><br />I: じゃあ、DSLって何?<br /><br />P: 3つのコンポーネントがあると思っている。<br />まず1つは、Javaなどの汎用言語とは異なり、特定の問題を解決するためのものであるということ。<br />2つ目は、コンストラクションのレベルをひきあげるものであること。JavaやC#とおなじようにかかなくても良い。<br />3つ目は、実行可能であるということ。ユビキタス言語は必ずしも実行可能でなくてもいいが、DSLはジェネレーションやインタープリタを通して実行できる。<br /><br />I: それがユビキタス言語とDSLの違いなんだね?<br /><br />P: その通り。DSMはアプリケーションを生成したり実行したりするのに十分なユースケースのセットにフォーカスしていて、ユビキタス言語から直接アプリケーションを生成する。こうすることで色々メリットがある。<br /><br />I: プロジェクトでは、会話で使われるようなユビキタス言語もあればコードにあらわれるユビキタス言語もある。後者は実行可能なユビキタス言語、つまりDSLなのか?<br /><br />P: そう言える。えーとここで、DSMの世界で重要なDSLの興味深い区別について話しておきたい。内部DSLと外部DSLだ。内部DSLはAPIとかRuby Groovyのような言語を使って、人間が読めるようなDSLをコード内に作るアプローチだ。このアプローチではDSLの利点をフルに受けることはできない。なぜなら、ホスト言語の構文上の問題を気にしなければならないからだ。<br />外部DSLはよりパワフルで、DSLをコードの外部に持ち出し、DSLのステートメントを書くためのツールを別途用意できる。これは、箱と線で書けるようにもできるし、テキストで書くようにもできるし、スプレッドシートで書くようにもできる。<br />外部DSLの利点はジェネレートされた個々のステートメントをテストしなくていいので開発やメンテナンスのスピードをあげることができること。<br /><br />I: 利点についての話があったが、他に利点はある?<br />P: 最も大きなものとしては、テスティングコストの低下があげられる。よくできたユビキタス言語は確かに、ステークホルダーとプログラマの間のコミュニケーションの問題を改善できる。しかし、コードへの変換時にはインピーダンスミスマッチがあるため、ここで理解の齟齬が発生し、バグの発生につながってしまう。DSMではこのような事態を完全に避けられる。ステークホルダーとコミュニケートし、彼らが話すことをそのまま書き、コードをジェネレートできる。<br /><br />I: 言語が正しければ、テストの必要はない?<br />P: セマンティクスはもちろんテストする。DSLのステートメントが正しくその意図を表しているか、つまり与えられたステートメントが正しくジェネレートされるか、もしくは正しくインタープリタで実行されるかどうかはテストするということだ。しかし、すべての個々のステートメントをテストする必要はない。<br /><br />I: 開発のスピードがあがるとのことだが、アップグレードも頻繁になるのでは?<br />P: その通り。頻繁にビルドするようにもなる。だが、メンテナンスの際に細かなコードブロックを見るのではなく、意図が明示されたDSL(ユビキタス言語)を見ればいいからメンテナンスも楽になる。<br /><br />I: 利点にはすべてトレードオフがある。モデルが変更された場合、言語も変更することになると思うが、既存のツールでこの変更に対応するのはどれくらい難しい?<br />P: シンプルなリファクタリングサポートは既に存在しており、軽微な変更には問題なく対応できるが、根本的な変更に対しては無力。ただし、これはJavaやらC#を使っていても同じ。<br />ドメイン(に関する理解)が安定するまで、ジェネレータやインタープリタの作成を先延ばしにするのも良いかもしれない。<br /><br /><span style="font-weight: bold;font-size:130%;" >DSMにまつわる誤解</span><br />I: 誤解について話したい。DSMについては色んな話(誤解?)を聞いたが、そのうちのいくつかはUMLについてだった。<br />P: そりゃDSMではもっとも有害な誤解だと思う。仮に私がDSMをMDAやUMLからはじめていたとしても、UMLは使い続けなかったと思う。UMLは世界中で多くの人が使っていて、標準化もされており、多くの利点がある。しかしUMLの問題は、記述のレベルは抽象的すぎるということ。ステレオタイプでドメインのコンセプトを表せるようになってはいるが、クラスやメソッドが何をすべきかは何も決められていない。クラスごとに箱が1つ用意されるだけだ。なので、モデルからモデルへの変換やモデルからのテキストへの変換は簡単ではない。XMIみたいに。MDAがDSMの小さなサブセットにすぎないことを理解しておくことは非常に重要だと思う。<br />MetaCaseとかOpenArchitectureWareはEclipseプラグインも提供していて、開発者はテキスト指向のDSLを書く事ができる。これは、MDAに比べるとだいぶ使いやすいと思う。<br /><br /><span style="font-weight: bold;font-size:130%;" >DSLとドメインエキスパート</span><br />I: DSLはドメインエキスパートが書けるようにするべき?<br />P: ここはDSMに関してさまざまな関心がある部分だ。秘書が会計システムを書けるようにしようとしている、とかね。DSMアプローチでドメインエキスパートがDSLを書けるようにすることはできる。が、より利点があるのはドメインエキスパートが読めるようなDSLを作る事。ドメインエキスパートとプログラマの間のミスコミュニケーションを防ぐ事ができる。ユビキタス言語が引き起こしがちな、実装時の齟齬を防ぐ事ができる。<br /><br />I: 少し自分の経験について話させてもらうと、ユニットテストやシナリオテストを書いてドメインエキスパートと共有した時、ドメインエキスパートはJavaなどのシンタックスノイズに悩まされていた。ユビキタス言語を使っていたとしても、ドメインエキスパートには(コードが何を意味しているのか)説明しなくてはならない。DSLを使えばわかりやすくできるように思うが、どうか?<br /><br />P: BDDのようなアプローチが既に存在しているよね。統合テストではあまりできていないが、DSLが貢献できるいい例だと思う。統合テストにDSLのアプローチを持ち込むことで、ドメインエキスパートにとってとても読みやすくなる。将来はもっとよくなって欲しい。<br /><br /><span style="font-weight: bold;font-size:130%;" >Big Design Upfront or Agile</span><br />I: ドメインを前もって知っていれば、急激な変更が少なくなり、DSLにとって利点が大きいとするなら、前もってヘビーな分析作業をしなくてはならないのでは?<br />P: Big Design Upfrontをやりたがる人は最近ではほとんどいないと思う。コミュニティは、よりアジャイルなアプローチを取ろうとしている。<a href="http://www.metacase.com/ja/mep/">MetaEdit + MetaCase</a>などが良い例だ。これは、頻繁なモデルの変更を助けるような機能が豊富に用意されている。DSMは決してBDUではないことを強調しておきたい。<br /><br /><span style="font-weight: bold;font-size:130%;" >どの程度コード生成すべきか</span><br />I: アプリケーション全体を生成すべきか?<br />P: コード生成については色んな考えがある。アプリケーション全体を生成しなければならない、というものもあれば、アプリケーション全体を生成なんてできっこない、というものもある。これは、どちらも間違っていると思う。<br />100%の自動生成は可能ではある。変数のないテンプレートのようなものを使えば、既存のコードに1対1対応するようなコード生成はできる。だが現実には、(このようなアプローチで)すべてのコードを生成するのは意味がない。<br />DSMの世界では、色んなコードジェネレーションのツールがあり、コードを書くのが非常につらい、クラスやAOP、イベントドリブンプログラミングなどを書かなくてすむようにしている。これらのツールではジェネレートされたコードとカスタムコードは分離して扱うことができ、これら両方でアプリケーション全体を構成することができる。100%のコードを自動生成する必要はない。ドメインモデルが比較的リッチな場所を探し、ドメインエキスパートとコミュニケートして、DSLを作る、といった作業にスタッフをあてるといいだろう。そういうエリアにDSMを適用するのは労力に見合った利点があるからだ。<br /><br /><span style="font-weight: bold;font-size:130%;" >DSMに適したプロジェクト</span><br />I: DSMはどんなプロジェクトに向いている?<br />P: 良い質問だ。プロジェクトをよりDSMに適したものにしてくれるいくつかの要素があると思う。<br />1つ目、これはあまり言ってないことだが、DSMの熟達度だ。SpringやAOPを導入する時と同じで、最初に技術を導入するときには色んな面倒なことがある。また、動的言語、パーシャルクラス、クロージャなどを使う事でエレガントなアプリケーションをすばやく作り上げる事ができるが、開発者がそれをメンテナンスできるとは限らない。<br />なので、DSMの経験がある人をプロジェクトにいれて、経験をプロジェクトに持ち込むことが重要だ。これは非常に助けになる。<br /><br />他の話としては、能力が許す範囲でいくつものプロジェクトを並行にすすめられるしても、投資を回収するには、ドメインの特定のエリアにとどまり、DSMがより長い時間使われるようにしなければならないということだ。DSMにはかなりのオーバーヘッドがあるので、6回以上やりたいかもしれないが…外部DSL用のツールがこの種の問題を解決しようとしてはいる。<br /><br /><span style="font-weight: bold;font-size:130%;" >水平的ドメインと垂直的ドメイン</span><br />ドメインは水平的にも垂直的にもなり得ることを理解するのも重要だ。<br />垂直的なドメインでは、成果は(例えば)1つの保険会社のためだけに使われる。<br /><br />だが一方で、Webの部分は何度も同じようなものを生成することになる。例えば、ドレスショップ向けのeコマースと法律事務所向けの文書リポジトリなど。これが水平的で技術的なドメイン。水平的な技術ドメインはどこでも変わらないので、我々はモデル、コントローラー、バリデーション、リレーションシップなどWebアプリケーションを迅速に構築するための一連のDSLを既にもっている。<br />1つの企業で働いている人…つまり垂直的ドメインを対象にしている人たちは、領域を限定することで、DSMの能力を最大限に生かし、素早くアプリケーションを作ったりメンテナンスしたりしている。多量のJavaのコードに戻ることなく、少ない文で正確に意図が表現されているからだ。<br /><br /><span style="font-weight: bold;font-size:130%;" >現実のDSL/DSLの構築方法</span><br />I: HibernateはDSL?<br />P: HibernateはORMに関するDSLをいくつか示している。<br />こういう言語を作る場合、どのように始めればいいか聞かれることがあるのだが、盗めばいい。<br />ORM, DI, AOPのような水平的ドメインを扱うなら、既に多数のDSLが存在するので、この上にかぶせる形でシンプルな、カスタマイズされた自分のユースケース向けの小さなサブセットを作れば良い。<br />水平的ドメイン(たぶん垂直的の間違い)では、XMLスキーマも良い出発点になるだろう。銀行や保険の業界では、標準がすでに存在している。それらのサブセットを作る形で、必要に応じて自分の状況に応じてカスタマイズすればいい。<br /><br /><span style="font-weight: bold;font-size:130%;" >ドメインのコアコンセプトを理解する方法</span><br />I: ある特定のドメインを扱うような場合、ドメインに関する市販本などもあるが、読んでる?ドメインのコアコンセプトをどうやって知っている?<br />P: DDDと連携していくのがいいと思っている。<br />DDDは(DSLにつながる)ユビキタス言語を作るためのアプローチをあげており、DSMはジェネレートやインタープリタを使って効率的に実行する方法を持っている。これら2つのコミュニティは、お互いにディスカッションするといいと思う。既に2つのコミュニティでは活発なコミュニケーションがあると思っているが、より強くしていきたい。DSMコミュニティはDDDコミュニティからよりよく言語を設計する方法を学べるし、DDDは言語を実行可能にする方法を学べる。<br /><br />I: 今日はどうもありがとう。<br /><br /><span style="font-weight: bold;font-size:130%;" >雑感</span><br />一部マーケ的においはするものの、全体としてはまっとうなことを話している印象。コード生成に関するスタンスも現実的だとは思う。しかし、DSMという新たな用語は必要なんだろうか?世の中を混乱させたり、コミュニティの評判を下げかねないので"DSL"を使い続けた方が良いのではないかと感じた。<br />また、DDDが向かうべき方向として良いのかどうか、今ひとつ確信が持てない。実行可能なユビキタス言語を作ることで、色んなロスがなくなるというが、それが本当かどうかは具体例を見てみないとなんとも言えないな。ドメインエキスパートの可読性を保ったままDSLを構築できるのだろうか?ユビキタス言語全体がDSLとして構築されるとは思えないのでサブセットになるのだろうが、一部だけ妙に形式的になるのだろうか?モノが見てみたい。Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-23864877.post-7080971228447777202009-04-24T10:20:00.028+09:002009-05-07T08:26:07.602+09:00技術者/プログラマのためのモナドと圏論 第1回 行ってきた<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_Sde1cTDCAXc/SfFTDVfzXmI/AAAAAAAAA_c/MOFUgFgv5qw/s1600-h/mapfo-1.png"></a><div>またまた行ってきた。前回(論理・ラムダ・圏)、タイトルに「圏」とありながら、実際は圏の話がほとんどできなかったことを受けてはじまった、新シリーズ。細かいところや背景知識なんてわかるわけがない(数学ほとんどやってないし)ので、わかった範囲で書きとめておく。間違いまくってる可能性大。</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size:large;">全体的に</span></span></div>教科書的に進めようかと思っていたそうだが、檜山さんが体調不良で方針転換。形式的なものより、お絵かきメインで進めることになった。<div><br /></div><div>というわけで、第1回の予定はこうでした。</div><div><ol><li>まえおき/まえせつ</li><li>いろいろな図の描き方</li><li>圏の定義と実例</li><li>休憩</li><li>行列の圏で遊ぶ</li><li>コレクション・データ</li></ol><div>実際は、3の途中まで(休憩はやったよ!)で終了しました:-D</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size:large;">まえおき/まえせつ</span></span></div><div>シリーズ全体の目標としては…</div><div><ol><li>圏の基本概念を学ぶ<br /></li><li>モナドの実例をたくさん知る</li><li>モナド法則に慣れる</li><li>モナドのクライスリ圏の作り方を知る</li><li>モナドがモノイドであることを理解する</li></ol><div>こんなとこで、4くらいまではいきたいそうだ。自分としては、ここまでいければ当面満足なので、しばらくは独学であがかなくてもよさそうなのが非常に嬉しい。</div><div><br /></div><div>今日の目標は…</div><div><ol><li>圏の定義と直感的なイメージの両方を知る<br /></li><li>お絵かき実習する<br /></li><li>圏の実例をいじって体になじませる<br /></li><li>横道にそれて面白そうな話題を紹介する<br /></li></ol><div><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size:large;">モナドの意義</span></span></div><div>今のところさっぱりわかっていないモナドの意義。計算の観点からは、</div><div><ul><li>コレクション・データ構造に統一的見方を与える、らしい</li><li>関数計算を拡張・一般化できる、らしい</li><li>文や式の構文論を整理できる</li></ul><div>どれもこれも現段階では具体例がわからないのでいまいちピンと来ないんだけど、1番目と2番目はHaskellやらの関数型言語をさわる際に、(気持ち・理解的な)役に立ちそう。特に、関数計算に部分関数、エラー・例外、状態・副作用などを導入する形で拡張するのに出てくる、というあたりはとても興味深い。楽しみだ。</div><div>圏論の観点からの意義は、知らない語ばっかりでいまいちよくわからなかった。好奇心の観点からは、色んなものがモナドでっせーみたいな話のようで、もしかしたら後で出てくる「色んなものを圏の枠組みで見ると同じように見え、同じような問題が同じように解ける」とかいう話と関係しているのかもしれない。が、よくわからない。</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size:large;">回路とか関数とかの書き方</span></span></div><div>[ ボックス図 ]<br /></div><div>関数をブラックボックスとして記述。</div><div><br /></div><div><span class="Apple-style-span" style="color: rgb(0, 0, 238);"><img src="http://2.bp.blogspot.com/_Sde1cTDCAXc/SfEf49jLBLI/AAAAAAAAA8o/WHYXYQfSfYs/s320/box.png" alt="" id="BLOGGER_PHOTO_ID_5328074897611228338" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 186px; height: 320px;" border="0" /></span></div><div><br /></div><div>[ オダンゴ図 ]</div><div>ボックス図の省略版。箱を書くのがめんどうくさいので生まれたらしい。ボックス図もそうだが、ブラックボックスの内部を書くこともできる。</div><div><br /></div><div><span class="Apple-style-span" style="color: rgb(0, 0, 238);"><img src="http://3.bp.blogspot.com/_Sde1cTDCAXc/SfEgBy40C_I/AAAAAAAAA8w/5IVkxNqfp2g/s320/dango.png" alt="" id="BLOGGER_PHOTO_ID_5328075049368030194" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 170px; height: 320px;" border="0" /></span></div><div><br /></div><div>[ ストリング図 ]</div><div>オダンゴが小さくなった感じ。</div><div><br /></div><div><span class="Apple-style-span" style="color: rgb(0, 0, 238);"><img src="http://4.bp.blogspot.com/_Sde1cTDCAXc/SfEgLmYe1NI/AAAAAAAAA84/x1HI26RkILA/s320/string.png" alt="" id="BLOGGER_PHOTO_ID_5328075217809888466" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 182px; height: 320px;" border="0" /></span></div><div>さて、以下の3つの関数で…</div><div><ul><li>f(x, y) = 3x + y<br /></li><li>g(z) = z + 1<br /></li><li>h(x) = x * x + x<br /></li></ul></div><div>f(x, y) と g(z) のComposition(結合・合成)をオダンゴ図で書いてみる。<br /></div><div><br /></div><div><span class="Apple-style-span" style="color: rgb(0, 0, 238);"><img src="http://4.bp.blogspot.com/_Sde1cTDCAXc/SfEgb-6lKVI/AAAAAAAAA9A/x4-QWv-vALs/s320/fg.png" alt="" id="BLOGGER_PHOTO_ID_5328075499273267538" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 266px; height: 320px;" border="0" /></span></div><div>きたねええええええ!</div><div>…h(x) をオダンゴ図で書いてみる。</div><div><br /></div><div><span class="Apple-style-span" style="color: rgb(0, 0, 238);"><img src="http://4.bp.blogspot.com/_Sde1cTDCAXc/SfEgqW7vUeI/AAAAAAAAA9I/KK2IlnUBEJk/s320/h.png" alt="" id="BLOGGER_PHOTO_ID_5328075746238747106" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 226px; height: 320px;" border="0" /></span></div><div>h が少し面白いのは、普通に書こうとすると、x が1つしかないので2乗などができずに困ってしまう点。xを複製するようなワイヤリングをすればいいのだけど、このようにに、引数も消尽され得るリソースだと考えると、コンピュータによる計算のリソースセンシティブな部分をうまく表現できるようだ。これは、論理の世界で考えると<a href="http://ja.wikipedia.org/wiki/%E7%B7%9A%E5%BD%A2%E8%AB%96%E7%90%86">線形論理</a>に対応しているらしい。なんか前回そんなことを言っていた。この複製(や交差)なんかのワイヤリングを計算と考えることもできる。</div><div>テキスト表記(Symbolic Calculationというらしい)だとわからなかったことが、絵算(Pictorial Calculationというらしい)だとわかる、というのも面白いところ。これらは一長一短があるので、状況によって使い分けるといい、とのこと。<br /></div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size:large;">引数・戻り値の数</span></span></div><div>引数は複数あるが、戻り値は常に1つでないといけないのか?</div><div>そんなことはない。実際、先ほどの f と g の合成関数の例では、ボックス(ダンゴ)の位置を少し変えれば(合成関数自体は同じでも)簡単に戻り値が複数あるような関数に変更できる。</div><div><br /></div><div><span class="Apple-style-span" style="color: rgb(0, 0, 238);"><img src="http://1.bp.blogspot.com/_Sde1cTDCAXc/SfEk_rIXQdI/AAAAAAAAA9Q/pMvf425p7rI/s320/fgh.png" alt="" id="BLOGGER_PHOTO_ID_5328080510484169170" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 202px; height: 320px;" border="0" /></span></div><div><br /></div><div>が、人間は多値(特に戻り値)を扱うのはあまり得意ではないので、1つにしていることが多い。複数必要になった場合には、タプルで対応する。</div><div><br /></div><div>f: A, B => C</div><div><br /></div><div>これはAとBの2引数を取り、Cを返す関数だが、</div><div><br /></div><div>f': A×B => C</div><div><br /></div><div>このような、A×B型のタプルを引数として取る関数とまぁ同じと考えて良い。掛け算記号の×は、タプル型をあらわす。タプルは色んな表記法があり、(特にプログラミング言語では)()だったり[]だったり{}だったりする。プログラミング言語から中立であることを示しつつタプルを表記するため、<>をよく使うらしい。</div><div><br /></div><div>f'(<x, y><x, y=""><x,>) = f(x, y)</x,></x,></div><div>g'(x, y) = g(<x, y><x,><x, y="">)</x,></x,></div><div><br /></div><div>これは、絵算で言うと、ワイヤーを束ね(て1本にす)ることに相当する。フラットケーブルとかそういうやつ。こんな感じ。</div><div><br /></div><div><span class="Apple-style-span" style="color: rgb(0, 0, 238);"><img src="http://2.bp.blogspot.com/_Sde1cTDCAXc/SfEmoYsF6UI/AAAAAAAAA9Y/uyyOjloc200/s320/tuple.png" alt="" id="BLOGGER_PHOTO_ID_5328082309420017986" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 270px; height: 320px;" border="0" /></span></div><div>ダンゴ図で書くときは、右下にちっちゃく書いてるように、ゴムみたいなので束ねるように書いたりする。</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size:large;">ストリング図とアロー図</span></span></div><div>今まで書いてきた、ボックス図・オダンゴ図は、どちらもストリング図という種類になるが、一般的に図(Diagram)というと、たいていはアロー図を指す。以下のような関数について考えてみる。</div><div>f: A => B</div><div><br /></div><div>[ ストリング図 ]</div><div><br /></div><div><span class="Apple-style-span" style="color: rgb(0, 0, 238);"><img src="http://4.bp.blogspot.com/_Sde1cTDCAXc/SfEoPLFAPbI/AAAAAAAAA9g/eEudb6ugncg/s320/string-d.png" alt="" id="BLOGGER_PHOTO_ID_5328084075292933554" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 276px;" border="0" /></span></div><div>関数が箱(または点)、引数や戻り値が矢印(アロー)になっている。</div><div><br /></div><div>[ アロー図 ]</div><div><br /></div><div><span class="Apple-style-span" style="color: rgb(0, 0, 238);"><img src="http://4.bp.blogspot.com/_Sde1cTDCAXc/SfEofrVO5TI/AAAAAAAAA9o/lid-hTi-MR4/s320/arrow-d.png" alt="" id="BLOGGER_PHOTO_ID_5328084358828844338" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 305px; height: 126px;" border="0" /></span></div><div>関数が矢印(アロー)、引数や戻り値が点になっている。</div><div># なんか、圏っぽい。てか圏のセミナーでした。</div><div><br /></div><div>この2つの違いは単に趣味的なものではなく、大きな差である、らしい。ちなみに、アロー図はペースティング(Pasting)図や球状(Globular)図とも言うらしいが、これは絵を2次~3次元に拡張した場合に円や球に見えるから、だそう。スライドには高次圏とか書いてあるし、とりあえず今はわからなさそうなので飛ばしてしまう。</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size:large;">矢印で何を表すのか</span></span></div><div>矢印は、色んな意味で使われるので注意が必要。違うことが同じ記号や同じ言葉で語られるため、混乱しやすい。これから出てくるものとしては…</div><div><ul><li>要素関の対応関係(集合の要素、元同士の対応関係)</li><li>集合同士の対応関係(集合同士の対応関係、写像?)</li><li>関手(どうやら圏と圏の対応のようなものらしい)</li><li>自然変換(関手同士の対応のようなものに見えるが)</li></ul></div><div>こんなものが、すべて矢印であらわされる。</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size:large;">圏、しりとり圏</span></span></div><div>はじめての圏論で書かれていた、<a href="http://d.hatena.ne.jp/m-hiyama/20060821/1156120185">しりとり圏</a>をもとに圏を説明。以下、しりとり圏の構成要素の転記。</div><div><ol><li>対象の集合: H -- ひらがな文字全体の集合</li><li>射の集合: HStr -- ひらがな文字列全体の集合</li><li>域 dom と余域 cod : first, last : HStr => H(最初と最後の文字)</li><li>恒等 id : unit : H => HStr(1文字からなる文字列)</li><li>結合(composition) : しりとり結合 s;t は last(s) = first(t) のときだけ定義される</li></ol><div>まずは、圏のなんとなーくのイメージをつかむ。といっても、今まで出てきた話の延長線上にある。というか、もちろんそういう風に話を持っていっているんだと思います :-D</div><div><br /></div><div>対象というのは、アローダイアグラムでの点みたいなもの。射というのは、アローダイアグラムでの矢印のようなもの。域というのは、矢印の出発点側にくっついている点のようなもの。余域というのは、アローダイアグラムの終点側についている点のようなもの。</div><div><span class="Apple-style-span" style="color: rgb(0, 0, 238);"><img src="http://1.bp.blogspot.com/_Sde1cTDCAXc/SfExjMJVyNI/AAAAAAAAA9w/fhySGr_W6os/s320/omdc.png" alt="" id="BLOGGER_PHOTO_ID_5328094314781591762" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 231px;" border="0" /></span></div><div><br /></div><div>結合は、(つなげられる)矢印同士をつなげること。</div><div><br /></div><div><span class="Apple-style-span" style="color: rgb(0, 0, 238);"><img src="http://2.bp.blogspot.com/_Sde1cTDCAXc/SfExyh_YS8I/AAAAAAAAA94/Fsa4NHeC30U/s320/composition.png" alt="" id="BLOGGER_PHOTO_ID_5328094578343431106" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 272px;" border="0" /></span></div><div># f;g は、fとgの結合です。</div><div><br /></div><div>恒等は…ものすごくぶっちゃけていえば、ある点から出て同じ点に帰ってくる矢印みたいなもの。</div><div><br /></div><div><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_Sde1cTDCAXc/SfE1NbhuSpI/AAAAAAAAA-A/vYlVa8bNmo8/s1600-h/id.png"><img src="http://3.bp.blogspot.com/_Sde1cTDCAXc/SfE1NbhuSpI/AAAAAAAAA-A/vYlVa8bNmo8/s320/id.png" alt="" id="BLOGGER_PHOTO_ID_5328098338999782034" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 146px; height: 145px;" border="0" /></a><br /></div><div>で、同じ点に帰ってくる矢印なんだから、他の矢印と結合しても、元の矢印(がたどり着く点)は変わらないでしょう、というようなもの。</div><div><br /></div><div><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_Sde1cTDCAXc/SfE1X3afArI/AAAAAAAAA-I/-BPwGi-p_YM/s1600-h/id-composition.png"><img src="http://2.bp.blogspot.com/_Sde1cTDCAXc/SfE1X3afArI/AAAAAAAAA-I/-BPwGi-p_YM/s320/id-composition.png" alt="" id="BLOGGER_PHOTO_ID_5328098518284305074" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 227px; height: 193px;" border="0" /></a>なんかこんなイメージ。これを、しりとりにあてはめると、こんな感じになる。</div><div><br /></div><div><div><span class="Apple-style-span" style="color: rgb(0, 0, 238);"><img src="http://1.bp.blogspot.com/_Sde1cTDCAXc/SfE5ftr3fRI/AAAAAAAAA-Q/Vo6EBrwhdA8/s320/siritori.png" alt="" id="BLOGGER_PHOTO_ID_5328103051158322450" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 271px; height: 320px;" border="0" /></span></div></div><div># 実際には、点や線はもっとたくさんある。</div><div>以下、圏の構成要素がしりとり(圏)において何に対応しているのか考える。</div><div><br /></div><div>[ 対象 ]<br /></div><div>対象は、ここで言えばひらがな1文字1文字のことにしてある。'あ' とか 'い' とかそういうやつ。なので、対象の集合は、ひらがな文字全体の集合になる。</div><div><br /></div><div>[ 射 ]</div><div>射は、対象、つまりひらがな文字の間に引く矢印みたいなもので、今回は(ひらがな文字を並べた)文字列、ということにする。射の集合は、ひらがな文字列全体の集合。</div><div><br /></div><div>[ 域と余域 ]</div><div>域は、文字列の先頭の文字とする。"きまいら"の域は、'き'。余域は、文字列の末尾の文字とする。"きまいら"の余域は、'ら'。</div><div><br /></div><div>[ 結合 ]</div><div>結合は、射(つまり文字列)同士をくっつけることで、定義では「1つめの射の余域」と「2つめの射の域」が同じでなくては結合できない。これを今までの定義で言い換えると、「1つめの文字列の末尾の文字」と、「2つめの文字列の最初の文字」が同じでなければ結合できない、となる。つまり、しりとりできる文字列しか結合できない。今回の結合では、(しりとり可能な)文字列同士を結合し、重複した文字を(1つ)取り除くこと、とする。</div><div><br /></div><div>"きまいら";"らいおん" => "きまいらいおん"</div><div><br /></div><div>こんな感じ。なんかしりとりっぽくなってきた。</div><div><br /></div><div>[ 恒等 ]</div><div>恒等は、射と結合しても変わらない射なので、これまで決めてきたことから考えると、長さ1の文字列になる。"あ"とか"い"とか。例としては…</div><div><br /></div><div>"きまいら";"ら" => "きまいら"</div><div>"き";"きまいら" => "きまいら"</div><div><br /></div><div>こんな感じ。少し前のざっくりした説明だと、同じ点に帰ってくる矢印みたいなもん、って書いてたんだけど、同じ点に帰ってくる射(文字列)でも、"きつつき" なんかは恒等にはならない。これは、他の射と結合した場合に違う射になってしまい、定義を満たさないから。たぶん。</div><div># 射が同じってのは、定義しなくても大丈夫なんだろうか?文字列が同じって考えていいんだよなぁ…?</div><div><br /></div><div>恒等自体は射(矢印)なので、"あ"とか"い"とかは、文字ではなく文字列なのに注意。</div><div><span class="Apple-style-span" style="color: rgb(0, 0, 238);"></span></div><div><br /></div><div><span class="Apple-style-span" style="font-size:large;"><span class="Apple-style-span" style="font-weight: bold;">圏の法則</span></span></div><div>ここで、圏の法則をば。下つき文字の書き方がわからないので unit はプログラミング言語っぽく書いちまいます。今作ったしりとりの圏が、この法則を満たしていることを確認する。</div><div><ol><li>first(unit(x)) = last(unit(x)) = x (x∈H)<br /></li><li>first(s;t) = first(s), last(s;t) = last(t)<br /></li><li>(s;t);u = s;(t;u)<br /></li><li>x = first(s), y = last(s) なら、unit(x);s = s;unit(y) = s<br /></li></ol></div><div>[ 1つめ ]</div><div><ul><li>対象xの恒等(射)の域は、対象xに等しい。</li><li>対象xの恒等(射)の余域は、対象xに等しい。</li></ul>と言っている。しりとりで文字をあてはめてみると…</div><div><ul><li>文字: 'あ'<br /></li><li>対応する1文字の文字列: "あ"<br /></li><li>文字列 "あ" の域: 'あ'<br /></li></ul></div><div>というわけで、きちんと法則を満たしている。当たり前か。末尾も同じ。</div><div><br /></div><div>[ 2つめ ]</div><div><ul><li>射sと射tを結合した射の域は、射sの域に等しい<br /></li><li>射sと射tを結合した射の余域は、射tの余域に等しい</li></ul><div>これもしりとりで文字をあてはめてみると…</div><div><ul><li>射s: "きまいら"</li><li>射t: "らいおん"</li><li>射sとtの結合: "きまいらいおん"</li><li>射sとtの結合の域: 'き'<br /></li><li>射sの域: 'き'</li><li>射sとtの結合の余域: 'ん'</li><li>射tの余域: 'ん'</li></ul><div>というわけで、成り立っている。</div><div><br /></div><div>[ 3つめ ]</div><div><ul><li>射sと射tを結合し、それに射uを結合したものは、射sに射tと射uの結合を結合したものと同じ</li></ul><div>全然わかりやすくなってないな…。しりとり。</div><div><ul><li>射s: "でんき"</li><li>射t: "きまいら"</li><li>射u: "らいおん"</li><li>(s;t);u: ("でんき";"きまいら");"らいおん = "でんきまいら";"らいおん" = "でんきまいらいおん"</li><li>s(t;u): "でんき";("きまいら";"らいおん") = "でんき";"きまいらいおん" = "でんきまいらいおん"</li></ul><div>成り立っている。なんかむなしくなってきた。</div><div><br /></div><div>[ 4つめ ]</div><div><ul><li>射sの域がxであり、余域がyであるならば…</li><li>xの恒等(射)unit(x) と 射sの結合は、射sに等しい</li><li>射sとyの恒等(射)unit(y) の結合は、射sに等しい</li></ul><div>しりとりで。</div><div><ul><li>射s: "きまいら"</li><li>射sの域 x: 'き'</li><li>射sの余域 y: 'ら'</li><li>xの恒等 : "き"</li><li>yの恒等 : "ら"</li><li>xの恒等と射sの結合 : "き";"きまいら" = "きまいら"<br /></li><li>射sとyの恒等の結合 : "きまいら";"ら" = "きまいら"<br /></li></ul><div>OK。しりとり圏はちゃんとした圏。らしい。</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size:large;">unitで混乱</span></span></div><div>セミナーの最後に、unitに関して質問があり、微妙に混乱した。内容は…</div><div>構成要素には、unit が「対象」から「射」への写像(って言ってたかなぁ…)だとされているけど、絵で見ると恒等というのは「対象」から「対象」への射になっているので、別のものですよね?というもの。</div><div>これはたぶん…</div><div><ul><li>unit: unit(x) で「対象xに関する恒等(射)」をあらわすもの、つまり対象から射への写像</li><li>unit(x) : ある対象xに関する恒等(射)、unitに具体的に対象が与えられたもの<br /></li></ul><div>というものがごっちゃになって混乱した、という話だと思った。あってるのだろうか。</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size:large;">Map Finite Ordinals</span></span></div><div>2つめの圏の例。こんな対象を考えてみる。</div><div><ul><li>[0] = {}</li><li>[1] = {1}</li><li>[2] = {1, 2}</li><li>[3] = {1, 2, 3}</li><li>[4] = {1, 2, 3, 4}</li><li>…</li></ul></div><div>射の具体的な内容は、要素間の対応関係(の組み合わせ)になる。ここで、対象間の矢印と要素間の矢印は違うものをあらわしていることに注意。</div><div style="text-align: center;"><span class="Apple-style-span" style="color: rgb(0, 0, 238);"><img src="http://4.bp.blogspot.com/_Sde1cTDCAXc/SfFTDVfzXmI/AAAAAAAAA_c/MOFUgFgv5qw/s320/mapfo-1.png" alt="" id="BLOGGER_PHOTO_ID_5328131150931254882" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 249px; height: 320px;" border="0" /></span></div><div><br /></div><div>具体的に域が[2], 余域が[3]であるような射について考えてみると、射の数は9つになる。これは、実際に書いてみればわかる(が省略!)。[1]も加えて射の数を考えてみると…</div><div><br /></div><div><span class="Apple-style-span" style="color: rgb(0, 0, 238);"><img src="http://2.bp.blogspot.com/_Sde1cTDCAXc/SfFLNWTBA9I/AAAAAAAAA-g/GXsY7mtDXmc/s320/mapfo-2.png" alt="" id="BLOGGER_PHOTO_ID_5328122526851728338" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 203px; height: 320px;" border="0" /></span></div><div>こんな感じ。一般化すると、[n] から [m]への射の数は、mのn乗になる。</div><div><br /></div><div># この先はハイスピードでとばしまくり。</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size:large;">部分圏</span></span></div><div>MapFOの中でも、こんなものは部分圏になる。</div><div><ul><li>InjFO 単射の圏</li><li>IsoFO 同型射の圏</li><li>IncFO 包含写像の圏</li></ul><div>IncFOよくわからなかった。</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size:large;">関手</span></span></div><div>スライド0.2秒くらい、説明ゼロでした :-D</div><div>例を見ると、HSiri => KSiri が関手になっているので、圏を「対象」として見たとき、つまり圏の圏を考えたときの射が関手、ということなんだと思う。けど、具体的なイメージが…。</div><div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;"><span class="Apple-style-span" style="font-size:large;">同じに見える色んな問題</span></span></div><div>スライドに書いてある色んな問題たちが同じようにみなせるらしい。が、どれとどれが同じなのか、はたまた全部同じなのか、よくわからなかった。</div><div><br /></div><div>時間切れ、終了。なんか飲み会行ってテンションあがったので頑張って書いてみた。他の出席者の方のように、「あー、なるほど、あれがあれね!」とか「じゃああれはこうですか?」みたいなつっこんだ話は全然できず、道のりの長さが感じられたんだけど、それはそれでよかった。わかってること勉強しにいってもしょうがないしね。もう少し初級者向け(幻想?)の圏論読書会も立ち上がるかもしれない雰囲気。</div></div></div></div></div></div></div></div></div></div></div></div></div></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-23864877.post-66068028086052774972009-04-18T23:00:00.009+09:002009-04-27T08:42:45.798+09:00アーキテクトの審美眼<div style="border-width: 0px; margin: 0px; padding: 3px; font-size-adjust: none; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; text-align: left; width: auto;font-family:Georgia,serif;font-size:100%;"><div><span style="font-family:'MS PGothic';">MS萩原さんのセッション。同名の書籍(元ネタはDBマガジンの同名の連載)が元になっていて、そのダイジェスト版+最新の動向の補足、という形。</span></div><div><span style="font-family:'MS PGothic';">とても示唆に富んでいるんだけど、抽象的な上に、1つ1つのトピックがめちゃめちゃ重たいので、きちんと理解しようとすると調べる量がとても多くなってしまう上に、そもそも理解しきるのが難しすぎる。とりあえずは現段階の自分の稚拙な理解をもとに、こんなことじゃないかなーと補足しながら書いていく。</span><br /><br /></div><div><span style=";font-family:'MS PGothic';font-size:130%;" ><span style="font-weight: bold;">アーキテクチャの原則</span></span></div><div><span style="font-family:'MS PGothic';">アーキテクトにとっては、アーキテクチャの原則を理解することが重要。アーキテクチャの原則は、インフラなどが変化しても変わらず、クラウドでも通用する。</span></div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style=";font-family:'MS PGothic';font-size:130%;" ><span style="font-weight: bold;">アーキテクチャ先行定義の原則</span></span></div><div><span style="font-family:'MS PGothic';">アーキテクチャは先行定義せねばならぬ、という原則。アーキテクチャ設計を含むソフトウェア開発は、こんな風な流れになるはず。</span></div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';"><a href="http://2.bp.blogspot.com/_Sde1cTDCAXc/SeaXdVn40BI/AAAAAAAAA8Y/NLGd2e-oplc/s1600-h/architecture.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" id="BLOGGER_PHOTO_ID_5325110139688636434" src="http://2.bp.blogspot.com/_Sde1cTDCAXc/SeaXdVn40BI/AAAAAAAAA8Y/NLGd2e-oplc/s320/architecture.png" style="margin: 0px auto 10px; cursor: pointer; display: block; height: 315px; text-align: center; width: 320px;" border="0" /></a></span></div><div><span style="font-family:'MS PGothic';">モデリングとアーキテクチャ設計の双方のインプットとして、システムの機能要求・非機能要求があげられていた。</span></div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';">■ モデリング</span></div><div><span style="font-family:'MS PGothic';">この部分は、システム化対象(ドメイン)を何らかのパラダイム(DOA/OOAなど)でモデル化する作業だと思われる。ドメインモデリングであれば、主に機能要件がそのインプットとなりそうだ。</span></div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';">■ アーキテクチャ設計</span></div><div><span style="font-family:'MS PGothic';">アーキテクチャパターンやリファレンスモデルをもとに、機能/非機能要件を満たしうるアーキテクチャを整備していく作業だと思われる。アーキテクチャ設計では、例として以下のような項目を(仮)決めしていくようだ。</span></div><div><span style="font-family:'MS PGothic';"># メモしきれなかったので一部のみ ^^;</span></div><div><ul><span style="font-family:'MS PGothic';"><li>プラットフォーム</li><li>フレームワーク</li><li>データモデル</li><li>トランザクションモデル</li><li>セキュリティ</li></span></ul></div><div><span style="font-family:'MS PGothic';">[メモ]</span></div><div><span style="font-family:'MS PGothic';">図では、モデリングとアーキテクチャ設計が並列になっているが、モデリングとアーキテクチャ設計を完全に独立で実施できるとは思えない。アーキテクチャ設計にフレームワークやデータモデルが入っていることから、お互いになんらかの関係があることを示唆している気もする。もしかしたら、順序関係や依存関係を定義した図ではないのかもしれないし、マッピング/設計のフェーズがそれを包含しているのかもしれないが、セッションからはよくわからなかった。</span></div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';">個人的にここで重要だと思うのは、システム開発にはなんらかの形での「システム化対象のモデリング」が存在することを明示している点。そして、DOAやOOAを包含して「モデリング」としている点。データモデリングやオブジェクト指向モデリングをしているんじゃなく、「システム化対象」を「データの観点」や「オブジェクトの観点」からモデリングしているんだ、というのは、個人的になんだかしっくりくる。</span><br /><span style="font-family:'MS PGothic';">[/メモ]<br /></span></div><div><span style=";font-family:'MS PGothic';font-size:130%;" ><br /></span></div><div><span style=";font-family:'MS PGothic';font-size:130%;" ><span style="font-weight: bold;">データアーキテクチャの原則</span></span></div><div><span style="font-family:'MS PGothic';">データには、マスターデータとトランザクションデータが存在するが、それぞれのデータには特性があり、扱う方法にも原則がある、という話。</span></div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';">■ マスターデータ</span></div><div><ul><span style="font-family:'MS PGothic';"><li>複数のアプリケーションで共通的に使われるデータ</li><li><span style="font-weight: bold;">論理的には</span>アプリケーションの外に出すのが原則</li></span></ul></div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';">■ トランザクションデータ</span></div><div><ul><span style="font-family:'MS PGothic';"><li>属性として「時間」を持っている</li><li>追加(新規作成)のみで、変更も削除もされない</li><li>ETLなどでDWHやDMにぶちこまれる</li></span></ul><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';"><span style="color: rgb(0, 0, 238);"><img alt="" id="BLOGGER_PHOTO_ID_5325118038219482242" src="http://1.bp.blogspot.com/_Sde1cTDCAXc/SeaepF8Y5II/AAAAAAAAA8g/s3TII3Lj8m8/s320/dataarchitecture.png" style="margin: 0px auto 10px; cursor: pointer; display: block; height: 242px; text-align: center; width: 320px;" border="0" /></span></span></div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';"># なんかこんな感じだった気がする。</span></div><div><span style="font-family:'MS PGothic';">実際は、特にマスターデータに関してはこのようになっていないことが多い。これは、マスターデータ自体の共通性は高いのだが、ビューが異なると必要な属性が異なってくる(属性にバリエーションがある)ため、Factor outしづらいのが原因。</span></div><div><span style="font-family:'MS PGothic';">なお、マスターデータは論理的に一箇所で管理すればよく、必ずしも物理的に一箇所で管理する必要はない。</span></div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';">[メモ]</span></div><div><ul><span style="font-family:'MS PGothic';"><li>マスター、トランザクションの区分はデータモデリングの王道中の王道。THでもTMでも、定義の厳密性や名前の違い(イベント/リソースなど)こそあれ、基本的なスタンスは同じ。<br /></li><li>マスターデータをアプリケーションにまたがって共通的に持つ、というのは、最近DOA界隈(と言ってしまっていいのだろうか)ではやりのMDM(Master Data Management)と同じですね。データ総研の椿さんも同じこと言ってました。<br /></li><li>マスターデータがコンテキストごとに属性のバリエーションを持つ、という問題を解決する方法は明示されなかった気がするんだけど、どのように考えているんだろうか?「外だしする=共通性として認識する」、「コンテキスト(アプリケーションやビュー)ごとに持つ=可変性として認識する」と考えると、結局は共通性と可変性の認識の問題になる気がする。負の可変性とか。この境界は、時間の経過や事業領域の変更でも変わっていくのだと思われる。<br /></li><li>物理的に一箇所にする(大福帳DB?)のではなく、論理的に一箇所にすれば良い、というのは現実を考えると非常に重要だと思う。<br /></li></span></ul></div><div><span style="font-family:'MS PGothic';">[/メモ]</span></div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style=";font-family:'MS PGothic';font-size:130%;" ><span style="font-weight: bold;">Entity(個体)識別の問題</span></span></div><div><span style="font-family:'MS PGothic';">Entityはそれ単独(そのものが持つ本質的な特性)では決まらず、他との相対的な関係でしか決定できない。Relationshipは関数従属性であり、ビジネスから決まる、とも言っていた。</span></div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';">[メモ]</span></div><div><div><span style="font-family:'MS PGothic';">これは、データモデリング(OOも)の永遠の課題である、個体(Entity)をどうやって認識するのか、という話だと思うが、CoddのRelationalモデルとChecnのEntity-RelationshipモデルはどちらもEntityの識別方法を与えてくれない。詳しくは忘れてしまったけど、そもそもRelationalModelにはEntityなんてなかったと思うし。ChenのE-Rモデルでは、Eのまともな定義がないため、抽出の役に立たない。</span></div></div><div><span style="font-family:'MS PGothic';">TMとTH、両方のセミナーを受けたことがあるんだけど、ChenのERモデルが工学的(実務的?)に問題があることまでは共通の認識として持っていて、それぞれに定義を補足した上で抽出手順を決めている。詳しくはそれぞれのモデリング技法をどぞ!<br /><br />追記:<br />書籍の方では、データモデリングにおいては既存の帳票や画面からのボトムアップ+関数従属性による正規化によって、Entityは一意に識別できる。が、OOの場合はトップダウンにならざるを得ず、一意性を保証できない点が問題だ、という感じで書いてあった。<br /></span></div><div><span style="font-family:'MS PGothic';">[/メモ]</span></div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';">アプリケーションの設計モデルは、データモデルと独立して定義可能。ビジネスモデルをそのまま反映することもできる。アプリケーション設計モデルのコアな部分は、ユースケースと独立して、先行して定義する。関係はユースケースが決まらないと確定しないので、ブレが大きくなる。</span></div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';">[メモ]</span></div><div><span style="font-family:'MS PGothic';">「アプリケーション設計モデル」が少しわかりづらいんだけど、自分はアプリケーションの構造(特に、PoEAAのDomain Logic Patternsに相当するもの)の選択と、それがドメインごとに具体化されたものだと理解した。そうすると、Domain Logicのモデルはデータモデルとはある程度独立になる話も理解できるし、アプリケーション設計モデルのコアがUCの定義に先立つ、という話も、勘定構造(Accounting Patterns)の導入などと絡めて考えれば理解しやすい。気がする。</span></div><div><span style="font-family:'MS PGothic';">[/メモ]</span></div><div><span style=";font-family:'MS PGothic';font-size:130%;" ><br /></span></div><div><span style=";font-family:'MS PGothic';font-size:130%;" ><span style="font-weight: bold;">縦の構造と横の構造</span></span></div><div><span style="font-family:'MS PGothic';">アプリケーションの構造は、縦の構造(Entity)と横の構造(Relationship)から成ると考えることができる。縦の構造は比較的固定化されており、横の構造は比較的流動的。変更要求があった際に、それが縦の構造に影響を与えるか、横の構造に影響を与えるかによって、修正コストは大幅に違ってくる。</span></div><div><span style="font-family:'MS PGothic';"># よって、(このコンテキストでは)いかにEntityを安定なものにするかが重要になってくる。</span><br /><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';">[メモ]</span></div><div><span style="font-family:'MS PGothic';"> この「縦の構造」と「横の構造」は、ソフトウェア(ひいてはビジネス)は視点によって複数の構造を取りうることを表している。</span><br /><span style="font-family:'MS PGothic';">ただ、モデルとしては複数の構造を持っていたとしても、複数の構造をソフトウェアとして実装するのは</span><span style="font-family:'MS PGothic';">単一のパラダイムでは</span><span style="font-family:'MS PGothic';">難しい。</span><br /><span style="font-family:'MS PGothic';">手続き型では階層的に詳細化された手続きを呼び出すような単純な構成になるし、オブジェクト指向であってもクラス構造は基本的に単一で、まったく違うクラス構造を重ね合わせて実装することはできない(多重継承やMix-inはある程度これを可能にするが)。</span><br /><span style="font-family:'MS PGothic';">複数のパラダイムが形作る構造が対等な関係で関連し合うようなアーキテクチャも考えられるのかもしれないが、現段階では主たるパラダイムが主たる構造を構成し、それ以外のパラダイム(やメカニズム)が補足的な構造を形作ることが多い。この、主たる構造が縦の構造、補足的な構造が横の構造と呼ばれているのかなーと感じた。</span><br /><br /><span style="font-family:'MS PGothic';">補足的な構造を導入するためのパラダイムがアスペクト指向で、現状では主としてアスペクト指向プログラミングが、(ビジネス構造を表す主たるクラス構造に)非機能要求の実現を表す構造を導入する形で用いられている。ヤコブソンは、アスペクト指向による分析・設計を考えており、ユースケース(というアスペクト)を分析・設計段階で扱うことを考えているようだが…。</span></div><div><span style="font-family:'MS PGothic';">[/メモ]</span></div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style=";font-family:'MS PGothic';font-size:130%;" ><span style="font-weight: bold;">パラダイムの進化</span></span></div><div><span style="font-family:'MS PGothic';">オブジェクト指向には限界がある。</span></div><div><ul><span style="font-family:'MS PGothic';"><li>言語間の通信が困難</li><li>動的なオブジェクトのブートやシャットダウン</li><li>非機能の扱いが困難</li></span></ul><div><span style="font-family:'MS PGothic';">[メモ]</span></div><div><span style="font-family:'MS PGothic';">言語間の通信とか、OOの問題ではなく、OOの典型的なプラットフォームが持つ問題のような気がするんだけど…。動的なオブジェクトのブートやシャットダウンも同じく。</span></div><div><span style="font-family:'MS PGothic';">[/メモ]</span></div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';">パラダイムは進化してきた。</span></div><div><span style="font-family:'MS PGothic';">手続き型 => オブジェクト指向 => コンポーネント指向 => サービス指向 => Web指向</span></div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';">[メモ]</span></div><div><span style="font-family:'MS PGothic';">コンポーネント指向は、言語間の通信が困難である点を解消する。サービス指向が改善するものはなんだろう?再利用可能性だろうか?</span></div><div><span style="font-family:'MS PGothic';">Web指向というのは聞いたことがなかったんだけど、分散化され、メッシュ上にリンクされたリソースをコードが扱う、というモデルらしい。</span></div><div><span style="font-family:'MS PGothic';">[/メモ]</span></div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';">これらの進化は、古いものを置き換えてきた<span style="font-weight: bold;">というわけではない</span>点が重要。新たに登場したパラダイムでの開発には、以前にパラダイムも必要になる。組み合わせて使うことが必要。</span></div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';">[メモ]</span></div><div><span style="font-family:'MS PGothic';">フレームワークやミドルウェアの登場で開発はどんどん簡単になっているはずなのに、なぜか難しく感じる理由は、これである程度説明できるのかもしれない。抽象の破れとあわせて説明すれば、直接開発に関わらない人が「うまく開発することが、なぜいまだに難しいのか」を理解する助けになるだろうか。</span></div><div><span style="font-family:'MS PGothic';">[/メモ]</span></div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style=";font-family:'MS PGothic';font-size:130%;" ><span style="font-weight: bold;">モデルをどう作るか?</span></span></div><div><span style="font-family:'MS PGothic';">システムはさまざまな視点からのモデル化することになるが、どのようにすればうまく表現できるのか?</span></div><div><span style="font-family:'MS PGothic';"># モデルの話再び。個人的にはここが最重要トピック。</span></div><div><span style="font-family:'MS PGothic';">問題をうまく分類し、分割することが重要。単一のパラダイムではうまく対応できないため、マルチパラダイムで対応する。これから、いくつかのパラダイムとその問題点を見ていく。</span></div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';">■ オブジェクト指向</span></div><div><span style="font-family:'MS PGothic';">クラス決定に一意性がなく、属人的であることが問題とみなされる。このせいで、手続き指向への回帰が起こっているケースが多々見られる。</span></div><div><span style="font-family:'MS PGothic';">(個別UCの)要求によってクラスの構造を変えてはならない。要求の実現ではなく、保守性を目的としてクラス構造を取る。</span></div><div><span style="font-family:'MS PGothic';">OOには多くの制約があり、これを乗り越える・補完するためにさまざまなパラダイムが考案・導入されつつある。</span><br /><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';">■ アスペクト指向</span><br /><span style="font-family:'MS PGothic';">可変性にフォーカスした技術。メモで前述。このあたりから全部、ものすごいさらっと紹介していく流れに。<br /><br /></span></div><div><span style="font-family:'MS PGothic';">[メモ]</span><br /><span style="font-family:'MS PGothic';">可変性というのは、ドメイン工学やマルチパラダイムデザインの用語で、システム・もしくは概念の変わりうる部分のこと。AOPが可変性にフォーカスした技術である、ということは、システムの変わりうる部分をアスペクトとして実装することが意図されている、ということだろうか。あまりそんな風に使ってないような気がするが。</span><br /><span style="font-family:'MS PGothic';"> ユースケースをアスペクトとして扱うのであれば、この言説に合致するんだけど、あってるのだろうか。</span><br /><span style="font-family:'MS PGothic';"> [/メモ]<br /><br /></span></div><div><span style="font-family:'MS PGothic';">■ サブジェクト指向(Subject Oriented)</span><br /><span style="font-family:'MS PGothic';">再利用にフォーカスした技術らしい。こちらもさらっとした紹介程度で終了。</span><br /><br /><span style="font-family:'MS PGothic';">[メモ]</span><br /><span style="font-family:'MS PGothic';">どんなものかもわからないので、Webで調べてみた。</span><br /><br /><span style="font-family:'MS PGothic';"><a href="http://en.wikipedia.org/wiki/Subject-oriented_programming">サブジェクト指向プログラミング</a>(Wikipedia英語版):</span><br /><blockquote>サブジェクト指向プログラミングは、下記をサポートするようなプログラミング手法を指す。<br /><ul><li>サブジェクトの組み合わせによるオブジェクト指向システムの構築</li><li>システムの、既存サブジェクトおよび新規サブジェクトの組み合わせによる拡張</li><li>サブジェクトの組み合わせによる、システムの統合<br /></li></ul>サブジェクトの組み合わせがもたらす柔軟性によって、OOプログラムの開発やモジュール化に新たな機会がもたらされる。<br />広義のサブジェクト指向は、システムのサブジェクトへの分割や、サブジェクトを正確に組み合わせるためのルールの記述を含む。サブジェクト指向はOOPを補完し、以下のような問題を解決する。<br /><ul><li> OOPが大規模システム開発に用いられた際に発生する問題</li><li>OOPが、相互運用可能または統合されたアプリケーションスイート開発に用いられた際に発生する問題</li></ul> SOPは、サブジェクトを作る事で、プログラマの認知能力にまつわる問題も解決しようとしている。サブジェクトはその出自からして、アスペクトと大きくは違わない。アスペクトは初期に、主としてコンパイルタイムに先立ってソースを組み立てるようなコードウィーバーのコンセプトに労力を向けていたが、SOPパラダイムはクラスの組み立てに多くを依存している。</blockquote><br />なんのこっちゃ。雰囲気からすると、オブジェクト指向システムをクラスとは別の構造(サブジェクト)に分解し、サブジェクトを組み合わせることでオブジェクト指向システムを構築する、というコンセプトらしい。これも、補完的な構造(横の構造)を導入するためのパラダイムのようだ。<br /><br /><a href="http://www.alphaworks.ibm.com/tech/hyperj">Hyper/J</a>:<br />IBMによる、サブジェクト指向開発環境のJava実装らしい。暇があれば使ってみようかな。<br /><br />DCIA:<br />講演の中で出てきた、サブジェクト指向アプローチか製品のようだけど、調べてもよくわからなかった。<br />[/メモ]</div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';">■ <a href="http://domaindrivendesign.org/">DDD(Domain Driven Design)</a></span></div><div><span style="font-family:'MS PGothic';">ビジネスのモデルをそのままソフトウェアクラスの構造に反映する。ユースケースの要求はサービスとして実現することで、ビジネスのモデルを安定にできる。</span><br /><br /><span style="font-family:'MS PGothic';">[メモ]</span><br /><span style="font-family:'MS PGothic';"> DDDによる本来のサービスの定義は、ビジネスで認知されている純粋な手続きや、複数のドメインクラス(Entity/ValueObjet)にまたがる処理をサービスに記述することになっている。 </span><br /><span style="font-family:'MS PGothic';">結果的にユースケース要求がサービスに実装されることになることもあるかもしれないが、本来のDDDの意図とは少し違っているように思える。DDD本で紹介されている本でも、ユースケースによって徐々にドメインクラスを変更していっているしなぁ。このあたりはできれば直接質問したかったんだけど、できずじまい。</span><br /><span style="font-family:'MS PGothic';"> [/メモ]<br /></span></div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';">■ フィーチャ指向</span></div><div><span style="font-family:'MS PGothic';">可変点をフィーチャとして分析する。フィーチャ指向は、静的・コンパイル時バインディングが基本だが、これを動的にバインドできるようにしたものとして、コンテキスト指向というものがある。</span><br /><div><span style="font-family:'MS PGothic';"><br /></span></div><span style="font-family:'MS PGothic';">かなりさらっとした紹介で終了。もう少し掘り下げて調べてみようと思ったけど、それはそれで膨大になりそうなので今回は省略。それにしても、フィーチャ指向のフィーチャって可変点だけだっただろうか?システム自体を概念とフィーチャで分析していく手法で、フィーチャの分析として可変かどうかを調べていたような記憶があるんだけど、間違っているかもしれない…。</span></div><br /><div><span style="font-family:'MS PGothic';">■ セル生産方式</span><br /><span style="font-family:'MS PGothic';">プロセスの抽象化と再利用らしい。さらっと終了シリーズ。</span><br /><br /><span style="font-family:'MS PGothic';">[メモ]</span><br /><span style="font-family:'MS PGothic';">セル生産方式の解決する問題が、プロセスの再利用だとは知らなかった。簡単にしか紹介されなかったので、詳しいことはわからずじまい。書籍に期待。</span></div><div><span style="font-family:'MS PGothic';">[/メモ]</span><br /><br /><span style="font-family:'MS PGothic';">■ 関数型パラダイム</span><br /><span style="font-family:'MS PGothic';">すべてが関数。クラウドの普及によって、中〜長期的には重要になってくるはず。<br /></span><br /><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';">以上紹介してきたように、パラダイムは多数存在しているが、いずれにしろドメインに特化したパラダイムを選ぶのが重要。</span></div><div style="font-weight: bold;"><span style=";font-family:'MS PGothic';font-size:130%;" ><br /></span></div><div style="font-weight: bold;"><span style="font-size:130%;"><span style="font-family:'MS PGothic';">妥協のない意思決定の方法</span></span></div><div><span style="font-family:'MS PGothic';">目的-手段の階層を意識するのが重要。手段のレベルでトレードオフが発生した場合には、同じレベルでは選択できない。目的−手段階層をさかのぼり、上位の階層でトレードオフを解消できないか(まったく別の手段を取る事ができないか、目的レベルで考えると手段の1つは不要になるのでは、などなど)を考えることで、妥協せずに意思決定することができる。</span></div><div><br /><span style="font-family:'MS PGothic';">[メモ]</span><br /><span style="font-family:'MS PGothic';">これ重要っすよね。事業戦略もまったく同じで、経営レベルから自分へいたる意思決定のパスが明示されていないと、現場レベルでは判断つかないことが多い。</span><br /><span style="font-family:'MS PGothic';">[/メモ]</span><br /><span style=";font-family:'MS PGothic';font-size:130%;" ><br /></span></div><div><span style="font-size:130%;"><b><span style="font-family:'MS PGothic';">萩原さんの夢とメッセージ</span></b></span></div><div><span style="font-family:'MS PGothic';">プログラミングやインフラなどの実装に近い部分や、ビジネスや要求よりの部分は注目され、色んなことが試されているが、その間の設計の部分は意外と注目されておらず、軽視されているとも言える。ここにはまだまだ向上の可能性があるので、ここをきちんとやっていくということを夢として持っている。</span></div><div><span style="font-family:'MS PGothic';"><br /></span></div><div><span style="font-family:'MS PGothic';">みなさんへのメッセージとしては、</span><span style="font-family:'MS PGothic';">ユニーク性を持つ、ということをすすめたい。ユニーク性のない仕事は、どんどん代替可能な人材に置き換えられ、価値も下がってしまう。ユニーク性を持てば代替は不可能となり、価値を発揮できる。ぜひユニーク性を持ってください。</span><br /><br /><span style="font-size:large;"><b><span style="font-family:'MS PGothic';">雑感</span></b></span><br /><span style="font-family:'MS PGothic';"> 個人的には、一番ストライクゾーンに近かったセッション。ここ1年ほど興味を持って調べていた内容に非常に近く、自分の考えを確認しつつ新たな試みに触れることができた。もちろん、より良い整理のヒントも得ることができた。</span><br /><span style="font-family:'MS PGothic';">内容は全体に浅く広くだったとはいえ、モノの見方を紹介するという意味ではどんな人にとっても刺激になるセッションだったんじゃないだろうか。書籍「アーキテクトの審美眼」も発注したので、届いたら改めて深く掘り下げてみたい。</span><br /><br />目次:<br /><a href="http://hibituredure.blogspot.com/2009/04/qcon-tokyo-2009.html">QCon Tokyo 2009に行ってきた</a><span style="font-family:'MS PGothic';"><br /></span></div></div></div></div><span style="font-family:'MS PGothic';"></span>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-23864877.post-33344367737127061372009-04-17T20:33:00.009+09:002009-04-18T03:43:58.077+09:00Yコンビネータにトライvia <a href="http://d.hatena.ne.jp/nowokay/20090409#1239268405">おとうさん、ぼくにもYコンビネータがわかりましたよ!</a><br /><br />きしだんさんすごいっす。自分も学習のために、ラムダの復習も兼ねつつJavaScriptでトライしてみる。独学で適当にやってるので間違いも多数あると思いますが、ご容赦を。<br /><br /><span style="font-weight: bold;font-size:130%;" >ラムダ</span><br />ラムダ式は、関数の表現形式みたいなもので、おおよそfunction式に相当する。引数が複数あるのが違うところだけど、この話は後で解決する。(非形式的な)ラムダ式ってこんなもの。<br /><pre class="prettyprint">λx.x*2</pre>このラムダ式は、xを受け取ったら2倍して返す関数を表している。<br />最初は読むのに(特にλ記号が複数になった場合に)とても苦労したんだけど、引数を「λ」と「.」で挟み込む形で表現した関数だ、と考えるとずいぶん読みやすくなった。これをJavaScriptで表すと…<br /><pre class="prettyprint">function(x) { return x * 2 }<br /></pre>こうなる。ラムダ計算の体系では、計算のすべてをラムダ式であらわす。ラムダ式は関数なので、計算のすべてを関数であらわすということだ。ということで、JavaScriptから余計なものをそぎ落としていきましょー。<br /><br /><span style="font-weight: bold;font-size:130%;" >カリー化</span><br />さっきも少し出てきたけど、もともとのラムダ計算体系ではすべての関数は1引数関数として扱う。一般にラムダ計算体系では…<br /><pre class="prettyprint">f(x, y) = f(x)(y)<br /></pre>が成り立つ(理屈は省略)ので、多引数の関数はすべて1引数の関数に変換できる。こうすれば、多引数のことあんま考えなくてもいいから、世界がシンプルになる。たぶん。<br />で、カリー化とは、上記左辺の f(x, y) から f(x)(f) への変換のことを言う。Haskellとかで関数の部分適用の話が出てくるけど、Haskellの関数はすべてカリー化されている(1引数関数である)ので、部分適用といっても単に、順番に関数適用しているだけなんだと思う。<br /><br />JavaScriptの関数は引数を複数取ることができるが、上記の法則によって、必ず1引数の関数に変換できる。関数や引数が特定された形であれば、特別な機構がなくてもカリー化はできる。<br /><pre class="prettyprint">function func(x, y) { return x + y }<br /></pre>この関数を引数3でカリー化(+部分適用)したければ…<br /><pre class="prettyprint">curried_func = function(x) { return func(x, 3) }<br /></pre>こうすればいい。<br /># これをカリー化とか部分適用というかどうかは甚だ疑問だが、とりあえずイメージってことで…。<br />でも、これだと関数や引数が変わるたびにガリガリコードを書かなければいけないので、嬉しくない。どんな関数や引数でもカリー化できる機構があれば楽ちんだ。<br />JavaScriptには関数をカリー化する標準的な機構は用意されていないんだけど、カリー化する関数を作る事はできる。カリー化関数の実装にはいくつかバリエーションがあるんだけど、ここではわかりやすさを重視して <a href="http://nanto.asablo.jp/blog/2005/12/13/176033">nanto_vi</a> さんのカリー化関数を使わせていただくことにする。<br /><pre class="prettyprint">function curry(f) {<br /> if (f.length == 0) return f;<br /> function iterate(args) {<br /> if (args.length >= f.length)<br /> return f.apply(null, args);<br /> return function () {<br /> return iterate(args.concat(Array.prototype.slice.call(arguments)));<br /> };<br /> }<br /> return iterate([]);<br />}</pre>これを使えば、どんな関数でもカリー化できる。元ネタの例を拝借して、2引数の以下のような関数をカリー化してみる。<br /><pre class="prettyprint">function add(x, y) { return x + y }<br /></pre>curry関数を使って…<br /><pre class="prettyprint">var curried_add = curry(func(x, y))<br /></pre>これで、1引数関数になった。<br /><pre class="prettyprint">curried_add(1)(2)<br />> 3<br /></pre>OK。間にごちゃごちゃはさまるものの、関数は1引数だけ考えればよくなった。また1つ、世の中が単純になった。本当か?<br /><span style="font-weight: bold;font-size:130%;" ><br />ラムダで条件分岐</span><br />じゃ、次は1引数関数で条件分岐ができるようにしてみる。これができれば、if文なんていう特別な構文を用意しなくても if文相当のプログラムが書けるわけで、世界は単純なまま進行する(JavaScriptで言うなら、if文を忘れ去ることができる)わけだ。よーし、じゃあif関数みたいなものを作るぞ!こんな風に動けばいいよね。<br /><pre class="prettyprint">myIf (b)(exp1)(exp2)<br /></pre>…しかしmyIfで全部やろうとすると…<br /><pre class="prettyprint">var myIf = curry(function (b, exp1, exp2) {<br /> return b ? exp1 : exp2<br />}<br /></pre>結局は内部に if文相当のもの(ここでは3項演算子だけど)が出てきてしまう。余分なものをそぎ落とすのが基本方針なので、やはりきしださんと同じアプローチを取る。<br />関数はすべて1引数なので、if関数が条件として真偽値をとらなければならないなら、真偽値自体が実行する関数を選ばなくてはならない。とうわけで、真偽値を関数として定義する。ラムダ式で書くとこんな感じ。<br /><pre class="prettyprint">true=λx.λy.x<br />false=λx.λy.y<br /></pre> trueは、xとyを順に適用すると、xを返す関数。falseは、xとyを順番に適用するとyを返す関数として定義している。JavaScriptで書くと、こんな風になる。<br /><pre class="prettyprint">var myTrue = curry(function(x, y) { return x })<br />var myFalse = curry(function(x, y){ return y })<br />// trueやfalseは予約語だから使えない<br /></pre>さて、条件分岐を書いてみよう。せっかくだから右の扉を…じゃなくて if っぽい関数を書いてみよう。全然型安全じゃないのがアレな感じだけど、とりあえず気にしない。<br /><pre class="prettyprint">var myIf = function(x) { return x }<br />myIf(myFalse)(0)(1)<br />> 1<br /></pre>条件分岐できた。一応 (my)True も試しておく。条件分岐後に関数が実行されるようにもしてみる。<br /><pre class="prettyprint">myIf(myTrue)(curried_add(1, 2, 3))(10)<br />> 6<br /></pre>OK。なんかカッコだらけなんですけど…。言語はシンプルだけど、世の中はどんどん複雑になっていっている気も。<br /><br />さて、今のままだと、JavaScript の bool値はまったく使えない。ifを忘れ去るんだし、別になくても問題ない(というかなくしたい)んだけど、一応 JavaScript の bool と myTrue/myFalse/myIf をブリッジするための関数も用意してみる。<br /><pre class="prettyprint">var bool = function(b) { return b ? myTrue : myFalse }<br /></pre>myIf の JS boolean バージョン。<br /><pre class="prettyprint">myIf(bool(true))(curried_add(1, 2, 3))(10)<br />> 6<br /></pre>OK。振り返ってみると、真偽値自体を<br /><ul><li>Trueの場合は1番目の式を評価する関数</li><li>Falseの場合は2番目の式を評価する関数</li></ul>このように定義することで条件分岐を可能にする、というアイディアだったわけですね。たぶん。<br /><br /><span style="font-weight: bold;font-size:130%;" >ラムダでループ</span><br />やっと本題にきたよ!さて、世界をシンプルに保つために、今度は関数でループできるかやってみよう。関数だけでループするためには、再帰を使えば良いよね。<br />フィボナッチを考えてみよう。とりあえずはプレーンなJavaScriptで。<br /><pre class="prettyprint">function fib(n) {<br /> if(n < 2) { return n }<br /> else { return fib(n - 1) + fib(n - 2) }<br />} </pre>ここでは、fib関数の中で自分自身(fib)を呼び出す事で再帰を実現している。普通に関数で計算を表現するだけなら、別にこれで十分だと思う。myIfで書き直したいんだけど、自然数とか比較とか(+とかも)作ってないからとりあえずこのまま ^^;<br /><br />ただし、ラムダ計算の世界では自分自身を含む関数を定義することができない。せっかくなので、自分自身への呼び出しを取り除いて、ラムダ計算の体系に沿うように考えてみよう。<br /><br />自分自身を呼び出すように記述できないのなら、自分自身を表す関数を引数に取って、その関数を呼び出せばいいのでは?と一瞬思ったが、結局それ、自分自身を呼び出してるよな…。<br /><br />じゃあ、自分自身みたいだけど自分自身じゃない関数(fake_fibとでもしよう)が引数としてわたってきて、その関数を呼び出すことで間接的に自分自身が呼び出されるようにするのはどうだろう?JavaScriptで書くと、こんな感じ。<br /><pre class="prettyprint">function fib(fake_fib, n) {<br /> if (n < 2) { return n }<br /> else { return fake_fib(n - 1) + fake_fib(n - 2) }<br />} </pre>fake_fib(n - 1)呼び出しが、さらにfib(fake_fib, n - 1)を呼んでくれれば再帰が実現できることになるのでは?fibを g に、fake_fib を f にして簡潔に書きなおすと…<br /><pre class="prettyprint">function g(f, n) {<br /> if (n < 2) { return n }<br /> else { return f(n - 1) + f(n - 2) }<br />} </pre>こんな感じ。で、f(n - 1) が g(f, n - 1) に(1引数の世界で言えば、f が g(f) に)展開されれば再帰が実現できるはず。というわけで、展開するとg(f)になるような f、つまり<br /><pre class="prettyprint">f = g(f)<br /></pre>となるような f を見つける、という問題に帰結する。このような条件を満たす f は一般的に「不動点」と呼ばれており、以下のようなラムダ式で表すことができることが知られている。<br /><pre class="prettyprint">Y = λg.(λx.g(xx))(λx.g(xx))<br /></pre>これがいわゆるYコンビネータってやつらしい。<br /># このラムダ式がさきほどの条件を満たすことは、きしださんのところに書いてあるとおり、試してみればわかる。これをJavaScriptで書いてみると、<br /><pre class="prettyprint">function Y(f) {<br /> return function(x) {<br /> return f(x(x))<br /> }(function (x) {<br /> return f(x(x))<br /> });<br />}<br /></pre># ナンダコレハ…。<br />こうなる。これを使う形で、あらためてフィボナッチをJavaScriptでちゃんと書くと、こんな感じになる。<br /><pre class="prettyprint">var fib2 = curry(function(f, n){<br /> if(n < 2) {return n }<br /> else {return f(n - 1) + f(n - 2)}<br />}) </pre>実際に呼び出すには、Yを使ってこんな感じで呼べばいい。<br /><pre class="prettyprint">Y(fib2)(10)<br />> InternalError: too much recursion<br /></pre>しかし、こちらも同じく再帰エラー。まねっこしてZコンビネータを作ってみよう。<br /><pre class="prettyprint">function Z(f) {<br /> return function(x) {<br /> return function(m) {<br /> return f(x(x))(m)<br /> }<br /> }(function(x) {<br /> return function(m) {<br /> return f(x(x))(m)<br /> }<br /> })<br />}<br /></pre>…なんかもう慣れてきた。呼び出し。<br /><pre class="prettyprint">Z(fib2)(10)<br />> 55<br /></pre>えええ!動いちゃったよ!そりゃ動くように作ったけどさ!<br /><br />で、これで何ができるかっていうと…自分自身を参照しなくても、再帰が書ける。だから、無名関数でも再帰が書ける。他にどんな良いことがあるかというと、相変わらずよくわからない ^^; ラムダ計算の体系に沿って計算を組み立てておくことで、何か良いことがあるのだろうか。<br /><br />チャーチ数とかもやってみようと思ったけど、力尽きた。続く…かもしれない。Unknownnoreply@blogger.com0